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

#python #opencv #image-processing #computer-vision #yolo

#python #opencv #обработка изображений #компьютерное зрение #yolo

Вопрос:

Итак, я обучил нейронную сеть распознавания объектов (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()
  

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

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

Успешные результаты:

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

Безуспешно:

неудачно-примеры

Своего рода успехи:

своего рода-успешные-примеры

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

не четырехугольник -примеры

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

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

хаф-преобразование-примеры

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

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

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

Комментарии:

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

2. @GabrielDevillers к сожалению, изображения номерных знаков являются загруженными пользователем изображениями. нет доступа к камерам вообще.

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

4. @RickM. Точно, но вопрос в том, какая предварительная обработка. Я загрузил несколько примеров здесь: imgur.com/a/IsSYttk Также не стесняйтесь увеличивать выборку изображений, хотя при разных разрешениях я иногда получаю разные результаты.

5. @Moalana Я попробую и свяжусь с вами как можно скорее.

Ответ №1:

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

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

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

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

Конечно, обнаружение белых номеров не будет работать на белых автомобилях.

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

Ответ №2:

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

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

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

Комментарии:

1. Если у меня будет время в выходные, я в любом случае добавлю пример кода для удовольствия.