如何分离粘连Blob?OpenCV柠檬Blob检测计数问题求助
问题:粘连Blob的检测与计数修复
我用OpenCV编写了基于HSV值检测Blob的代码,整体功能正常,但当两个Blob粘连时会被识别为一个,原本7个Blob只能检测出6个。我了解可以通过4邻域操作和形态学滤波解决该问题,但尝试对Canny边缘执行腐蚀(erode)和膨胀(dilate)操作未获成效,仅保留腐蚀会导致所有Blob消失、图像变为全黑。后来修改为对轮廓执行腐蚀操作后,Blob分离问题已解决,但仍需正确绘制红色轮廓以完成计数。
输入图像

当前分离后效果

现有代码
import cv2 import numpy as np img = cv2.imread('./lemon.png') hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) fruit_mask = cv2.inRange(hsv_img, *hsv_bounds[plant_name]) fruit_mask = cv2.cvtColor(fruit_mask, cv2.COLOR_GRAY2BGR) result = cv2.bitwise_and(img, fruit_mask) counter = {} counter['lemon'] = 0 image_gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY) image_gray = cv2.GaussianBlur(image_gray, (5, 5), 0) image_edged = cv2.Canny(image_gray, 50, 100) # kernel = np.ones((4, 4), np.uint8) image_edged = cv2.dilate(image_edged, None, iterations=1) # kernel = np.ones((4, 4), np.uint8) image_edged = cv2.erode(image_edged, None, iterations=1) cnts = cv2.findContours( image_edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] for c in cnts: if cv2.contourArea(c) < 200: continue hull = cv2.convexHull(c) img_mask = cv2.drawContours(result, [hull], 0, (0, 0, 255), 1) counter['lemon'] += 1 print(counter) cv2.imwrite('./blob_testing/detected_55.png', img_mask)
修正方案
核心问题在于形态学操作的对象和时机错误——直接对Canny边缘做开闭运算效果差,应该先对HSV生成的掩码做形态学开运算(先腐蚀后膨胀),既能有效分离粘连Blob,又能避免单个Blob被腐蚀消失,再基于处理后的掩码提取轮廓、绘制红色轮廓完成计数。
修正后的代码
import cv2 import numpy as np # 补充柠檬的HSV范围定义(原代码未给出) hsv_bounds = { 'lemon': ([20, 100, 100], [30, 255, 255]) } plant_name = 'lemon' img = cv2.imread('./lemon.png') hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 生成HSV掩码 lower_hsv, upper_hsv = hsv_bounds[plant_name] fruit_mask = cv2.inRange(hsv_img, np.array(lower_hsv), np.array(upper_hsv)) # 用开运算分离粘连Blob:先腐蚀断开连接,再膨胀恢复Blob原始大小 kernel = np.ones((3, 3), np.uint8) fruit_mask = cv2.morphologyEx(fruit_mask, cv2.MORPH_OPEN, kernel, iterations=1) # 提取外部轮廓 cnts, _ = cv2.findContours(fruit_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) counter = {'lemon': 0} result_img = img.copy() # 基于原始图像绘制轮廓,避免覆盖掩码处理结果 for c in cnts: if cv2.contourArea(c) < 200: continue # 绘制红色凸包轮廓 hull = cv2.convexHull(c) cv2.drawContours(result_img, [hull], 0, (0, 0, 255), 2) counter['lemon'] += 1 print(f"检测到柠檬数量:{counter['lemon']}") cv2.imwrite('./blob_testing/detected_final.png', result_img)
关键修改点
- 将形态学操作从Canny边缘转移到HSV掩码上,使用
MORPH_OPEN开运算自动完成“腐蚀+膨胀”流程,精准断开Blob粘连同时保留单个Blob的完整性。 - 改用原始图像绘制轮廓,避免覆盖HSV掩码处理后的有效信息。
- 补充了原代码缺失的HSV范围定义,保证代码可直接运行。
内容的提问来源于stack exchange,提问作者Josh
相关产品推荐
相关产品推荐

