OpenCV中pointPolygonTest误判轮廓内外,合并轮廓是否合理?
问题解答
合并轮廓是否可行?
完全不可行。findContours返回的每个轮廓都是具有闭合拓扑结构的独立多边形(可能是外轮廓、内孔,或是分离的独立对象),用numpy.concatenate直接合并会把所有轮廓点打乱成无序的点集合,彻底破坏了多边形的边界结构,pointPolygonTest根本无法基于这种混乱的点集判断点的位置关系,这就是你得到错误结果的核心原因。
正确的点内外判断方案
需要根据轮廓的实际类型(带内孔的单对象/多独立对象)分别处理:
场景1:轮廓是带内孔的单个对象
OpenCV的findContours会通过hierarchy参数返回轮廓的层级关系,外轮廓和内孔是父子层级。判断点是否在对象内部,需要同时满足:点在外轮廓内部,且不在任何内孔内部。
实现步骤
- 调用
findContours时指定能获取层级的检索模式(如cv2.RETR_CCOMP或cv2.RETR_TREE),拿到contours和hierarchy; - 遍历所有轮廓,区分外轮廓(层级中父节点索引为-1的)和内孔(父节点对应外轮廓索引的);
- 对目标点,先判断是否在外轮廓内部,再检查是否不在所有内孔内部,同时满足则判定为在对象内部。
场景2:轮廓是多个独立的分离对象
只要点处于任意一个轮廓的内部,就判定为在目标区域内。
代码示例
import cv2 import numpy as np # 假设已得到二值化图像binary_img contours, hierarchy = cv2.findContours(binary_img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) test_point = (100, 100) # 场景1:处理带内孔的单对象 is_inside = False for i in range(len(contours)): # 筛选外轮廓(无父节点) if hierarchy[0][i][3] == -1: # 判断点是否在外轮廓内(measureDist=False返回1/0/-1,效率更高) outer_result = cv2.pointPolygonTest(contours[i], test_point, measureDist=False) if outer_result > 0: # 检查所有内孔 in_hole = False j = hierarchy[0][i][2] # 获取第一个子轮廓(内孔)的索引 while j != -1: hole_result = cv2.pointPolygonTest(contours[j], test_point, measureDist=False) if hole_result > 0: in_hole = True break j = hierarchy[0][j][0] # 遍历下一个同级内孔 if not in_hole: is_inside = True break # 场景2:处理多个独立对象(直接遍历所有轮廓) # is_inside = any(cv2.pointPolygonTest(contour, test_point, measureDist=False) > 0 for contour in contours) print(f"点是否在目标区域内: {is_inside}")
关键注意事项
- 轮廓检索模式要匹配场景:带内孔用
cv2.RETR_CCOMP/cv2.RETR_TREE,多独立对象可以用cv2.RETR_EXTERNAL(只取外轮廓)或cv2.RETR_LIST; - 仅做内外判断时,把
pointPolygonTest的measureDist设为False,能大幅提升运行效率。
内容的提问来源于stack exchange,提问作者Erfan Hamdi
相关产品推荐
相关产品推荐

