трудности cv2 SimpleBlobDetector

#python #image-processing #image-segmentation #cv2

#python #обработка изображений #сегментация изображений #cv2

Вопрос:

Я пытаюсь обнаружить несколько точек на некоторых кубиках для хобби-проекта. Кости красиво вырезаны, и есть более или менее хорошие их фотографии.

обрезанное изображение матрицы

Затем фотографии масштабируются серым цветом, обрабатываются срединным фильтром для защиты от шума и 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
 

Помеченное изображение матрицы

Комментарии:

1. Вы, вероятно, неправильно понимаете, что делает простой детектор больших двоичных объектов. Но эти пункты действительно понятны. Почему не просто пороговое значение?

2. У меня кости разного цвета. Они здесь действительно выскакивают, да. Я также боюсь, что в некоторых случаях threshold будет захватывать пипсы на стороне. Что я неправильно понимаю в детекторе больших двоичных объектов, пожалуйста?

Ответ №1:

Хорошо, и решение таково:

Некоторые параметры задаются еще до того, как вы начнете. Эти параметры оптимизированы для поиска темных и круглых больших двоичных объектов на светлом фоне. На моем изображении это не так! Это застало меня врасплох — после распечатки каждого отдельного параметра и исправления всего, что не соответствовало моему варианту использования, я, наконец, смог использовать эту функцию. Теперь он легко находит пипсы кубиков на нескольких разных типах кубиков, я пробовал.

Это было бы проще, если бы список параметров OpenCV был бы немного более доступным, например, как dict, или лучше прокомментирован.

Я оставлю свой код здесь — он содержит полный список параметров, которые использует эта функция, в комментариях также указано, как использовать некоторые из них, и функцию для использования функции. Я также оставляю здесь ссылку на документацию SimpleBlobDetector, поскольку ее довольно сложно найти в сети.

Исходя из фона C / C , эта функция совершенно не pythonic. Он не принимает все форматы изображений, как это было бы нормально в контексте python, вместо этого ему нужен очень специфический тип данных. В python, по крайней мере, он сказал бы вам, чего он хочет, но эта функция молчит, чтобы не разрушить загадку. Затем он выдает исключение без объяснения причин.

Итак, я создавал функцию, которая, по крайней мере, принимает numpy в цветном и черно-белом формате, а также PIL.Изображение. Это немного повышает удобство использования этой функции.

OpenCV, когда вы читаете это — обычно в python для каждой функции предоставляется читаемый текст в «тройных метках». Акцент на «читаемый».

 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)
 

умри с 5 сверху
изображение кости с отмеченными точками