Распознавание образов для программистов

ВНИМАНИЕ! БЛОГ ПЕРЕЕХАЛ ПО АДРЕСУ
RECOG.RU

15 Апрель 2011

Распознавание текста с использованием шаблонов

написано в рубрике: OpenCV — Кручинин Александр @ 1:05 ДП

Здесь показано, как распознавать текст с использованием контуров. Однако в случае зашумления и искажения контуров данный метод работает неудовлетворительно. Конечно, известны методы распознавание текста на базе нейронных сетей, но существует ещё более простой метод (в плане обучения), основанный на сравнении с эталоном (шаблоном). В ряде случае сравнение с шаблоном будет достаточно для распознавания текста, например, при распознавании автомобильных номеров.

Читать дальше

6 Апрель 2011

Детектирование QR Code с помощью средств OpenCV

написано в рубрике: OpenCV — Кручинин Александр @ 1:31 ПП
Распознавание двухмерных кодов является актуальной задачей, впрочем, уже решенной на ряде устройств и персональных компьютерах. Однако на настоящий момент отсутствуют BSD версии библиотек распознавания, а ограниченные лицензии в большинстве случаев не позволяют использовать открытые исходные кода для своих целей.
Популярный в Японии QrCode является одним из наиболее оптимальных кодов, хотя при малых размерах кода квадраты-мишени отнимают много места. На рисунке 1 приведен пример кода Qr с закодированной фразой «Test code».

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

Читать дальше

26 Март 2011

Слежение за баскетбольным мячом

написано в рубрике: OpenCV, Распознавание образов — Кручинин Александр @ 3:32 ПП

Известен подход выделения объектов на изображениях по распределению цветовой гаммы. Данный подход является в своей основе достаточно простым, но, не смотря на это, может использоваться в ряде случае. Иногда этот подход применяется как первоначальный этап обработки изображения, для решения более сложных задач, например детектирования лиц [1]. Такой подход может использоваться и в системах трекинга, если цвет объекта отличается от фона.

Рассмотрим задачу отслеживания движений баскетбольного мяча. Есть входной поток изображения. На каждом кадре изображения необходимо определить наличие или отсутствие баскетбольного мяча. Мяч при детектировании выделить окружностью.

Решение задачи разбивается на несколько этапов:

  • выделения пикселей, соответствующих баскетбольному мячу;
  • выделение контурами найденные объекты;
  • нахождении контура мяча;
  • построение окружности, в которую попадают все точки контура мяча.

С помощью средств OpenCV данная задача решается очень просто. На рисунках 1а представлены примеры кадров с баскетбольным мячом. Мячу соответствуют в основном оранжевые пиксели. Поэтому для выделения большинства из них достаточно следующего условия:

R > 1.5*G, R > 2*B,

где R, G, и B – соответствующие компоненты пикселя.

Условие подобрано примерно и работает удовлетворительно. На рисунках 1б представлены результаты выделения пикселей, соответствующих мячу, что показано в виде белых пикселей на чёрном фоне.

out1-5

out1-20

out1-100

а)

out2-5

out2-20

out2-100

б)

Рис. 1. Исходные изображения (а), изображения с выделенными пикселями, соответствующими цвету мяча (б)

Пример использования контуров в OpenCV приведен здесь http://blog.vidikon.com/?p=59. Из найденных контуров необходимо выделения максимального, который в данном примере будет соответствовать мячу (см. листинг). Результаты выделения максимального контура представлены на рисунке 2а.

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

int cvMinEnclosingCircle(const CvArr* points,

CvPoint2D32f* center,

float* radius);

Параметры:

points – последовательность или массив 2D точек;

center – выходной параметр: центр окружности;

radius – выходной параметр: радиус окружности.

Функция ищет минимальную окружность, включающую в себя все точки последовательности. При невозможности найти окружность функция возвращает 0.

На рисунке 2б приведены примеры выделения окружностей для приведенных случаев.

out3-5

out3-20

out3-100 а)

out4-5

out4-20

out4-100 б)

Рис. 2. Выделение контура мяча (а), выделение окружности (б)

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

#include “cv.h”

#include “highgui.h”

#include <stdio.h>

#include <ctype.h>

void FindBall(IplImage* Img);

void Counter(IplImage* img);

CvPoint2D32f center;

float radius;

long pointer=0;

int main( int argc, char** argv )

{

CvCapture* capture = 0;

capture = cvCaptureFromAVI( “capture-1.avi” );

cvNamedWindow( “Demo”, 1 );

for(;;)

{

IplImage* frame = 0;

int i, k, c;

frame = cvQueryFrame( capture );

if( !frame )

break;

FindBall(frame);

cvShowImage( “Demo”, frame );

c = cvWaitKey(50);

if( (char)c == 27 )

break;

pointer++;

}

cvWaitKey(0);

cvReleaseCapture( &capture );

cvDestroyWindow(”Demo”);

return 0;

}

void FindBall(IplImage* Img)

{

IplImage* Image=cvCreateImage( cvGetSize(Img), 8, 3 );

cvCopy(Img,Image);

//Теперь необходимо получить доступ к всем пикселям.

uchar* ptr1;

ptr1 = (uchar*) (Image->imageData );

int i,j;

for(i=0;i<Img->height;i++)

for(j=0;j<Img->width;j++)

{

//R > 1.5*G, R > 2*B

if (ptr1[j*3+2+i*Image->widthStep]>1.5*ptr1[j*3+1+i*Image->widthStep] &&

ptr1[j*3+2+i*Image->widthStep]>2*ptr1[j*3+i*Image->widthStep])

{

ptr1[j*3+i*Image->widthStep]=255;

ptr1[j*3+1+i*Image->widthStep]=255;

ptr1[j*3+2+i*Image->widthStep]=255;

}

else

{

ptr1[j*3+i*Image->widthStep]=0;

ptr1[j*3+1+i*Image->widthStep]=0;

ptr1[j*3+2+i*Image->widthStep]=0;

}

}

//Выделение контуров и поиск наибольшего контура

Counter(Image);

if (center.x>-1)

{

CvPoint p;

p.x=center.x;

p.y=center.y;

cvCircle( Img, p, radius, CV_RGB(255,0,0), 3, 8, 0 );

}

cvReleaseImage( &Image );

}

void Counter(IplImage* img)

{

IplImage* img_gray= cvCreateImage( cvSize(img->width,img->height), 8, 1);

CvSeq* contours = 0;

CvMemStorage* storage = cvCreateMemStorage(0);

cvCvtColor( img, img_gray, CV_BGR2GRAY );

cvFindContours( img_gray, storage, &contours, sizeof(CvContour),

CV_RETR_LIST  , CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );

CvSeq* h_next=0;

//Поиск максимального контура

for( CvSeq* c=contours; c!=NULL; c=c->h_next )

{

if (c!=contours)

{

//Проверяем какой контур больше

if (h_next->total>=c->total)

{

h_next->h_next=h_next->h_next->h_next;

continue;

}

}

h_next=c;

}

center.x=-1;

if (h_next->total<200) return;//нет  мяча – слишком маленькие контуры

cvDrawContours( img, h_next, CV_RGB(255,0,0), CV_RGB(0,255,0),2, 2, CV_AA, cvPoint(0,0) );

//Минимальная окружность

cvMinEnclosingCircle(h_next,&center,&radius);

cvReleaseMemStorage( &storage);

cvReleaseImage( &img_gray );

}

Ролик слежения за мячом.

Литература:

1. Yunlong Zhao, Tat-Seng Chua. Automatic Tracking of Face Sequences in MPEG Video. In Proceedings of Computer Graphics International’2003. pp.170~175

16 Февраль 2011

Трекинг лица 2

написано в рубрике: OpenCV, Распознавание образов — Кручинин Александр @ 6:11 ПП

Наклон головы и виртуальное нажатие кнопок движения клавиатуры

2 Февраль 2011

37. Реализация трекинга лица

написано в рубрике: OpenCV — Кручинин Александр @ 12:52 ПП

В предыдущей записи (http://blog.vidikon.com/?p=461) был приведён ролик трекинга лица, полученный с помощью средств OpenCV. Здесь будет описано, как добиться такого результата за короткое время.

Алгоритм использует следующие технологии:

1) детектируется лицо (http://blog.vidikon.com/?p=34);

2) на лице выделяются точки для трекинга и затем осуществляется их мониторинг (http://blog.vidikon.com/?p=277).

Я не стану приводить код и того и другого, поскольку используются вещи из стандартных примеров, описанных в частности в приведённых ссылках. После детектирования лица нам известен CvRect, который передаём в функцию cvSetImageROI для текущего изображения с Web-камеры. Ниже приведён пример инициализации точек:

IplImage* eig = cvCreateImage( cvGetSize(grey), 32, 1 );

IplImage* temp = cvCreateImage( cvGetSize(grey), 32, 1 );

double quality = 0.01;

double min_distance = 10;

cvSetImageROI(grey,RectFace);

count = MAX_COUNT;

cvGoodFeaturesToTrack( grey, eig, temp, points[1], &count,

quality, min_distance, 0, 3, 0, 0.04 );

cvFindCornerSubPix( grey, points[1], count,

cvSize(win_size,win_size), cvSize(-1,-1),

cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03));

cvResetImageROI(grey);

Листинг 37.1. Инициализация точек трекинга

Если какие-то параметры непонятные, то посмотрите пример OpenCV по трекингу – я их имена не менял. Но возникает резонный вопрос: а зачем вообще использовать трекинг, если можно постоянно детектировать лицо? Ответ: без использования пакета распараллеливания процедура детектирования лица полностью занимает ресурсы современного персонального компьютера, причём так, что не успевают обрабатываться все кадры. А при трекинге – на средненьком компьютере Core 2 Duo 2.2 ГГц затрачиваются не более 5% ресурсов центрального процессора.

Для определения положения лица и его наклона будем оперировать двумя переменными: Point1 и Point2. В следующем листинге показано их начальное определение после детектирования лица:

Point1.x=0;

Point1.y=0;

Point2.x=0;

Point2.y=0;

int pp=0;

for(i=0;i<count;i++){

points[1][i].x+=RectFace.x;

points[1][i].y+=RectFace.y;

//Здесь также необходимо считать средние точки

Point1.x+=points[1][i].x;

Point1.y+=points[1][i].y;

point_status[i]=0;

if (points[1][i].y<CenterFace.y)

{

point_status[i]=1;

Point2.x+=points[1][i].x;

Point2.y+=points[1][i].y;

pp++;

}

}

Point1.x/=count;

Point1.y/=count;

Point2.x/=pp;

Point2.y/=pp;

Листинг 37.2. Определение точек Point1 и Point2

Первоначально точки обнуляются. Затем перебираются все точки трекинга, к которым прибавляется смещение CvRect лица – RectFace. В Point1 суммируются все точки – эта точка будет нам показывать, где центр лица. Для определения наклона используется довольно простое соображение – первоначально считается, что лицо расположено прямо (можно было в принципе сразу определить наклон по детектированным глазам), и выделяются все точки, которые выше центра лица – CenterFace. Этим точкам устанавливается специальный статус. После завершения цикла вычисляются средние значения точек. Собственно, проведя линию между Point1 и Point2, мы получаем наклон оси.

При осуществлении трекинга необходимо обновлять значения точек Point1 и Point2, точка Point1 – это средняя всех точек, а точка Point2 – это средняя точка всех точек со статусом point_status.

Для вывода другого лица поверх своего (у нас это лицо вождя мирового пролетариата) необходимо получение координаты точки вывода и наклона лица. В листинге 37.3 показано, как это делается

double angle;

if (CenterFace.y-CenterE.y!=0) angle=atan((double)(CenterFace.x-CenterE.x)/(CenterFace.y-CenterE.y));

else angle=0;

double angle_=angle*180/PI;

CvSize Size1=cvGetSize(image_1);

//ещё угол

double angle1=atan((double)Size1.width/Size1.height);

Mat image_11=image_1;

Mat image_12=rotateImage(image_11,angle_);

IplImage image_2=image_12;

CvSize Size=cvGetSize(&image_2);

CvRect Rect;

double x=Size.width;

double y=Size.height;

Rect.x=CenterFace.x-x/2;Rect.y=CenterFace.y-y/2;

Rect.height=Size.height;

Rect.width=Size.width;

cvSetImageROI(image,Rect);

IplImage* image_2m=cvCreateImage(cvGetSize(&image_2), 8, 1);

cvCvtColor( &image_2,image_2m, CV_BGR2GRAY );

if (Rect.x>=0 && Rect.y>=0 && Rect.x+Rect.width<=639 && Rect.y+Rect.height<=479)

cvCopy(&image_2,image,image_2m);

cvResetImageROI( image);

cvReleaseImage(&image_2m);

Листинг 37.3. Вычисление координаты, угла и вывод изображения на экран

Первоначально вычисляется угол наклона angle, CenterFace до этого выражается через Point1, а CenterE – через Point2. Вычисляется размер изображения Вождя – Size1. Дальше происходит поворот изображения (http://blog.vidikon.com/?p=468) и установление прозрачного цвета (http://blog.vidikon.com/?p=466). Ну и собственно вывод изображения на экран.

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

Старые записи »

Работает на WordPress