2016-02-29 602 views
1

我想将我的图像分析脚本之一从Mathematica移植到Python OpenCV,但是我遇到了涉及的某个函数的问题。OpenCV简单的Blob检测器没有检测到所有的斑点

我设法将图像进行二值化和分水岭化,就像Mathematica中的一样。但是,筛选连接组件的属性的步骤似乎无法正常工作。

输入图像是如下:

Input image

然而,我试图运行下面的代码:

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) 

如该代码所示,我已经为团块的参数检测尽可能宽容。然而,大部分的斑点没有被检测到,也没有检测到分水斑点。

我检查了documentation for the function,并调整了其中的大部分阈值和repeatability(因为图像已经被二进制化)。为了让函数能够检测到所有的斑点,是否还有其他配置需要执行?

enter image description here

或者,是否有任何其他最近/孔更新的库,通过成分测量是能够过滤的?

回答

2

我知道它已经很久了,但我在这里与你有类似的任务。对如何使用width = 1行分隔连接的斑点感兴趣。

然而,我玩了一会儿与SimpleBlobDetector和它做什么是简要地执行以下步骤(从读取它的源代码):

  1. 双稳态使用不同的阈值从minThreshold图像与步骤thresholdStep到maxThreshold
  2. 找到每个二值化图像中的轮廓,在这里应用滤波器,例如区域,颜色,圆度,凸度,惯性等
  3. 结合所有过滤轮廓根据它们的位置,即距离比minDistBetweenBlobs更大和不重叠
  4. 存储并用于所有斑点返回关键点(轮廓)保持

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

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内核做腐蚀导致找到的斑点比原始斑点小1〜2个像素。我没有为此做过修正(甚至没有试图去想它)。如果你愿意,我想你可以自己做。希望这可以帮助。

test3-erosion.png

+0

@C王惊人的工作我必须尝试一下:D –