【问题标题】:OpenCV Simple Blob Detector not detecting all blobsOpenCV 简单 Blob 检测器未检测到所有 Blob
【发布时间】:2016-02-29 09:10:52
【问题描述】:

我正在尝试将我的一个图像分析脚本从 Mathematica 移植到 Python OpenCV,但是我在使用其中一个函数时遇到了问题。

我设法对图像进行二值化和分水岭处理,就像在 Mathematica 中所做的那样。但是,过滤连接组件属性的步骤似乎无法正常工作。

输入图片如下:

但是,我尝试运行以下代码:

import cv2
import numpy as np

img = cv2.imread('test2.4.png', 1)
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Set up the detector and configure its params.
params = cv2.SimpleBlobDetector_Params()
params.minDistBetweenBlobs = 0
params.filterByColor = True
params.blobColor = 255
params.filterByArea = True
params.minArea = 10
params.maxArea = 300000
params.filterByCircularity = False
params.filterByConvexity = False
params.filterByInertia = True
params.minInertiaRatio = 0.01
params.maxInertiaRatio = 1
detector = cv2.SimpleBlobDetector_create(params)

# Detect blobs.
keypointsb = detector.detect(img)

# Draw detected blobs as red circles.
im_with_keypoints = cv2.drawKeypoints(img, keypointsb, np.array([]), (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

# Show keypoints
cv2.imwrite('test3.png',im_with_keypoints)

从代码中可以看出,我已将 blob 检测的参数设置为尽可能宽松。但是,没有检测到很大比例的斑点,也没有检测到分水岭分裂的斑点。

我检查了documentation for the function 并调整了大多数,除了阈值和repeatability(因为图像已经二值化了)。为了让函数检测所有存在的 blob,我应该执行任何其他配置吗?

或者,是否有任何其他最近/更新良好的库能够通过组件测量进行过滤?

【问题讨论】:

    标签: python opencv computer-vision


    【解决方案1】:

    我知道这已经很久了,但我在这里和你有类似的任务。对如何使用 width=1 线来分隔这些连接的 blob 感兴趣。

    不过,我用 SimpleBlobDetector 玩了一会儿,它所做的只是简单地执行以下步骤(通过阅读它的源代码):

    1. 使用从 minThreshold 到 maxThreshold 的不同阈值(步长为 thresholdStep)对图像进行二值化
    2. 在每个二值化图像中找到轮廓,在这里应用过滤器,例如面积、颜色、圆度、凸度、惯性等。
    3. 根据位置组合所有过滤轮廓,即距离大于 minDistBetweenBlobs 且不重叠
    4. 为所有保留的 blob(轮廓)存储和返回关键点

    因此,我使用以下简单代码检查了 SimpleBlobDetector 的每个步骤,发现用于分隔连接的 blob 的 width=1 线被发现为单独的轮廓/blob(轮廓/blob 显示为红色和轮廓/斑点的中心在附加图像中显示为绿色),尤其是对于非水平/垂直线(1 像素轮廓)。然后这些小轮廓被 minArea 或 blobColor = 255 过滤掉。这就是为什么你的分裂 blob 被检测为更大的 blob。

    import cv2
    import numpy as np
    
    img = cv2.imread('test3.png', 1)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    ret, bin_img = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
    
    out_img = img
    temp_bin_img = bin_img.copy()
    ret, contours = cv2.findContours(temp_bin_img, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
    for i in range(len(contours)):
        M = cv2.moments(contours[i])
        if(M['m00'] == 0.0):
            continue
        x, y = int(M['m10'] / M['m00']), int(M['m01'] / M['m00'])
    
        out_img = cv2.drawContours(out_img, contours, i, (0,0,255), 1)
        cv2.circle(out_img, (x, y), 1, (0,255,0), -1)
    
    cv2.imwrite('test3-contours.png', out_img)
    

    test3-contours.png

    为了改进,可能先尝试侵蚀以增加边界的宽度,然后使用 SimpleBlobDetector 或自己使用 findContours。像这样:

    import cv2
    import numpy as np
    
    img = cv2.imread('YUSAQ.png', 1)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    ret, bin_img = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
    
    kernel = np.ones((3,3),np.uint8)
    erosion = cv2.erode(bin_img, kernel, iterations = 1)
    
    out_img = img
    temp_bin_img = erosion.copy()
    ret, contours = cv2.findContours(temp_bin_img, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
    for i in range(len(contours)):
        M = cv2.moments(contours[i])
        if(M['m00'] == 0.0):
            continue
        x, y = int(M['m10'] / M['m00']), int(M['m01'] / M['m00'])
    
        out_img = cv2.drawContours(out_img, contours, i, (0,0,255), 1)
        cv2.circle(out_img, (x, y), 1, (0,255,0), -1)
    
    cv2.imwrite('test3-erosion.png', out_img)
    

    使用 3x3 内核进行侵蚀会导致发现的 blob 比原始 blob 小 1~2 个像素。我没有对此进行更正(甚至没有想过)。如果你愿意,我想你可以自己做。希望这会有所帮助。

    test3-erosion.png

    【讨论】:

      猜你喜欢
      • 2019-11-21
      • 2017-11-21
      • 1970-01-01
      • 1970-01-01
      • 2018-07-08
      • 2018-08-10
      • 2021-02-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多