前提条件:
1.安装vmware16.0虚拟机
2.虚拟机里安装ubuntu16.04
3.虚拟机安装tools(方便与主机进行交互)
4.虚拟机里安装QT(Ubuntu版本)
5.在虚拟机的QT中添加opencv环境(这个比较复杂,可以查找资料或者评论拿资料)
6.界面设计直接用QT里面的设计就可以。如图(例子)
说明:
【1】拍照+录入信息:把当前拍摄的照片加入到指定的问价夹中,后台会存储10张这样的照片(存储10张目的是为了识别的时候数据更加可靠)。
【2】学习:目的是把你之前拍摄的照片进行“训练”。需要用到opencv的库。
【3】识别:只有把你拍摄的照片进行训练后,才能识别,识别后拍摄区会出现对应的名字(这个名字需要你后台去指定,这也是我这个项目不足之处,其实应该在你拍照后就可以直接输入名字的,这个功能就交给大家实现把,哈哈。
主要代码:
#include "widget.h"
#include "ui_widget.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include //判断文件是否存在
using namespace face;
bool openxuexi=false;
bool openshibie =false;
bool openluruxinxi=false;
bool isFileExists_stat(string& name);
int imagecount=0;
bool keyisgibie=false;
list<QString> mylist;
string doubleToStr(string b);
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
list<QString>::iterator it;
// int i=1;
// for ( it=mylist.begin() ; it != mylist.end(); it++ )
// {
// if(i==2){
// QString temp = *it; //依次取list里面的值到temp中
// qDebug()<
// }
// i=i+1;
// }
// qDebug()<<"list循环结束";
// ui->Widget->setStyleSheet("border-image:url(/home/lyx/桌面/bj.jpg)");
QImage _image;
_image.load("/home/lyx/桌面/bj.jpg");
setAutoFillBackground(true); // 这个属性一定要设置
QPalette pal(palette());
pal.setBrush(QPalette::Window, QBrush(_image.scaled(size(), Qt::IgnoreAspectRatio,
Qt::SmoothTransformation)));
// this->setStyleSheet("background-color:rgb(255,34,198)");
setPalette(pal);
ui->label->setStyleSheet("QLabel{background-color:rgb(173, 127, 168,%0);}");
ui->label_2->setStyleSheet("QLabel{background-color:rgb(173, 127, 168,%0);}");
ui->pushButton->setStyleSheet("QPushButton{background-color:rgb(52, 101, 164);}");
ui->pushButton_3->setStyleSheet("QPushButton{background-color:rgb(52, 101, 164);}");
ui->pushButton_4->setStyleSheet("QPushButton{background-color:rgb(52, 101, 164);}");
ui->pushButton_5->setStyleSheet("QPushButton{background-color:rgb(52, 101, 164);}");
ui->lineEdit_3->setStyleSheet("QLineEdit{background-color:rgb(114, 159, 207);}");
ui->lineEdit->setStyleSheet("QLineEdit{background-color:rgb(114, 159, 207);}");
//首先获取文件夹数量
for(int i=1;i<100;i++){
string path=format("/home/lyx/桌面/studeyphoto/image_%d",i);
bool cunzai=isFileExists_stat(path);
if(!cunzai)
{
imagecount=i-1;
qDebug()<<imagecount;
break;
}
}
tim.setInterval(33);//1s计数完成
//开启摄像机信号
connect(ui->pushButton,\
SIGNAL(clicked()),\
this,\
SLOT(on_pushButtons_clicked())
);
//定时器信号
connect(&tim,\
SIGNAL(timeout()),\
this,\
SLOT(timerout_solt()));
connect(ui->pushButton_4,\
SIGNAL(clicked()),\
this,\
SLOT(on_pushButton_4_clicked())
);
connect(ui->pushButton_5,\
SIGNAL(clicked()),\
this,\
SLOT(on_pushButton_5_clicked())
);
//加载脸部识别分类器
facedector.load("/home/lyx/OpenCv_Src/opencv-3.4.5/install/share/OpenCV/haarcascades/haarcascade_frontalface_alt2.xml");
//
}
Widget::~Widget()
{
delete ui;
}
int KeyValue;
//点击打开摄像头
void Widget::on_pushButton_clicked()
{
Mat cvimg;
cap.open(-1);
if(cap.isOpened()==false)//打开失败
{
cout<<"摄像头打开失败,结束进程";
exit(0);//结束进程
}
if(cap.isOpened()==true){
cout<<"摄像头打开ok";
}
//摄像头分辨率调整
cap.set(CAP_PROP_FRAME_WIDTH,411.0);
cap.set(CAP_PROP_FRAME_HEIGHT,361.0);
tim.start();//开始定时器计时
}
void Widget::timerout_solt()
{
Mat cvimg,tmpimg;
//定义一个rect类型的容器
vector<Rect> faces;
vector<Rect> eyes;
cap.read(cvimg);//读取一桢图片
flip(cvimg,cvimg,1);//反转
cvtColor(cvimg,tmpimg,CV_RGB2GRAY);//灰度处理
equalizeHist(tmpimg,tmpimg); //直方图均衡化,,用于提高图像的质量
//detectMultiScale 分类器对象调用
//第一个参数:要输入的图像 //第二个表示检测到的人脸序列(objects--被检测物体的矩形框向量组;代表四个坐标)
//第三个参数:每次图像扩大的比例1.1默认//第四个参数:最小认可度,认可度越小越容易识别,识别率越高,精度越低。
//第五个默认0,//第六个和第七个:目标最小尺寸和最大尺寸
// //会将识别到的人脸坐标和大小全部放入 faces 容器中
facedector.detectMultiScale(tmpimg,faces,1.1,3,0,Size(10,10),Size(640,480));
//最起码有一个人像
if(faces.size()>0)
{
for(int i=0;i<faces.size();i++)
{
if(openshibie==true){
cout<<"qq";
list<QString>::iterator it;
QString temp="没有赋值";
string temp2="默认值";
// 识别当前的脸是否为你之前训练的人脸
// qDebug()<<"现在开始识别";
Mat tmpface ;
int predictLabel = -1;
double predictConfidence = 0.0;
cv::resize(tmpimg(faces[i]),tmpface,Size(100,100));
// predict 这个函数是将一张人脸图片
// 和我们现在之前学习的模型进行对比!
//第一个参数:这个函数是将一张人脸图片,和我们现在之前学习的模型进行对比!识别你是谁!
// 第二个参数 会对不同的人脸做一个标记!一般是一个数字!
// !相似度。越低越好
model->predict(tmpface,predictLabel,predictConfidence);
cout<<"开始赋值"<<endl;
//
for(int i=1;i<imagecount;i++){
// cout<<"赋值进行中"<
waitKey(20);
if(predictLabel==i && predictConfidence<100)
{
int j=1;
//下面这个for循环就是取出来集合中对应的名字,把名字赋值给对应的人物
for ( it=mylist.begin() ; it != mylist.end(); it++ )
{
if(j==i)
{
QString temp = *it; //依次取list里面的值到temp中
temp2=temp.toStdString();
cout<<"你看";
qDebug()<<temp;
}
j=j*2;
}
//第二个参数转换重点!temp2是string类型
//为了与C兼容,在C中没有string类型,故必须通过string类对象的成员函数c_str()把string对象转换成C中的字符串样式。
ft2->putText(cvimg,format("%s",temp2.c_str()),faces[i].tl(),40,Scalar(0,0,255),-1,8,true);
double x=predictConfidence;
QString str_x = QString::number(x,'g',10);
//ui->lineEdit->setText("姓名:"+format("%s",temp2) +"相似度:"+str_x);
cout<<"姓名:";
cout<<temp2;
cout<<"相似度:";
cout<<predictConfidence;
cout<<endl;
}
}
// else
{
ft2->putText(cvimg,"",faces[i].tl(),40,Scalar(0,0,255),-1,8,true);
}
/
}
rectangle(cvimg,faces[i],Scalar(0,0,255),2,16); //cvimg加载的图,faces[i]矩形向量框,Scalaar线条颜色,2线条宽度,16是线型
}
}
QImage qimage=Mat2QImage(cvimg);
ui->label->setPixmap(QPixmap::fromImage(qimage));
}
//Mat->QImage
QImage Widget::Mat2QImage(cv::Mat cvImg)
{
QImage qImg;
cv::cvtColor(cvImg,cvImg,CV_BGR2RGB);
//cv::cvtColor(cvImg,cvImg,cv::COLOR_BGR2RGB);
qImg=QImage((const unsigned char*)(cvImg.data),
cvImg.cols,cvImg.rows, //宽,高
cvImg.step, //步长
QImage::Format_RGB888); //24位图,RGB=[0,1,2]
//return qImg.rgbSwapped();
return qImg;
}
void Widget::on_pushButton_4_clicked()
{
if(keyisgibie){
qDebug()<<"点击了开始识别";
openshibie=true;
}
else{
qDebug()<<"点击了开始识别,但是还没有学习,请先学习后识别";
}
}
//判断文件是否存在的函数
bool isFileExists_stat(string& name) {
struct stat buffer;
return (stat(name.c_str(), &buffer) == 0);
}
void Widget::on_pushButton_5_clicked()
{
qDebug()<<"开始学习";
cout<<endl;
model=LBPHFaceRecognizer::create();//创建学习模型
//从第一个文件夹开始遍历,直到全部学习完成!
cout<<imagecount;
cout<<"份人脸数据";
cout<<endl;
int n=1;
for(int i=1;i<=imagecount;i++)
{
//每个文件夹10个图片
for(int i=1;i<=10;i++)
{
//遍历学习
Mat scrimg =imread(format("/home/lyx/桌面/studeyphoto2/image_%d/myface_%d.jpg",n,i));
cvtColor(scrimg,scrimg,CV_BGR2GRAY);//转换为灰度图片
study_faces.push_back(scrimg);//压栈--往里面填充数据!
study_index.push_back(n);//imagecount就相当我这张人脸的索引号
}
//如果获取内容非空
if(!(ui->lineEdit_4->text()==""))
{
name =ui->lineEdit_4->text();
//将获取的值加入list集合
qDebug()<<name;
qDebug()<<"获取值list qdebug";
mylist.push_back(name);
}
n=n+1;
}
study_faces.pop_back();
study_index.pop_back();
//
list<QString>::iterator it;
for ( it=mylist.begin() ; it != mylist.end(); it++ )
{
QString temp = *it; //依次取list里面的值到temp中
qDebug()<<"遍历";
qDebug()<<temp;
}
qDebug()<<"list循环结束";
//
//识别不同人脸的特性进行学习和保存 //我们通过容器进行训练
model->train(study_faces,study_index);
ft2 = freetype::createFreeType2();//初始化中文容器
ft2->loadFontData("/usr/share/fonts/truetype/arphic/uming.ttc",0);
qDebug()<<"完成学习";
keyisgibie=true;
}
void Widget::on_pushButton_3_clicked()
{
qDebug()<<"按键按下!×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××\r\n\r\n\r\n";
//打开ok
if(cap.isOpened()==true)
{
Mat cvimg2,tmpimg2;
cap.read(cvimg2);//读取一桢图片
flip(cvimg2,cvimg2,1);//反转
cvtColor(cvimg2,tmpimg2,CV_RGB2GRAY);//灰度处理
equalizeHist(tmpimg2,tmpimg2); //直方图均衡化,,用于提高图像的质量
//将读取的图片写入此路径
//
//如果点击了录入信息,开始写入10张图片数据
vector<Rect> faces2;
facedector.load("/home/lyx/OpenCv_Src/opencv-3.4.5/install/share/OpenCV/haarcascades/haarcascade_frontalface_alt2.xml");
facedector.detectMultiScale(tmpimg2,faces2,1.1,3,0,Size(10,10),Size(640,480));
openluruxinxi=true;
///
//opencv图像转换为qt类型的图像
QImage qimage=Mat2QImage(cvimg2);
imwrite("/home/lyx/桌面/image.jpg",cvimg2);
qDebug()<<"拍照成功";
//展示ui中的label中
ui->label_2->setPixmap(QPixmap::fromImage(qimage));
/
if(openluruxinxi==true )
{
qDebug()<<"开始";
//最大限度假如是10个图像文件夹
for(int i=1;i<=10;i++)
{
string path=format("/home/lyx/桌面/studeyphoto2/image_%d",i);
bool cunzai=isFileExists_stat(path);
if(cunzai)
{
qDebug()<<"存在";
}
else
{
qDebug()<<"不存在,创建文件夹";
string folderPath =format("/home/lyx/桌面/studeyphoto2/image_%d",i);
string command;
command = "mkdir -p " + folderPath;
system(command.c_str());
qDebug()<<"asdsadsadsadsadsadsa";
qDebug()<<"文件创建完成,写入图片数据";
Mat dst;//存储人脸的mat数据类型
for(int count=1;count<=10;count++)
{
qDebug()<<"aa";
// if(cvimg2.empty())
// {
// qDebug()<<"Photo ERRRR!!!!";
// }
if(faces2.size()<=0)
{
qDebug()<<"meiyou face";
break;
}
qDebug()<<i<<"::";
cv::resize(cvimg2(faces2[i-1]),dst,Size(100,100));
qDebug()<<"bb";
//得到了dst图片--仅仅存储着人脸
//人脸数据就是 100*100
imwrite(format("/home/lyx/桌面/studeyphoto2/image_%d/myface_%d.jpg",i,count),dst);
}
imagecount=i;
qDebug()<<"信息已经录入完成";
//这个break代表录入一个人的信息后(拍摄10张照片)就停下了,
break;
}
}
qDebug()<<"循环已经跳出";
qDebug()<<"文件夹数量";
qDebug()<<imagecount;
}
}
}
string doubleToStr(double d){
char buffer[30];
sprintf(buffer,"%f",d);
string str=buffer;
return str;
}