Идентификация контура с использованием OpenCV

У меня есть коллекция объектов на изображении. Проверьте образец входного изображения здесь.

Я хотел бы найти контур каждого объекта. Я следую приведенному ниже подходу к определению контура с помощью OpenCV2.

gray = cv2.cvtColor(input_image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 0)
edged = cv2.Canny(gray, 50, 100)
dilate= cv2.dilate(edged, None, iterations=1)
erode= cv2.erode(dilate, None, iterations=1)
cnts = cv2.findContours(erode, cv2.RETR_EXTERNAL,
        cv2.CHAIN_APPROX_SIMPLE)

Это вывод контура, который я получаю для приведенного выше кода: см. выходное изображение

Есть ли лучший подход для идентификации объекта на изображении?


person Rayees Ck    schedule 10.10.2018    source источник
comment
Вы можете попробовать суперпиксельную сегментацию и выбрать суперпиксели, которые цветовую гистограмму, похожую на внутреннюю часть яблока, и отклонить те, у которых внешний вид похож на яблочный, который вы можете примерно определить с некоторой предварительной обработкой и пороговым значением. Автоматизированный способ — это алгоритм GrabCut. Для лучшего качества ищите нейронные сети для семантической сегментации объектов.   -  person Slowpoke    schedule 10.10.2018
comment
Например, в одном из своих ранних проектов я написал приложение, в котором я мог исправить некорректную сегментацию суперпикселей, вручную выбирая/снимая выделение с суперпикселей с помощью мыши, и сохранять полученную бинарную маску. После того, как у меня было около сотни реальных примеров (изображение и бинарная маска), я обучил нейронную сеть pip2pix с изображением в качестве входных данных и маской в ​​качестве выходных данных.   -  person Slowpoke    schedule 10.10.2018


Ответы (1)


Вы пропустили простой шаг в своем фрагменте кода, cv2.findContours() лучше всего работает с бинарными изображениями, но вы просто передаете изображение в градациях серого cv2.findContours. Я выполнил следующие шаги, чтобы отделить яблоки от фона:

Шаг 1: Отделите фон, который в основном содержит пиксели в оттенках серого.

Здесь вы можете использовать цветовой домен HSV, где низкое значение насыщенности приведет к сегментации фона следующим образом:

img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV_FULL)

# Filter out low saturation values, which means gray-scale pixels(majorly in background)
bgd_mask = cv2.inRange(img_hsv, np.array([0, 0, 0]), np.array([255, 30, 255]))

введите описание изображения здесь

Шаг 2: Для черных как смоль пикселей значение насыщенности было резким, поэтому мы сегментировали крайние черные и белые пиксели:

# Get a mask for pitch black pixel values
black_pixels_mask = cv2.inRange(img_bgr, np.array([0, 0, 0]), np.array([70, 70, 70]))

# Get the mask for extreme white pixels.
white_pixels_mask = cv2.inRange(img_bgr, np.array([230, 230, 230]), np.array([255, 255, 255]))

«Маска Маска белых пикселей

Шаг 3: Объедините эти маски, чтобы получить окончательную маску для cv2.findContours:

final_mask = cv2.max(bgd_mask, black_pixels_mask)
final_mask = cv2.min(final_mask, ~white_pixels_mask)
final_mask = ~final_mask

Объединенная маска

Шаг 4: Теперь, чтобы заполнить дыры, мы размываем и расширяем изображение:

final_mask = cv2.erode(final_mask, np.ones((3, 3), dtype=np.uint8))
final_mask = cv2.dilate(final_mask, np.ones((5, 5), dtype=np.uint8))

введите описание изображения здесь

Шаг 5: Используйте cv2.findContours(), чтобы получить контуры и отфильтровать их по области, чтобы удалить меньшие:

# Now you can finally find contours.
im, contours, hierarchy = cv2.findContours(final_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

final_contours = []
for contour in contours:
    area = cv2.contourArea(contour)
    if area > 2000:
        final_contours.append(contour)

Шаг 6: Покажите окончательные контуры

Окончательный результат

Вот полный фрагмент кода:

import cv2
import numpy as np

img_bgr = cv2.imread("/home/anmol/Downloads/tWuTW.jpg")
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV_FULL)

# Filter out low saturation values, which means gray-scale pixels(majorly in background)
bgd_mask = cv2.inRange(img_hsv, np.array([0, 0, 0]), np.array([255, 30, 255]))

# Get a mask for pitch black pixel values
black_pixels_mask = cv2.inRange(img_bgr, np.array([0, 0, 0]), np.array([70, 70, 70]))

# Get the mask for extreme white pixels.
white_pixels_mask = cv2.inRange(img_bgr, np.array([230, 230, 230]), np.array([255, 255, 255]))

final_mask = cv2.max(bgd_mask, black_pixels_mask)
final_mask = cv2.min(final_mask, ~white_pixels_mask)
final_mask = ~final_mask

final_mask = cv2.erode(final_mask, np.ones((3, 3), dtype=np.uint8))
final_mask = cv2.dilate(final_mask, np.ones((5, 5), dtype=np.uint8))

# Now you can finally find contours.
im, contours, hierarchy = cv2.findContours(final_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

final_contours = []
for contour in contours:
    area = cv2.contourArea(contour)
    if area > 2000:
        final_contours.append(contour)


for i in xrange(len(final_contours)):
    img_bgr = cv2.drawContours(img_bgr, final_contours, i, np.array([50, 250, 50]), 4)


debug_img = img_bgr
debug_img = cv2.resize(debug_img, None, fx=0.3, fy=0.3)
cv2.imwrite("./out.png", debug_img)
person ZdaR    schedule 10.10.2018
comment
Отличный подход! +1 - person kavko; 10.10.2018
comment
Спасибо за ответ. Я проверил с другим изображением, но определение контура было не очень хорошим. Вы можете помочь с этим? Для справки проверьте входное и выходное изображение: imgur.com/a/jG4Wb4r - person Rayees Ck; 10.10.2018
comment
Я только что предоставил вам отправную точку, очевидно, вам нужно будет поэкспериментировать с множеством разных изображений, чтобы получить некоторые общие значения для этого скрипта, я настроил значения только для данного изображения. Вы можете взять концепции отсюда и настроить значения в соответствии с вашими потребностями. Главный вывод: поскольку ваш фон черного цвета, попробуйте сначала его разделить, а не яблоки. Вы также можете попробовать другие цветовые домены, такие как YCrCb, LAB и т. д. - person ZdaR; 11.10.2018
comment
Спасибо за предложение. Буду пробовать другими методами. - person Rayees Ck; 11.10.2018