Анализ водораздела монет - неправильный вывод - PullRequest
0 голосов
/ 05 декабря 2018

Для подсчета круглых объектов на изображении я хочу использовать алгоритм водораздела.Чтобы узнать, как это работает и как я могу использовать его для своих нужд, я искал некоторые рабочие примеры в python (https://docs.opencv.org/3.1.0/d3/db4/tutorial_py_watershed.html; http://scikit -image.org / docs / dev / auto_examples /segmentation / plot_label.html )

Наконец-то я нашел рабочее решение, которое более или менее готово для моих собственных целей ( Как определить маркеры для Водораздела вOpenCV? )

С этим кодом я получаю хорошие результаты, как с файлом примера, так и с моими собственными изображениями.Я получаю странное поведение, хотя после анализа водораздела.По некоторым причинам шаг водораздела также добавляет границу вокруг изображения.Таким образом, рядом с обнаруженными объектами обнаруживается и окрашивается весь край изображения.

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

это код:

import cv2
import numpy as np
from scipy.ndimage import label
def segment_on_dt(a, img):
    border = cv2.dilate(img, None, iterations=3)
    border = border - cv2.erode(border, None)
    dt = cv2.distanceTransform(img, cv2.DIST_L2, 3)
    dt = ((dt - dt.min()) / (dt.max() - dt.min()) * 255).astype(np.uint8)
    _, dt = cv2.threshold(dt, 200, 255, cv2.THRESH_BINARY)
    lbl, ncc = label(dt)
    # Completing the markers now. 
    lbl[border == 255] = 255 
    lbl = lbl.astype(np.int32)
    cv2.watershed(a, lbl)
    lbl[lbl == -1] = 0
    lbl = lbl.astype(np.uint8)
    return 255 - lbl

# Load image file
img = cv2.imread('coins.jpg')
# Pre-processing.
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_gray = cv2.GaussianBlur(img_gray,(5,5),0)  
width, height = img_gray.shape
_, img_bin = cv2.threshold(img_gray, 0,  255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
img_bin = cv2.morphologyEx(img_bin, cv2.MORPH_OPEN,np.ones((5, 5),     dtype=int))
result = segment_on_dt(img, img_bin)
result[result != 255] = 0
result = cv2.dilate(result, None)
img[result == 255] = (0, 0, 255)
cv2.imwrite('Img_output.png',img)

Запуск этого кода даст этот результат (по крайней мере, на моем компьютере)

Coins detected after watershed, edge of image also colored

Результат для обнаружения монет достаточно хорош для моих целей, но я немного озадачен краем изображения, которое также обнаруживается.Из того, что я вижу во время отладки, водораздел добавляет это преимущество, но мне неясно, почему это происходит.

1 Ответ

0 голосов
/ 05 декабря 2018

Вы можете исправить это, добавив метку фона, используя учебное пособие, предоставленное openCV.https://docs.opencv.org/3.1.0/d3/db4/tutorial_py_watershed.html

Они добавили дополнительный шаг для вставки определенного фона и определенной области переднего плана, чтобы помочь алгоритму водораздела правильно сегментировать области монеты.

*********** редактировать **************

После прочтения вашего кода снова.Я обнаружил, что ваш оригинальный код не имеет проблем.Фоновая метка была установлена ​​с помощью переменной border.

Вы, вероятно, получите тот же результат, выполнив код, найденный в руководстве по OpenCV.Проблема в том, как вы рисуете результаты.Так как это проблема с отображением, есть много способов решить эту проблему.Одним из многих является использование информации верного фона

Вот модификация функции сегмент_on_dt

def segment_on_dt(a, img):
    sure_background = cv2.dilate(img, None, iterations=3)
    border = sure_background - cv2.erode(sure_background, None)


    dt = cv2.distanceTransform(img, cv2.DIST_L2, 3)
    dt = ((dt - dt.min()) / (dt.max() - dt.min()) * 255).astype(np.uint8)
    _, dt = cv2.threshold(dt, 200, 255, cv2.THRESH_BINARY)
    lbl, ncc = label(dt)


    # Completing the markers now. 
    lbl[border == 255] = 255 


    lbl = lbl.astype(np.int32)
    cv2.watershed(a, lbl)
    lbl[lbl == -1] = 0
    # Only draw red line if its not in sure background
    lbl[sure_background == 0] = 255

    lbl = lbl.astype(np.uint8)
    cv2.imshow('lbl_2',lbl)

    return 255 - lbl

Я добавил новое условие длякрасные линии, которые будут нарисованы.Линия рисуется только в том случае, если она не находится в определенной фоновой области.

Ваш конечный результат должен выглядеть следующим образом.

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...