You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何分离粘连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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 13:25:09