#include "cv.h" #include "cxcore.h" #include "highgui.h" #include #include #include using namespace std; // Create memory for calculations static CvMemStorage* storage = 0; // Create a new Haar classifier static CvHaarClassifierCascade* cascade = 0; // Create a string that contains the cascade name const char* cascade_name = "haarcascade_frontalface.xml"; /* "haarcascade_profileface.xml";*/ void detect_and_draw(IplImage* img); bool writeActive; IplImage* im; IplImage* imFace; IplImage* imR; IplImage* imG; IplImage* imB; struct face { CvRect rectangle; int dx, dy, confidence; float weight; CvHistogram* rHistogram; CvHistogram* gHistogram; CvHistogram* bHistogram; }; vector allFaces; CvHistogram* getHistogram(IplImage* im, CvRect r) { cvSetImageROI(im, r); int numBins = 64; float range[] = {0.0,255.0}; float* ranges[] = {range}; CvHistogram* h = cvCreateHist(1, &numBins, CV_HIST_ARRAY, ranges); cvCalcHist(&im, h); /*for(int binIter=0; binIter getSamples(face f, int predX, int predY, int predW, int predH, int numSamples, float searchSTD, int wLimit, int hLimit) { vector samples; float u1,u2,u3,u4,n1,n2,n3,n4,probability,scale,rCorr,gCorr,bCorr,likelihood; int newWidth,newHeight; //generate random samples for(int randGenIter=0; randGenIter0 && n2>0 && n1 resample(vector samples, face f, int wLimit, int hLimit) { float totalWeight=0; for(int sampleIter=0; sampleIter resamples; vector allResamples; int numSamplesToDraw; for(int sampleIter=0; sampleIterwidth,im->height), 1); imFace = cvCloneImage(im); IplImage* imCopy = cvCloneImage(im); //allocate some images used to extract a skin likelihood map IplImage* imHSV = cvCreateImage(cvSize(im->width,im->height),IPL_DEPTH_8U, 3); IplImage* skin = cvCreateImage(cvSize(im->width,im->height),IPL_DEPTH_8U, 1); imR = cvCreateImage(cvSize(im->width,im->height),IPL_DEPTH_8U, 1); imG = cvCreateImage(cvSize(im->width,im->height),IPL_DEPTH_8U, 1); imB = cvCreateImage(cvSize(im->width,im->height),IPL_DEPTH_8U, 1); IplImage* sampling = cvCreateImage(cvSize(im->width,im->height),IPL_DEPTH_32F, 1); int frame = 0; int keyPressed = -1; writeActive=true; while(i!=0 && (keyPressed==-1 || keyPressed=='f' || keyPressed=='w')) { cvShowImage("Given",im); cvCvtColor(im, imHSV, CV_BGR2HSV); CvScalar pixRGB, pixHSV; float cb, cr; //separate into channels cvSetImageCOI(im,1); cvCopy(im,imB); cvSetImageCOI(im,2); cvCopy(im,imG); cvSetImageCOI(im,3); cvCopy(im,imR); cvSetImageCOI(im,0); if(keyPressed=='w') { writeActive=!writeActive; } if (frame==0 || allFaces.size()==0 || keyPressed=='f') //detect faces { // Clear the memory storage which was used before cvClearMemStorage( storage ); // There can be more than one face in an image. So create a growable sequence of faces. // Detect the objects and store them in the sequence CvSeq* faces = cvHaarDetectObjects( im, cascade, storage, 1.1, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize(40, 40) ); for(int currentFace=0; currentFacetotal; currentFace++) { //get rectangle bounding first face CvRect* r = (CvRect *)cvGetSeqElem( faces, currentFace ); face newFace; newFace.rectangle = *r; newFace.confidence = 2; newFace.dx = 0; newFace.dy = 0; //find the total amount of skin-colored pixels in the face float skinSum=0; for (int y=r->y; yy+r->height; y++) { for (int x=r->x; xx+r->width; x++) { pixRGB = cvGet2D(im,y,x); pixHSV = cvGet2D(imHSV,y,x); cb = 0.148*pixRGB.val[2] - 0.291*pixRGB.val[1] + 0.439*pixRGB.val[0] + 128; cr = 0.439*pixRGB.val[2] - 0.368*pixRGB.val[1] - 0.071*pixRGB.val[0] + 128; if ( ( pixHSV.val[0]>245 || pixHSV.val[0]<25.5) && 140<=cr && cr<=165 && 140<=cb && cb<=195) { skinSum++; } } } //if less than 30% skin, this face doesnt count if (skinSum / (r->width*r->height) < 0.3) { //break; } //check to see if this face is roughly matching an existing face bool matchesExisting=false; for(int faceIter = 0; faceIter < allFaces.size(); faceIter++ ) { //find the width and height of the region of overlap int overlapWidth, overlapHeight; if ( newFace.rectangle.x < allFaces.at(faceIter).rectangle.x) { overlapWidth = min( newFace.rectangle.x + newFace.rectangle.width - allFaces.at(faceIter).rectangle.x, allFaces.at(faceIter).rectangle.width); }else{ overlapWidth = min( allFaces.at(faceIter).rectangle.x + allFaces.at(faceIter).rectangle.width - newFace.rectangle.x, newFace.rectangle.width); } if ( newFace.rectangle.y < allFaces.at(faceIter).rectangle.y) { overlapHeight = min( newFace.rectangle.y + newFace.rectangle.height - allFaces.at(faceIter).rectangle.y, allFaces.at(faceIter).rectangle.height); }else{ overlapHeight = min( allFaces.at(faceIter).rectangle.y + allFaces.at(faceIter).rectangle.height - newFace.rectangle.y, newFace.rectangle.height); } //if region of overlap is greater than 60% of larger rectangle, then faces are the same if ( ((float)overlapWidth*overlapHeight)/(max( newFace.rectangle.width*newFace.rectangle.height, allFaces.at(faceIter).rectangle.width*allFaces.at(faceIter).rectangle.height) )>0.6) { matchesExisting = true; allFaces.at(faceIter).confidence = min( 4, allFaces.at(faceIter).confidence+2); allFaces.at(faceIter).rectangle = newFace.rectangle; allFaces.at(faceIter).dx = newFace.dx; allFaces.at(faceIter).dy = newFace.dy; allFaces.at(faceIter).rHistogram = getHistogram(imR, newFace.rectangle); allFaces.at(faceIter).gHistogram = getHistogram(imG, newFace.rectangle); allFaces.at(faceIter).bHistogram = getHistogram(imB, newFace.rectangle); break; } } if (!matchesExisting) //if its new, add it to our vector { newFace.rHistogram = getHistogram(imR, newFace.rectangle); newFace.gHistogram = getHistogram(imG, newFace.rectangle); newFace.bHistogram = getHistogram(imB, newFace.rectangle); allFaces.push_back(newFace); } } //subtract 1 from confidence of all faces for(int faceIter = 0; faceIter < allFaces.size(); faceIter++ ) { allFaces.at(faceIter).confidence--; if (allFaces.at(faceIter).confidence < 1) //if confidence gone, remove it { allFaces.erase(allFaces.begin()+faceIter, allFaces.begin()+faceIter+1); faceIter--; } } } if(allFaces.size()>0) //track faces { cvSet(sampling,cvScalar(0)); for(int faceIter = 0; faceIter < allFaces.size(); faceIter++ ) //first face only for now { //predicted position int predX = allFaces.at(faceIter).rectangle.x + allFaces.at(faceIter).dx; int predY = allFaces.at(faceIter).rectangle.y + allFaces.at(faceIter).dy; vector samples = getSamples(allFaces.at(faceIter), predX, predY, allFaces.at(faceIter).rectangle.width, allFaces.at(faceIter).rectangle.height, 100, 0.2, im->width, im->height); //do importance resampling a number of times for(int resampling=0; resampling<3; resampling++) { samples = resample(samples, allFaces.at(faceIter), im->width, im->height); } int bestIdx=0; float bestWeight=0; //generate random samples for(int sampleIter=0; sampleIter bestWeight) { bestWeight = samples.at(sampleIter).weight; bestIdx = sampleIter; } //cvSet2D(sampling, samples.at(sampleIter).rectangle.y,samples.at(sampleIter).rectangle.x, cvScalar(samples.at(sampleIter).weight)); } //move to best sample allFaces.at(faceIter).dx = samples.at(bestIdx).rectangle.x - allFaces.at(faceIter).rectangle.x; allFaces.at(faceIter).dy = samples.at(bestIdx).rectangle.y - allFaces.at(faceIter).rectangle.y; allFaces.at(faceIter).rectangle = samples.at(bestIdx).rectangle; /*cvCopyHist(samples.at(bestIdx).rHistogram, &allFaces.at(faceIter).rHistogram); cvCopyHist(samples.at(bestIdx).gHistogram, &allFaces.at(faceIter).gHistogram); cvCopyHist(samples.at(bestIdx).bHistogram, &allFaces.at(faceIter).bHistogram);*/ } drawFaces(); //cvCvtColor(imFace, imCopy, CV_BGR2RGB); //if(writeActive) //cvWriteFrame(writer, imFace); //scaleAndShow(sampling,"Sampling"); //cvWaitKey(1); } i = cvGrabFrame(capture); im = cvRetrieveFrame(capture); frame++; keyPressed = cvWaitKey(100); } cvReleaseImage(&im); cvReleaseImage(&imCopy); cvReleaseImage(&imHSV); cvReleaseImage(&skin); cvReleaseCapture(&capture); cvReleaseVideoWriter(&writer); return 0; }