Я пытаюсь идентифицировать прямоугольник под водой в шумной обстановке. Я реализовал Canny для поиска ребер и нарисовал найденные ребра с помощью cv2.circle. Отсюда я пытаюсь определить несовершенный прямоугольник на изображении (черный под длинным прямоугольником, закрывающим верхнюю часть кадра).
Я пробовал несколько решений, включая пороги, размытие и изменение размера изображения для обнаружения прямоугольника. Ниже приведен базовый код, в котором просто отрисованы идентифицированные ребра.
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()
Где вывод отображает это:
Отсюда я хочу иметь возможность отдельно обнаруживать только прямоугольник и рисовать другой прямоугольник поверх вывода зеленым цветом, но я не смог найти способ обнаружить исходный прямоугольник самостоятельно.
Я думаю, что OP пытается обнаружить этот темный прямоугольник, вероятно, хочет получить ограничивающую рамку вокруг него.
@nathancy Верно.
Для вашего конкретного изображения я получил неплохие результаты с помощью простой пороговой обработки на синем канале.
image = cv2.imread("test.png")
t, img = cv2.threshold(image[:,:,0], 80, 255, cv2.THRESH_BINARY)
Чтобы адаптировать порог, я предлагаю простой способ варьирования порога, пока вы не получите один компонент. Я также реализовал рисунок прямоугольника:
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)
И результаты на предоставленных примерах изображений:
Идея этого подхода основана на наблюдении, что большая часть информации содержится в синем канале. Если вы разделите изображения по каналам, то увидите, что в синем канале темный квадрат имеет наилучший контраст. Это также самая темная область на этом канале, поэтому работает пороговое значение. Проблема остается в настройке порога. Основываясь на вышеизложенной интуиции, мы ищем самый нижний порог, который что-то выведет (и надеемся, что это будет квадрат). Я просто постепенно увеличивал порог, пока что-то не появилось.
Затем я применил некоторые морфологические операции, чтобы устранить другие мелкие точки, которые могут появиться после пороговой обработки, и сделать квадрат немного больше (края квадрата светлее, поэтому не весь квадрат захвачен). Затем нужно было нарисовать прямоугольник.
Код можно сделать намного лучше (и эффективнее), выполнив статистический анализ гистограммы. Просто вычислите порог таким образом, чтобы 5% (или несколько процентов) пикселей были темнее. Вам может потребоваться анализ подключенных компонентов, чтобы сохранить самый большой двоичный объект.
Кроме того, мое использование ConnectedComponents очень плохое и неэффективное. Опять же, код написан в спешке, чтобы доказать концепцию.
( imgur.com/a/SBLQIda ) ( imgur.com/a/9milAWb ) Используя Canny, эти другие прямоугольники успешно подобраны. Как можно было бы соответствующим образом отрегулировать порог? Если я изменю диапазон с изображения (..., 80, 255,...) на изображение (..., 100, 255,...), я смогу выбрать прямоугольник. Есть ли другие методы? Кроме того, что вы имеете в виду, находя координаты с помощью canny? Спасибо за помощь
Вы можете использовать обнаружение края Canny, а затем findContours()
, чтобы получить координаты ограничивающей рамки.
Фантастический! Спасибо за ваше время и помощь. Не могли бы вы интуитивно объяснить, почему и как вы придумали этот метод? Это такой другой подход, чем то, что я видел в Интернете.
@ CZP3 Я добавил некоторые детали алгоритма. Если мне удастся получить немного свободного времени, я также обновлю его, чтобы он был лучше и эффективнее.
@ Paul92 Спасибо за подробное объяснение!! Отличная работа
etect the original rectangle on its own
что вы хотите этим сказать?