cv2 SimpleBlobDetector 困难

cv2 SimpleBlobDetector difficulties

我尝试在业余爱好项目中检测一些骰子上的一些点。 骰子切得很好,也有或多或少的好照片。

然后将照片灰度化,中值滤镜抗噪,做成np.array让cv2喜欢

现在我尝试计算点数,然后......好吧...... SimpleBlobDetector 根据参数的精确调整,发现到处都是斑点,或者根本没有斑点,而且从来没有发现那些最明显的点最佳。特别是如果我激活“圆度”大于 0.7 或“惯性”,它什么也找不到。

这是怎么回事?我需要进一步预处理我的图片,还是在下面的参数中?

我尝试用高斯模糊交换滤镜,我还尝试对图像进行色调分离,以获得具有完全相同灰度值的相当大的区域。没有任何帮助。

我现在尝试了很多变体,当前的变体结果如下图所示。

blob_params = cv2.SimpleBlobDetector_Params()
blob_params.minDistBetweenBlobs = 1
blob_params.filterByCircularity = True
blob_params.minCircularity = 0.5

blob_params.minThreshold = 1
blob_params.thresholdStep = 1
blob_params.maxThreshold = 255
#blob_params.filterByInertia = False
#blob_params.minInertiaRatio = 0.2

blob_params.minArea = 6
blob_params.maxArea = 10000
detector = cv2.SimpleBlobDetector_create(blob_params)

keypoints = detector.detect(die_np) # detect blobs... just it doesn't work

image = cv2.drawKeypoints(die_np, 
                                   keypoints, 
                                   np.array([]), 
                                   (255,255,0), 
                                         cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

im = Image.fromarray(image)
im

好的,解决方案是:

有些参数甚至在您开始之前就设置好了。这些参数针对在浅色背景中查找深色和圆形斑点进行了优化。在我的形象中不是这样!这让我感到惊讶 - 在打印出每个参数并更正所有不适合我的用例的内容后,我终于能够使用此功能。现在它很容易找到几种不同类型的骰子上的骰子点,我试过了。

如果 openCV 参数列表更易于访问,例如 dict 或更好的注释,这会更容易。

我将在此处留下我的代码 - 它包含此函数使用的参数的完整列表,在注释中还说明了如何使用其中的一些参数,以及使用该函数的函数。我也留下了the link to the simpleBlobDetector documentation here,网上有点难找

来自C/C++背景,这个功能完全不是pythonic。它不接受所有图像格式,因为它在 python 上下文中是正常的,相反它需要一个非常特定的数据类型。在 python 中至少它会告诉你它想要什么,但是这个函数保持安静以免破坏谜语。然后它继续抛出异常而没有解释。

所以我正在制作一个函数,该函数至少接受彩色和 black/white 格式的 numpy,以及 PIL.Image。这使该功能的可用性提高了一点。

OpenCV,当您阅读本文时 - 通常在 python 中为“'triple marks'”中的每个函数提供可读文本。强调“可读性”。

import cv2
import numpy as np
from PIL import Image

def blobize(im, blob_params):
    '''
    Takes an image and tries to find blobs on this image. 


    Parameters
    ----------
    im : nd.array, single colored. In case of several colors, the first
    color channel is taken. Alternatively you can provide an 
    PIL.Image, which is then converted to "L" and used directly.
    
    blob_params : a cv2.SimpleBlobDetector_Params() parameter list

    Returns
    -------
    blobbed_im : A greyscale image with the found blobs circled in red
    keypoints : an OpenCV keypoint list.

    '''
    if Image.isImageType(im):
        im = np.array(im.convert("L"))
    if isinstance(im, np.ndarray):
        if (len(im.shape) >= 3 
        and im.shape[2] > 1):
            im = im[:,:,0]
        
    detector = cv2.SimpleBlobDetector_create(blob_params)
    try:
        keypoints = detector.detect(im)
    except:
        keypoints = None
    if keypoints:    
        blobbed_im = cv2.drawKeypoints(im, keypoints, np.array([]), 
                    (255,0,0), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
    else:
        blobbed_im = im
    return blobbed_im, keypoints

blob_params = cv2.SimpleBlobDetector_Params()

# images are converted to many binary b/w layers. Then 0 searches for dark blobs, 255 searches for bright blobs. Or you set the filter to "false", then it finds bright and dark blobs, both.
blob_params.filterByColor = False
blob_params.blobColor = 0 

# Extracted blobs have an area between minArea (inclusive) and maxArea (exclusive).
blob_params.filterByArea = True
blob_params.minArea = 3. # Highly depending on image resolution and dice size
blob_params.maxArea = 400. # float! Highly depending on image resolution.

blob_params.filterByCircularity = True
blob_params.minCircularity = 0. # 0.7 could be rectangular, too. 1 is round. Not set because the dots are not always round when they are damaged, for example.
blob_params.maxCircularity = 3.4028234663852886e+38 # infinity.

blob_params.filterByConvexity = False
blob_params.minConvexity = 0.
blob_params.maxConvexity = 3.4028234663852886e+38

blob_params.filterByInertia = True # a second way to find round blobs.
blob_params.minInertiaRatio = 0.55 # 1 is round, 0 is anywhat 
blob_params.maxInertiaRatio = 3.4028234663852886e+38 # infinity again

blob_params.minThreshold = 0 # from where to start filtering the image
blob_params.maxThreshold = 255.0 # where to end filtering the image
blob_params.thresholdStep = 5 # steps to go through
blob_params.minDistBetweenBlobs = 3.0 # avoid overlapping blobs. must be bigger than 0. Highly depending on image resolution! 
blob_params.minRepeatability = 2 # if the same blob center is found at different threshold values (within a minDistBetweenBlobs), then it (basically) increases a counter for that blob. if the counter for each blob is >= minRepeatability, then it's a stable blob, and produces a KeyPoint, otherwise the blob is discarded.

res, keypoints = blobize(im2, blob_params)