2012-02-29 101 views
2

我正在嘗試使用網絡攝像頭進行在線人臉識別。我用這兩個網站作爲參考使用OpenCV進行在線人臉識別

shervinemami.co.cc
cognotics.com

我有幾個問題:

在面部識別中,有6個步驟:

  1. 抓鬥從相機架
  2. 檢測圖像中的臉部
  3. 裁剪框只顯示在臉上
  4. 轉換框架爲灰度
  5. 預處理圖像
  6. 認識的人的形象。

我能夠完成前五個步驟。最後一步我無法做到。我不知道如何鏈接步驟5到步驟6.

我已經創建了train.txt文件和test.txt文件,其中包含訓練和測試圖像的信息。我已經在代碼中添加了learn(),doPCA()等函數...

但是關鍵是如何在主要中使用這些函數來識別已經過預處理的圖像。

需要一些關於它的幫助...

附代碼如下:

// Real-time.cpp : Defines the entry point for the console application. 

#include "stdafx.h" 
#include <cv.h> 
#include <cxcore.h> 
#include <highgui.h> 
#include <cvaux.h> 

IplImage ** faceImgArr  = 0; // array of face images 
CvMat * personNumTruthMat = 0; // array of person numbers 
int nTrainFaces    = 0; // the number of training images 
int nEigens     = 0; // the number of eigenvalues 
IplImage * pAvgTrainImg  = 0; // the average image 
IplImage ** eigenVectArr  = 0; // eigenvectors 
CvMat * eigenValMat   = 0; // eigenvalues 
CvMat * projectedTrainFaceMat = 0; // projected training faces 


IplImage* getCameraFrame(CvCapture* &camera); 
IplImage* detectFaces(IplImage *img ,CvHaarClassifierCascade* facecascade,CvMemStorage* storage); 
CvRect detectFaceInImage(IplImage *inputImg, CvHaarClassifierCascade* cascade); 
IplImage* preprocess(IplImage* inputImg); 
IplImage* resizeImage(const IplImage *origImg, int newWidth, 
    int newHeight, bool keepAspectRatio); 
void learn(); 
void recognize(); 
void doPCA(); 
void storeTrainingData(); 
int loadTrainingData(CvMat ** pTrainPersonNumMat); 
int findNearestNeighbor(float * projectedTestFace); 
int loadFaceImgArray(char * filename); 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    CvCapture* camera = 0; // The camera device. 
    CvMemStorage   *storage; 
    cvNamedWindow("Realtime:", CV_WINDOW_AUTOSIZE); 
    char *faceCascadeFilename = "C:/OpenCV2.1/data/haarcascades/haarcascade_frontalface_alt.xml"; 
    CvHaarClassifierCascade* faceCascade; 
    faceCascade = (CvHaarClassifierCascade*)cvLoad(faceCascadeFilename, 0, 0, 0); 
    storage = cvCreateMemStorage(0); 

    learn(); 

    while (cvWaitKey(10) != 27) // Quit on "Escape" key 
     { 
     IplImage *frame = getCameraFrame(camera); 
     //IplImage* resized=cvCreateImage(cvSize(420,240),frame->depth,3); 
     //cvResizeWindow("Image:", 640, 480); 
     //cvResize(frame,resized); 
     //cvShowImage("Realtime:", resized); 
     IplImage *imgA = resizeImage(frame, 420,240, true); 
     IplImage *frame1 = detectFaces(imgA,faceCascade,storage); 
     frame1 = preprocess(frame1); 
     } 
    // Free the camera. 
    cvReleaseCapture(&camera); 
    cvReleaseMemStorage(&storage); 
    return 0; 
} 

IplImage* getCameraFrame(CvCapture* &camera) 
{ 
    IplImage *frame; 
    int w, h; 

    // If the camera hasn't been initialized, then open it. 
    if (!camera) { 
     printf("Acessing the camera ...\n"); 
     camera = cvCreateCameraCapture(0); 
     if (!camera) { 
      printf("Couldn't access the camera.\n"); 
      exit(1); 
     } 
     // Try to set the camera resolution to 320 x 240. 
     cvSetCaptureProperty(camera, CV_CAP_PROP_FRAME_WIDTH, 320); 
     cvSetCaptureProperty(camera, CV_CAP_PROP_FRAME_HEIGHT, 240); 
     // Get the first frame, to make sure the camera is initialized. 
     frame = cvQueryFrame(camera); 
     if (frame) { 
      w = frame->width; 
      h = frame->height; 
      printf("Got the camera at %dx%d resolution.\n", w, h); 
     } 
     // Wait a little, so that the camera can auto-adjust its brightness. 
     Sleep(1000); // (in milliseconds) 
    } 

    // Wait until the next camera frame is ready, then grab it. 
    frame = cvQueryFrame(camera); 
    if (!frame) { 
     printf("Couldn't grab a camera frame.\n"); 
     exit(1); 
    } 
    return frame; 
} 

CvRect detectFaceInImage(IplImage *inputImg, CvHaarClassifierCascade* cascade) 
{ 
    // Smallest face size. 
    CvSize minFeatureSize = cvSize(20, 20); 
    // Only search for 1 face. 
    int flags = CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_DO_ROUGH_SEARCH; 
    // How detailed should the search be. 
    float search_scale_factor = 1.1f; 
    IplImage *detectImg; 
    IplImage *greyImg = 0; 
    CvMemStorage* storage; 
    CvRect rc; 
    double t; 
    CvSeq* rects; 
    CvSize size; 
    int i, ms, nFaces; 

    storage = cvCreateMemStorage(0); 
    cvClearMemStorage(storage); 


    // If the image is color, use a greyscale copy of the image. 
    detectImg = (IplImage*)inputImg; 
    if (inputImg->nChannels > 1) { 
     size = cvSize(inputImg->width, inputImg->height); 
     greyImg = cvCreateImage(size, IPL_DEPTH_8U, 1); 
     cvCvtColor(inputImg, greyImg, CV_BGR2GRAY); 
     detectImg = greyImg; // Use the greyscale image. 
    } 

    // Detect all the faces in the greyscale image. 
    t = (double)cvGetTickCount(); 
    rects = cvHaarDetectObjects(detectImg, cascade, storage, 
      search_scale_factor, 3, flags, minFeatureSize); 
    t = (double)cvGetTickCount() - t; 
    ms = cvRound(t/((double)cvGetTickFrequency() * 1000.0)); 
    nFaces = rects->total; 
    printf("Face Detection took %d ms and found %d objects\n", ms, nFaces); 

    // Get the first detected face (the biggest). 
    if (nFaces > 0) 
     rc = *(CvRect*)cvGetSeqElem(rects, 0); 
    else 
     rc = cvRect(-1,-1,-1,-1); // Couldn't find the face. 

    if (greyImg) 
     cvReleaseImage(&greyImg); 
    cvReleaseMemStorage(&storage); 
    //cvReleaseHaarClassifierCascade(&cascade); 

    return rc; // Return the biggest face found, or (-1,-1,-1,-1). 
} 

IplImage* detectFaces(IplImage *img ,CvHaarClassifierCascade* facecascade,CvMemStorage* storage) 
{ 
    int i; 
    CvRect *r; 
    CvSeq *faces = cvHaarDetectObjects(
      img, 
      facecascade, 
      storage, 
      1.1, 
      3, 
      0 /*CV_HAAR_DO_CANNY_PRUNNING*/, 
      cvSize(40, 40)); 

    int padding_width = 30; // pixels 
    int padding_height = 30; // pixels 

    for(i = 0 ; i < (faces ? faces->total : 0) ; i++) { 
     r = (CvRect*)cvGetSeqElem(faces, i); 
     cvRectangle(img, 
        cvPoint(r->x, r->y), 
        cvPoint(r->x + r->width, r->y + r->height), 
        CV_RGB(255, 0, 0), 1, 8, 0); 
    } 

    cvShowImage("Realtime:", img); 

    //cropping the face 
    cvSetImageROI(img, cvRect(r->x,r->y,r->width,r->height)); 
    IplImage *img2 = cvCreateImage(cvGetSize(img), 
          img->depth, 
           img->nChannels); 
    cvCopy(img, img2, NULL); 
    cvResetImageROI(img); 

    return img; 
} 

IplImage* preprocess(IplImage* inputImg){ 
    IplImage *detectImg, *greyImg = 0; 
    IplImage *imageProcessed; 
    CvSize size; 
    detectImg = (IplImage*)inputImg; 
    if (inputImg->nChannels > 1) { 
     size = cvSize(inputImg->width, inputImg->height); 
     greyImg = cvCreateImage(size, IPL_DEPTH_8U, 1); 
     cvCvtColor(inputImg, greyImg, CV_BGR2GRAY); 
     detectImg = greyImg; // Use the greyscale image. 
    } 

    imageProcessed = cvCreateImage(cvSize(inputImg->width, inputImg->height), IPL_DEPTH_8U, 1); 
    cvResize(detectImg, imageProcessed, CV_INTER_LINEAR); 
    cvEqualizeHist(imageProcessed, imageProcessed); 
    return imageProcessed; 
} 

IplImage* resizeImage(const IplImage *origImg, int newWidth, 
    int newHeight, bool keepAspectRatio) 
{ 
    IplImage *outImg = 0; 
    int origWidth; 
    int origHeight; 
    if (origImg) { 
     origWidth = origImg->width; 
     origHeight = origImg->height; 
    } 
    if (newWidth <= 0 || newHeight <= 0 || origImg == 0 
     || origWidth <= 0 || origHeight <= 0) { 
     //cerr << "ERROR: Bad desired image size of " << newWidth 
     // << "x" << newHeight << " in resizeImage().\n"; 
     exit(1); 
    } 

    if (keepAspectRatio) { 
     // Resize the image without changing its aspect ratio, 
     // by cropping off the edges and enlarging the middle section. 
     CvRect r; 
     // input aspect ratio 
     float origAspect = (origWidth/(float)origHeight); 
     // output aspect ratio 
     float newAspect = (newWidth/(float)newHeight); 
     // crop width to be origHeight * newAspect 
     if (origAspect > newAspect) { 
      int tw = (origHeight * newWidth)/newHeight; 
      r = cvRect((origWidth - tw)/2, 0, tw, origHeight); 
     } 
     else { // crop height to be origWidth/newAspect 
      int th = (origWidth * newHeight)/newWidth; 
      r = cvRect(0, (origHeight - th)/2, origWidth, th); 
     } 
     IplImage *croppedImg = cropImage(origImg, r); 

     // Call this function again, with the new aspect ratio image. 
     // Will do a scaled image resize with the correct aspect ratio. 
     outImg = resizeImage(croppedImg, newWidth, newHeight, false); 
     cvReleaseImage(&croppedImg); 

    } 
    else { 

     // Scale the image to the new dimensions, 
     // even if the aspect ratio will be changed. 
     outImg = cvCreateImage(cvSize(newWidth, newHeight), 
      origImg->depth, origImg->nChannels); 
     if (newWidth > origImg->width && newHeight > origImg->height) { 
      // Make the image larger 
      cvResetImageROI((IplImage*)origImg); 
      // CV_INTER_LINEAR: good at enlarging. 
      // CV_INTER_CUBIC: good at enlarging.   
      cvResize(origImg, outImg, CV_INTER_LINEAR); 
     } 
     else { 
      // Make the image smaller 
      cvResetImageROI((IplImage*)origImg); 
      // CV_INTER_AREA: good at shrinking (decimation) only. 
      cvResize(origImg, outImg, CV_INTER_AREA); 
     } 

    } 
    return outImg; 
} 

void learn() 
{ 
    int i, offset; 

    // load training data 
    nTrainFaces = loadFaceImgArray("C:/Users/HP/Desktop/OpenCV/50_images_of_15_people.txt"); 
    if(nTrainFaces < 2) 
    { 
     fprintf(stderr, 
       "Need 2 or more training faces\n" 
       "Input file contains only %d\n", nTrainFaces); 
     return; 
    } 

    // do PCA on the training faces 
    doPCA(); 

    // project the training images onto the PCA subspace 
    projectedTrainFaceMat = cvCreateMat(nTrainFaces, nEigens, CV_32FC1); 
    offset = projectedTrainFaceMat->step/sizeof(float); 
    for(i=0; i<nTrainFaces; i++) 
    { 
     //int offset = i * nEigens; 
     cvEigenDecomposite(
      faceImgArr[i], 
      nEigens, 
      eigenVectArr, 
      0, 0, 
      pAvgTrainImg, 
      //projectedTrainFaceMat->data.fl + i*nEigens); 
      projectedTrainFaceMat->data.fl + i*offset); 
    } 

    // store the recognition data as an xml file 
    storeTrainingData(); 
} 

void recognize() 
{ 
    int i, nTestFaces = 0;   // the number of test images 
    CvMat * trainPersonNumMat = 0; // the person numbers during training 
    float * projectedTestFace = 0; 

    // load test images and ground truth for person number 
    nTestFaces = loadFaceImgArray("C:/Users/HP/Desktop/OpenCV/test.txt"); 
    printf("%d test faces loaded\n", nTestFaces); 

    // load the saved training data 
    if(!loadTrainingData(&trainPersonNumMat)) return; 

    // project the test images onto the PCA subspace 
    projectedTestFace = (float *)cvAlloc(nEigens*sizeof(float)); 
    for(i=0; i<nTestFaces; i++) 
    { 
     int iNearest, nearest, truth; 

     // project the test image onto the PCA subspace 
     cvEigenDecomposite(
      faceImgArr[i], 
      nEigens, 
      eigenVectArr, 
      0, 0, 
      pAvgTrainImg, 
      projectedTestFace); 

     iNearest = findNearestNeighbor(projectedTestFace); 
     truth = personNumTruthMat->data.i[i]; 
     nearest = trainPersonNumMat->data.i[iNearest]; 

     printf("nearest = %d, Truth = %d\n", nearest, truth); 
    } 
} 

int loadTrainingData(CvMat ** pTrainPersonNumMat) 
{ 
    CvFileStorage * fileStorage; 
    int i; 

    // create a file-storage interface 
    fileStorage = cvOpenFileStorage("facedata.xml", 0, CV_STORAGE_READ); 
    if(!fileStorage) 
    { 
     fprintf(stderr, "Can't open facedata.xml\n"); 
     return 0; 
    } 

    nEigens = cvReadIntByName(fileStorage, 0, "nEigens", 0); 
    nTrainFaces = cvReadIntByName(fileStorage, 0, "nTrainFaces", 0); 
    *pTrainPersonNumMat = (CvMat *)cvReadByName(fileStorage, 0, "trainPersonNumMat", 0); 
    eigenValMat = (CvMat *)cvReadByName(fileStorage, 0, "eigenValMat", 0); 
    projectedTrainFaceMat = (CvMat *)cvReadByName(fileStorage, 0, "projectedTrainFaceMat", 0); 
    pAvgTrainImg = (IplImage *)cvReadByName(fileStorage, 0, "avgTrainImg", 0); 
    eigenVectArr = (IplImage **)cvAlloc(nTrainFaces*sizeof(IplImage *)); 
    for(i=0; i<nEigens; i++) 
    { 
     char varname[200]; 
     sprintf(varname, "eigenVect_%d", i); 
     eigenVectArr[i] = (IplImage *)cvReadByName(fileStorage, 0, varname, 0); 
    } 

    // release the file-storage interface 
    cvReleaseFileStorage(&fileStorage); 

    return 1; 
} 

void storeTrainingData() 
{ 
    CvFileStorage * fileStorage; 
    int i; 

    // create a file-storage interface 
    fileStorage = cvOpenFileStorage("facedata.xml", 0, CV_STORAGE_WRITE); 

    // store all the data 
    cvWriteInt(fileStorage, "nEigens", nEigens); 
    cvWriteInt(fileStorage, "nTrainFaces", nTrainFaces); 
    cvWrite(fileStorage, "trainPersonNumMat", personNumTruthMat, cvAttrList(0,0)); 
    cvWrite(fileStorage, "eigenValMat", eigenValMat, cvAttrList(0,0)); 
    cvWrite(fileStorage, "projectedTrainFaceMat", projectedTrainFaceMat, cvAttrList(0,0)); 
    cvWrite(fileStorage, "avgTrainImg", pAvgTrainImg, cvAttrList(0,0)); 
    for(i=0; i<nEigens; i++) 
    { 
     char varname[200]; 
     sprintf(varname, "eigenVect_%d", i); 
     cvWrite(fileStorage, varname, eigenVectArr[i], cvAttrList(0,0)); 
    } 

    // release the file-storage interface 
    cvReleaseFileStorage(&fileStorage); 
} 

int findNearestNeighbor(float * projectedTestFace) 
{ 
    //double leastDistSq = 1e12; 
    double leastDistSq = DBL_MAX; 
    int i, iTrain, iNearest = 0; 

    for(iTrain=0; iTrain<nTrainFaces; iTrain++) 
    { 
     double distSq=0; 

     for(i=0; i<nEigens; i++) 
     { 
      float d_i = 
       projectedTestFace[i] - 
       projectedTrainFaceMat->data.fl[iTrain*nEigens + i]; 
      //distSq += d_i*d_i/eigenValMat->data.fl[i]; // Mahalanobis 
      distSq += d_i*d_i; // Euclidean 
     } 

     if(distSq < leastDistSq) 
     { 
      leastDistSq = distSq; 
      iNearest = iTrain; 
     } 
    } 

    return iNearest; 
} 

void doPCA() 
{ 
    int i; 
    CvTermCriteria calcLimit; 
    CvSize faceImgSize; 

    // set the number of eigenvalues to use 
    nEigens = nTrainFaces-1; 

    // allocate the eigenvector images 
    faceImgSize.width = faceImgArr[0]->width; 
    faceImgSize.height = faceImgArr[0]->height; 
    eigenVectArr = (IplImage**)cvAlloc(sizeof(IplImage*) * nEigens); 
    for(i=0; i<nEigens; i++) 
     eigenVectArr[i] = cvCreateImage(faceImgSize, IPL_DEPTH_32F, 1); 

    // allocate the eigenvalue array 
    eigenValMat = cvCreateMat(1, nEigens, CV_32FC1); 

    // allocate the averaged image 
    pAvgTrainImg = cvCreateImage(faceImgSize, IPL_DEPTH_32F, 1); 

    // set the PCA termination criterion 
    calcLimit = cvTermCriteria(CV_TERMCRIT_ITER, nEigens, 1); 

    // compute average image, eigenvalues, and eigenvectors 
    cvCalcEigenObjects(
     nTrainFaces, 
     (void*)faceImgArr, 
     (void*)eigenVectArr, 
     CV_EIGOBJ_NO_CALLBACK, 
     0, 
     0, 
     &calcLimit, 
     pAvgTrainImg, 
     eigenValMat->data.fl); 

    cvNormalize(eigenValMat, eigenValMat, 1, 0, CV_L1, 0); 
} 

int loadFaceImgArray(char * filename) 
{ 
    FILE * imgListFile = 0; 
    char imgFilename[512]; 
    int iFace, nFaces=0; 


    // open the input file 
    if(!(imgListFile = fopen(filename, "r"))) 
    { 
     fprintf(stderr, "Can\'t open file %s\n", filename); 
     return 0; 
    } 

    // count the number of faces 
    while(fgets(imgFilename, 512, imgListFile)) ++nFaces; 
    rewind(imgListFile); 

    // allocate the face-image array and person number matrix 
    faceImgArr  = (IplImage **)cvAlloc(nFaces*sizeof(IplImage *)); 
    personNumTruthMat = cvCreateMat(1, nFaces, CV_32SC1); 

    // store the face images in an array 
    for(iFace=0; iFace<nFaces; iFace++) 
    { 
     // read person number and name of image file 
     fscanf(imgListFile, 
      "%d %s", personNumTruthMat->data.i+iFace, imgFilename); 

     // load the face image 
     faceImgArr[iFace] = cvLoadImage(imgFilename, CV_LOAD_IMAGE_GRAYSCALE); 

     if(!faceImgArr[iFace]) 
     { 
      fprintf(stderr, "Can\'t load image from %s\n", imgFilename); 
      return 0; 
     } 
    } 

    fclose(imgListFile); 

    return nFaces; 
} 
+3

您已經提出了一個相當模糊的問題「發現連接步驟5到步驟6時遇到困難」,並且發佈了大量代碼。爲了提高獲得良好答案的機會,請在說明您嘗試用於識別面部的方法之後,考慮只發布代碼的相關部分。 – Chris 2012-03-01 08:57:24

回答

0

我剛纔讀

int _tmain(int argc, _TCHAR* argv[]) 
{ 
....... 
} 

你的代碼的一部分。此代碼用於檢測圖像中的臉部。可以說它是Face_x。現在從Face_x提取功能,將其稱爲F_x。在您的數據庫中,您應該存儲從n不同面{Face_1, Face_2,..Face_N}提取的功能{F_1, F_2,..., F_N}

簡單算法識別Face_x是計算F_xn特徵之間的歐幾里德距離。最小距離(低於閾值)給出相應的人臉。如果最小距離不低於閾值,則Face_x是一個新面孔。將功能F_x添加到數據庫。這樣你可以增加你的數據庫。您可以在數據庫中沒有功能的情況下開始您的算法隨着每個新面孔,數據庫都在不斷增長。
我希望通過我建議的方法會導致你

0

我的答案可能來晚瞭解決方案,但如果我回答它。我正在上一個類似的項目工作可能對好朋友是有益的,我都面臨着同樣的問題。我通過編寫函數來解決這個問題,將檢測到的,裁剪過的和預處理後的圖像保存到我的計算機的硬盤上(使用CvWrite)。並將保存圖像的參數提供給代碼的識別部分。它讓我的生活變得更輕鬆。對我來說,通過感興趣的區域的參數有點難。如果您或其他人這樣做了,那麼與我們分享代碼可能會很好。 您可以使用以下代碼在使用代碼上的resizeimage函數將其調整爲常量值之後保存圖像。

void saveCroppedFaces(CvSeq* tempon,IplImage* DetectedImage) 
{ 

     char* name; 
     int nFaces; 
     CvRect rect; 
     nFaces=tempon->total; 
     name =new char[nFaces]; 
     IplImage* cropped = 0; 
     IplImage* croppedResized=0; 
     Mat croped; 
     for(int k=0;k<nFaces;k++) 
     { 
      itoa(k,(name+k),10); 
      rect = *(CvRect*)cvGetSeqElem(tempon, k); 
      cropped= cropImage(DetectedImage,rect); 
      //i can resize the cropped faces in to a fixed size here 

      //i can write a function to save images and call it so 
        //that it will save it in to hard drive 
      //cvNamedWindow((name+k),CV_WINDOW_AUTOSIZE); 

      //cvShowImage((name+k),cropped); 
      croppedResized=resizeImage(cropped,60,60); 
      croped=IplToMatConverter(croppedResized); 
      saveROI(croped,itoa(k,(name+k),10)); 
      cvReleaseImage(&cropped); 
     } 
    name=NULL; 
    delete[] name; 

} 

void saveROI(Mat mat,String outputFileName) 
{ 
    string store_path("C://Users/sizusuzu/Desktop/Images/FaceDetection2 
                /"+outputFileName+".jpg"); 
    bool write_success = imwrite(store_path,mat); 

} 

在這之後,你可以改變的IplImage *使用

 Mat IplToMatConverter(IplImage* imageToMat) 
    { 
    Mat mat = cvarrToMat(imageToMat); 
    return mat; 
    } 

到墊子使用FaceRecognizer API.Or的墊只是做其他/更難方式。 謝謝