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

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

26 Ноябрь 2009

5. Детектирование лиц и глаз

написано в рубрике: OpenCV — Кручинин Александр @ 11:50 ПП
Рис. 5.1. Выделение лица и глаз с помощью средств OpenCV

Рис. 5.1. Выделение лица и глаз с помощью средств OpenCV

OpenCV обладает возможностью детектировать лица и глаза на изображениях. Для того, чтобы понять, как это делается, обратимся к следующему примеру (Листинг 5.1). Данный пример модифицирован их стандартного, поставляемого с OpenCV.

Листинг 5.1. Детектирование лиц и глаз

#include “cv.h”

 

#include “highgui.h”

 

 

 

#include <stdio.h>

 

#include <stdlib.h>

 

#include <string.h>

 

#include <assert.h>

 

#include <math.h>

 

#include <float.h>

 

#include <limits.h>

 

#include <time.h>

 

#include <ctype.h>

 

 

 

#define MAX_EYE 10

 

 

 

static CvMemStorage* storage = 0;

 

static CvHaarClassifierCascade* cascade = 0;

 

static CvHaarClassifierCascade* nested_cascade = 0;

 

int use_nested_cascade = 0;

 

 

 

void detect_and_draw( IplImage* image);

 

 

 

const char* cascade_name =

 

“data/haarcascades/haarcascade_frontalface_alt.xml”;

 

const char* nested_cascade_name =

 

“data/haarcascades/haarcascade_eye_tree_eyeglasses.xml”;

 

double scale = 1;

 

 

 

CvSeq* contours = 0;

 

 

 

void Init();

 

 

 

int _tmain(int argc, _TCHAR* argv[])

 

{

 

Init();

 

return 0;

 

}

 

 

 

void Init()

 

{

 

CvCapture* capture = 0;

 

IplImage  *frame_copy = 0;

 

IplImage *image = 0;

 

 

 

int i;

 

const char* input_name = 0;

 

 

 

//Загрузка базы данных, обученной на детектирование лиц в Фас

 

cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );

 

//Загрузка быза данных, обученной для детектирования глаз

 

nested_cascade = (CvHaarClassifierCascade*)cvLoad( nested_cascade_name, 0, 0, 0 );

 

 

 

if( !cascade )

 

{

 

return ;

 

}

 

//Создание хранилища памяти

 

storage = cvCreateMemStorage(0);

 

 

 

 

 

char *array_1[4]={

 

“picture03.jpg”,

 

“image.jpg”,

 

“26.jpg”,

 

“27.jpg”

 

};

 

 

 

cvNamedWindow( “result”, 1 );

 

 

 

for(i=0;i<4;i++)

 

{

 

//Загружаем картинку

 

image = cvLoadImage( array_1[i], 1 );

 

if( image )

 

{

 

//Производим детектирование

 

detect_and_draw( image);

 

//Удаляем картинку

 

cvReleaseImage( &image );

 

}

 

}

 

}

 

 

 

void detect_and_draw( IplImage* img )

 

{

 

static CvScalar colors[] =

 

{

 

{{0,0,255}},

 

{{0,128,255}},

 

{{0,255,255}},

 

{{0,255,0}},

 

{{255,128,0}},

 

{{255,255,0}},

 

{{255,0,0}},

 

{{255,0,255}}

 

};

 

 

 

IplImage *gray, *small_img;

 

int i, j;

 

 

 

gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );

 

small_img = cvCreateImage( cvSize( cvRound (img->width/scale),

 

cvRound (img->height/scale)), 8, 1 );

 

 

 

cvCvtColor( img, gray, CV_BGR2GRAY );

 

cvResize( gray, small_img, CV_INTER_LINEAR );

 

cvEqualizeHist( small_img, small_img );

 

cvClearMemStorage( storage );

 

 

 

if( cascade )

 

{

 

double t = (double)cvGetTickCount();

 

CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,

 

1.1, 2, 0

 

//|CV_HAAR_FIND_BIGGEST_OBJECT

 

//|CV_HAAR_DO_ROUGH_SEARCH

 

|CV_HAAR_DO_CANNY_PRUNING

 

//|CV_HAAR_SCALE_IMAGE

 

,

 

cvSize(30, 30) );

 

t = (double)cvGetTickCount() – t;

 

printf( “detection time = %gms\n”, t/((double)cvGetTickFrequency()*1000.) );

 

for( i = 0; i < (faces ? faces->total : 0); i++ )

 

{

 

CvRect* r = (CvRect*)cvGetSeqElem( faces, i );

 

CvMat small_img_roi;

 

CvSeq* nested_objects;

 

CvPoint center;

 

CvScalar color = colors[i%8];

 

int radius;

 

center.x = cvRound((r->x + r->width*0.5)*scale);

 

center.y = cvRound((r->y + r->height*0.5)*scale);

 

radius = cvRound((r->width + r->height)*0.25*scale);

 

cvCircle( img, center, radius, color, 3, 8, 0 );

 

if( !nested_cascade )

 

continue;

 

cvGetSubRect( small_img, &small_img_roi, *r );

 

nested_objects = cvHaarDetectObjects( &small_img_roi, nested_cascade, storage,

 

1.1, 2, 0

 

//|CV_HAAR_FIND_BIGGEST_OBJECT

 

//|CV_HAAR_DO_ROUGH_SEARCH

 

//|CV_HAAR_DO_CANNY_PRUNING

 

//|CV_HAAR_SCALE_IMAGE

 

,

 

cvSize(0, 0) );

 

for( j = 0; j < (nested_objects ? nested_objects->total : 0); j++ )

 

{

 

CvRect* nr = (CvRect*)cvGetSeqElem( nested_objects, j );

 

center.x = cvRound((r->x + nr->x + nr->width*0.5)*scale);

 

center.y = cvRound((r->y + nr->y + nr->height*0.5)*scale);

 

radius = cvRound((nr->width + nr->height)*0.25*scale);

 

cvCircle( img, center, radius, color, 3, 8, 0 );

 

}

 

}

 

}

 

 

 

cvShowImage( “result”, img );

 

cvWaitKey(1000);

 

cvReleaseImage( &gray );

 

cvReleaseImage( &small_img );

 

}

Первоначально с помощью функции cvLoad() загружаются базы для детектирования лиц и глаз (OpenCV\data\haarcascades\). Вы можете скопировать эти базы в свой каталог или указать на точный путь до OpenCV. Помимо базы для детектирования лиц в фас, есть ещё база для детектирования лиц в профиль. Если базы нормально загружаются, то переходим к созданию хранилища памяти. Затем с помощью функции cvNamedWindow() создаём окно, в которое будут выводиться результаты детектирования, и программа входит цикл в котором последовательно выполняется загрузка изображения в память, детектирование его с использованием функции detect_and_draw(), удаление изображения из памяти.

Опишем подробнее процесс детектирования в функции detect_and_draw().

Первоначально определяется массив colors – в нём содержатся цвета для окружностей, которыми будут выделяться лица и глаза. С помощью функции cvCreateImage() создаются два дополнительных изображения (IplImage *gray, *small_img;), на которых и будет осуществляться детектирование. Эти изображения представлены в градациях серого, для перевода в этот формат использовалась функция cvCvtColor(). Далее обнуляется хранилище памяти cvClearMemStorage().

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

Первоначально на экран исходное изображение img выводится с помощью cvCircle() окружность. Затем, если база для детектирования глаз загрузилась успешно, программа с использованием cvGetSubRect() устанавливает границы, внутри которых будут искаться глаза. А затем, использую ту же функцию cvHaarDetectObjects() детектируются глаза внутри области лица. Программа опять входит в цикл, в котором перебираются все найденные глаза и обводятся окружностью.

Если глаз всего один – значит это циклоп, если глаза больше чем три – пришелец. А если серьёзно, то областей глаз может быть больше – и вам придётся выбирать  самим, которые реальные, а в которых программа ошиблась.

Используя cvShowImage() выводим на экран результат детектирования лица. Ждём секунду (cvWaitKey(1000)) и, не забывая удалять созданные картинки, выходим из функции.

 

Детектирование лиц и глаз завершено. Правда просто?

Нет комментариев

Еще нет комментариев.

RSS лента комментариев к этой записи.

Извините, комментирование на данный момент закрыто.

Работает на WordPress