Члены команды: Прабхат Кумар, Атул Панвар, Анкита Джайсвал

Доцент/руководитель проекта: Йогита Шарма.

Модель, которая будет обнаруживать автомобиль в прямом эфире или видео и распознавать символы на номерном знаке автомобиля.
Во-вторых, она будет использовать символы и получать информацию о владельце с помощью RTO API.
Шаги
1. Обнаружение номерного знака
Давайте возьмем образец изображения автомобиля и начнем с определения номерного знака на этом автомобиле. Затем мы будем использовать одно и то же изображение для сегментации символов и распознавания символов. Если вы хотите сразу перейти к коду без объяснений, вы можете прокрутить вниз до конца этой страницы, где представлен полный код. Тестовое изображение, которое я использую для этого урока, показано ниже.

ссылка на источник изображения: https://rb.gy/lxmiuv

Шаг 1. Измените размер изображения до нужного размера, а затем оттените его оттенками серого. Код для того же приведен ниже.

img = cv2.resize(img, (620,480))
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #конвертировать в оттенки серого

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

Шаг 2: Каждое изображение будет иметь полезную и бесполезную информацию, в данном случае для нас полезной информацией является только номерной знак, остальные практически бесполезны для нашей программы. Эта бесполезная информация называется шумом. Обычно использование двустороннего фильтра (Размытие) удаляет нежелательные детали изображения. Код для того же размыт.

серый = cv2.bilateralFilter(серый, 13, 15, 15)

Синтаксис: target_image = cv2.bilateralFilter(source_image, диаметр пикселя, sigmaColor, sigmaSpace). Вы можете увеличить сигма-цвет и сигма-пространство с 15 до более высоких значений, чтобы размыть больше фоновой информации, но будьте осторожны, чтобы полезная часть не была размыта. Выходное изображение показано ниже, поскольку вы можете видеть, что детали фона (дерево и здание) размыты на этом изображении. Таким образом, мы можем избежать концентрации программы на этих регионах позже.

Шаг 3: Следующий шаг интересен, когда мы выполняем обнаружение краев. Есть много способов сделать это, самый простой и популярный способ — использовать метод canny edge из OpenCV. Строка, чтобы сделать то же самое, показана ниже.

edged = cv2.Canny(gray, 30, 200) #Выполнить обнаружение границ

Синтаксис будет следующий: target_image = cv2.Canny(source_image, пороговое значение 1, пороговое значение

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

Шаг 4: Теперь мы можем начать искать контуры на нашем изображении.

contours=cv2.findContours(edged.copy(),cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
контуры = imutils.grab_contours(contours)

contours = sorted(contours,key=cv2.contourArea, reverse = True)[:10]
screenCnt = None

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

для c в cnts:
# аппроксимировать контур
peri = cv2.arcLength(c, True)
приблизительно = cv2.приблизительноPolyDP(c, 0,018 * peri, True)
# если наш аппроксимированный контур имеет четыре точки, то
# можно считать, что мы нашли свой экран
if len(приблизительно) == 4:
screenCnt = приблизительно
перерыв

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

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

# Маскировка части, отличной от номерного знака
mask = np.zeros(gray.shape,np.uint8)
new_image = cv2.drawContours(mask,[screenCnt],0,255,-1 ,)
new_image = cv2.bitwise_and(img,img,mask=mask)

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

2. Сегментация символов
Следующим шагом в распознавании номерных знаков является выделение номерного знака из изображения путем его обрезки и сохранения как нового изображения. Затем мы можем использовать это изображение для обнаружения в нем символа. Код для обрезки изображения области интереса (ROI) из основного изображения показан ниже.

# Теперь урожая
(x, y) = np.where(mask == 255)
(topx, topy) = (np.min(x), np.min(y))
(нижняя частьx, нижняя часть) = (np.max(x), np.max(y))
Обрезано = серый[верхняя часть:нижняя частьx+1, верхняя часть:нижняя часть+1]

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

3. Распознавание символов
Последним шагом в этом распознавании номерных знаков является фактическое считывание информации о номерном знаке из сегментированного изображения. Мы будем использовать пакет pytesseract для чтения символов из изображений, как мы это делали в предыдущем уроке. Код для того же приведен ниже.

#Прочитать номерной знак
text = pytesseract.image_to_string(Cropped, config=’ — psm 11’)
print("Обнаружен номерной знак:",текст)

Как вы можете видеть, на исходном изображении был номер «CZ20FSE», и наша программа обнаружила, что оно печатает то же значение в блокноте Jupiter.
Неудачные случаи распознавания номерных знаков
Полный код этой лицензии Plate Recognition можно скачать отсюда, он содержит программу и тестовые изображения, которые мы использовали для проверки нашей программы. Не говоря уже о том, что следует помнить, что результаты этого метода не будут точными. Точность зависит от четкости изображения, ориентации, освещенности и т. д. Чтобы получить лучшие результаты, вы можете попробовать реализовать алгоритмы машинного обучения вместе с этим.

Как видите, наша программа смогла правильно определить номерной знак и обрезать его. Но библиотека Tesseract не смогла правильно распознать символы. Вместо фактического «MH 13 CD 0096» OCR распознал его как «MH13CD 0036». Подобные проблемы можно исправить, используя изображения с лучшей ориентацией или настроив механизм Tesseract.
Другие удачные примеры
В большинстве случаев качество и ориентация изображения правильные, программа смогла идентифицировать номерной знак и считать с него номер. На приведенных ниже снимках показаны полученные успешные результаты.