Python+OpenCV:高效排除与第一组Blob重叠的第二组Blob方案问询
问题描述
现有两张黑背景含白色目标Blob的图像,需要排除第二组中与第一组Blob存在任何重叠的所有Blob。当前暴力实现耗时高达10秒,期望达到毫秒级效率。
现有暴力实现代码:
occupied_mask = fill_countours(contours0) # 高优先级轮廓的掩码(numpy数组) contours, hierarchy = cv2.findContours(thresh2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) mask_of_a_layer = np.zeros(occupied_mask.shape) for i in range(len(contours)): tmp_mask = np.zeros(occupied_mask.shape) cv2.drawContours(tmp_mask, contours, i, color=1, thickness=cv2.FILLED) if np.sum(tmp_mask) == np.sum(tmp_mask * (1-occupied_mask)): mask_of_a_layer = (mask_of_a_layer + tmp_mask).clip(0,1) occupied_mask = (occupied_mask + mask_of_a_layer).clip(0,1)
个人思路:计算初始掩码与mask * (1 - occupied)的所有轮廓,得到两组坐标数组;计划将坐标数组转换为哈希值,求哈希集合交集后用cv2.drawContours保留符合条件的轮廓,但不确定该方案是否可行,同时希望了解更高效的实现方式。
示例场景为部分重叠的Blob,期望输出为仅保留未重叠的第二组Blob区域。
高效实现方案
方案一:掩码直接运算(最快,纯矩阵并行操作)
完全避免循环,通过opencv/numpy的矩阵级运算完成过滤,毫秒级即可完成:
- 生成第二组Blob的完整掩码(一次性填充所有轮廓)
- 直接通过位运算提取第二组中未被第一组占用的区域
- 对过滤后的掩码重新提取轮廓,即为目标结果
- 若需更新
occupied_mask,直接合并过滤后的掩码即可
代码示例:
# 生成第二组Blob的完整掩码 second_mask = np.zeros(occupied_mask.shape, dtype=np.uint8) cv2.drawContours(second_mask, contours, -1, color=255, thickness=cv2.FILLED) # 过滤掉与第一组重叠的区域 filtered_mask = cv2.bitwise_and(second_mask, cv2.bitwise_not(occupied_mask)) # 提取过滤后的有效轮廓 filtered_contours, _ = cv2.findContours(filtered_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 更新occupied_mask(如果需要) occupied_mask = cv2.bitwise_or(occupied_mask, filtered_mask)
方案二:轮廓级快速预过滤(适合轮廓数量极少的场景)
如果不想重新生成掩码,可以先通过轮廓外接矩形快速排除大概率重叠的轮廓,再对剩余轮廓做精确判断:
- 将
occupied_mask转为灰度图,用于区域检测 - 遍历每个轮廓时,先检查其外接矩形区域内是否存在第一组的白色像素
- 无重叠的直接保留;有重叠嫌疑的再做完整掩码验证
代码示例:
occupied_gray = (occupied_mask * 255).astype(np.uint8) mask_of_a_layer = np.zeros(occupied_mask.shape, dtype=np.uint8) for cnt in contours: x, y, w, h = cv2.boundingRect(cnt) # 先通过外接矩形快速排查 roi = occupied_gray[y:y+h, x:x+w] if np.any(roi == 255): # 有重叠可能,做精确验证 tmp_mask = np.zeros(occupied_mask.shape, dtype=np.uint8) cv2.drawContours(tmp_mask, [cnt], 0, 1, cv2.FILLED) if np.sum(tmp_mask * occupied_mask) == 0: cv2.drawContours(mask_of_a_layer, [cnt], 0, 1, cv2.FILLED) else: # 无重叠,直接保留 cv2.drawContours(mask_of_a_layer, [cnt], 0, 1, cv2.FILLED) occupied_mask = cv2.bitwise_or(occupied_mask, mask_of_a_layer)
关于哈希思路的可行性分析
该思路理论上可行,但完全不适合你的场景:
- 每个Blob的坐标点数量多,哈希计算、集合操作的开销远大于掩码运算
- 无法处理部分重叠的情况(你的需求是排除任何重叠的Blob,而非完全重合的),因此实际无法满足需求
内容的提问来源于stack exchange,提问作者sixtytrees
相关产品推荐
相关产品推荐

