Opencv人脸识别学习记录

【Opencv人脸识别学习记录】


环境:

  1. opencv3.0.0
  2. vs2012
  3. opencv_contrib3.0.0 —— — 编译和配置点此
  4. ORL人脸数据库,下载地址:点此进入下载
       
    【注意事项】
    !!!自己测试的图片一定要和ORL人脸数据图片的尺寸和颜色通道一模一样!!!!!!
     
     
    【工程下载】完成工程下载地址,包含数据集以及测试图片等:
    https://download.csdn.net/download/qq153471503/10370732
    这里写图片描述

1、制作csv文件

                一个面孔对应一个标签,在程序中一个个读取图片和标签,那么效率很低,所以将图片路径和标签制作成一个文件,在程序中直接读取文件中的路径和标签,就能将面孔和标签对应起来。
 
下面一段python代码就是生成这个csv文件,使用方法:
                python [这个python文件名] [参数一:ORL文件目录] [参数二:输出的csv文件]
 
例如我在当前工程目录下打开命令行,键入:
                python create_csv.py ./faces_data/ ./at.txt
效果:这个文件就是at.txt
这里写图片描述

# -*- coding: UTF-8 -*-

import os
import os.path
import sys

if __name__ == "__main__":

    if len(sys.argv) != 3:
        print 
        print("Input error. conmond format: \n \
             python %s [images path] [output file] \n \
             For example:  python %s ./faces_data ./at.txt  ")%(sys.argv[0], sys.argv[0])
        sys.exit(0)

    BASE_PATH = sys.argv[1]
    SEPARATOR = ";"

    fh = open(sys.argv[2], "w")

    label = 0
    for dirname, dirnames, filenames in os.walk(BASE_PATH):
        for subdirname in dirnames:
            subject_path = os.path.join(dirname, subdirname)
            for filename in os.listdir(subject_path):
                abs_path = "%s/%s" % (subject_path, filename)
                print "%s%s%d" % (abs_path, SEPARATOR, label)
                fh.write(abs_path)
                fh.write(SEPARATOR)
                fh.write(str(label))
                fh.write('\n')
            label = label + 1
    fh.close()

2、人脸检测代码

#if 1
    CascadeClassifier face_cascade;    //载入分类器
    //加载分类训练器,OpenCv官方文档提供的xml文档,可以直接调用
    //xml文档路径  opencv\sources\data\haarcascades
    cout << "loading haarcascade_frontalface_alt.xml..." << endl;
    if (!face_cascade.load("haarcascade_frontalface_alt.xml"))
    {
        cout << "load haarcascade_frontalface_alt failed!" << endl;
        exit(-1);
    }
    cout << "OK" << endl;

    Mat matTestImg = imread("test.png");        // 输入测试图像
    resize(matTestImg, matTestImg, matTestImg.size());
    Mat showImg;
    matTestImg.copyTo(showImg);
    vector<Rect> face_rect;
    vector<Mat> res = FaceDetectMultiScale(face_cascade, matTestImg, face_rect);        // 多尺度检测
    if (res.empty())        // 如果为空说明未检测到人脸
    {
        cout << "failed, Please try again." << endl;
        exit(-1);
    }
#if 0
    for (size_t i=0; i!=res.size(); i++)
    {
        // 显示检测到的人脸
        imshow("", res[i]);
        waitKey(0);
    }
#endif


    /// 将人脸框出
    for (size_t i=0; i!=face_rect.size(); i++)
    {
        rectangle(showImg, face_rect[i], Scalar(0,0,255));
    }
    imshow("", showImg);    // 显示识别结果
    waitKey(0);

#else

效果

这里写图片描述


3、人脸识别代码

Ptr<FaceRecognizer> faceR = createEigenFaceRecognizer();        // 创建人脸特征识别器
    vector<Mat> images;
    vector<int> labels;
    vector<Rect> face_rect;
    read_csv("at.txt", images, labels);     // 读取数据集

    string filename = "face_model.xml";     // 保存的文件名

// 如果定义了该宏,则不进行训练
#ifdef ALREADY_TRAIN
    cout << "loading " << filename + "..." << endl;
    faceR->load(filename);
    cout << "OK" << endl;
#else
    face_train(faceR, images, labels, filename);        // 训练
#endif

    //test(faceR, images);                  // 测试

    //resize(tmp, tmp, Size(92, 112));      // 重新调整大小,调整到和训练数据一样的尺寸


    while (true)
    {
        string filename;
        cout << "Please input file, enter 'q' exit: " << flush;
        cin >> filename;
        if (filename == "q")
        {
            break;
        }

        if (access(filename.c_str(), 0) < 0)
        {
            cout << filename + " not exists." << endl;
            continue;
        }

        Mat img = imread(filename, IMREAD_GRAYSCALE);       // 读入灰度图
        imwrite("img.png", img);
        int label = face_identify(faceR, img);
        printf("Identify the results: label = %d \n", label);
    }

效果

这里写图片描述

由运行结果可见,预测到的标签是0, 在我创建的csv文件at.txt文件中,s1/7.pgm这个图片的标签就是0,所以识别成功!


3、完整代码

#include <opencv2\opencv.hpp>
#include <opencv\ml.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <opencv2/face.hpp>
#include <fstream>
#include <opencv2/calib3d/calib3d.hpp>
#include <io.h> // for access

using namespace std;
using namespace cv;
using namespace face;


// 定义了该宏,则不需要进行人脸的训练
#define ALREADY_TRAIN


/**
 * 读取csv文件。使用CSV文件去读图像和标签,主要使用stringstream和getline方法。
 * 生成csv文件可用本工程下的create_csv.py这个python文件,使用方法:
 * 
 *      python create_csv.py [数据图像路径] [输出的svc文件名]
 * 
 * @param filename  svc文件名
 * @param images    用于存储测试图像
 * @param labels    存储标签
 * @param separator 分隔符
 */
void read_csv(const string &filename, vector<Mat> &images, vector<int> &labels, char separator = ';')
{
    std::ifstream file(filename.c_str(), ifstream::in);
    if (!file)
    {
        string error_message = "No valid input file was given, please check the given filename.";
        CV_Error(CV_StsBadArg, error_message);
    }
    string line, path, classlabel;
    while (getline(file, line))
    {
        stringstream liness(line);
        getline(liness, path, separator);
        getline(liness, classlabel);
        if (!path.empty() && !classlabel.empty())
        {
            // 读入灰度图
            images.push_back(imread(path, IMREAD_GRAYSCALE));
            labels.push_back(atoi(classlabel.c_str()));
        }
    }
}


/**
 * 人脸训练
 * 
 * @param faceR    识别器
 * @param images   图像训练集
 * @param labels   标签集
 * @param saveName 训练结束后保存的模型文件名
 */
void face_train(Ptr<FaceRecognizer>& faceR, vector<Mat> &images, vector<int> &labels, string& saveName)
{
    cout << "start train..." << endl;
    faceR->train(images, labels);       // 开始训练
    faceR->save(saveName);              //保存训练模型
    cout << "train done." << endl;
}

/**
 * 人脸识别
 *
 * @param  faceR  识别器
 * @param  srcImg 待测图像
 * @return        预测的标签值
 */
int face_identify(Ptr<FaceRecognizer>& faceR, Mat& srcImg)
{
    int label_predict = -1;
    double accuracy = -1;
    faceR->predict(srcImg, label_predict, accuracy);        // 预测
    return label_predict;
}


/**
 * 测试人脸识别
 *
 * @param faceR  识别器
 * @param images 测试数据集
 */
void test(Ptr<FaceRecognizer>& faceR, vector<Mat>& images)
{
    int label_predict = -1;
    double accuracy = -1;

    for (int i=0; i!=images.size(); i++)
    {
        faceR->predict(images[i], label_predict, accuracy);
        // 打印预测到的标签值和准确率
        printf("label_predict: %d   accuracy : %f \n", label_predict, 100.0-accuracy);
    }
}


/**
 * 人脸多尺度检测
 *
 * @param face          分类器
 * @param inputArr      带测图像
 * @param face_rect     存储识别到的人脸区域框
 * @return              检测到的人脸Mat图像
 */
vector<Mat> FaceDetectMultiScale(CascadeClassifier& face, Mat& inputArr, vector<Rect>& face_rect)
{
    vector<Mat> res;

    Mat img_src, img_equa;
    img_src = inputArr;

    if(img_src.channels() != 1)
        cvtColor(img_src, img_src, CV_BGR2GRAY);        // 转换为灰度图

    equalizeHist(img_src, img_equa);                    //直方图均衡化

    // 人脸检测,多尺度
    face.detectMultiScale(
        img_equa, 
        face_rect, 
        1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, 
        Size(30, 30));

    for (int i=0; i!=face_rect.size(); i++)
    {
        Mat tmp;
        inputArr(face_rect[i]).copyTo(tmp);
        res.push_back(tmp);
    }
    return res;
}


int main()
{
#if 0
    CascadeClassifier face_cascade;    //载入分类器
    //加载分类训练器,OpenCv官方文档提供的xml文档,可以直接调用
    //xml文档路径  opencv\sources\data\haarcascades
    cout << "loading haarcascade_frontalface_alt.xml..." << endl;
    if (!face_cascade.load("haarcascade_frontalface_alt.xml"))
    {
        cout << "load haarcascade_frontalface_alt failed!" << endl;
        exit(-1);
    }
    cout << "OK" << endl;

    Mat matTestImg = imread("test.jpg");        // 输入测试图像
    resize(matTestImg, matTestImg, matTestImg.size());
    Mat showImg;
    matTestImg.copyTo(showImg);
    vector<Rect> face_rect;
    vector<Mat> res = FaceDetectMultiScale(face_cascade, matTestImg, face_rect);        // 多尺度检测
    if (res.empty())        // 如果为空说明未检测到人脸
    {
        cout << "failed, Please try again." << endl;
        exit(-1);
    }
#if 0
    for (size_t i=0; i!=res.size(); i++)
    {
        // 显示检测到的人脸
        imshow("", res[i]);
        waitKey(0);
    }
#endif


    /// 将人脸框出
    for (size_t i=0; i!=face_rect.size(); i++)
    {
        rectangle(showImg, face_rect[i], Scalar(0,0,255));
    }
    imshow("", showImg);    // 显示识别结果
    waitKey(0);

#else

    Ptr<FaceRecognizer> faceR = createEigenFaceRecognizer();        // 创建人脸特征识别器
    vector<Mat> images;
    vector<int> labels;
    vector<Rect> face_rect;
    read_csv("at.txt", images, labels);     // 读取数据集

    string filename = "face_model.xml";     // 保存的文件名

// 如果定义了该宏,则不进行训练
#ifdef ALREADY_TRAIN
    cout << "loading " << filename + "..." << endl;
    faceR->load(filename);
    cout << "OK" << endl;
#else
    face_train(faceR, images, labels, filename);        // 训练
#endif

    //test(faceR, images);                  // 测试

    //resize(tmp, tmp, Size(92, 112));      // 重新调整大小,调整到和训练数据一样的尺寸


    while (true)
    {
        string filename;
        cout << "Please input file, enter 'q' exit: " << flush;
        cin >> filename;
        if (filename == "q")
        {
            break;
        }

        if (access(filename.c_str(), 0) < 0)
        {
            cout << filename + " not exists." << endl;
            continue;
        }

        Mat img = imread(filename, IMREAD_GRAYSCALE);       // 读入灰度图
        imwrite("img.png", img);
        int label = face_identify(faceR, img);
        printf("Identify the results: label = %d \n", label);
    }

#endif

    system("pause");
    return 0;
}

ends…

猜你喜欢

转载自blog.csdn.net/qq153471503/article/details/80064653
今日推荐