分为图像采集,训练,及辨认:
#include "mainwindow.h"
#include <opencv.hpp>
#include "face.hpp"
#include "ui_mainwindow.h"
#include "QMediaRecorder"
#include <QDebug>
#include<iostream>
#include<direct.h>//创建目录等
#include<io.h>//文件是否存在
#include "qDebug"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
,capture(0)
{
ui->setupUi(this);
std::thread t(&MainWindow::findImageByXML,this);
t.detach();
}
static Scalar randomColor(RNG& rng)
{
int icolor = (unsigned)rng;
return Scalar(icolor & 255, (icolor >> 8) & 255, (icolor >> 16) & 255);
}
MainWindow::~MainWindow()
{
destroyAllWindows();
capture.release();
delete ui;
}
//bool pointTrackingFlag = false;
//Point2f currentPoint;
// Function to detect mouse events
//void onMouse(int event, int x, int y, int, void*)
//{
// // Detect the mouse button down event
// if(event == EVENT_LBUTTONDOWN)
// {
// // Assign the current (x,y) position to currentPoint
// currentPoint = Point2f((float)x, (float)y);
// // Set the tracking flag
// pointTrackingFlag = true;
// }
//}
Point originPoint;
Rect selectedRect;
bool selectRegion = false;
int trackingFlag = 0;
void drawOpticalFlow(const Mat& flowImage, Mat flowImageGray)
{
int stepSize = 16;
Scalar color = Scalar(0, 255, 0);
// Draw the uniform grid of points on the input image along with the motion vectors
for(int y = 0; y < flowImageGray.rows; y += stepSize)
{
for(int x = 0; x < flowImageGray.cols; x += stepSize)
{
// Circles to indicate the uniform grid of points
int radius = 2;
int thickness = -1;
circle(flowImageGray, Point(x,y), radius, color, thickness);
// Lines to indicate the motion vectors
Point2f pt = flowImage.at<Point2f>(y, x);
line(flowImageGray, Point(x,y), Point(cvRound(x+pt.x), cvRound(y+pt.y)), color);
}
}
}
// Function to track the mouse events
void onMouse(int event, int x, int y, int, void* image)
{
if(selectRegion)
{
selectedRect.x = MIN(x, originPoint.x);
selectedRect.y = MIN(y, originPoint.y);
selectedRect.width = std::abs(x - originPoint.x);
selectedRect.height = std::abs(y - originPoint.y);
auto originMat=static_cast<Mat*>(image);
selectedRect &= Rect(0, 0, originMat->cols, originMat->rows);
}
switch(event)
{
case cv::EVENT_LBUTTONDOWN:
originPoint = Point(x,y);
selectedRect = Rect(x,y,0,0);
selectRegion = true;
break;
case EVENT_LBUTTONUP:
selectRegion = false;
if( selectedRect.width > 0 && selectedRect.height > 0 )
{
trackingFlag = -1;
}
break;
}
}
void MainWindow::imageCapture()
{
string cascade_file = "haarcascade_frontalface_alt.xml";//定义级联文件路径
string save_path = "C:/Users/104005162/Desktop/face/%d/";//保存图片路径
//定义摄像头设备
VideoCapture capture(0);
//调整摄像头分辨率
//capture.set(CV_CAP_PROP_FRAME_WIDTH,1024);//设置宽
//capture.set(CV_CAP_PROP_FRAME_HEIGHT,768);//设置高
if (!capture.isOpened()) {//未打开,报错
cout << "capture open fault!" << endl;
return;
}
//定义必要的变量
CascadeClassifier cascade_face = CascadeClassifier("F:/image-recognition/visionAlgorithm/haarcascades/haarcascade_frontalface_alt.xml");//定义级联变量并读取级联文件
vector<Rect> faces;//定义人脸位置矩形向量
Mat frame;//定义帧图,用于U读取
int count = 0;//定义统计数量
long current_tick_count = 0;//记录子目录名的数字
bool save_state = false;//保存状态,用于用于控制
//循环读取帧图
while (capture.read(frame)){
//printf("width=%d,height=%d\n",frame.cols,frame.rows);//打印提示
//左右翻转,参数:(原图,目标图,反转代码)
flip(frame,frame,1);
//级联发现脸,参数:(图,矩形向量,尺度系数,高斯金字塔最小临近值,标记(0),最小尺寸,最大尺寸)
cascade_face.detectMultiScale(frame,faces,1.09,1,0,Size(200,200),Size(400,400));
//保存脸和绘制脸位置
for (int i = 0; i < faces.size();i++) {//循环脸向量位置
//获得人脸部分矩形
Rect rect = faces[i];
rect.x = rect.x + rect.width*0.16;//重定x
rect.y = rect.y + rect.height*0.10;//重定y
rect.width = rect.width*0.70;//重定宽
rect.height = rect.height*0.78;//重定高
//当为保存状态,且为10的倍数,且为小于401时,保存图片(保存40张图)
if (save_state&&count%10==0&&count<401){
Mat dst;//定义新图
//调整脸图片大小,128*128,参数:(原图,目标图,尺寸,x比例,y比例,线性插值类型)
cv::resize(frame(rect),dst,Size(128,128),0,0,INTER_LINEAR);
//保存到指定位置
string path = format(save_path.c_str(), current_tick_count);//获得完整路径,以当前时间数的决定值为子目录名
//判断路径是否存在
/*
R_OK 只判断是否有读权限
W_OK 只判断是否有写权限
X_OK 判断是否有执行权限
F_OK 只判断是否存在
在宏定义里面分别对应:
0x00 只存在
0x02 写权限
0x04 读权限
0x06 读和写权限
*/
if (_access(path.c_str(), _A_NORMAL)==-1) {//当路径不存在(-1),创建路径
_mkdir(path.c_str());//创建路径
}
path = path + string(format("%d.jpg",count/10));//添加路径文件名
imwrite(path.c_str(),dst);//保存图片,参数:(路径名,矩阵图)
//提示正在保存图片,头不要动,以眼睛作为基准线,变换表情。
string content("Don't move your head. Use your eyes as a baseline to change your expression.");//指定文本
//添加文本到图片,参数:(图,文本,原点,字体,缩放比,颜色,线宽,线型,左底起源状态(倒置效果))
putText(frame,content, Point(20, 30), 0, 0.5, Scalar(0,255, 0), 1, 8, false);
}
else if (save_state&& count<401) {//当保存状态为真,且统计数小于401时,说明在记录范围内,只提示
//提示正在保存图片,头不要动,以眼睛作为基准线,变换表情。
string content("Don't move your head. Use your eyes as a baseline to change your expression.");//指定文本
//添加文本到图片,参数:(图,文本,原点,字体,缩放比,颜色,线宽,线型,左底起源状态(倒置效果))
putText(frame, content, Point(20, 30), cv::FONT_HERSHEY_PLAIN, 0.5, Scalar(0, 255, 0), 1, 8, false);
}else {//否则提示等待状态
//添加文本到图片,参数:(图,文本,原点,字体,缩放比,颜色,线宽,线型,左底起源状态(倒置效果))
putText(frame,"Wait for the key to be pressed.",Point(20,30),cv::FONT_HERSHEY_PLAIN,1.0,Scalar(255,0,0),1,8,false);
}
//绘制矩形,参数:(图,矩形变量,颜色,线宽,线型,偏移量)
rectangle(frame, rect, Scalar(0, 255, 0), 1, 8, 0);
}
//显示图
imshow("frame",frame);
//按键判断
char c = waitKey(33);//等待33毫秒并获得按键值,-1时表示没有输入
if (c==27) {//当为ESC(27)时,退出循环
break;
}else if(c!=-1) {//当用户点击除ESC的任意键时,应拍照保存人脸部分或改变状态
save_state = (save_state ? false : true);//反转保存状态,当保存状态为真时,给假,否则给真
count = 0;//统计数量给0,从新计数
current_tick_count = (save_state?abs(getTickCount()):0);//当保存状态为真是,获得当前时间统计值的绝对值,否则为0
}
count++;//统计变量加1
}
//释放摄像头资源
capture.release();
}
void getFiles(string path, vector<string>& files)
{
intptr_t hFile = 0;//文件句柄,过会儿用来查找
struct _finddata_t fileinfo;//文件信息
string p;
if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
//如果查找到第一个文件
{
do
{
if ((fileinfo.attrib & _A_SUBDIR))//如果是文件夹
{
if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
getFiles(p.assign(path).append("\\").append(fileinfo.name), files);
}
else//如果是文件
{
files.push_back(p.assign(path).append("\\").append(fileinfo.name));
}
} while (_findnext(hFile, &fileinfo) == 0); //能寻找到其他文件
_findclose(hFile); //结束查找,关闭句柄
}
}
void MainWindow::trainImage()
{
vector<string> filesPath,filesPath1;
//此处80的训练阈值可由正确识别时人物置信度所处大致范围决定
cv::Ptr<cv::face::LBPHFaceRecognizer> model = cv::face::LBPHFaceRecognizer::create(1,8,8,8,80);
std::vector<cv::Mat>referceneImage;
std::vector<int>labels;
getFiles("C:\\Users\\104005162\\Desktop\\face\\liu",filesPath);
getFiles("C:\\Users\\104005162\\Desktop\\face\\zhu",filesPath1);
for(auto each:filesPath)
{
qDebug()<<QString::fromStdString(each);
referceneImage.push_back(cv::imread(each,cv::IMREAD_GRAYSCALE));
labels.push_back(1);
}
for(auto each:filesPath1)
{
qDebug()<<QString::fromStdString(each);
referceneImage.push_back(cv::imread(each,cv::IMREAD_GRAYSCALE));
labels.push_back(2);
}
model->train(referceneImage,labels);
model->save(".\\myfirst3.xml");
qDebug()<<"6666666666";
//int label=-1;
//double confidence=0;
//model->predict(cv::imread("C:\\Users\\104005162\\Desktop\\face\\liu\\1.jpg",cv::IMREAD_GRAYSCALE),
// label,confidence);
//qDebug()<<label<<"con:"<<confidence;
}
void MainWindow::predictImage()
{
int label=-1;
double confidence=-1;
string name="myfirst3.xml";
FileStorage fs("myfirst3.xml", FileStorage::READ);
CV_Assert(fs.isOpened());
cv::Ptr<cv::face::LBPHFaceRecognizer> model=Algorithm::
load<cv::face::LBPHFaceRecognizer>(name);
if(model.empty()){qDebug()<<"ok";};
model->predict(cv::imread("C:\\Users\\104005162\\Desktop\\face\\zhu\\5.jpg",cv::IMREAD_GRAYSCALE),
label,confidence);
qDebug()<<label<<"con:"<<confidence;
}
void MainWindow::findImageByXML()
{
int label=-1;
double confidence=-1;
string name="myfirst3.xml";
cv::Ptr<cv::face::LBPHFaceRecognizer> model=Algorithm::
load<cv::face::LBPHFaceRecognizer>(name);
if(model.empty()){qDebug()<<"ok";};
//定义摄像头设备
VideoCapture capture(0);
//调整摄像头分辨率
//capture.set(CV_CAP_PROP_FRAME_WIDTH,1024);//设置宽
//capture.set(CV_CAP_PROP_FRAME_HEIGHT,768);//设置高
if (!capture.isOpened()) {//未打开,报错
cout << "capture open fault!" << endl;
return;
}
//定义必要的变量
CascadeClassifier cascade_face = CascadeClassifier("F:/image-recognition/visionAlgorithm/haarcascades/haarcascade_frontalface_alt.xml");//定义级联变量并读取级联文件
vector<Rect> faces;//定义人脸位置矩形向量
Mat frame;//定义帧图,用于U读取
//循环读取帧图
while (capture.read(frame)){
//printf("width=%d,height=%d\n",frame.cols,frame.rows);//打印提示
//左右翻转,参数:(原图,目标图,反转代码)
flip(frame,frame,1);
//级联发现脸,参数:(图,矩形向量,尺度系数,高斯金字塔最小临近值,标记(0),最小尺寸,最大尺寸)
cascade_face.detectMultiScale(frame,faces,1.09,1,0,Size(200,200),Size(400,400));
//保存脸和绘制脸位置
for (int i = 0; i < faces.size();i++) {//循环脸向量位置
//获得人脸部分矩形
Rect rect = faces[i];
rect.x = rect.x + rect.width*0.16;//重定x
rect.y = rect.y + rect.height*0.10;//重定y
rect.width = rect.width*0.70;//重定宽
rect.height = rect.height*0.78;//重定高
//当为保存状态,且为10的倍数,且为小于401时,保存图片(保存40张图)
Mat dst;//定义新图
//调整脸图片大小,128*128,参数:(原图,目标图,尺寸,x比例,y比例,线性插值类型)
cv::resize(frame(rect),dst,Size(128,128),0,0,INTER_LINEAR);
//保存到指定位置
cvtColor(dst,dst,COLOR_BGR2GRAY);
model->predict(dst,label,confidence);
if(label==1&&confidence<85)
{
QString text="liuhao"+QString::number(confidence);
putText(frame,text.toStdString(), Point(rect.x, rect.y), 0, 0.5, Scalar(0,255, 0), 1, 8, false);
}
else if(label==2&&confidence<85)
{
QString text="zhongdong"+QString::number(confidence);
putText(frame,text.toStdString(), Point(rect.x, rect.y), 0, 0.5, Scalar(0,255, 0), 1, 8, false);
}
else
{
putText(frame,"unknown!", Point(rect.x, rect.y), 0, 0.5, Scalar(0,255, 0), 1, 8, false);
}
}
//显示图
imshow("frame",frame);
//按键判断
char c = waitKey(33);//等待33毫秒并获得按键值,-1时表示没有输入
if (c==27) {//当为ESC(27)时,退出循环
break;
}
}
//释放摄像头资源
capture.release();
}
QImage Mat2QImage(cv::Mat cvImg)
{
QImage qImg;
if(cvImg.channels()==3) //3 channels color image
{
cv::cvtColor(cvImg,cvImg,COLOR_BGR2RGB);
qImg =QImage((const unsigned char*)(cvImg.data),cvImg.cols, cvImg.rows,cvImg.cols*cvImg.channels(),QImage::Format_RGB888);
}
else if(cvImg.channels()==1) //grayscale image
{
qImg =QImage((const unsigned char*)(cvImg.data),cvImg.cols,cvImg.rows,cvImg.cols*cvImg.channels(),QImage::Format_Indexed8);
}
else{
qImg =QImage((const unsigned char*)(cvImg.data),cvImg.cols,cvImg.rows,cvImg.cols*cvImg.channels(),QImage::Format_RGB888);
}
return qImg;
}
训练好的xml文件:下载