Проекции изображения лица
Материал из CompVision
Проекция изображения лица
Пример иллюстрирует применение функций поиска лица на изображении, а так же работу с матрицам OpenCv (нахождение среднего по строкам и столбцам (суммируются интенсивности для изображения в серых тонах, и результат отображается на захваченном изображении ф-ция cvReduce) ).
Результат работы программы приведен на рисунке ниже.
Файлы проекта: Проект
Текст примера (Компилировался с в C++Builder6 OpenCV2.0):
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop # define _STLP_NO_CSTD_FUNCTION_IMPORTS //#define SKIP_INCLUDES #define _FM_NO_REMAP #include "cv.h" #include "highgui.h" #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; CvCapture* capture = 0; // Описатель шрифта (см. дальше) CvFont font; IplImage *frame=0, *frame_copy = 0; IplImage* gray=0; static CvHaarClassifierCascade* cascade = 0; // Заменяя эти файлы можно искать разные вещи // см. директорию haarcascades/ там все понятно // ищем лицо фронтально const char* cascade_name ="haarcascades/haarcascade_frontalface_alt2.xml"; void ProcessFrame( IplImage* image ); #define WIDTHBYTES(bits) ((((bits) + 31) / 32) * 4) //--------------------------------------------------------------------------- // Создание API шного битмапа из интеловского RGB изображения //--------------------------------------------------------------------------- HBITMAP CreateRGBBitmap(IplImage* _Grab) { char *App; LPBITMAPINFO lpbi = new BITMAPINFO; lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); lpbi->bmiHeader.biWidth = _Grab->width; lpbi->bmiHeader.biHeight =_Grab->height; lpbi->bmiHeader.biPlanes = 1; lpbi->bmiHeader.biBitCount = 24; lpbi->bmiHeader.biCompression = BI_RGB; lpbi->bmiHeader.biSizeImage = WIDTHBYTES((DWORD)_Grab->width * 8) * _Grab->height; lpbi->bmiHeader.biXPelsPerMeter = 0; lpbi->bmiHeader.biYPelsPerMeter = 0; lpbi->bmiHeader.biClrUsed = 0; lpbi->bmiHeader.biClrImportant = 0; void* pBits; HBITMAP hBitmap = CreateDIBSection( NULL, lpbi, DIB_RGB_COLORS, (void **)&pBits, NULL, 0 ); delete lpbi; if ( hBitmap ) App=(char*)pBits; long int length=0; if(_Grab->nChannels==1) // Серое или бинарное { length = _Grab->width*(_Grab->height); for (int i=0;i<_Grab->height;i++) { for (int j=0;j<_Grab->width;j++) { App[_Grab->width*3*(_Grab->height-i-1)+j*3]=_Grab->imageData[_Grab->width*(i)+j]; App[_Grab->width*3*(_Grab->height-i-1)+j*3+1]=_Grab->imageData[_Grab->width*(i)+j]; App[_Grab->width*3*(_Grab->height-i-1)+j*3+2]=_Grab->imageData[_Grab->width*(i)+j]; } } } if(_Grab->nChannels==3) // Цветное { for (int i=0;i<_Grab->height;i++) { memcpy(App+_Grab->width*3*(_Grab->height-i-1),_Grab->imageData+_Grab->width*3*i,_Grab->width*3); // Копируем память } } return hBitmap; } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // Функция вывода изображения на HANDLE оконного компонента //--------------------------------------------------------------------------- void APIDrawIpl(int x,int y,IplImage* _Grab,void *HANDLE) { HDC hMemDC,hDC; hDC=GetDC(HANDLE); hMemDC = CreateCompatibleDC(hDC); HBITMAP Bitmap=CreateRGBBitmap(_Grab); SelectObject(hMemDC,Bitmap); BitBlt(hDC,x,y,_Grab->width,_Grab->height,hMemDC,0,0,SRCCOPY); DeleteObject(Bitmap); DeleteDC(hMemDC); DeleteDC(hDC); } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 ); if( !cascade ) { Close(); } capture = cvCaptureFromCAM(0); Application->OnIdle = IdleLoop; // Поток обработки простоя } //--------------------------------------------------------------------------- void __fastcall TForm1::IdleLoop(TObject*, bool& done) { done = false;// Поток обработки простоя if( capture ) { // Даем приказ на захват кадра if( !cvGrabFrame( capture )) goto skip; // Если удачно - получаем кадр frame = cvRetrieveFrame( capture ); if( !frame ) // Если захват не удался - пропускаем дальнейшее goto skip; //********************************************************* // Если стерли то что ниже - это надо раскомментировать // if( !frame_copy ) // frame_copy = cvCreateImage( cvSize(frame->width,frame->height), // IPL_DEPTH_8U, frame->nChannels ); // Делаем копию кадра, иначе может пропасть. // cvCopy( frame, frame_copy, 0 ); // Если стерли то что ниже - это надо раскомментировать //********************************************************* //********************************************************* // Если не нужно подгонять размер кадра - это можно стереть // Выделяем память под копию кадра if( !frame_copy ) frame_copy = cvCreateImage( cvSize(640,480), IPL_DEPTH_8U, frame->nChannels ); // Масштабируем под заданный размер cvResize( frame, frame_copy, CV_INTER_LINEAR ); // Если не нужно подгонять размер кадра - это можно стереть //********************************************************* // Выделяем память под серую копию кадра if( !gray ) gray = cvCreateImage( cvSize(frame_copy->width,frame_copy->height), IPL_DEPTH_8U,1); // Обработка полученного кадра ProcessFrame( frame_copy ); } skip:; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { cvReleaseImage( &frame_copy ); cvReleaseImage( &gray ); cvReleaseCapture( &capture ); } //--------------------------------------------------------------------------- void ProcessFrame( IplImage* Grab ) { static CvMemStorage* storage = 0; storage = cvCreateMemStorage(0); CvMemStorage* storage_cd = cvCreateMemStorage(0); cvCvtColor(Grab, gray, CV_BGR2GRAY); // Получаем серый цвет // Необходимо удалить белый бордюр cvRectangle(gray, cvPoint(0,0), cvPoint(gray->width-1,gray->height-1),CV_RGB(0,0,0)); //--------------------------------------------------------------------------- //----------------------Поиск лица------------------------------------------- if( cascade ) { // Это собственоо главная функция // параметры см. в документации CvSeq* faces = cvHaarDetectObjects( gray, cascade, storage, 1.2, 2, 0 |CV_HAAR_FIND_BIGGEST_OBJECT //|CV_HAAR_DO_ROUGH_SEARCH |CV_HAAR_DO_CANNY_PRUNING //|CV_HAAR_SCALE_IMAGE ); // Обводим все лица в кадре for(int i = 0; i < (faces ? faces->total : 0); i++ ) { CvRect* r = (CvRect*)cvGetSeqElem( faces, i ); CvMat gray_roi; CvPoint center; int radius; //------------------------------------------------------ //----------------------Обработка области лица---------- //------------------------------------------------------ cvRectangle(Grab, cvPoint(r->x,r->y), cvPoint(r->x+r->width,r->y+r->height),CV_RGB(0,255,0)); cvSetImageROI(gray,*r); //--- Определили прямоугольник лица CvMat MV,MH; double *VertSumS; double *HorSumS; VertSumS=new double[r->height]; HorSumS=new double[r->width]; cvInitMatHeader( &MV,r->height,1, CV_64FC1, VertSumS ); cvInitMatHeader( &MH,1,r->width,CV_64FC1, HorSumS ); cvReduce(gray, &MV,1,CV_REDUCE_AVG); // Среднее по строкам cvReduce(gray, &MH,0,CV_REDUCE_AVG); // Среднее по столбцам for (int i=0;i<r->height ;i++) { double v=cvGetReal2D(&MV,i,0)*0.5; cvLine( Grab, cvPoint(r->x,r->y+i), cvPoint(r->x-v,r->y+i), CV_RGB(100,0,0), 1, 8 ); } for (i=0;i<r->width ;i++) { double v=cvGetReal2D(&MH,0,i)*0.5; cvLine( Grab, cvPoint(r->x+i,r->y), cvPoint(r->x+i,r->y-v), CV_RGB(0,100,0), 1, 8 ); } delete [] VertSumS; delete [] HorSumS; //--- Сбросили прямоугольник лица cvResetImageROI(gray); } } //----------------------Поиск лица------------------------------------------- //--------------------------------------------------------------------------- APIDrawIpl(10,10,Grab,Form1->Handle); // Рисуем результат cvReleaseMemStorage(&storage); }
