Распознавание автомобильных номеров (iANPR SDK) / Прикладные вопросы распознавания образов / Recog.ru - Распознавание образов для программистов


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

Сейчас, пока идет разработка и тестирование 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.

  • 0
  • 16 июня 2013, 13:52
  • vidikon

Комментарии (0)

RSS свернуть / развернуть

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