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

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

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 ПП

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

24 Январь 2011

Трекинг лица

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

Существует много задач, где необходимо детктировать лицо на видеопотоке, а затем следить за ним. При использовании средств OpenCV простейшую программу можно написать за короткое время. Ниже приведён пример слежения за лицом.

1. Есть не однородный фон
2. Стандартные средства OpenCV работы с камерой
3. После детектирования лица и глаз сразу определяются точки для трекинга
4. Детектирование лица человека
5. Определение точек
6. Трекинг
7. Программно детектирование лиц делается достаточно просто
8. Можно наложить чьё-то фото на лицо человека
9. Наклонение оси и положение центра лица человека
10. И ещё раз слежение

1. There are not a homogeneous background
2. Standard tools OpenCV to work with camera
3. After detecting the face and eyes immediately determined point for tracking
4. Detection of a human face
5. Definition points
6. Tracking
7. Software detection faces is simply
8. Possible to impose someone else’s photo on the face of a man
9. Inclination of the axis and the center of the human face
10. And once again tracking

25 Декабрь 2010

35. Подсчёт объектов (людей), пересекающих линию (People counting)

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

Самый простейший путь при подсчёте объектов – это использование детектирования движений. Например, используя ту же функцию update_mhi из примеров OpenCV. Собственно решение напрашивается само – следить за выделяемыми областями движения, и как только происходит пересечение заданной линии, то увеличивать значение счётчика. Однако функция update_mhi не предназначена для слежения за объектами, поэтому эту часть придётся делать самостоятельно. На рисунке 35.1 показано обнаруженные центра движений (а), и изменения положений центров движений (б).

Рис. 35. 1. Центры движений в кадре (а), изменение движений (b)

Рис. 35. 1. Центры движений в кадре (а), изменение движений (b)

Красные центры – старое местоположение, чёрные – новое. Одной из красных точек не соответствует чёрной, т.к. объект остановился и не двигается. R – максимальное расстояние, на которое может сместиться объект за один кадр.

Для наблюдения за объектами будет использоваться следующая структура:

struct _OBJECT_

{

int x,y; //Координаты центра объекта

int w,h; //Ширина, высота объекта

int timer; //Задержка, позволяющая следить за объектом после остановки

int num; //Номер объекта

int object;//Соответствие с новым объектом

int inn; //Переменная, показывающая где находится объект относительно линии пересечения

}VObject[MAX_OBJECTS],BVObject[MAX_OBJECTS];

VObject – текущий массив объектов, BVObject – предыдущий массив объектом. При каждом анализе детектируемых зон, необходимо сначала сохранить предыдущий массив, например так:

memcpy(BVObject,VObject,sizeof(_OBJECT_)*MAX_OBJECTS);

Если в предыдущем массиве нет ни одного объекта, то при анализе детектируемых зон можно вызвать следующий листинг:

if (all_object<MAX_OBJECTS){

VObject[all_object].num=end_object;

VObject[all_object].timer=timer_1;

VObject[all_object].x=xx;

VObject[all_object].y=yy;

VObject[all_object].w=comp_rect.width;

VObject[all_object].h=comp_rect.height;

VObject[all_object].object=-1;

VObject[all_object].inn=2;

cur_object=all_object;

all_object++;

end_object++;

}

Здесь, end_object – глобальный счётчик номеров объектов (всегда увеличивается); timer_1 – максимальное время задержки, после которого объект, которому не соответствия движения, уничтожается; xx, yy – текущие координаты центра движения; comp_rect – размер зоны движения.

Если от предыдущего кадра сохранились объекты, то необходимо проверять соответствие со старыми объектами:

min=-1;

for(j=0;j<local_all_object;j++)

if (BVObject[j].object==-1)

{

dd=LengthLine(xx,yy,BVObject[j].x,BVObject[j].y);

if (dd<maxdist && (min==-1 || dd1>dd))

{

min=j;

dd1=dd;

}

}

if (min==-1) {

VObject[all_object].num=end_object;

VObject[all_object].inn=2;

end_object++;

}

else {

VObject[all_object].num=BVObject[min].num;

VObject[all_object].inn=BVObject[min].inn;

BVObject[min].object=0;

}

VObject[all_object].timer=timer_1;

VObject[all_object].x=xx;

VObject[all_object].y=yy;

VObject[all_object].w=comp_rect.width;

VObject[all_object].h=comp_rect.height;

VObject[all_object].object=-1;

cur_object=all_object;

all_object++;

Здесь, local_all_object – общее количество старых объектов. Если указатель ссылки на новый объект (BVObject[j].object) равен -1, то сравнивается его удалённость с текущим объектом, если она минимальна и меньше расстояния R, заданного переменной maxdist, то соответствие найдено. Если соответствие не было найдено, то создаётся новый объект, иначе текущему объекту присваиваются номера и положения относительно граничной линии старого объекта.

Определение пересечения линии достаточно просто – необходимо сравнивать значения inn текущего и старого объекта. Определить inn относительно положения текущей линии можно по следующему листингу:

float ang=MakePolarF(center.x-Center.x,center.y-Center.y);//Из библиотеки ImagePak

byte inn=0;

if ((ang>In_ && ang<In_+PI) || (In_>PI  && ang<PI-In_)) {

inn=1;

}

if (VObject[cur_object].inn==0 && inn==1) All_In++;

if (VObject[cur_object].inn==1 && inn==0) {

All_Out++;

}

VObject[cur_object].inn=inn;

Здесь, center – это центр области движения; Center – центр заданной нами линии; In_ – угол в радианах вектора из центра линии в одну из сторон линии.

Этот метод прост и не лишён недостатков, возможно он не всегда работает, но я не нашёл подходящих видео для тестирования. Если у вас есть видео с камеры, расположенный сверху в коридоре (выходе/входе), через которые проходят много людей, и вам несложно передать эти видео мне для тестирования, то свяжитесь со мной!

24 Декабрь 2010

Подсчёт людей (people counting)

написано в рубрике: Распознавание образов — Кручинин Александр @ 8:43 ПП

Случайно в Интернете наткнулся на ряд фирм (как отечественных, так и зарубежных), занимающихся тем, что предоставляют аппаратно-программные средства подсчёта количества проходящих людей, например, через коридор. Сколько вошло и сколько вышло. Решение данного вопроса не очень сложно с использованием OpenCV (на базе процедуры детектирования движений).

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

Пример видео взят с сайта http://homepages.inf.ed.ac.uk/rbf/CAVIARDATA1/

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

Работает на WordPress