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

如何使用OpenCV去除图像中的内部轮廓与边界轮廓?

解决OpenCV findContours去除边界与内部轮廓的问题

我明白你现在的需求:用findContours提取轮廓后,想要剔除掉图像的边界大轮廓,以及目标内部的孔洞轮廓,只保留中间有效的轮廓。下面我来一步步帮你实现这个需求。

核心思路:利用轮廓层级(Hierarchy)筛选

当你使用cv.RETR_TREE模式提取轮廓时,findContours会返回一个hierarchy数组,每个轮廓对应的层级信息是[next, prev, first_child, parent],我们可以通过这个信息区分不同类型的轮廓:

  • 边界轮廓:通常是面积接近图像大小的最外层轮廓(对应层级中parent=-1,且面积极大)
  • 内部孔洞轮廓:属于某个外层轮廓的子轮廓(parent!=-1),且自身没有子轮廓(child=-1)

修改后的完整代码

import numpy as np
import cv2 as cv

# 读取图像并预处理
im = cv.imread('0.jpg')
imgray = cv.cvtColor(im, cv.COLOR_BGR2GRAY)
blur = cv.GaussianBlur(imgray,(5,5),0)
ret3,thresh = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)

# 提取轮廓与层级信息
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

filtered_contours = []
img_area = im.shape[0] * im.shape[1]  # 计算图像总面积

for cnt, hier in zip(contours, hierarchy[0]):
    cnt_area = cv.contourArea(cnt)
    # 1. 排除图像边界的大轮廓(面积超过图像90%的基本就是边界)
    if cnt_area > 0.9 * img_area:
        continue
    # 2. 排除内部孔洞轮廓:有父轮廓但没有子轮廓的轮廓
    parent_idx = hier[3]
    child_idx = hier[2]
    if parent_idx != -1 and child_idx == -1:
        continue
    # 保留符合要求的轮廓
    filtered_contours.append(cnt)

# 绘制并保存筛选后的轮廓
cv.drawContours(im, filtered_contours, -1 ,(0,0,255), 1)
cv.imwrite('image.jpg',im)

代码解释

  1. 预处理部分:保留了你原来的高斯模糊+OTSU阈值分割逻辑,这部分没问题,能很好地提取目标轮廓。
  2. 轮廓筛选:
    • 用面积判断排除边界轮廓:因为图像边界的轮廓面积几乎等于图像本身的面积,用90%的阈值可以有效过滤掉它,同时不会误删正常的外层目标轮廓。
    • 用层级信息排除内部孔洞:内部孔洞是外层轮廓的子轮廓,且自身没有下一级子轮廓,通过parent_idx != -1和child_idx == -1可以精准识别这类轮廓。
  3. 绘制轮廓:只绘制筛选后的filtered_contours,就得到了你想要的结果。

如果你对轮廓的层级关系还有疑问,可以打印hierarchy数组看看每个轮廓的层级值,这样能更直观地理解不同轮廓的结构~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:44:35