zoukankan      html  css  js  c++  java
  • Opencv摄像头实时人脸识别

    • Introduction

    网上存在很多人脸识别的文章,这篇文章是我的一个作业,重在通过摄像头实时采集人脸信息,进行人脸检测和人脸识别,并将识别结果显示在左上角。

    利用 OpenCV 实现一个实时的人脸识别系统,人脸库采用 ORL FaceDatabase (网上下载) ,另外在数据库中增加了作业中自带的20张照片和自己利用摄像头采集到的10张照片,系统利用摄像头实时的采集到场景图像,从中检测出人脸用方框标出,并利用提供的数据库进行人脸识别,并在图像左上角显示相匹配的数据库图片。

    • Method

    算法流程分两步,分别是人脸检测和人脸识别。人脸检测使用的是 ViolaJones 人脸检测方法,利用样本的 Haar-like 特征进行分类器训练,得到级联boosted 分类器,加载训练好的人脸分类器,利用分类器在视频帧中查找人脸区域;人脸识别利用了局部二进制模式直方图。

    • Haar-like 特征

    Haar-like 特征如下图所示

     

    图1 Haar-like 特征

    • LBPH

     

    人脸识别常用的方法有三种,Eigenfaces、Fisherfaces 和 LBPH;对于高维的图像空间,我们首先应该进行降维操作。LBP 不把图像看做高维的矢量,而是通过物体的局部特征来描述。将每个像素和其相邻像素对比形成局部的结构,把该像素看做中心,并以该值对邻接像素做阈值处理,如果临界像素的亮度大于该像素则为 1 否则为 0,这样每个像素点都可以用一个二进制数来表示,比如一个使用 3*3 临界点的 LBP 操作如下图所示:

    图2 LBP

    • Implementation
    • 识别训练

    利用准备好的数据库进行识别训练:首先我们利用Opencv安装文件中的python脚本create_csv.py建立CSV文件,文件中每条记录如:orl/s13/2.pgm;12,分号之前是图片所存路径,而分号之后是图片的标签号,每一组图片对应着唯一的标签号;之后利用代码中的train_data和read_csv函数对数据集进行训练。使用到的 OpenCV 类和函数有:FaceRecognizer,createLBPHFaceRecognizer

    • 人脸检测

    运用Opencv安装文件中的haarcascade_frontalface_alt.xml文件,使用分类器在视频帧中查找人脸区域,并用绿色方框标出。用到的 OpenCV 类和函数有:CascadeClassifier,detectMultiScale。

    • 人脸识别

    读取训练好的 yaml文件,对每个监测到的区域的图像分类,并在视频帧人脸区域上方显示分类结果(分类结果显示为标签和可信度),在左上角显示缩略图。用到的 OpenCV 函数主要有:predict.

    • Code

    看到评论,大家需要config.h,抱歉事情多添加有些晚,我放在下面了,有什么问题欢迎交流~

    #include "opencv2/core/core.hpp"
    #include "opencv2/contrib/contrib.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/objdetect/objdetect.hpp"
    
    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <string.h>
    
    char *FACES_TXT_PATH = "face.txt";
    char *HARR_XML_PATH = "haarcascade_frontalface_alt.xml";
    char *FACES_MODEL = "face.yaml";
    char *POTRAITS ="potraits.jpg";
    int DEVICE_ID = 0;

    主文件内容:

      1 /*头文件:*/
      2 #include "opencv2/core/core.hpp"
      3 #include "opencv2/contrib/contrib.hpp"
      4 #include "opencv2/highgui/highgui.hpp"
      5 #include "opencv2/imgproc/imgproc.hpp"
      6 #include "opencv2/objdetect/objdetect.hpp"
      7 
      8 #include <iostream>
      9 #include <fstream>
     10 #include <sstream>
     11 #include <string.h>
     12 
     13 char *FACES_TXT_PATH = "face.txt";
     14 char *HARR_XML_PATH = "haarcascade_frontalface_alt.xml";
     15 char *FACES_MODEL = "face.yaml";
     16 char *POTRAITS ="potraits.jpg";
     17 int DEVICE_ID = 0;
     18 
     19 /*主文件*/
     20 #include "config.h"
     21 
     22 using namespace cv;
     23 using namespace std;
     24 int FACE_WIDHT=92;
     25 int FACE_HEIGHT=112;
     26 int POTRITE_WIDTH = 100;
     27 int POTRITE_HEIGHT = 100;
     28 
     29 static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') {
     30     std::ifstream file(filename.c_str(), ifstream::in);
     31     if (!file) {
     32         string error_message = "找不到文件,请核对路径";
     33         CV_Error(CV_StsBadArg, error_message);
     34     }
     35     string line, path, classlabel;
     36     while (getline(file, line)) {
     37         stringstream liness(line);
     38         getline(liness, path, separator);
     39         getline(liness, classlabel);
     40         if(!path.empty() && !classlabel.empty()) {
     41             images.push_back(imread(path, 0));
     42             labels.push_back(atoi(classlabel.c_str()));
     43         }
     44     }
     45 
     46 }
     47 
     48 /*利用csv文件读取数据集并训练对应模型*/
     49 void train_data(String fn_csv)
     50 {    
     51     vector<Mat> images;
     52     vector<int> labels;
     53     //获取数据集,如果出错抛出异常
     54     try {
     55         read_csv(fn_csv, images, labels);        
     56     }
     57     catch (cv::Exception& e) {
     58         cerr << "打开文件失败 "" << fn_csv << "". 原因: " << e.msg << endl;
     59         exit(1);
     60     }
     61 
     62     // 如果训练集数量不够退出
     63     if(images.size() <= 1) {
     64         string error_message = "训练集图片少于2";
     65         CV_Error(CV_StsError, error_message);
     66     }
     67 
     68     //训练模型
     69     Ptr<FaceRecognizer> model = createLBPHFaceRecognizer();
     70     model->train(images, labels);
     71     model->save(FACES_MODEL);
     72 }
     73 
     74 void show_portrait(Mat &potrait, Mat &frame) {
     75     int channels = potrait.channels();
     76     int nRows = potrait.rows;
     77     int nCols = potrait.cols*channels;
     78     
     79     uchar *p_p, *p_f;
     80     for(auto i=0; i<nRows; i++) {
     81         p_p = potrait.ptr<uchar>(i);
     82         p_f = frame.ptr<uchar>(i);
     83         for(auto j=0; j<nCols; j++) {
     84             p_f[j*3] = p_p[j];
     85             p_f[j*3+1] = p_p[j+1];
     86             p_f[j*3+2] = p_p[j+2];
     87         }
     88     }
     89     
     90 }
     91 
     92 void makePotraitImages(vector<Mat> potraits) {
     93     int rows = potraits.size()/6;
     94     if(potraits.size()-rows *6>0)rows++;
     95     rows *= POTRITE_HEIGHT;
     96     int cols = 6*POTRITE_HEIGHT;
     97     Mat potrait_s = Mat(rows,cols,CV_8UC3);
     98     rows = POTRITE_HEIGHT;
     99     cols = POTRITE_WIDTH;
    100     uchar *p_ps, *p_p;
    101     for(auto i=0; i<potraits.size(); i++) {
    102         for(auto j=0; j<rows; j++) {
    103             p_ps = potrait_s.ptr<uchar>(i/6*POTRITE_HEIGHT+j)+3*(i%6)*POTRITE_WIDTH;
    104             p_p = potraits[i].ptr<uchar>(j);
    105             for(auto k=0; k<cols; k++) {
    106                 p_ps[k*3] = p_p[k];
    107                 p_ps[k*3+1] = p_p[k+1];
    108                 p_ps[k*3+2] = p_p[k+2];
    109             }
    110         }
    111     }
    112     imwrite(POTRAITS, potrait_s);
    113 }
    114 
    115 void loadPortraits(const string& filename, vector<Mat>& images, char separator = ';') {
    116     string fn_csv = string(FACES_TXT_PATH);
    117     std::ifstream file(fn_csv.c_str(), ifstream::in);
    118     if (!file) {
    119         string error_message = "找不到文件,请核对路径.";
    120         CV_Error(CV_StsBadArg, error_message);
    121     }
    122     string line, path, classlabel;
    123     int label(0);
    124     while (getline(file, line)) {
    125         stringstream liness(line);
    126         getline(liness, path, separator);
    127         getline(liness, classlabel);
    128         if(!path.empty() && !classlabel.empty()) {
    129             if(atoi(classlabel.c_str()) != label) {
    130                 Mat potrait = imread(path, 0);
    131                 resize(potrait, potrait,Size(POTRITE_WIDTH, POTRITE_HEIGHT));
    132                 images.push_back(potrait);
    133                 label = atoi(classlabel.c_str());
    134             }
    135         }
    136     }
    137 }
    138 
    139 int main(int argc, const char *argv[]) {
    140     // 保存图像和对应标签的向量,要求同一个人的图像必须对应相同的标签
    141     string fn_csv = string(FACES_TXT_PATH);
    142     string fn_haar = string(HARR_XML_PATH);
    143 
    144     Ptr<FaceRecognizer> model = createLBPHFaceRecognizer();
    145     FileStorage model_file(FACES_MODEL, FileStorage::READ);    
    146     if(!model_file.isOpened()){
    147         cout<<"无法找到模型,训练中..."<<endl;
    148         train_data(fn_csv);//训练数据集,1表示EigenFace 2表示FisherFace 3表示LBPHFace
    149     }
    150     model->load(model_file);
    151     model_file.release();
    152     vector<Mat> potraits;
    153     loadPortraits(FACES_MODEL,potraits);
    154     makePotraitImages(potraits);
    155     CascadeClassifier haar_cascade;
    156     haar_cascade.load(fn_haar);
    157 
    158     VideoCapture cap(DEVICE_ID);
    159     if(!cap.isOpened()) {
    160         cerr << "设备 " << DEVICE_ID << "无法打开" << endl;
    161         return -1;
    162     }
    163 
    164     Mat frame;
    165     for(;;) {
    166         cap >> frame;
    167         if(!frame.data)continue;
    168         // 拷贝现有frame
    169         Mat original = frame.clone();
    170         // 灰度化
    171         Mat gray;
    172         cvtColor(original, gray, CV_BGR2GRAY);
    173         // 识别frame中的人脸
    174         vector< Rect_<int> > faces;
    175         haar_cascade.detectMultiScale(gray, faces);
    176         
    177         if(faces.size() != 0)
    178         {
    179             int max_area_rect=0;
    180             for(int i = 0; i < 1; i++) {
    181                 if(faces[i].area() > faces[max_area_rect].area()){
    182                     max_area_rect = i;
    183                 }
    184             
    185             }
    186 
    187             // 顺序处理
    188             Rect face_i = faces[max_area_rect];
    189 
    190             Mat face = gray(face_i);
    191             rectangle(original, face_i, CV_RGB(0, 255,0), 1);
    192             int pridicted_label = -1;
    193             double predicted_confidence = 0.0;
    194             model->predict(face, pridicted_label, predicted_confidence);
    195             string result_text = format("Prediction = %d confidence=%f", pridicted_label, predicted_confidence);
    196             int text_x = std::max(face_i.tl().x - 10, 0);
    197             int text_y = std::max(face_i.tl().y - 10, 0);
    198             putText(original,result_text,  Point(text_x, text_y),FONT_HERSHEY_PLAIN, 1.0, CV_RGB(0,255,0), 2.0);
    199             if(pridicted_label >0)
    200                 show_portrait(potraits[pridicted_label], original);
    201         }
    202         // 显示结果:
    203         imshow("face_recognizer", original);
    204 
    205         char key = (char) waitKey(20);
    206         if(key == 32)
    207             exit(0);;
    208     }
    209     return 0;
    210 }
    • Experiment

    图3 结果展示

    图4 人脸库拼图

     

  • 相关阅读:
    内联模板 C++快速入门46
    delphi演示程序
    delphi演示程序
    容器和算法 C++快速入门47
    Delphi7_Lite_Fullv7.3优化精简全功能版
    Delphi7_Lite_Fullv7.3优化精简全功能版
    容器和算法 C++快速入门47
    [转载 js]alt美化效果
    “谁动了我的奶酪?”的故事
    谁动了我的奶酪[续] 讨论
  • 原文地址:https://www.cnblogs.com/xlturing/p/3587919.html
Copyright © 2011-2022 走看看