Opencv和c ++ Fisherface算法总是预测错误,即使图像与输入完全相同,也会重建黑色图像

时间:2016-11-03 01:52:26

标签: c++ image opencv face-recognition

正如标题所说,我在使用Windows窗体的界面上使用opencv时遇到问题只能在程序上发送操作的输入,基本上我将处理过的图像保存在文件夹上并恢复它们没有任何问题我甚至检查了一百次,如果有任何问题,当我恢复图像和没有,没有什么不对,所以我开始测试程序给出的输出图像,我意识到重建的图像取自FaceRecognizer是完全黑色的,我试图改变声明,但没有任何改变,有趣的是,这个相同的算法工作在我创建的另一个项目作为测试,没有接口,只有控制台,所以程序正在运行在主要功能上,在此测试项目中,当我从脸部FaceRecognizer重建图像时,它返回正常的脸部图像并识别正确的脸部,但在带有界面的新项目中我使用相同的图像作为输入,它识别所有错误,并重建黑色图像,我认为这是FaceRecognizer模型的错误,但我不知道它究竟是什么!有谁可以帮助我?

以下是从文件夹中恢复图像的代码:

            if (traiModel)
            {
                // read all folders on the images and for each one give an number id
                // read the images for each folder and add on a vector of images
                // read the folder name and give to all images to set the label info
                Preprocessed_Faces.clear();
                faceLabels.clear();
                Preprocessed_Faces_Names.clear();

                std::string folder = "TrainingFolder\\";
                std::vector<cv::string> foldernames;
                foldernames = get_all_files_names_within_folder(folder);
                std::vector<int> labels;
                for (int f = 0; f < foldernames.size(); f++)
                {
                    std::string thisfoldername = folder + foldernames[f];
                    std::vector<cv::string> filenames;
                    cv::glob(thisfoldername, filenames);
                    Preprocessed_Faces_Names.push_back(foldernames[f]);
                    labels.push_back(f + 1);
                    for (int fn = 0; fn < filenames.size(); fn++)
                    {
                        Preprocessed_Faces.push_back(cv::imread(filenames[fn]));
                        //std::cout << filenames[fn] << std::endl;
                        faceLabels.push_back(f + 1);
                    }
                }

                cv::imwrite("Traintest.PNG", Preprocessed_Faces[0]);

                std::map<int, std::string> map1;
                for (int i = 0; i < Preprocessed_Faces_Names.size(); i++)
                {
                    map1.insert(std::pair<int, std::string>(labels[i], Preprocessed_Faces_Names[i]));
                    std::cout << Preprocessed_Faces_Names[i] << std::endl;
                }
                model->setLabelsInfo(map1);
                model->train(Preprocessed_Faces, faceLabels);
                traiModel = false;
            }

这是用于识别他首先尝试重建面部并识别出面部的代码:

        if (identif)
        {
            // identify the current face looking on the database
            // Prediction Validation
            // Get some required data from the FaceRecognizer model.
            cv::Mat eigenvectors = model->get<cv::Mat>("eigenvectors");
            cv::Mat averageFaceRow = model->get<cv::Mat>("mean");

            // Project the input image onto the eigenspace.
            cv::Mat projection = cv::subspaceProject(eigenvectors, averageFaceRow, filtered.reshape(1, 1));

            // Generate the reconstructed face back from the eigenspace.
            cv::Mat reconstructionRow = cv::subspaceReconstruct(eigenvectors, averageFaceRow, projection);

            // Make it a rectangular shaped image instead of a single row.
            cv::Mat reconstructionMat = reconstructionRow.reshape(1, filtered.rows);

            // Convert the floating-point pixels to regular 8-bit uchar.
            cv::Mat reconstructedFace = cv::Mat(reconstructionMat.size(), CV_8U);
            reconstructionMat.convertTo(reconstructedFace, CV_8U, 1, 0);

            cv::imwrite("Teste.PNG", filtered);
            cv::imwrite("Teste2.PNG", reconstructedFace);

            int identity = model->predict(filtered);
            double similarity = getSimilarity(filtered, reconstructedFace);
            if (similarity > .7f)
            {
                //identity = -1; // -1 means that the face is not registred in the trainer
            }
            std::cout << "This is: " << identity << " and: " << model->getLabelInfo(identity) << std::endl;
            identif = false;
        }

这里是代码,其中用于识别面部的完整循环以及上面2个以上的FaceRecognizer的声明在那里:

void RecognitionAlgo::Running()
{
    // Create the cascade classifier object used for the face detection
    cv::CascadeClassifier face_cascade;
    // Use the haarcascade frontalface_alt.xml library
    if (!face_cascade.load("haarcascade_frontalface_alt.xml"))
    {
        Log("Error at face Cascade Load!")
    }


    // Setup image files used in the capture process
    cv::Mat captureFrame;
    cv::Mat grayscaleFrame;
    cv::Mat shrinkFrame;


    // Create a vector to store the face found
    std::vector<cv::Rect> faces;
    std::vector<cv::Mat> Preprocessed_Faces;
    std::vector<cv::string> Preprocessed_Faces_Names;
    cv::string myname;
    std::vector<int> faceLabels;

    // Init the face Recognizer
    cv::initModule_contrib();

    std::string facerecAlgorithm = "FaceRecognizer.Fisherfaces";
    cv::Ptr<cv::FaceRecognizer> model;
    // Use OpenCV's new FaceRecognizer in the "contrib" module;
    model = cv::Algorithm::create<cv::FaceRecognizer>(facerecAlgorithm);
    if (model.empty())
    {
        std::cerr << "ERROR: FaceRecognizer" << std::endl;
    }
    try
    {
        //model->load("TrainedModel.xml");
    }
    catch (const std::exception&)
    {

    }

    // Create a loop to caoture and find faces
    while (true)
    {
        // Capture a new image frame
        if (swCamera)
        {
            captureDevice >> captureFrame;
        }
        else
        {
            captureFrame = cv::imread("face3.PNG");
        }

        // Shrink the captured image, Convert to gray scale and equalize
        cv::cvtColor(captureFrame, grayscaleFrame, CV_BGR2GRAY);
        cv::equalizeHist(grayscaleFrame, grayscaleFrame);
        shrinkFrame = ShrinkingImage(grayscaleFrame);

        // Find faces on the shrink image (because it's faster) and store them in the vector array
        face_cascade.detectMultiScale(shrinkFrame, faces, 1.1, 4, CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_SCALE_IMAGE, cv::Size(30, 30));

        if (faces.size() > 0)
            faces = EnlargeResults(captureFrame, faces);

        // Draw a rectangle for all found faces in the vector array on original image
        for (int i = 0; i < faces.size(); i++)
        {
            cv::Point pt1(faces[i].x + faces[i].width, faces[i].y + faces[i].height);
            cv::Point pt2(faces[i].x, faces[i].y);

            cv::Mat theFace = grayscaleFrame(faces[i]);

            // try to treat the face by identifying the eyes, if the eyes fail to detect, it returns theface
            cv::Mat filtered = TreatmentForFace(theFace);

            // Collecting faces and learning from them.

            if (starTraining && TrainName != "")
            {
                if (colFace)
                {
                    Preprocessed_Faces.push_back(filtered);
                    if (myname == "")
                    {
                        myname = TrainName;
                    }
                    colFace = false;
                }
            }
            else
            {
                if (!starTraining && Preprocessed_Faces.size() > 0)
                {
                    // create the person folder
                    std::string command = "mkdir ";
                    std::string foldercom = "TrainingFolder\\" + myname;
                    command += foldercom;
                    system(command.c_str());

                    // create a string to access the recent created folder
                    std::string foldername = foldercom.substr(0, foldercom.size() - (myname.size() + 1));
                    foldername.append("/");
                    foldername.append(myname);
                    foldername.append("/");
                    foldername.append(myname);
                    // save the colected faces on the folder
                    for (int i = 0; i < Preprocessed_Faces.size(); i++)
                    {
                        std::ostringstream oss;
                        oss << i;
                        cv::imwrite(foldername + oss.str() + ".PNG", Preprocessed_Faces[i]);
                    }
                    myname = "";
                    Preprocessed_Faces.clear();
                }
            }

            if (traiModel)
            {
                // read all folders on the images and for each one give an number id
                // read the images for each folder and add on a vector of images
                // read the folder name and give to all images to set the label info
                Preprocessed_Faces.clear();
                faceLabels.clear();
                Preprocessed_Faces_Names.clear();

                std::string folder = "TrainingFolder\\";
                std::vector<cv::string> foldernames;
                foldernames = get_all_files_names_within_folder(folder);
                std::vector<int> labels;
                for (int f = 0; f < foldernames.size(); f++)
                {
                    std::string thisfoldername = folder + foldernames[f];
                    std::vector<cv::string> filenames;
                    cv::glob(thisfoldername, filenames);
                    Preprocessed_Faces_Names.push_back(foldernames[f]);
                    labels.push_back(f + 1);
                    for (int fn = 0; fn < filenames.size(); fn++)
                    {
                        Preprocessed_Faces.push_back(cv::imread(filenames[fn]));
                        //std::cout << filenames[fn] << std::endl;
                        faceLabels.push_back(f + 1);
                    }
                }

                cv::imwrite("Traintest.PNG", Preprocessed_Faces[0]);

                std::map<int, std::string> map1;
                for (int i = 0; i < Preprocessed_Faces_Names.size(); i++)
                {
                    map1.insert(std::pair<int, std::string>(labels[i], Preprocessed_Faces_Names[i]));
                    std::cout << Preprocessed_Faces_Names[i] << std::endl;
                }
                model->setLabelsInfo(map1);
                model->train(Preprocessed_Faces, faceLabels);
                traiModel = false;
            }

            if (identif)
            {
                // identify the current face looking on the database
                // Prediction Validation
                // Get some required data from the FaceRecognizer model.
                cv::Mat eigenvectors = model->get<cv::Mat>("eigenvectors");
                cv::Mat averageFaceRow = model->get<cv::Mat>("mean");

                // Project the input image onto the eigenspace.
                cv::Mat projection = cv::subspaceProject(eigenvectors, averageFaceRow, filtered.reshape(1, 1));

                // Generate the reconstructed face back from the eigenspace.
                cv::Mat reconstructionRow = cv::subspaceReconstruct(eigenvectors, averageFaceRow, projection);

                // Make it a rectangular shaped image instead of a single row.
                cv::Mat reconstructionMat = reconstructionRow.reshape(1, filtered.rows);

                // Convert the floating-point pixels to regular 8-bit uchar.
                cv::Mat reconstructedFace = cv::Mat(reconstructionMat.size(), CV_8U);
                reconstructionMat.convertTo(reconstructedFace, CV_8U, 1, 0);

                cv::imwrite("Teste.PNG", filtered);
                cv::imwrite("Teste2.PNG", reconstructedFace);

                int identity = model->predict(filtered);
                double similarity = getSimilarity(filtered, reconstructedFace);
                if (similarity > .7f)
                {
                    //identity = -1; // -1 means that the face is not registred in the trainer
                }
                std::cout << "This is: " << identity << " and: " << model->getLabelInfo(identity) << std::endl;
                identif = false;
            }
        }

        // Print the output
        cv::resize(captureFrame, captureFrame, cv::Size(800, 600));
        cv::imshow("outputCapture", captureFrame);
        // pause for 33ms
        cv::waitKey(33);
    }
}

1 个答案:

答案 0 :(得分:0)

OpenCV FaceRecognizer用于与灰度图像一起使用。问题是您使用cv :: imread()从磁盘读取映像的位置。

(cv::imread(filenames[fn]));

即使您可能保存了灰度图像,默认情况下imread()也会加载3个通道图像。指定CV_LOAD_IMAGE_GRAYSCALE,如下所示。

(cv::imread(filenames[fn],CV_LOAD_IMAGE_GRAYSCALE));