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

Сейчас, пока идет разработка и тестирование SDK для распознавания автомобильных номеров iANPR, решил поделиться с некоторыми предварительными результатами. Первоначальная версия SDK рассчитана на стандартные российские номера. Библиотека работает на базе OpenCV. Тестируется версия под Windows, но потом возможна поддержка и других операционных систем.
Интерфейс далеко не окончательный, но пока h-файл имеет следующий вид:
#pragma once
#include "opencv2/core/core_c.h"
#include "opencv2/imgproc/imgproc_c.h"
#define ANPR_DETECTMODE1 0x01
#define ANPR_DETECTMODE2 0x02
#define ANPR_DETECTMODE3 0x04
#define ANPR_RUSSIAN_BASE 0x00
struct ANPR_OPTIONS
{
int min_plate_size; // минимальная площадь номера
int max_plate_size; // максимальная площадь номера
int Detect_Mode; // Режимы детектирования
bool Border_Number; // Ограничение на распознавание касающихся краев номеров
int max_text_size; // Максимальный размер символов номера
int type_number; // тип номера
int param; // дополнительный параметр для типа номера, если ANPR_RUSSIAN_BASE, то при param = 1 предполагается, что 1-ка в регионе
int type_rect_detect; // пока не используется
int type_text_recognition; // пока не используется
int sort_cand_number; // пока не используется
};
int
#ifdef WIN32
__stdcall
#endif
anprPlate( IplImage* Image8, ANPR_OPTIONS Options, int* AllNumber, CvRect* Rects, char** Texts );
Как видно из файла, интерфейс библиотеки представлен в виде единственной функции. На вход передается изображение 8-битное 1-канальное в градациях серого, заполненная структура ANPR_OPTIONS с опциями. На выходе будут: количество распознанных номеров AllNumber, их местоположения Rects, распознанный номер *Texts. Сам тестовый пример представлен ниже:
#include "opencv2/highgui/highgui_c.h"
#include "..\..\src\iANPR.h"
#include <stdio.h>
int main(int argc, char** argv)
{
CvCapture* capture = cvCaptureFromFile(argv[1]);
char buffer[256];
sprintf( buffer, "%s.avi", argv[1] );
CvVideoWriter* cvVideoWriter = 0;
IplImage* object = 0;
IplImage* image = cvCreateImage( cvSize( 960, 540 ), 8, 3 );
int i = 0;
char mem[100][20];
int all_mem = 0;
for(;;)
{
IplImage* frame = 0;
frame = cvQueryFrame(capture );
if( !frame )
break;
if (!object)
{
object = cvCreateImage(cvGetSize(frame), 8, 1);
cvZero( object );
object->origin = frame->origin;
}
cvCvtColor( frame, object, CV_BGR2GRAY );
int all = 100;
CvRect Rects[100];
char** res = new char*[all];
for(int j=0;j<all;j++) res[j] = new char[20];
ANPR_OPTIONS a;
a.Border_Number = 0;
a.Detect_Mode = ANPR_DETECTMODE2 | ANPR_DETECTMODE3;
a.min_plate_size = 500;
a.max_plate_size = 25000;
a.max_text_size = 20;
a.sort_cand_number = 0;
a.type_number = ANPR_RUSSIAN_BASE;
a.type_rect_detect = 0;
a.type_text_recognition = 0;
a.param = 1;
DWORD tick1 = GetTickCount();
int i1 = anprPlate( object, a, &all, Rects, res );
DWORD tick2 = GetTickCount();
printf( "Num:%d; time:%5.3f; cand:%d\n", i, (float) ( tick2 - tick1) / 1000, all );
if ( i1 == 0 )
{
for(int j = 0; j < all; j++ )
{
if ( strlen( res[j] ) >= 8 )
{
int k =0;
for( int j1 = 0; j1 < all_mem; j1++ )
if ( strcmp( res[j], mem[j1]) == 0 ) k =1;
if ( k == 0 ) continue;
cvRectangle( frame,cvPoint( Rects[j].x, Rects[j].y),cvPoint(Rects[j].x+Rects[j].width,
Rects[j].y+Rects[j].height), CV_RGB(255,255,0), 2);
if ( strlen( res[j] ) == 9 ) res[j][6] = '1';
CvFont font;
float aa=0.001f*frame->width;
cvInitFont( &font, CV_FONT_HERSHEY_SIMPLEX, aa,
aa,0,1, 8 );
CvPoint pp2,pp1;
pp2.x=Rects[j].x;
pp2.y=Rects[j].y;
pp1.x=Rects[j].x+1;
pp1.y=Rects[j].y+1;
cvPutText( frame, res[j], pp1, &font, CV_RGB(0,0,0) );
cvPutText( frame, res[j], pp2, &font, CV_RGB(0,255,0) );
}
}
// Копирование в память
for(int j = 0; j < all; j++ )
{
if ( strlen( res[j] ) >= 8 )
{
strcpy( mem[j], res[j] );
}
}
all_mem = all;
}
for(int j=0;j<100;j++) delete [] res[j];
delete [] res;
i++;
cvResize( frame, image );
cvShowImage( "frame", image);
if (!cvVideoWriter)
{
cvVideoWriter=cvCreateVideoWriter( buffer, CV_FOURCC('U', '2', '6', '3'), 30,
cvGetSize( frame) );
}
cvWriteFrame( cvVideoWriter, frame );
int c = cvWaitKey( 20 );
if ( c== 27 ) break;
}
cvReleaseCapture( &capture );
cvReleaseVideoWriter( &cvVideoWriter );
return 0;
}
Пример работает с видеофайлами, которые были сформированы регистратором с Full HD качеством. С помощью cvCvtColor получается нужный формат изображения. Затем выделяется память для хранения областей CvRect нахождения номера и информации о распознанном номере. В примере на 100 элементов, но на практике было бы достаточно и 10 номеров в одном кадре.
Затем заполняется структура ANPR_OPTIONS.
ANPR_OPTIONS a;
a.Border_Number = 0;
a.Detect_Mode = ANPR_DETECTMODE2 | ANPR_DETECTMODE3;
a.min_plate_size = 500;
a.max_plate_size = 25000;
a.max_text_size = 20;
a.sort_cand_number = 0;
a.type_number = ANPR_RUSSIAN_BASE;
a.type_rect_detect = 0;
a.type_text_recognition = 0;
a.param = 1;
Border_Number = 0; говорит о том, что будут фиксироваться все номера, даже те, которые с краю.
В a.Detect_Mode выбирается два типа детектирования номеров (можно включать и все 3). Пока типов детектирования 3, но они могут поменяться.
a.min_plate_size – минимальная площадь номера.
a.max_plate_size – максимальная площадь номера.
a.max_text_size – размер буфера для каждого номера.
a.type_number – тип распознаваемых номеров, пока он один — ANPR_RUSSIAN_BASE.
Если распознавание происходит успешно (if ( i1 == 0 )), то номера выводятся на изображение чуть выше места распознавания. Ну а далее – действия и функции обычные для программ на основе OpenCV. Ниже представлен небольшой ролик в Full HD качестве, иллюстрирующий работу SDK.
Оригинал статьи здесь
- +1
-
chip
- Поделиться
Комментарии (14)
Я дурил программу с помощью коленки, которая распознавалась как лицо.
Идея гиперплоскости наверно хорошая, но мне кажется, сначала мозг, как конкурент OpenCV, распознаёт улицу (асфальт?), затем распознаёт автомобили, затем места, где вешают номера: перед и зад авто, а уже после этих распознаваний будет меньший процент ошибок для номеров.
А вот знаки бы различать — вот это было бы классно!!!
А то иногда не успеваешь или отвлекаешься. Вот очень надо бы!
Или хорошо бы разработать для каждого знака, перекрестка или вообще события всякие радиомаячки и программой выводить на дисплей.
Давайте разработаем!