使用OpenCV进行在线人脸识别

时间:2012-02-29 17:57:36

标签: opencv computer-vision

我正在尝试使用网络摄像头实现在线人脸识别。我使用这两个网站作为参考

shervinemami.co.cc
cognotics.com

我几乎没有问题:

在面部识别中,有6个步骤:

  1. 从相机中抓取一个框架
  2. 检测图像中的脸部
  3. 裁剪框架以仅显示面部
  4. 将帧转换为灰度
  5. 预处理图像
  6. 识别图像中的人物。
  7. 我能够完成前五个步骤。最后一步我无法做到。我不知道如何将第5步与第6步联系起来。

    我已经创建了train.txt文件和test.txt文件,其中包含培训和测试图像的信息。我已经将诸如learn(),doPCA()等函数添加到代码中......

    但关键是如何在main中使用这些函数来识别已经预处理的图像。

    需要一些帮助...

    附上以下代码:

    // 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;
    }
    

2 个答案:

答案 0 :(得分:0)

我刚看完

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

您的部分代码。此代码用于检测图像中的面部。让我们说它是Face_x。现在从Face_x中提取要素,将其称为F_x。在您的数据库中,您应存储从{F_1, F_2,..., F_N}个不同的面n中提取的功能{Face_1, Face_2,..Face_N}

识别Face_x的简单算法是计算F_xn要素之间的欧几里德距离。最小距离(低于阈值)给出相应的面。如果最小距离不低于阈值,则Face_x是新面孔。将功能F_x添加到数据库。这样您就可以增加数据库。您可以在数据库中没有功能的情况下开始算法。随着每个新面孔,数据库都在增长 我希望我建议的方法能引导您找到解决方案

答案 1 :(得分: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
      Mat IplToMatConverter(IplImage* imageToMat)
     {
    Mat mat = cvarrToMat(imageToMat);
    return mat;
     }

在FaceRecognizer API中使用Mat。或者只是做其他/更难的方式。 感谢