#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)