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

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

void FoFindBox( IplImage* img, float max_ratio, float min_ratio, int max_area, int min_area, int Min_Lenght_Fo,
CvBox2D* boxes, CvRect *Rects, double* areas, int* all_boxes )
{
const float Min_Fill_Area = 0.4f;
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contours = 0;
cvFindContours( img, storage, &contours, sizeof(CvContour),
CV_RETR_LIST , CV_CHAIN_APPROX_NONE, cvPoint(0,0) );
int all = 0;
for( CvSeq* c=contours; c!=NULL; c=c->h_next)
{
CvBox2D b = cvMinAreaRect2( c );
if ( b.size.height < Min_Lenght_Fo || b.size.width < Min_Lenght_Fo ||
(b.size.width*b.size.height) < min_area || (b.size.width*b.size.height) > max_area ) continue;
if ( fabs( cvContourArea( c ) ) / (b.size.width*b.size.height) < Min_Fill_Area ) continue;
float ratio = ( (b.size.width < b.size.height)?
(float)b.size.width /b.size.height:
(float)b.size.height/b.size.width);
if ( ratio < min_ratio || ratio > max_ratio ) continue;
boxes[all] = b;
Rects[all] = cvBoundingRect( c );
ratio = (float) Rects[all].height / Rects[all].width;
if ( ratio < min_ratio || ratio > max_ratio ) continue;
if ( areas != NULL) areas[all] = cvContourArea©;
all++;
if ( all >= (*all_boxes) ) {
break;
}
}
(*all_boxes) = all;
cvReleaseMemStorage( &storage);
}
Вызывать эту функцию в программе будем следующим образом:
IplImage* Img=cvLoadImage(buf,CV_LOAD_IMAGE_GRAYSCALE); // buf – буфер с именем файла
IplImage* Img2=cvCreateImage( cvGetSize(Img), 8, 1);
IplImage*ImgOut=cvLoadImage(buf);
cvAdaptiveThreshold( Img, Img2, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY,15, 0 );
CvBox2D b[1000];
CvRect r[1000];
double a[1000];
int all = 1000;
FoFindBox( Img2, 0.5f, 0.15f, 25000, 500, 5, b, r, a, &all );
for(j=0;j<all;j++)
if ( r[j].width > r[j].height )
cvRectangle(ImgOut,cvPoint(r[j].x,r[j].y),cvPoint(r[j].x+r[j].width,r[j].y+r[j].height), CV_RGB(255,255,0), 2);
Результат можно посмотреть на следующих картинках:






В этом случае нужно после распознавания буквы и цифр (6 в сумме) продлить границы номера.
После детектирование для каждого кандидата на номер необходимо вызвать функцию распознавания.
В целом использование этой простейшей функции позволяет детектировать 70-80% автомобильных номеров, что однако при построении действующей системы распознавания автомобильных номеров является неудовлетворительным, поэтому необходимо усложнить функцию и/или добавить другой метод детектирования номера.
Одним из явных преимуществ контурного анализа является четко выделенная граница автомобильного номера.
- +1
-
Magatron
- Поделиться
Комментарии (14)