77217

Распознавание автомобильных номеров с помощью нейронных сетей

Курсовая

Информатика, кибернетика и программирование

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

Русский

2015-02-02

230 KB

2 чел.

Санкт-Петербургский государственный университет

математико-механический факультет

кафедра системного программирования

Курсовая работа на тему

Распознавание автомобильных номеров с помощью нейронных сетей

Студента 445 группы

Федяшова Виктора

Научный руководитель:

Преподаватель кафедры Системного Программирования

Пименов Александр Александрович

 

Оценка:

Санкт-Петербург

2009

Введение

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

В настоящее время существует некоторое количество реализаций подобных систем ANPR (automatic number plate recognition), однако большинство из них требует серьезных затрат, так как высокий уровень точности и быстроты требует установки дорогостоящей аппаратуры (камеры + компьютеры, отвечающие собственно за распознавание номера и занесение его в базу). Поэтому массовое внедрение возможно только при дальнейшей оптимизации алгоритмов, что позволит использовать более дешевое оборудование.

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

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

Нейронные сети: основные понятия

Биологические нейронные сети:

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

 

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

Теперь нетрудно перейти к математической модели, описывающую данный билогический процесс.


Математическая модель нейронной сети:

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

Функция g(x) используется для сужения диапазона выхода перцептрона, и называется sigmoid function. Вариант классической активационной функции показан выше, но, несмотря на общепринятость, оказывается неудобным на практике, потому как не является симметричным. В нашей реализации мы будем использовать гиперболический тангенс (tanh(x)). Удобство такого выбора будет обосовано ниже.

Таким образом нейронная сеть – это набор уровней (layers), на каждом из которых (кроме входного и выходного) – некоторое число нейронов, которое можно варьировать для улучшения результата или ускорения его получения. В каждый из нейронов отдельно взятого уровня входят все нейроны предыдущего уровня с определенным весом, а также пороговый нейрон (threshold), значение которого всегда 1 (его нельзая обучить, только изменить вес).

Итак, формально наша задача сводится к следующему: пусть на вход подается bitmap (в нашем случае 19x31), то есть фактически массив из 589 чисел. Это первый уровень нейронов. Затем идет произвольное число промежуточных уровней с варьируемым количеством нейронов на каждом из них, на выходе же – массив из 10 элементов, где i-й элемент означает вклад входных данных в цифру i.

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

Самая распространенная структура для задачи распознавания цифровых символов – трехуровневая нейронная сеть (один скрытый слой (hidden layer)). Схема работы такой сети показана на схеме ниже:

 

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

Ниже будет рассказано о двух ключевых фазах работы нейронной сети: активная (feed-forward) и коррекци ошибки (Backpropagate), являющееся основой для процесса обучения, но сначала будет представлена основа структуры нейронной сети, которая используется в данной реализации.

Выдержки из кода:

struct TrainPair

{

 double *inputVector;

 double *desiredOutput;

};

typedef vector<TrainPair*> TrainingSet;

class Weight

{

public:

   Weight(double val = 0.0 );

   virtual ~Weight();

   double value;

};

typedef vector<Weight*> VectorWeights;

class Connection

{

public:

   Connection(int neuron = ULONG_MAX, int weight = ULONG_MAX);

   virtual ~Connection();

   int NeuronIndex;

   int WeightIndex;

};

typedef vector<Connection*> VectorConnections;

class Neuron

{

public:

   Neuron();

   virtual ~Neuron();

   void AddConnection( int iNeuron, int iWeight );

   void AddConnection( Connection const & conn );

   double output;

   VectorConnections m_Connections;

};

typedef vector<Neuron*> VectorNeurons;

class Layer

{

public:

   Layer(Layer* pPrev = NULL );

   virtual ~Layer();

   void Calculate();

   void Backpropagate(vector< double >& dErr_wrt_dXn /* in */,

       vector< double >& dErr_wrt_dXnm1 /* out */,

       double etaLearningRate );

   Layer* m_pPrevLayer;

   VectorNeurons m_Neurons;

   VectorWeights m_Weights;

};

typedef vector<Layer*> VectorLayers;

class NeuralNetwork

{

public:

   VectorLayers m_Layers;

   double m_etaLearningRate;

   NeuralNetwork();

   void Init(int number_Of_Layers, int *neurons_Per_Layer);

   virtual ~NeuralNetwork();

   void FeedForward( double* inputVector, int iCount,

       double* outputVector = NULL, int oCount = 0 );

   void Backpropagate( double *actualOutput,

        double *desiredOutput);

};

Замечание: Connection и Weight это по сути одно и то же, первое введено для того, чтобы можно было хранить меньше весов, чем связей, и виду повторного использования, обучать их меньше.


Обучение нейронной сети (adaptation mechanism)

Feed-Forward:

Для начала еще раз вспомним про активационную функцию. Как было сказано выше, в данной реализации нейронной сети она взята за F(y) = tanh(y). Тогда:

то есть если X = tanh(Y),  то

Это значит, что мы можем посчитать производную, зная только выход, и не зная вход. Это принципиальный момент для процесса обучения. Остальные свойства этой функции были описаны выше: значения лежат в диапазоне [-1; 1], и она симметрична.

Процесс вычисления выходных значений сети достаточно прост: выходные значения первого уровня совпадают с входными, дальше происходит вычисление снизу-вверх в соответствии с весами:

 

После того, как на всех уровнях вычислены выходные значения нейронов, мы имеем на выходе результирующий вектор. Затем мы можем сравнить его с желаемым результатом (target output) для данного входа. Мы знаем его для пар из множества для обучения (Training Set). Дальнейшая идея сосоит в том, чтобы менять веса таким образом, чтобы в результате ошибка (погрешность) на всех парах тренировочного множества была меньше заданного eps. Если это удается за конечное (также заданное наперед) число шагов, то мы говорим, что сеть обучилась. Фактически это значит, что нейронная сеть «выучила все примеры», и предполагается, что сообразно с этим на произвольных входных данных результат будет правильный с большой долей вероятности (если тренировочное множество достаточно объемлюще). Сначала введем понятие ошибки:

 

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


Backpropogate:

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

Для последнего уровня

   

Где G(x) – производная активационной функции

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

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

 


В данной реализации была сделана попытка улучшить стандартный метод градиентного спуска (gradient descent) посредством добавления еще одного слагаемого:

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

 

 


Заключение

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

 

После многих прогонов предыдущего блока проекта (выделения и сегментации номеров) было получено достаточно большое тренировочное множество, на котором и происходило обучение.

Дальнейшее поле деятельности – выбор оптимальной структуры сети непосредственно для данной задачи, а также более серьезная оптимизация процесса градиентного спуска. Первое может быть достинуто только эмпирическим путем, с помощью тестирования, для второго же существует достаточно много известных численных методов, улучшающих скорость сходимости и позволяющих уходить от локальных минимумов. Например можно динамически менять коэфициенты от шага к шагу, а также отслеживать «скачки» на близких поверхностях уровня.

Также будет достаточно логично обучить сеть работать не только с цифрами, но и с буквами, для чего в принципе нужно только получить достаточно полное тренировочное множество.


Список литературы:

  1.  «Algoritmic and Mathematical principles of Autimatic Number Plate Recognition Systems», BRNO 2007
  2.  Neural Network for Recognition of Handwritten Digits” by Mike O’Neill, 2008
  3.  “Neural Networks for Pattern Recognition” by Bishop, Christopher, Oxford, 1995
  4.  “Neural Networks - A Systematic Introduction” by Raul Rojas, 1996
  5.  “Neural Networks Made Simple” by Steffen Nissen, 2000


 

А также другие работы, которые могут Вас заинтересовать

25623. Внезародышевые органы 43.5 KB
  Амнион временный орган обеспечивающий водную среду для развития зародыша. В эмбриогенезе человека он появляется на второй стадии гаструляции сначала как небольшой пузырек дном которого является первичная эктодерма эпибласт зародыша. Желточный мешок наиболее древний в эволюции внезародышевый орган возникший как орган депонирующий питательные вещества желток необходимые для развития зародыша.