Haar Cascade Classifier
OpenCV ialah open source library
computer vision, yang memudahkan pemrograman deteksi wajah, face
tracking, face recognition, kalman filtering dn berbagai metode artificial
intelligent.
OpenCV menggunakan sebuah tipe
face detector yang dsebut Haar Cascade classifier. Gambar menunjukkan
face detector berhasil bekerja pada sebuah gambar. Jika ada sebuah image
(bias dari file /live video), face detector menguji tiap lokasi image dan
mengklasifikasinya sebagai “wajah” atau “bukan wajah”. Klasifikasi dimisalkan
sebuah skala fix untuk wajah, misal 50x50 pixel. Jika wajah pada image
lebih besar atau lebih kecil dari pixel tersebut, classifier terus menerus
jalan beberapa kali, untuk mencari wajah pada gambar tersebut.
Classifier menggunakan data yang
disimpan pada file XML untuk memutuskan bagaimana mengklasifikasi tiap lokasi
image. OpenCV menggunakan 4 data XML untuk deteksi wajah depan, dan 1
untuk wajah profile. Termasuk juga 3 file XML bukan wajah: 1 untuk
deteksi full body, 1 untuk upper body, dan 1 untuk lower body. Anda harus
memberitahukan classifier dimana menemukan file data yang akan anda gunakan.
Salah satunya bernama haarcascade_frontalface_default.xml. Pada OpenCV, terletak
pada :
Program_Files/OpenCV/data/haarcasades/haarcascade_frontalface_default.xml.
Konsep Pendeteksian Wajah
OpenCV face detector menggunakan
metode Paul Viola dan Michael Jones, silahkan baca detail paper mereka di CD
Program. Metode mengkombinasikan :
· Fitur
rectangular sederhana yang disebut fitur Haar
· Integral
imag untuk deteksi fitur yang cepat
· Metode
machine learning AdaBoost.
· Sebuah
pengklasifikasi cascade untkmengkombinasikan banyak fitur secara efisien.
Fitur yang digunakan Viola dan
Jones menggunakan bentuk gelombang Haar. Bentuk gelombang Haar ialah sebuah
gelombang kotak. Pada 2 dimensi, gelombang kotak ialah pasangan persegi
yang bersebelahan, 1 terang dan 1 gelap. Haar ditentukan oleh pengurangan pixel
rata-rata daerah gelap dari pixel rata-rata daerah terang. Jika
perbedeaan diatas threshold (diset selama learning), fitur tersebut dikatakan
ada.
Implementasi Deteksi Wajah:
1. Variable
CvHaarClassifierCascade * pCascade menyimpan data dari file XML. Untuk
meload data XML ke pCascade, Anda dapat menggunakan fungsi cvLoad().
cvLoad ialah fungsi umum untuk meload data dari file yang membutuhkan hingga 3
parameter input. JIka anda membuat kode pada C, set parameter sisanya menjadi
0, jika menggunakan C++ hilangkan parameter yang tidak digunakan.
2. Sebelum
mendeteksi wajah pada images, Anda membutuhkan objek CvMemStorage.
Detector akan mendaftar wajah yang terdeteki ke buffer. Yang harus anda
kerjakan ialah membuatnya
pStorage=CvCreateMemStorage(0);
dan mereleasenya ketika
telah selesai.
cvReleaseMemStorage(&pStorage);
3. Anda
akan sering meload data dari file, tentu ada kemungkinan salah path, sebaiknya
berikan pengecekan untuk memastikan file diload dengan benar.
if(!pInpImg
|| !pStorage || !pCascade)
{
printf
(“Inisialisasi gagal \n”);
}
exit (-1);
}
4. Untuk
menjalankan detector, panggil objek cvHaarDetect. Fungsi ini membutuhkan
7 parameter, 3 pertama ialah pointer image, XML data dan memory
buffer, sisanya diset pada default C++.
pFaceRectSeq
=cvHaarDetectObjects
(pInpImg,
pCascade, pStorage,
1.1, //tingkatkan
skala pencarian dengan 10% tiap passing
3, //drop
group yang kurang dari
3 deteksi
CV_HAAR_DO_CANNY_PRUNNING
//skip region yang tidak berisi wajah
cvSize(0,));
//gunakan XML default untuk skala pencarian terkecil.
5. Untuk membuat display Window
gunakan cvNamedWindow seperti berikut:
cvNamedWindow
(“Haar Window”, CV_WINDOW_AUTOSIZE);
Untuk memasukkan
image ke display, panggil fungsi cvShowImage() dengan nama yang telah dibuat
pada window dan nama image yang ingin ditampilkan.
Berikut ini kode lengkapnya :
DetectFace.cpp:
// Capturing.cpp :
Defines the entry point for the console application.
static CvMemStorage* storage = 0;
static CvHaarClassifierCascade* cascade = 0;
void detect_and_draw( IplImage* image );
const char* cascade_name =
"C:/Program Files/OpenCV/data/haarcascades/haarcascade_frontalface_alt.xml";
/*"haarcascade_profileface.xml";*/
int main(int argc, char** argv)
{
CvCapture* capture = 0;
IplImage *frame, *frame_copy = 0;
argc = 1;
argv = 0;
int optlen = strlen("--cascade=");
const char* input_name;
input_name = 0;
if( argc > 1 && strncmp( argv[1], "--cascade=", optlen ) == 0 )
{
cascade_name = argv[1] + optlen;
input_name = argc > 2 ? argv[2] : 0;
}
else
{
fprintf( stderr,
"Usage: facedetect --cascade=\"\" [filename|camera_index]\n" );
//return -1;
/*input_name = argc > 1 ? argv[1] : 0;*/
}
cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );
if( !cascade )
{
fprintf( stderr, "ERROR: Could not load classifier cascade\n" );
//return -1;
}
storage = cvCreateMemStorage(0);
if( !input_name || (isdigit(input_name[0]) && input_name[1] == '\0') )
capture = cvCaptureFromCAM( !input_name ? 0 : input_name[0] - '0' );
else
capture = cvCaptureFromAVI( input_name );
cvNamedWindow( "Face Detection", 1 );
if( capture )
{
for(;;)
{
if( !cvGrabFrame( capture ))
break;
frame = cvRetrieveFrame( capture );
if( !frame )
break;
if( !frame_copy )
frame_copy = cvCreateImage( cvSize(frame->width,frame->height),
IPL_DEPTH_8U, 3 );
if( frame->origin == IPL_ORIGIN_TL )
cvCopy( frame, frame_copy, 0 );
else
cvFlip( frame, frame_copy, 0 );
detect_and_draw( frame_copy );
if( cvWaitKey( 10 ) >= 0 )
break;
}
cvReleaseImage( &frame_copy );
cvReleaseCapture( &capture );
}
else
{
const char* filename = "lena.jpg";
IplImage* image = cvLoadImage( filename, 1 );
if( image )
{
detect_and_draw( image );
cvWaitKey(0);
cvReleaseImage( &image );
}
else
{
/* assume it is a text file containing the
list of the image filenames to be processed - one per line */
FILE* f = fopen( filename, "rt" );
if( f )
{
char buf[1000+1];
while( fgets( buf, 1000, f ) )
{
int len = (int)strlen(buf);
while( len > 0 && isspace(buf[len-1]) )
len--;
buf[len] = '\0';
image = cvLoadImage( buf, 1 );
if( image )
{
detect_and_draw( image );
cvWaitKey(0);
cvReleaseImage( &image );
}
}
fclose(f);
}
}
}
cvDestroyWindow("Face Detection");
return 0;
}
void detect_and_draw( IplImage* img )
{
int scale = 1;
IplImage* temp = cvCreateImage( cvSize(img->width/scale,img->height/scale), 8, 3 );
CvPoint pt1, pt2;
int i;
//cvPyrDown( img, temp, CV_GAUSSIAN_5x5 );
cvClearMemStorage( storage );
if( cascade )
{
CvSeq* faces = cvHaarDetectObjects( img, cascade, storage,
1.2, 2, CV_HAAR_DO_CANNY_PRUNING,
cvSize(40, 40) );
for( i = 0; i < (faces ? faces->total : 0); i++ )
{
CvRect* r = (CvRect*)cvGetSeqElem( faces, i );
pt1.x = r->x*scale;
pt2.x = (r->x+r->width)*scale;
pt1.y = r->y*scale;
pt2.y = (r->y+r->height)*scale;
cvRectangle( img, pt1, pt2, CV_RGB(0,255,0), 3, 8, 0 );
/* IplImage * faceSave = cvCreateImage(cvGetSize(img),img->depth,img->nChannels);
IplImage * faceToSave = 0;
if( !faceToSave )
faceToSave = cvCreateImage( cvGetSize(pImg), 8, 3 );
cvCopy(pImg, faceToSave, 0);
faceToSave->origin = pImg->origin;
int pointX = 0;
int pointY = 0;
int lebar = 0;
if (r->width > r->height)
{
lebar = r->width;
pointX = r->x - ((r->width - r->height)/2);
pointY = r->y - ((r->width - r->height)/3);
} else if (r->width < r->height)
{
lebar = r->height;
pointX = r->x - ((r->height - r->width)/2);
pointY = r->y - ((r->height - r->width)/3);
}
cvSetImageROI(img, cvRect(pointX,pointY,lebar,lebar));
faceSave = img;
cvNamedWindow("Result", 1 );
cvShowImage("Result", img);
cvResetImageROI(img);*/
}
}
cvShowImage( "Face Detection", img );
cvReleaseImage( &temp );
}
#ifdef _EiC
main(1,"facedetect.c");
#endif
static CvMemStorage* storage = 0;
static CvHaarClassifierCascade* cascade = 0;
void detect_and_draw( IplImage* image );
const char* cascade_name =
"C:/Program Files/OpenCV/data/haarcascades/haarcascade_frontalface_alt.xml";
/*"haarcascade_profileface.xml";*/
int main(int argc, char** argv)
{
CvCapture* capture = 0;
IplImage *frame, *frame_copy = 0;
argc = 1;
argv = 0;
int optlen = strlen("--cascade=");
const char* input_name;
input_name = 0;
if( argc > 1 && strncmp( argv[1], "--cascade=", optlen ) == 0 )
{
cascade_name = argv[1] + optlen;
input_name = argc > 2 ? argv[2] : 0;
}
else
{
fprintf( stderr,
"Usage: facedetect --cascade=\"\" [filename|camera_index]\n" );
//return -1;
/*input_name = argc > 1 ? argv[1] : 0;*/
}
cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );
if( !cascade )
{
fprintf( stderr, "ERROR: Could not load classifier cascade\n" );
//return -1;
}
storage = cvCreateMemStorage(0);
if( !input_name || (isdigit(input_name[0]) && input_name[1] == '\0') )
capture = cvCaptureFromCAM( !input_name ? 0 : input_name[0] - '0' );
else
capture = cvCaptureFromAVI( input_name );
cvNamedWindow( "Face Detection", 1 );
if( capture )
{
for(;;)
{
if( !cvGrabFrame( capture ))
break;
frame = cvRetrieveFrame( capture );
if( !frame )
break;
if( !frame_copy )
frame_copy = cvCreateImage( cvSize(frame->width,frame->height),
IPL_DEPTH_8U, 3 );
if( frame->origin == IPL_ORIGIN_TL )
cvCopy( frame, frame_copy, 0 );
else
cvFlip( frame, frame_copy, 0 );
detect_and_draw( frame_copy );
if( cvWaitKey( 10 ) >= 0 )
break;
}
cvReleaseImage( &frame_copy );
cvReleaseCapture( &capture );
}
else
{
const char* filename = "lena.jpg";
IplImage* image = cvLoadImage( filename, 1 );
if( image )
{
detect_and_draw( image );
cvWaitKey(0);
cvReleaseImage( &image );
}
else
{
/* assume it is a text file containing the
list of the image filenames to be processed - one per line */
FILE* f = fopen( filename, "rt" );
if( f )
{
char buf[1000+1];
while( fgets( buf, 1000, f ) )
{
int len = (int)strlen(buf);
while( len > 0 && isspace(buf[len-1]) )
len--;
buf[len] = '\0';
image = cvLoadImage( buf, 1 );
if( image )
{
detect_and_draw( image );
cvWaitKey(0);
cvReleaseImage( &image );
}
}
fclose(f);
}
}
}
cvDestroyWindow("Face Detection");
return 0;
}
void detect_and_draw( IplImage* img )
{
int scale = 1;
IplImage* temp = cvCreateImage( cvSize(img->width/scale,img->height/scale), 8, 3 );
CvPoint pt1, pt2;
int i;
//cvPyrDown( img, temp, CV_GAUSSIAN_5x5 );
cvClearMemStorage( storage );
if( cascade )
{
CvSeq* faces = cvHaarDetectObjects( img, cascade, storage,
1.2, 2, CV_HAAR_DO_CANNY_PRUNING,
cvSize(40, 40) );
for( i = 0; i < (faces ? faces->total : 0); i++ )
{
CvRect* r = (CvRect*)cvGetSeqElem( faces, i );
pt1.x = r->x*scale;
pt2.x = (r->x+r->width)*scale;
pt1.y = r->y*scale;
pt2.y = (r->y+r->height)*scale;
cvRectangle( img, pt1, pt2, CV_RGB(0,255,0), 3, 8, 0 );
/* IplImage * faceSave = cvCreateImage(cvGetSize(img),img->depth,img->nChannels);
IplImage * faceToSave = 0;
if( !faceToSave )
faceToSave = cvCreateImage( cvGetSize(pImg), 8, 3 );
cvCopy(pImg, faceToSave, 0);
faceToSave->origin = pImg->origin;
int pointX = 0;
int pointY = 0;
int lebar = 0;
if (r->width > r->height)
{
lebar = r->width;
pointX = r->x - ((r->width - r->height)/2);
pointY = r->y - ((r->width - r->height)/3);
} else if (r->width < r->height)
{
lebar = r->height;
pointX = r->x - ((r->height - r->width)/2);
pointY = r->y - ((r->height - r->width)/3);
}
cvSetImageROI(img, cvRect(pointX,pointY,lebar,lebar));
faceSave = img;
cvNamedWindow("Result", 1 );
cvShowImage("Result", img);
cvResetImageROI(img);*/
}
}
cvShowImage( "Face Detection", img );
cvReleaseImage( &temp );
}
#ifdef _EiC
main(1,"facedetect.c");
#endif
Gambar wajah hasil deteksi
Sumber : http://bajay-x.blogspot.co.id/2010/04/pengenalan-wajah.html