You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从cv2.findContours返回结果重建包含孔洞的原始图像

OpenCV轮廓还原带孔洞二值图解决方案

核心问题

你遇到的错误主要来自两点:

  • 轮廓是在带1像素padding的12x12输入图上检测的,绘制到10x10原始尺寸图时没有做坐标偏移校正
  • 没有利用轮廓层级区分外轮廓和孔洞,填充规则不符合需求

完整实现方案

如果你需要单独获取外轮廓、孔洞的坐标,使用分层绘制的方案:

import cv2
import numpy as np

# 测试数据生成
def a_small_hole_with_diagonal_border() -> np.ndarray:
    bitmask = np.zeros((10, 10), dtype=np.uint8) + 255
    indices = [(2, 2), (2, 3), (2, 4), (2, 5), (2, 6),
               (3, 4), (3, 5), (3, 6),
               (4, 4), (4, 5), (4, 6)]
    row_indices, col_indices = zip(*indices)
    bitmask[row_indices, col_indices] = 0
    bitmask[5:, 7:] = 0
    return bitmask

bitmask = a_small_hole_with_diagonal_border()
padded_bitmask = np.zeros((bitmask.shape[0] + 2, bitmask.shape[1] + 2), dtype=bitmask.dtype)
padded_bitmask[1:-1, 1:-1] = bitmask

# 检测轮廓
contours, hierarchy = cv2.findContours(
    image=padded_bitmask,
    mode=cv2.RETR_TREE,
    method=cv2.CHAIN_APPROX_SIMPLE
)

# 初始化还原画布
restored = np.zeros_like(bitmask)

for idx, cnt in enumerate(contours):
    # 校正坐标:减去padding的1像素偏移,匹配原始10x10图像坐标
    cnt_corrected = cnt - 1
    # hierarchy[0][idx][3]为-1表示当前是最外层外轮廓
    if hierarchy[0][idx][3] == -1:
        cv2.fillPoly(restored, [cnt_corrected], 255)
    # 有父轮廓的为孔洞,填充为黑色挖空
    else:
        cv2.fillPoly(restored, [cnt_corrected], 0)

# 验证还原结果和原图完全一致
print(np.array_equal(restored, bitmask)) # 输出为True

其中校正后的cnt_corrected就是你需要的孔洞最外侧边界坐标,直接使用即可。

最简实现

如果你不需要单独提取轮廓坐标,仅需还原二值图,可以直接调用cv2.drawContours自带的层级绘制能力,无需手动处理轮廓:

padded_restored = np.zeros_like(padded_bitmask)
# maxLevel=1表示绘制最外层轮廓和它的直接子级(孔洞),OpenCV自动处理填充规则
cv2.drawContours(
    padded_restored, contours, -1, 255,
    thickness=cv2.FILLED, hierarchy=hierarchy, maxLevel=1
)
# 裁剪掉padding得到最终结果
restored = padded_restored[1:-1, 1:-1]

内容的提问来源于stack exchange,提问作者RunOrVeith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 11:06:04