Выявление несовершенных форм с шумным фоном с помощью OpenCV

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

Выявление несовершенных форм с шумным фоном с помощью OpenCV

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

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

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

выход

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

etect the original rectangle on its own что вы хотите этим сказать?
Quang Hoang 19.06.2019 21:39

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

nathancy 19.06.2019 21:50

@nathancy Верно.

CZP3 20.06.2019 02:12
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
772
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

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? Спасибо за помощь

CZP3 20.06.2019 02:12

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

coffeewin 20.06.2019 04:07

Фантастический! Спасибо за ваше время и помощь. Не могли бы вы интуитивно объяснить, почему и как вы придумали этот метод? Это такой другой подход, чем то, что я видел в Интернете.

CZP3 21.06.2019 00:54

@ CZP3 Я добавил некоторые детали алгоритма. Если мне удастся получить немного свободного времени, я также обновлю его, чтобы он был лучше и эффективнее.

Paul92 21.06.2019 01:09

@ Paul92 Спасибо за подробное объяснение!! Отличная работа

CZP3 21.06.2019 01:27

Другие вопросы по теме