Skip to main content

Распознавание регистрационных номеров с автомобилей с помощью MatLab. Третья часть. Видео

Добрый день!

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

frame15

Итак, мы имеем видеопоследовательность длительностью порядка 1-3 секунд (30-70 кадров), с одной проезжающей машиной сверху-вниз. Это вполне стандартная ситуация для фиксированных камер наблюдения. Так же нам дана обучающая выборка, состоящая из номерных знаков и фрагментов не являющимися таковыми.

input frameset

Введение.

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

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

План работы
  1. Сканировать верхнюю часть изображения до появления чего-нибудь, похожего на номер;
  2. Найти номер на первом годном кадре;
  3. Отследить положение номера на всех кадрах (кстати, тут нам предлагалось еще оценить скорость машины, исходя из ГОСТ геометрии номера, частоты кадров и оценки положения камеры);
  4. Попытаться распознать номер на каждом кадре, методами из первой или второй части(или любым другим);
  5. Провести голосование между кадрами за итоговый номер
  6. Выдать результат
Загрузка видео в матлаб.

  1. [fname,path,fi] = uigetfile({'*.avi;*.mpg','Video file'},'Choose a video');
  2. if ~fi,return,end
  3. video = mmreader([path fname]);
  4. nFrames = video.NumberOfFrames;
  5. vidHeight = video.Height;
  6. vidWidth = video.Width;
  7. global mov
  8. mov = struct('cdata',{},'colormap', []);
  9. mov(1:nFrames) = ...
  10.     struct('cdata', zeros(vidHeight, vidWidth, 1, 'uint8'),...
  11.     'colormap', []);
  12. for k = 1 : nFrames-1
  13.     mov(k).cdata = (rgb2gray(read(video, k)));
  14. end

* This source code was highlighted with Source Code Highlighter.

Для сканирования нам нужен какой нибудь простой метод, который будет выдавать нам минимальное количество ложных срабатываний. Одним из напрашивающихся решений, исходя из предоставленных материалов, было обучение классификатора для скользящего окна, которое бы сканировало верхнюю четверть-треть изображения в поисках искомого номера. Тут ничего нового нет, весь метод описан во второй статье. Берем выборку, обучаем решающий лес. Пишем цикл по изображению для окна подходящего размера (камера у нас статическая, помните, поэтому размер окна можно подобрать по размеру номера из тестового видео + 10-15%).

Все довольно просто. Но можно еще упростить себе жизнь для следующих этапов. Зачем нам сканировать дорогу, и слаботекстурированные участки кадра? Возьмем, да и вычтем два соседних кадра. Получим только то, что в соседних кадрах менялось ( а номер уезжает на значительное расстояние для того, чтобы остаться полностью в разнице). Но пользоваться мы будем конечно не самой разностью. Ее мы обрубим по некоторому порогу, потом хорошенько раскроем и получим маску, которую наложим на текущий кадр. Таким образом получим зоны кадра, где мы можем просто не искать изображение. Например, все, что не попало под маску, зальем красным. И если в текущем положении скользящего окна больше 50% красных пикселей — даже не скармливаем его дереву, а идем дальше.

car difference

  1. mov2 = struct('cdata',{},'colormap', []);
  2.  
  3. mov2(1:nFrames) = ...
  4.     struct('cdata', zeros(vidHeight, vidWidth, 1, 'uint8'),...
  5.     'colormap', []);
  6.  
  7. mov2(1).cdata = mov(1).cdata;
  8. for i=2:nFrames
  9.     mov2(i).cdata = mov(i).cdata - mov(i-1).cdata;
  10. end
  11. for i=1:nFrames
  12.     idx = find(imclose ((medfilt2(mov2(i).cdata,[5 5]) > 30) ,strel('disk',10 ) ) );
  13.     mov2(i) = ... fill
  14.         struct('cdata', zeros(vidHeight, vidWidth, 1, 'uint8'),...
  15.         'colormap', []);
  16.     mov2(i).cdata(idx) = mov(i).cdata(idx);
  17. end

* This source code was highlighted with Source Code Highlighter.

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

Для голосования нам нужны следующие параметры:

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

Заполняя и корректируя в течение 11 (ну или сколько у нас будет полезных) кадров эти гистограммы на выходе мы получим наиболее вероятную конфигурации номерного знака.

На этом я завершаю цикл статей по распознаванию номеров в матлабе. Надеюсь, что они были полезны для вас!
Увы, по семейным причинам, код для третьего задания дописать я так и не смог, Поэтому статья получилась несколько куцая.

Код и ссылки:

http://static.scaytrase.ru/cnr/CV2010.zip — Полный архив исходных кодов, включая тестовую и обучающую выборку по всем трем заданиям.
http://courses.graphicon.ru/ — сайт курсов лаборатории КГиММ ВМК МГУ. Много интересных материалов по теме.
http://courses.graphicon.ru/main/vision/2010/lectures — архив лекций нашего года.
http://cgm.computergraphics.ru/ — сетевой журнал о КГиММ. Тоже много хороших статей.

Спасибо за внимание!