如何快速筛选同时接触图像顶部与底部的OpenCV轮廓?
优化同时接触图像顶底部的轮廓筛选效率的建议
处理的目标图像:
需求是获取所有同时接触图像顶部和底部的轮廓列表,当前实现是先提取所有轮廓再遍历筛选,以下是具体优化方案:
一、直接优化现有筛选逻辑
当前代码中0 in contour[:,0,1]和rows in contour[:,0,1]会遍历轮廓所有点的y坐标,效率较低。利用numpy的向量化操作直接取轮廓y坐标的最小/最大值,能大幅提升判断速度:
import cv2 import numpy as np contours, hier = cv2.findContours(projection, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 改用外轮廓+压缩点格式 validContours = [] rows = projection.shape[0] # 获取图像行数(底部y坐标为rows-1) for contour in contours: y_coords = contour[:, 0, 1] min_y = y_coords.min() max_y = y_coords.max() # 检查是否同时接触顶部(y=0)和底部(y=rows-1) if min_y == 0 and max_y == rows - 1: validContours.append(contour)
额外优化点:
- 用
cv2.RETR_EXTERNAL替代cv2.RETR_LIST:只提取外轮廓,减少轮廓总数 - 用
cv2.CHAIN_APPROX_SIMPLE替代cv2.CHAIN_APPROX_NONE:压缩轮廓点数量,降低内存占用和计算量
二、基于FloodFill的定向筛选方案
如果图像中不符合条件的轮廓占比高,这种方法能避免提取所有轮廓,直接定位符合要求的连通区域:
import cv2 import numpy as np projection = ... # 你的输入二值图像 rows, cols = projection.shape validContours = [] mask = np.zeros((rows, cols), dtype=np.uint8) # 获取顶部和底部的前景像素列坐标 top_foreground = np.where(projection[0, :] > 0)[0] bottom_foreground = np.where(projection[-1, :] > 0)[0] # 遍历顶部前景像素,执行FloodFill并检查是否连通到底部 for x in top_foreground: if mask[0, x] == 0: # 填充当前连通区域到掩码 _, filled_mask, _, _ = cv2.floodFill(projection, mask, (x, 0), 255) # 检查填充区域是否接触底部 if np.any(filled_mask[-1, :] == 255): # 从填充后的掩码提取轮廓 cnts, _ = cv2.findContours(filled_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) validContours.extend(cnts)
三、自定义连通区域分析(可选)
如果需要极致性能,可以用并查集(Union-Find)实现连通区域标记:
- 遍历图像,标记所有前景像素的连通关系
- 收集顶部前景像素所在的连通组,检查这些组是否包含底部前景像素
- 提取对应连通组的轮廓
这种方法适合大规模图像的批量处理,但实现复杂度较高,OpenCV内置函数已能满足大部分场景需求。
内容的提问来源于stack exchange,提问作者lchavez
相关产品推荐
相关产品推荐

