Извлечь параллелограмм номерного знака из окружающего его ограничивающего прямоугольника?

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

образцы изображений

Я попытался выполнить обнаружение краев и контуров с использованием встроенных функций OpenCV, как в следующем минимальном коде, но мне удалось добиться успеха только на небольшом подмножестве изображений таким образом:

import cv2
import matplotlib.pyplot as plt
import numpy as np

def auto_canny(image, sigma=0.25):
    # compute the median of the single channel pixel intensities
    v = np.median(image)

    # apply automatic Canny edge detection using the computed median
    lower = int(max(0, (1.0 - sigma) * v))
    upper = int(min(255, (1.0 + sigma) * v))
    edged = cv2.Canny(image, lower, upper)

    # return the edged image
    return edged


# Load the image
orig_img = cv2.imread(input_file)

img = orig_img.copy()

dim1,dim2, _ = img.shape

# Calculate the width and height of the image
img_y = len(img)
img_x = len(img[0])

#Split out each channel
blue, green, red = cv2.split(img)
mn, mx = 220, 350
# Run canny edge detection on each channel

blue_edges = auto_canny(blue)

green_edges = auto_canny(green)

red_edges = auto_canny(red)

# Join edges back into image
edges = blue_edges | green_edges | red_edges

contours, hierarchy = cv2.findContours(edges.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

cnts=sorted(contours, key = cv2.contourArea, reverse = True)[:20]
hulls = [cv2.convexHull(cnt) for cnt in cnts]
perims = [cv2.arcLength(hull, True) for hull in hulls]
approxes = [cv2.approxPolyDP(hulls[i], 0.02 * perims[i], True) for i in range(len(hulls))]

approx_cnts = sorted(approxes, key = cv2.contourArea, reverse = True)
lengths = [len(cnt) for cnt in approx_cnts]

approx = approx_cnts[lengths.index(4)]

#check the ratio of the detected plate area to the bounding box
if (cv2.contourArea(approx)/(img.shape[0]*img.shape[1]) > .2):
    cv2.drawContours(img, [approx], -1, (0,255,0), 1)

plt.imshow(img);plt.show()

вот несколько примеров результатов:

(Изображения в верхнем ряду являются результатами этапа обнаружения края)

Успешно:

успешные-примеры

Неудачные:

unsuccessful-examples

Довольно удачно:

kinda-success-examples

И случай, когда четырехугольник / параллелограмм не найден, но нарисован многоугольник с наибольшей площадью:

примеры, не относящиеся к четырехугольнику

все эти результаты имеют один и тот же набор параметров (пороговые значения и т. д.)

Я также попытался применить преобразование Хафа с помощью cv2.HoughLines, но я не знаю, почему вертикально наклоненные линии всегда пропускаются, независимо от того, насколько низко я установил порог аккумулятора. Также, когда я понижаю порог, я получаю эти диагональные линии из ниоткуда:

hough-transform-examples

и код, который я использовал для рисования линий Хафа:

lines = cv2.HoughLines(edges,1,np.pi/180,20)
for i in range(len(lines)):
    for rho,theta in lines[i]:
        a = np.cos(theta)
        b = np.sin(theta)
        x0 = a*rho
        y0 = b*rho
        x1 = int(x0 + 1000*(-b))
        y1 = int(y0 + 1000*(a))
        x2 = int(x0 - 1000*(-b))
        y2 = int(y0 - 1000*(a))

        cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2)
plt.imshow(img);plt.show()

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


person Moalana    schedule 10.04.2019    source источник
comment
Если вы используете ограниченный набор камер и имеете к ним физический доступ, неискажение изображений с помощью калибровки может помочь (чтобы прямые линии мира, такие как края пластины, выглядели прямо на неискаженных изображениях).   -  person Gabriel Devillers    schedule 10.04.2019
comment
@GabrielDevillers, к сожалению, изображения номеров загружены пользователями. никакого доступа к камерам вообще нет.   -  person Moalana    schedule 10.04.2019
comment
Очевидно, вам необходимо применить некоторую предварительную обработку, прежде чем применять обнаружение ловкости и / или контура. Можете ли вы загрузить несколько оригинальных изображений, чтобы я мог попробовать?   -  person Rick M.    schedule 10.04.2019
comment
@RickM. Совершенно верно, но о какой препроцессоре идет речь. Я загрузил здесь несколько примеров: imgur.com/a/IsSYttk Также не стесняйтесь повышать разрешение изображений даже хотя с разными разрешениями иногда получаются разные результаты.   -  person Moalana    schedule 10.04.2019
comment
@Moalana Я попробую и свяжусь с вами как можно скорее.   -  person Rick M.    schedule 10.04.2019
comment
@Moalana Итак, я попробовал выполнить некоторую предварительную обработку, используя несколько техник, и действительно выделялся тот, который был CLAHE. Кажется, это хорошо работает с изображениями с отражениями, а также с размытыми, единственная проблема заключалась в том, что необходимо было настроить параметры. Основная проблема возникает из-за крайне низкого качества некоторых ваших изображений. Я также пробовал нерезкую маску, но, похоже, это не помогает с этими изображениями.   -  person Rick M.    schedule 16.04.2019
comment
Поскольку вы уже используете YOLO, почему бы вам не использовать вместо него Mask R-CNN. Это даст вам ограничительную рамку вокруг номерного знака и маску на номерном знаке. Получить параллелограмм можно с помощью маски. Для обучения вы можете создавать маски на нескольких номерных знаках с помощью такого инструмента, как это. Вы также можете взглянуть на API-интерфейс R-CNN для обнаружения объектов TensorFlow.   -  person Safwan    schedule 15.05.2019
comment
@Safwan, потому что время вывода очень важно для поставленной задачи (требования, близкие к реальному времени), а маска R-CNN слишком медлительна для этого, особенно при разрешениях, которые я передаю входные изображения с повышенной дискретизацией в YOLOv3. Кроме того, я думаю, что для четко очерченного номерного знака в форме параллелограмма Mask R-CNN в любом случае будет излишним. Добавьте все это к проблеме обнаружения мелких объектов с помощью Mask RCNN. размеры номерных знаков на моих исходных изображениях транспортных средств находятся в небольшом ~ очень маленьком диапазоне)   -  person Moalana    schedule 15.05.2019


Ответы (2)


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

Алгоритм будет выглядеть примерно так:

  1. Укажите значения RGB, которые вы хотите обнаружить.
  2. Определите позиции (x, y), в которых встречаются эти значения RGB
  3. Определите верхнее левое, нижнее левое, верхнее правое и нижнее правое положения.
  4. Постройте линии между этими позициями

Этот пример определения цвета из PyImagesearch может помочь вы кодируете это.

Конечно, обнаружение белых номеров не сработает на белых машинах.

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

person leermeester    schedule 10.04.2019

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

Возьмите любую точку в BLOB-объекте и найдите самую дальнюю точку в BLOB-объекте от этой точки. В результате должна получиться угловая точка. Затем возьмите полученную угловую точку и найдите самую дальнюю точку от нее. Это должно дать вам два противоположных угла. Затем найдите точку капли, которая имеет наибольшее суммарное расстояние от обеих точек. Повторите последний раз для самых дальних из всех трех точек. Теперь у вас есть все 4 угла. Чтобы упорядочить их, получите среднюю точку и создайте векторы для каждого угла. Сделайте намотку по часовой стрелке.

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

person Sneaky Polar Bear    schedule 12.01.2020
comment
Если у меня будет время на выходных, я в любом случае добавлю пример кода, чтобы повеселиться. - person Sneaky Polar Bear; 12.01.2020