Выявление несовершенных форм с шумным фоном с помощью OpenCV - PullRequest
1 голос
/ 19 июня 2019

Я пытаюсь определить прямоугольник под водой в шумной обстановке.Я реализовал Canny, чтобы найти края, и нарисовал найденные края, используя cv2.circle.Отсюда я пытаюсь определить несовершенный прямоугольник на изображении (черный под длинным прямоугольником, который покрывает верхнюю часть кадра)

rectangle

Я попытался несколько решений, включая пороги, размытие и изменение размера изображения, чтобы обнаружить прямоугольник.Ниже приведен код «barebones» с простым рисованием идентифицированных ребер.

import numpy as np
import cv2
import imutils

img_text = 'img5.png'
img = cv2.imread(img_text)
original = img.copy()

min_value = 50
max_value = 100

# draw image and return coordinates of drawn pixels
image = cv2.Canny(img, min_value, max_value)
indices = np.where(image != 0)
coordinates = zip(indices[1], indices[0])

for point in coordinates:
    cv2.circle(original, point, 1, (0, 0, 255), -1)

cv2.imshow('original', original)
cv2.waitKey(0)
cv2.destroyAllWindows()

Где вывод отображает это:

output

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

1 Ответ

2 голосов
/ 19 июня 2019

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

image = cv2.imread("test.png")
t, img = cv2.threshold(image[:,:,0], 80, 255, cv2.THRESH_BINARY)

enter image description here


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

def find_square(image):

    markers = 0
    threshold = 10

    while np.amax(markers) == 0:
        threshold += 5
        t, img = cv2.threshold(image[:,:,0], threshold, 255, cv2.THRESH_BINARY_INV)
        _, markers = cv2.connectedComponents(img)

    kernel = np.ones((5,5),np.uint8)

    img = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
    img = cv2.morphologyEx(img, cv2.MORPH_DILATE, kernel)

    nonzero = cv2.findNonZero(img)
    x, y, w, h = cv2.boundingRect(nonzero)
    cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)

    cv2.imshow("image", image)

А результаты на предоставленных примерах изображений:

enter image description here enter image description here enter image description here

Идея этого подхода основана на наблюдении, что большая часть информации находится в синем канале. Если вы разделите изображения в каналах, вы увидите, что в синем канале темный квадрат имеет наилучшую контрастность. Это также самая темная область на этом канале, поэтому порог работает. Проблема остается в настройке порога. Основываясь на вышеизложенной интуиции, мы ищем самый низкий порог, который будет что-то вызывать (и надеемся, что это будет квадрат). Я просто постепенно увеличивал порог, пока что-то не появилось.

Затем я применил некоторые морфологические операции, чтобы убрать другие маленькие точки, которые могут появиться после установки порога, и чтобы квадрат выглядел немного больше (края квадрата светлее, и поэтому захватывается не весь квадрат). Тогда нужно было нарисовать прямоугольник.

Код можно сделать намного лучше (и эффективнее), выполнив некоторый статистический анализ гистограммы. Просто вычислите порог так, чтобы 5% (или несколько процентов) пикселей были темнее. Вам может потребоваться выполнить анализ связанных компонентов, чтобы сохранить самый большой двоичный объект.

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

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