Детектор индийских номерных знаков на базе искусственного интеллекта.

Вдохновение: парень, который сбил мою машину и сошёл с рук!

Предыстория: После незабываемого вечера с друзьями, когда мы собирались уехать домой, произошло кое-что, что сделало тот вечер еще более незабываемым: огромная вмятина на переднем бампере моей машины, казалось, в нее попал другой автомобиль, но кто виноват? Вокруг не было никого, кто бы это видел. И что я мог с этим поделать?
Я точно скажу вам, что я с этим сделал.
Я применил свои навыки машинного обучения и программирования и решил создать на основе искусственного интеллекта детектор индийских номерных знаков, который был бы достаточно способным, чтобы следить за автомобиль, обнаруживая номерные знаки автомобилей вокруг него, и в этом блоге я расскажу вам, как я это сделал!

Перво-наперво. Всегда есть возможность импровизировать, поэтому, если у вас возникнут какие-то лучшие идеи или возникнут сомнения относительно этого проекта, воспользуйтесь приведенным ниже разделом для ответов.

Подход:

Нам нужно построить систему, которая способна:

  • Принимая изображение / видео (серию изображений) из окружения:
    со стороны оборудования нам нужен компьютер (или Raspberry Pi) вместе с камерой, а со стороны программного обеспечения нам нужна библиотека для захвата и обработки данные (изображение). Я использовал OpenCV (4.1.0) и Python (3.6.7) для этого проекта.
  • Ищем номерной знак на изображении:
    Чтобы обнаружить объект (номерной знак) на изображении, нам нужен другой инструмент, который может распознавать индийский номерной знак, поэтому для этого я использовал каскад Хаара, предварительно обученный индийскому номерные знаки (скоро будут обновлены до YOLO v3).
  • Анализируя и выполняя некоторую обработку изображений на номерном знаке:
    Используя шкалу серого OpenCV, пороговое значение, размывание, расширение, определение контура и настройку некоторых параметров, мы можем легко получить достаточно информации о пластине, чтобы решить, действительно ли данные достаточно полезен для передачи другим процессам или нет (иногда, если изображение очень искажено или неправильное, мы можем предположить только 8 из 10 символов, тогда нет смысла передавать данные по конвейеру, кроме как игнорировать их и посмотрите на следующий кадр для пластины), также перед передачей изображения в следующий процесс нам нужно убедиться, что оно без шума и обработано.
  • Сегментирование буквенно-цифровых символов на номерном знаке:
    если все в вышеуказанных шагах работает нормально, мы должны быть готовы извлечь символы из номера, это можно сделать, умело установив пороговые значения, размывая, расширяя и размывая изображение, например что в конечном итоге изображение, которое у нас есть, почти не содержит шумов и с ним легко работать с другими функциями. Теперь мы снова используем обнаружение контуров и настройку некоторых параметров для извлечения символов.
  • Рассматривая символы один за другим, распознавая символы, объединяя результаты и выдавая номерной знак в виде строки:
    Теперь самое интересное! Поскольку у нас есть все символы, нам нужно передать символы по одному в нашу обученную модель, и она должна распознать символы и вуаля! Мы будем использовать Keras для нашей модели сверточной нейронной сети.

Предпосылки:

  • OpenCV: OpenCV - это библиотека функций программирования, в основном нацеленная на компьютерное зрение в реальном времени, плюс ее открытый исходный код, увлекательный для работы и мой личный фаворит. Я использовал для этого проекта версию 4.1.0.
  • Python: он же швейцарский армейский нож программирования. Я использовал здесь версию 3.6.7.
  • IDE: здесь я буду использовать Jupyter.
  • Каскад Хаара: это алгоритм обнаружения объектов машинного обучения, используемый для идентификации объектов на изображении или видео и основанный на концепции функций, предложенной Полом Виолой и Майклом Джонсом. в своей статье Быстрое обнаружение объектов с использованием усиленного каскада простых функций в 2001 году. Подробнее
  • Keras: простой в использовании и широко поддерживаемый, Keras делает глубокое обучение настолько простым, насколько это может быть глубокое обучение.
  • Scikit-Learn: - это бесплатная библиотека машинного обучения для языка программирования Python.
  • И, конечно же, не забудьте про кофе!

Шаг 1

Создание рабочего пространства.

Я рекомендую создать среду conda, потому что она значительно упрощает управление проектами. Пожалуйста, следуйте инструкциям в этой ссылке для установки miniconda. После установки откройте cmd / terminal и создайте среду, используя -

>conda create -n 'name_of_the_environment' python=3.6.7

Теперь давайте активируем среду:

>conda activate 'name_of_the_environment'

Это должно поместить нас в нашу виртуальную среду. Пора установить некоторые библиотеки-

# installing OpenCV
>pip install opencv-python==4.1.0
# Installing Keras
>pip install keras
# Installing Jupyter
>pip install jupyter
#Installing Scikit-Learn
>pip install scikit-learn

Шаг 2

Настройка среды!

Мы начнем с запуска jupyter notebook, а затем импортируем необходимые библиотеки в нашем случае OpenCV, Keras и sklearn.

# in your conda environment run
>jupyter notebook

Это должно открыть блокнот Jupyter в веб-браузере по умолчанию.
После открытия импортируем библиотеки.

#importing openCV
>import cv2
#importing numpy
>import numpy as np
#importing pandas to read the CSV file containing our data
>import pandas as pd
#importing keras and sub-libraries
>from keras.models import Sequential
>from keras.layers import Dense
>from keras.layers import Dropout
>from keras.layers import Flatten, MaxPool2D
>from keras.layers.convolutional import Conv2D
>from keras.layers.convolutional import MaxPooling2D
>from keras import backend as K
>from keras.utils import np_utils
>from sklearn.model_selection import train_test_split

Шаг 3

Обнаружение номерного знака:

Давайте начнем с простого, импортируя образец изображения автомобиля с номерным знаком и определим некоторые функции:

Вышеупомянутая функция работает, принимая изображение в качестве входных данных, а затем применяя каскад хаара, который предварительно обучен для обнаружения индийских номерных знаков, здесь параметр scaleFactor обозначает значение, на которое входное изображение может быть масштабировано для лучшего обнаружения номерного знака ( узнать больше"). minNeighbors - это просто параметр для уменьшения количества ложных срабатываний, если это значение низкое, алгоритм может быть более склонен к выдаче неверно распознанных выходных данных. (вы можете скачать каскадный файл haar как файл «indian_license_plate.xml из моего профиля github.)

Шаг 4

Выполняем некоторую обработку изображения номерного знака.

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

Вышеупомянутая функция принимает изображение в качестве входных данных и выполняет с ним следующую операцию:

  • изменяет его размер до такого размера, чтобы все символы казались отчетливыми и четкими
  • преобразовать цветное изображение в изображение с серым масштабом, т.е. вместо 3 каналов (BGR) изображение имеет только один 8-битный канал со значениями в диапазоне от 0 до 255, где 0 соответствует черному, а 255 соответствует белому. Делаем это, чтобы подготовить изображение к следующему процессу.
  • теперь пороговая функция преобразует масштабированное по серому изображение в двоичное изображение, то есть каждый пиксель теперь будет иметь значение 0 или 1, где 0 соответствует черному, а 1 соответствует белому. Это делается путем применения порога, который имеет значение от 0 до 255, здесь значение равно 200, что означает, что в изображении в градациях серого для пикселей, имеющих значение выше 200, в новом двоичном изображении этому пикселю будет присвоено значение 1. А для пикселей, имеющих значение ниже 200, в новом двоичном изображении этому пикселю будет присвоено значение 0.
  • Теперь изображение имеет двоичную форму и готово для следующего процесса. Размытие.
    Размытие - это простой процесс, используемый для удаления нежелательных пикселей с границы объекта, то есть пикселей, которые должны иметь значение 0, но имеют значение 1. Он работает, рассматривая каждый пиксель в изображении один за другим, а затем рассматривая соседа пикселя (количество соседей зависит от размера ядра), пикселю присваивается значение 1, только если все его соседние пиксели равны 1, в противном случае ему дается значение 0.
  • Изображение теперь чистое и без граничного шума, теперь мы расширим изображение, чтобы заполнить отсутствующие пиксели, то есть пиксели, которые должны иметь значение 1, но имеют значение 0. Функция работает аналогично размыванию, но с небольшим уловом, он работает, рассматривая каждый пиксель в изображении один за другим, а затем рассматривая соседа пикселя (количество соседей зависит от размера ядра), пикселю присваивается значение 1, если хотя бы один из его соседних пикселей равен 1.
  • Следующий шаг - сделать границы изображения белыми. Это необходимо для удаления любого пикселя вне кадра, если он присутствует.
  • Затем мы определяем список измерений, который содержит 4 значения, с которыми мы будем сравнивать размеры персонажа, чтобы отфильтровать необходимые символы.
  • С помощью описанных выше процессов мы уменьшили наше изображение до обработанного двоичного изображения, и мы готовы передать это изображение для извлечения символов.

Шаг 5

Сегментация буквенно-цифровых символов на номерном знаке.

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

  • Нахождение всех контуров на входном изображении. Функция cv2.findContours возвращает все контуры, найденные на изображении. Контуры можно объяснить просто как кривую, соединяющую все непрерывные точки (вдоль границы), имеющие одинаковый цвет или интенсивность.

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

  • Поскольку у нас есть размеры этого ограничивающего прямоугольника, все, что нам нужно сделать, это настроить параметры и отфильтровать требуемый прямоугольник, содержащий требуемые символы. Для этого мы проведем некоторое сравнение размеров, приняв только тот прямоугольник, ширина которого находится в диапазоне 0, (длина рисунка) / (количество символов) и длина в диапазоне (ширина рисунка) / 2, 4 * (ширина рисунка) / 5. Если все работает хорошо, все символы должны быть извлечены как двоичные изображения.

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

ШАГ 6

Создание модели машинного обучения и обучение на ней персонажей.

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

  • Для моделирования мы будем использовать сверточную нейронную сеть с 3 слоями.
## create model
>model = Sequential()
>model.add(Conv2D(filters=32, kernel_size=(5,5), input_shape=(28, 28, 1), activation='relu'))
>model.add(MaxPooling2D(pool_size=(2, 2)))
>model.add(Dropout(rate=0.4))
>model.add(Flatten())
>model.add(Dense(units=128, activation='relu'))
>model.add(Dense(units=36, activation='softmax'))

  • Чтобы модель оставалась простой, мы начнем с создания последовательного объекта.
  • Первый слой будет сверточным слоем с 32 выходными фильтрами, окном свертки размером (5,5) и функцией активации «Relu».

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

  • Теперь мы добавим некоторую частоту отсева, чтобы позаботиться о переобучении.
    Выпадение - это гиперпараметр регуляризации, инициализируемый для предотвращения переобучения нейронных сетей. Отсев - это метод, при котором случайно выбранные нейроны игнорируются во время обучения. Они случайным образом "выпадают - выпадают". Мы выбрали коэффициент отсева 0,4, что означает, что 60% узла будет сохранено.
  • Теперь пришло время сгладить данные узла, поэтому мы добавляем для этого плоский слой. Сглаженный слой берет данные из предыдущего слоя и представляет их в одном измерении.

  • Наконец, мы добавим 2 плотных слоя, один с размерностью выходного пространства 128, функцией активации = 'relu' и другим, наш последний слой с 36 выходами для категоризации 26 алфавитов (AZ) + 10 цифр (0– 9) и функция активации = 'softmax'

Шаг 7.

Обучение нашей модели CNN.

  • Данные, которые мы будем использовать, содержат изображения алфавитов (A – Z) и цифр (0–9) размером 28x28, а также данные сбалансированы, поэтому нам не нужно выполнять здесь какую-либо настройку данных.
  • Я создал zip-файл, содержащий данные в соответствии со структурой каталогов ниже, с разделением теста поезда 80:20

  • Мы будем использовать класс ImageDataGenerator, доступный в keras, чтобы сгенерировать дополнительные данные с помощью таких методов увеличения изображения, как сдвиг ширины и высоты. Чтобы узнать больше об ImageDataGenerator, загляните в этот красивый блог.
  • Сдвиг ширины: принимает значение с плавающей запятой, обозначающее, на какую долю изображение будет смещено влево и вправо.
    Сдвиг по высоте: принимает значение с плавающей запятой, обозначающее, на какую долю изображение будет смещено вверх и вниз.
  • Пришло время обучить нашу модель!
    мы будем использовать «categoryical_crossentropy» как функцию потерь, «Adam» как функцию оптимизации и «Accuracy» как нашу матрицу ошибок.
  • После обучения в течение 23 эпох модель достигла точности 99,54%.

Шаг 8

Результат.

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

Выход-

Заключительный комментарий

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

И если у вас есть сомнения по поводу этого проекта, оставьте, пожалуйста, комментарий в разделе ответов.

Полный проект доступен на моем Github:
https://github.com/SarthakV7/AI-based-indian-license-plate-detection

Найдите меня в LinkedIn: www.linkedin.com/in/sarthak-vajpayee