Opencv+Qt【拍照&人脸识别】

环境:VS2012+Qt5+Opencv2.4.10,window10系统
功能:打开电脑摄像头进行人脸显示,可以拍照存储到本地,最重要的是能够实现人脸的检测与识别。

一、第一部分:人脸识别

先讨论人脸的识别过程:
1、收集训练库,这里采用的是ORL人脸数据集,总共有40个人,每人10张,为了能够识别自己,需要采集自己不同角度以及光照的10张脸部分的照片,加入ORL数据集存储在s41文件夹内(PS:这里面主要是要制作一个CSV文件,即txt文件,把dataset中的所以图片的路径存储在txt文件中,然后可以通过Python的一个文件批处理的程序给每个路径的图片进行加上label,中间用“;”分号隔开;目的是为了接下来的训练数据读取图片准备的)。
2、训练。Opencv提供了三种方式来训练并产生xml分类文件。分类模型有EigenFaceRecognizer()、FisherFaceRecognizer()、LBPHFaceRecognizer()这三种。训练的代码也十分简洁。只需要三行代码即可,以LBP(局部二值化模式)为例!代码如下:

    Ptr<FaceRecognizer> model2 = createLBPHFaceRecognizer();
    model2->train(images, labels);
    model2->save("My_Face_LBPHModel.xml");

其他两种都是这样的格式,是不是十分简单粗暴。
3、检测。这里面需要用到Opencv自带的人脸检测的级联分类器。haarcascade_frontalface_alt.xml,这在Opencv中data文件夹下的haarcascade中,这里面官方训练好了许多分类器模型,有兴趣的可以自己研究Haar特征LBP特征提取原理,这里不作详解;如果有需要交流的可以私信。这里给出检测的核心部分。

void dectectAndDisplay(Mat& frame)
{
    vector faces;
    Mat frame_gray;
    cvtColor(frame,frame_gray,CV_BGR2GRAY);
    equalizeHist(frame_gray,frame_gray);

    face_cascade.detectMultiScale(frame_gray,faces,1.1,2,0|CV_HAAR_SCALE_IMAGE,Size(30,30));

    for(int i = 0;i0.5,faces[i].y+faces[i].height*0.5);
        ellipse(frame,center,Size(faces[i].width*0.5,faces[i].height*0.5),0,0,360,Scalar(255,0,255),4,8,0);

    }
    imshow(window_face,frame);
}

通过一个vector faces;将检测到的人脸部分以Rec类型存储在容器中,然后通过绘图函数直接绘出,以圆形圈出或者矩形框出都可以。检测的重点在

face_cascade.detectMultiScale(frame_gray,faces,1.1,2,0|CV_HAAR_SCALE_IMAGE,Size(30,30));

这个代码部分,这是实现多尺度检测人脸的,如果想详细了解分类型是如何做检测的可以参考这篇博文。
4、识别
识别部分就特别简单了,就一句

predictPCA = modelPCA->predict(face_test);
即可这里面传进来的face_test人脸图片需要进行预处理,归一化直方图(减小光照的影响),大小resize到(92,112)大小等操作,目的是需要跟数据集中的图片大小一致。最后再将返回检测的predictPCA的值和我的41(因为算在开始训练的时候加上了我自己共41个人,从1开始标签数据。同一个人标签一样,我标为41)进行比较,如果一致则putText进行显示我的名字,这个还是很简单的。
大致人脸识别的过程就是以上的说明。这仅仅是在VS中实现了这个功能,还没有结合Qt做界面,所以接下来的部分将介绍如何将人脸识别嵌入Qt中实现友好的人机交互界面的设计。人脸识别代码如下:
#include
#include

using namespace std;
using namespace cv;

//变量声明区
Mat frame;
Mat edges;
Mat gray;
CascadeClassifier cascade;
bool stop = false;

//函数声明区
static void HelpText();
int main()
{
    HelpText();
    VideoCapture cap(0);    //打开默认摄像头
    if (!cap.isOpened())
    {
        return -1;
    }

    //训练好的文件名称,放置在可执行文件同目录下
    cascade.load("haarcascade_frontalface_alt.xml");

    Ptr modelPCA = createEigenFaceRecognizer();
    modelPCA->load("MyFacePCAModel.xml");

    while (!stop)
    {
        cap >> frame;

        //建立用于存放人脸的向量容器
        vector faces(0);

        cvtColor(frame, gray, CV_BGR2GRAY);
        //改变图像大小,使用双线性差值
        //resize(gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR);
        //变换后的图像进行直方图均值化处理
        equalizeHist(gray, gray);
        double timeA = (double)cvGetTickCount();
        cascade.detectMultiScale(gray, faces,
            1.1, 2, 0
            //|CV_HAAR_FIND_BIGGEST_OBJECT
            //|CV_HAAR_DO_ROUGH_SEARCH
            | CV_HAAR_SCALE_IMAGE,
            Size(30, 30));
        double timeB = ((double)cvGetTickCount() - timeA)/(double)cvGetTickFrequency()*1000000;
        cout<<"DetcetMultiscale is :"<char AA[20];
        for (size_t i = 0; i < faces.size(); i++)
        {
            if (faces[i].height > 0 && faces[i].width > 0)
            {
                face = gray(faces[i]);
                text_lbd = Point(faces[i].x+faces[i].height*0.5, faces[i].y+faces[i].width*0.5);
                text_lb = Point(faces[i].x, faces[i].y);
                cout<<"x:"<0.5<<" "<<"y:"<<" "<0.5<sprintf(AA,"%d %d",faces[i].x+faces[i].height*0.5,faces[i].y+faces[i].width*0.5);
                cout<<"AA is :"<2,1.0,Scalar(255,122,134),2,8);
                rectangle(frame, faces[i], Scalar(255, 0, 0), 1, 8, 0);
            }
        }

        Mat face_test;

        int predictPCA = 0;
        if (face.rows >= 70)
        {
            resize(face, face_test, Size(92, 112));
            //resize(face,);
        }
        //Mat face_test_gray;
        //cvtColor(face_test, face_test_gray, CV_BGR2GRAY);

        if (!face_test.empty())
        {
            //测试图像应该是灰度图
            predictPCA = modelPCA->predict(face_test);
        }

        cout << predictPCA << endl;
        if (predictPCA == 41)
        {
            string name = "W.Chaolong";
            putText(frame, name, text_lb, FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255));
        }

        imshow("face", frame);
        if (waitKey(10) >= 0)
            stop = true;
    }

    return 0;
}

static void HelpText()
{
    system("color 5F");
    cout<<"********************************************\n"<cout<<"**           应用AT&T数据集ORL            **\n"<cout<<"**             实现识别自己               **\n"<cout<<"********************************************"<

二、第二部分:Qt+Opencv

本部分即将介绍Qt+Opencv实现一个简单的界面环境。如果有Qt不熟悉的可以参考如下[《Qt学习之路2》](https://www.devbean.net/2012/08/qt-study-road-2-catelog/)系列教程。如果不会配置在VS中配置Qt的可以参照这篇VS+Qt+Opencv博客。如果还有不懂的可以私信还有主要就是通过互联网解决问题。
在这一部分如果只是刚开始接触Qt的话,可以在网上先搜索在Qt中打照片以及通过按钮打开视频来学习,C++比较好的话很容易上手。  这个主要就是实现了人脸的检测,因为没有采集检测这个人的图片集,所以只能检测出来不能进行识别

在实验我自己的时候是可以检测并识别出来,而且可以putText在人脸左上方。后期具体的过程再补!
先贴上代码如下:
1、Ctest_Qt_VideoCapture_0607.hpp(因为我的文件名字就是这个)
 #ifndef CTEST_QT_VIDEOCAPTURE_0607_H
#define CTEST_QT_VIDEOCAPTURE_0607_H

#include 
#include "ui_ctest_qt_videocapture_0607.h"
#include
#include
#include
#include

//#include<>
using namespace cv;
using namespace std;

class Ctest_Qt_VideoCapture_0607 : public QMainWindow
{
    Q_OBJECT

public:
    Ctest_Qt_VideoCapture_0607(QWidget *parent = 0);
    ~Ctest_Qt_VideoCapture_0607();
   QImage Mat2Qimage(const Mat& mat);
  // Mat BackFrame();
private:
    Ui::Ctest_Qt_VideoCapture_0607Class ui;
    Mat frame;
    Mat CannyImg;
    QImage TakeP;
    bool start;
    char file[20];
    //人脸识别
    Mat edges;
    Mat gray;
    QString tempStr;
    VideoCapture cap;
    //CvCapture *cap;
    QTimer *timer;
    int AA;
private slots:
    void OpenVideoCap();
    void CloseVideoCap();
    void TakePhoto();
    //人脸识别
    void FaceRecognition();
    //初始化
    void Start();
    void Quit();
    void Slider(int);
    //void checkBox();
};

#endif // CTEST_QT_VIDEOCAPTURE_0607_H
2、Ctest_Qt_VideoCapture_0607.cpp
#include "ctest_qt_videocapture_0607.h"

Ctest_Qt_VideoCapture_0607::Ctest_Qt_VideoCapture_0607(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
    ui.pushButton_3->setEnabled(false);
    ui.pushButton->setEnabled(false);
    ui.pushButton_2->setEnabled(false);
    ui.pushButton_6->setEnabled(false);
    timer = new QTimer(this);
    timer->start(50);
}

Ctest_Qt_VideoCapture_0607::~Ctest_Qt_VideoCapture_0607()
{

}

void Ctest_Qt_VideoCapture_0607::OpenVideoCap()
{
    //VideoCapture cap(0);
    start = true;
    while(start)
    {
        cap>>frame;
        imshow("Camera",frame);
        waitKey(10);
        timer->start(50);
        QImage img = Mat2Qimage(frame);
        //Canny(frame,CannyImg,100,255);
        //QImage img1 = Mat2Qimage(CannyImg);
        TakeP = img;
        ui.label->setPixmap(QPixmap::fromImage(img));
        //ui.label1->setPixMap(QPixmap::fromImage(img1));
        //ui.label_1->setPixmap(QPixmap::fromImage(img1));
        //ui.label->setScaledContents(true);

        int c = waitKey(30);
        if(c>=0)
        {
            waitKey(0);
        }
    }
}

QImage Ctest_Qt_VideoCapture_0607::Mat2Qimage(const Mat& mat)
{
    if(mat.type()==CV_8UC1)
    {
        QVector colorTable;
        for(int i=0;i<256;i++)
        {
            colorTable.push_back(qRgb(i,i,i));

        }
        const uchar* qImageBuff = (const uchar*)mat.data;
        QImage img(qImageBuff,mat.cols,mat.rows,mat.step,QImage::Format_Indexed8);
        img.setColorTable(colorTable);
        return img;
    }
    if(mat.type()==CV_8UC3)
    {
        const uchar* qImageBuffer = (const uchar*)mat.data;
        QImage img(qImageBuffer,mat.cols,mat.rows,mat.step,QImage::Format_RGB888);
        return img.rgbSwapped();
    }
    else
    {
        return QImage();
    }
}

void Ctest_Qt_VideoCapture_0607::CloseVideoCap()
{
    start = false;
}

void  Ctest_Qt_VideoCapture_0607::TakePhoto()
{
    static int i =1;
    ui.pushButton_3->setEnabled(false);
    ui.label_1->setPixmap(QPixmap::fromImage(TakeP));

    sprintf(file,"../Images/Pic_%d.jpg",i);
    i++;
    imwrite(file,frame);
    waitKey(10);
    ui.pushButton_3->setEnabled(true);
    //cout<<"jjjjj"<

}

//人脸识别
void Ctest_Qt_VideoCapture_0607::FaceRecognition()
{


    CascadeClassifier cascade;
    //bool stop = false;

    //while中
    vector faces(0);
    Mat face;
    Point text_lb;
    Point text_lbd;
    char AA[20];
    Mat face_test;
    int predictPCA = 0;
    //训练好的文件名称,放置在可执行文件同目录下
    cascade.load("haarcascade_frontalface_alt2.xml");

    Ptr modelPCA = createEigenFaceRecognizer();
    modelPCA->load("MyFacePCAModel.xml");

    while (start)
    {
        cap >> frame;

        //建立用于存放人脸的向量容器

        QImage img4 = Mat2Qimage(frame);
        ui.label->setPixmap(QPixmap::fromImage(img4));
        cvtColor(frame, gray, CV_BGR2GRAY);
        //改变图像大小,使用双线性差值
        //resize(gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR);
        //变换后的图像进行直方图均值化处理
        equalizeHist(gray, gray);
        double timeA = (double)cvGetTickCount();
        cascade.detectMultiScale(gray, faces,
            1.1, 2, 0
            //|CV_HAAR_FIND_BIGGEST_OBJECT
            //|CV_HAAR_DO_ROUGH_SEARCH
            | CV_HAAR_SCALE_IMAGE,
            Size(30, 30));
        double timeB = ((double)cvGetTickCount() - timeA)/(double)cvGetTickFrequency()*1000;
        ui.label_3->setText(tempStr.setNum(timeB));
        cout<<"DetcetMultiscale is :"<for (size_t i = 0; i < faces.size(); i++)
        {
            if (faces[i].height > 0 && faces[i].width > 0)
            {
                face = gray(faces[i]);
                text_lbd = Point(faces[i].x+faces[i].height*0.5, faces[i].y+faces[i].width*0.5);
                text_lb = Point(faces[i].x, faces[i].y);
                ui.label_4->setText(tempStr.setNum(faces[i].area()));
                //cout<<"x:"<
                //sprintf(AA,"%d %d",faces[i].x+faces[i].height*0.5,faces[i].y+faces[i].width*0.5);
                //cout<<"AA is :"<
                //ui.label_2->setText(tempStr.setNum(faces[i].x));
                //ui.label_3->setText(tempStr.setNum(faces[i].y));
                //putText(frame,AA,text_lbd,2,1.0,Scalar(255,122,134),2,8);
                rectangle(frame, faces[i], Scalar(255, 0, 0), 1, 8, 0);
            }
        }

        if (face.rows >= 70)
        {
            //cvResize(face, face_test, Size(92, 112));
            //resize(face,face_test,Size(92,112));
            cv::resize(face,face_test,Size(92,112));
            //resize(face,);
        }
        //Mat face_test_gray;
        //cvtColor(face_test, face_test_gray, CV_BGR2GRAY);

        if (!face_test.empty())
        {
            //测试图像应该是灰度图
            predictPCA = modelPCA->predict(face_test);
        }

        //cout << predictPCA << endl;
        if (predictPCA == 41)
        {
            string name = "W.Chaolong";
            putText(frame, name, text_lb, FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255));
        }
        ui.label_2->setText(tempStr.setNum(predictPCA));
        imshow("face", frame);
        QImage img2 = Mat2Qimage(frame);
        ui.label_1->setPixmap(QPixmap::fromImage(img2));

        waitKey(5);
        //if (waitKey(10) >= 0)
        //  stop = true;
    }
}

//返回Cap拍摄的frame
void Ctest_Qt_VideoCapture_0607::Start()
{
    //VideoCapture cap(0);
    //while(true)
    //{
    //  cap>>frame;
    //  waitKey(1);
    //}
    cap.open(0);
    ui.pushButton_3->setEnabled(true);
    ui.pushButton->setEnabled(true);
    ui.pushButton_2->setEnabled(true);
    ui.pushButton_6->setEnabled(true);
    //ui.pushButton_7->setText("关闭");
    ui.pushButton_7->setEnabled(false);


}

void Ctest_Qt_VideoCapture_0607::Quit()
{
    qApp->quit();
}

void Ctest_Qt_VideoCapture_0607::Slider(int value)
{
    //ui.Slider->getValue
    AA = ui.Slider->value();
    QString BB = QString("%1").arg(AA);
    ui.progressBar->setValue(AA);
    ui.label_5->setText(BB);
}


3、main.cpp(主函数可以不动)
#include "ctest_qt_videocapture_0607.h"
#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Ctest_Qt_VideoCapture_0607 w;
    w.show();
    return a.exec();
}

结果真是太感人,仅仅用Opencv中自带的分类器效率还有待提高。这个还需要后期优化代码或者CUDA编程利用GPU加速处理,不然完全不能用到实际工程中去。本实验仅仅是实现了一个结合Qt的界面话的小实验。还有许多地方需要完善,如有不当之处,还望批评指正!共同学习进步!
这里贴一张界面图:
Opencv+Qt【拍照&人脸识别】_第1张图片

你可能感兴趣的:(Computer,Vision,OpenCV,C++)