在Python的OpenCV中为已排序的轮廓匹配关联的层级结构
解决轮廓层级与排序匹配的问题
嘿,我来帮你搞定这个关联轮廓层级并排序的问题!结合你用的OpenCV 3.4.0.12和Python 3.6.3,我一步步给你讲清楚怎么做:
先补全核心代码(获取完整层级结构)
首先,你的cv2.findContours必须用cv2.RETR_TREE模式,这个模式会保留所有轮廓的完整层级关系,否则拿不到父子轮廓的关联信息。补全后的代码片段:
import copy import cv2 BLACK_THRESHOLD = 200 THIN_THRESHOLD = 10 ANNOTATION_COLOUR = (0, 0, 255) img = cv2.imread('input.png') orig = copy.copy(img) # 把数字6换成可读性更好的枚举常量 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) thresh = cv2.threshold(gray, thresh=BLACK_THRESHOLD, maxval=255, type=cv2.THRESH_BINARY_INV)[1] # 关键:用RETR_TREE获取完整层级结构 _, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
理解Hierarchy层级结构
OpenCV返回的hierarchy是一个形状为(1, N, 4)的数组(N是轮廓总数),每个轮廓对应的层级条目是[next, prev, first_child, parent]:
next:同一层级下的下一个轮廓索引,-1表示没有prev:同一层级下的上一个轮廓索引,-1表示没有first_child:当前轮廓的第一个子轮廓索引,-1表示没有子轮廓parent:当前轮廓的父轮廓索引,-1表示没有父轮廓(最外层轮廓)
关联轮廓与层级并按嵌套深度排序
我们可以给每个轮廓计算嵌套深度(比如最外层深度为0,它的子轮廓深度为1,以此类推,最内层深度最大),然后按深度排序:
1. 计算轮廓的嵌套深度
写一个小函数来迭代计算每个轮廓的深度:
def get_contour_depth(contour_idx, hierarchy): """计算指定索引轮廓的嵌套深度""" depth = 0 parent_idx = hierarchy[0][contour_idx][3] # 一直向上找父轮廓,直到没有父轮廓为止 while parent_idx != -1: depth += 1 parent_idx = hierarchy[0][parent_idx][3] return depth
2. 关联轮廓与层级信息
把每个轮廓的深度、索引、轮廓本身、层级数据打包在一起:
contour_info_list = [] for idx, (cnt, hier_entry) in enumerate(zip(contours, hierarchy[0])): depth = get_contour_depth(idx, hierarchy) # 打包成(深度,轮廓索引,轮廓对象,层级条目) contour_info_list.append( (depth, idx, cnt, hier_entry) )
3. 按嵌套深度排序
按深度降序排列,这样最内层(深度最大)的轮廓会排在最前面:
# 按深度从大到小排序 sorted_contours = sorted(contour_info_list, key=lambda x: -x[0])
提取最内层轮廓
如果你的最终目标是提取最内层轮廓,直接筛选深度最大的那些即可:
# 获取最大深度值 max_depth = max(info[0] for info in contour_info_list) # 筛选所有深度等于最大深度的轮廓(就是最内层) innermost_contours = [info[2] for info in contour_info_list if info[0] == max_depth] # 可视化验证:在原图上画出最内层轮廓 for cnt in innermost_contours: cv2.drawContours(orig, [cnt], -1, ANNOTATION_COLOUR, 2) cv2.imwrite('innermost_output.png', orig)
额外说明
- 如果你只是想找没有子轮廓的轮廓(不一定是最内层,但通常最内层都没有子轮廓),可以直接筛选
hier_entry[2] == -1的轮廓,但这种方法可能会误判(比如某些中间层轮廓也没有子轮廓),所以用深度排序更准确。 - 注意OpenCV 3.x和4.x的
findContours返回值不同,你用的3.x版本返回三个值,代码是适配的。
内容的提问来源于stack exchange,提问作者Aadit
相关产品推荐
相关产品推荐

