OpenCV不使用RETR_EXTERNAL去除形状轮廓双层重复边缘的方法问询
解决方法
核心思路是通过cv2.findContours返回的层级信息hierarchy识别成对的内外嵌套轮廓,再对对应点坐标取平均值得到合并后的轮廓。
具体实现步骤:
- 提取轮廓时保留
RETR_TREE参数,拿到完整的层级关系,层级数组的四个值分别为[下一个同层级轮廓索引, 上一个同层级轮廓索引, 第一个子轮廓索引, 父轮廓索引] - 遍历所有轮廓,筛选出有子轮廓的外层轮廓,和对应的子轮廓(内层轮廓)组成配对
- 由于内外轮廓的顶点数通常是一致的(比如空心正方形内外都是4个顶点),直接对每个对应位置的顶点坐标求平均,得到中间轮廓
- 如果顶点数不一致,可以先将轮廓点重采样到相同数量再计算平均值
修改后的代码如下:
import cv2 import numpy as np def extract_contours(): path = 'test.png' blank = np.zeros((184,184,3), np.uint8) blank[:] = (255,255,255) raw = cv2.imread(path, cv2.IMREAD_UNCHANGED) raw = 255 - raw img = cv2.cvtColor(raw, cv2.COLOR_BGR2GRAY) contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) used_indices = set() merged_contours = [] for i in range(len(contours)): if i in used_indices: continue # 获取当前轮廓的层级信息 h = hierarchy[0][i] # 有子轮廓,说明是外层轮廓,子轮廓是内层 if h[2] != -1: outer_cnt = contours[i] inner_cnt = contours[h[2]] # 过滤面积过小的轮廓 if cv2.contourArea(outer_cnt) < 400 or cv2.contourArea(inner_cnt) < 400: continue # 多边形近似,保证顶点数一致 epsilon_outer = 0.009 * cv2.arcLength(outer_cnt, True) approx_outer = cv2.approxPolyDP(outer_cnt, epsilon_outer, True) epsilon_inner = 0.009 * cv2.arcLength(inner_cnt, True) approx_inner = cv2.approxPolyDP(inner_cnt, epsilon_inner, True) # 顶点数一致直接取平均 if len(approx_outer) == len(approx_inner): merged = np.zeros_like(approx_outer) for j in range(len(approx_outer)): merged[j][0][0] = (approx_outer[j][0][0] + approx_inner[j][0][0]) // 2 merged[j][0][1] = (approx_outer[j][0][1] + approx_inner[j][0][1]) // 2 merged_contours.append(merged) # 标记已经处理过的轮廓 used_indices.add(i) used_indices.add(h[2]) # 没有子轮廓的单独轮廓直接保留 else: if cv2.contourArea(contours[i]) > 400: approx = cv2.approxPolyDP(contours[i], 0.009 * cv2.arcLength(contours[i], True), True) merged_contours.append(approx) # 绘制合并后的轮廓 for cnt in merged_contours: cv2.drawContours(blank, [cnt], 0, (0, 0, 255), 1) cv2.imwrite('contours.png', blank) extract_contours()
注意事项:
- 如果遇到内外轮廓顶点顺序不一致的情况,可以先通过匹配轮廓起始点(比如找左上角顶点对齐)再计算平均值,避免出现错位的问题
- 对于非规则的嵌套轮廓,可以先对两个轮廓做采样,生成相同数量的点后再逐个求平均,兼容性更强
内容的提问来源于stack exchange,提问作者Zhehao Chen
相关产品推荐
相关产品推荐

