1.编译时问题汇总
windows下编译opencv-4.5.4
问题1:配套使用opencv-4.5.4,opencv_contrib-4.5.4,cmake3.22.3问题会少一点
问题2:在windows下哪里执行该命令
解决:
问题3:在对应cmake中搜索不到要修改的配置
解决:自己添加
windows下编译Seetaface2
ubuntu下编译opencv-4.5.4
问题1:
出现在编译库的时候使用make -j4 make出错时
解决:
扩大虚拟机内存
调整后重启虚拟机
问题2:
1.没连接摄像头 2.在cmake 之前必须安装依赖库
解决:
看这篇
连接摄像头
问题3:
找不到这两个cmake文件路径
ubuntu下编译安装opencv_contrib-4.5.4
未出现问题
ubuntu下编译安装Seetaface2
也会出现两个cmake文件找不到,添加cmake路径即可
2.Windows下测试opencv和Seetaface
头文件路径/库文件路径
测试代码
验证成功
3.ubuntu下测试opencv和seetaface
将windows下刚才的qt文件复制到共享目录下面去
共享目录在ubuntu中会放到ubuntu的/mnt/hgfs下
ubuntu下库文件/头文件路径指明
测试代码
问题1:
terminate called after throwing an instance of 'cy::xception'
what(): 0penc!(4.5.4) /home/xyd/face/opencv-4.5.4/modules/core/src/array.cp:2494: error: (-206:Bad flag (paraneter or structure field)) unrecognized or umsuported array
type in function 'cvGetMat'
解决:
将资源路径改为绝对路径(测试代码中已经修改)
问题2:
ubuntu安装完qt后找不到图标
问题3:
在ubuntu下测试opencv和seetaface时如果出现cannot find -lgl问题
问题4:
在ubuntu下qt测试opencv和seetaface的时候不知道指定opencv的哪个库
解决:
验证成功
4.摄像头数据在Qt界面上实时显示
头文件/库路径包含
face.h
face.cpp
摄像头数据在Qt界面实时显示
5.opencv检测人脸,并跟随
使用到opencv中的级联分类器,通过导入训练好的级联分类器文件,将从摄像头读取的一帧视频数据使用detectMultiScale函数来检测人脸,如果检测到人脸的话,就会用一个矩形来表示人脸的位置,并把该矩形位置信息放到vector中,如果该容器中有数据,就说明检测到了人脸
如果第一个参数为灰度图像的话会加快检测速度,第二个参数是检测到人脸的位置信息就会放到该容器中,后面的参数都可以缺省不用管。
我们可以先将srcimage转化为灰度图像就可以加快检测速度
6.考勤中断网络编程实现断线重连
使用到网络编程,添加network
使用QTimer定时器实现断线重连,使用tcp连接服务器
需要添加头文件
定义两个变量
使用ipconfig指令查看ip地址(192.168.0.109)
使用该软件来做测试
作为tcp服务器对7777端口做监听,等待客户端连接
测试:
客户端断线重连服务器
7.人脸识别服务器网络基础实现
在Qt下建立tcp服务器,新建一个工程,因为要用到网络编程,所以用到网络模块,添加netwok
需要要建立tcp服务器以及网络编程,用到的头文件有
QTcpServer, QTcpSocket
创建两个变量来使用到网络编程
首先服务器进行监听任意ip地址上的7777端口,如果有客户端连接服务器的话,server变量会发送一个newconnection的信号,然后通过server.nextPendingConnection();将服务端发过来的信息通过tsocket套接字来访问,当客户端有信息发过来,tsocket会发出readyread信号,如果接收到该信号的话,我们就来处理数据,通过tsocket
服务器测试
8.考勤终端人脸数据的压缩与发送
当考勤机客户端检测到人脸的时候
也就是faceRects.size()>0的时候,在这个if语句里面,将视频一帧数据做编码,
使用到cv::imencode函数
c
std::vector<uchar>buf;// 存放转化后的jpg格式的视频一帧数据
cv::imencode(".jpg",srcimage,buf);//编码转化----->将srcimage图像编码转化为jpg结构,存放在buf中
srcimage变量中保存的是视频一帧数据的Mat格式,第一个参数为要编码为的格式,第二个参数为要被编码的图片变量,第三个参数为转化为jpg格式后输出到buf中
然后将buf的vector< uchar >转化为QByteArray ,并获取编码后数据大小
c
QByteArray byte((const char*)buf.data(),buf.size());//将字符串转化为QByteArray放在Byte中
quint64 backsize=byte.size();//获取编码 后数据的大小
然后通过QDataStream,相当于一个缓冲区,可以理解为一个序列化过程,该缓冲区前面是编码后数据的大小,后面是编码后的数据
c
QByteArray senddata;
QDataStream stream(&senddata,QIODevice::WriteOnly);//以写 字节流方式打开 senddata
stream.setVersion(QDataStream::Qt_5_14);//设置版本,不同版本有不同的序列方式
stream<<backsize<<byte;//构建写入格式相当于sprintf
然后发送出去
c
msocket.write(senddata);//向服务器发送视频数据

9.服务器端接收人脸数据并且显示
上一步我们将数据从客户端发送到服务端,发送到服务端这边(数据大小+数据)
c
QDataStream stream(tsocket);//套接字绑定数据流
stream.setVersion(QDataStream::Qt_5_14);
将tsocket和stream绑定说明tsocket接收到的数据会放在stream的缓冲区
c
if(bsize==0)
{
if(tsocket->bytesAvailable()<(qint64)sizeof(bsize)) return ; //如果数据有丢包,就不接收该图片数据
stream>>bsize;//相当于反序列化取出数据大小放在bsize中
}
c
if(tsocket->bytesAvailable()<bsize)//如果接收数据大小<实际数据大小
{
return ;//不接收
}
c
QByteArray data;//接收来自客户端的一帧视频放在data中
stream>>data;
bsize=0;
if(data.size()==0)//发送来的没数据
{
return ;
}
接着通过Qpixmap来显示出来
c
QPixmap mp;
mp.loadFromData(data,"jpg");//data的格式为jpg
mp=mp.scaled(ui->buffer->size());//调整大小和标签大小一样
ui->buffer->setPixmap(mp);//显示

10.人脸识别模块封装(注册和查询)
上一个步骤将人脸发到了服务端这边并且进行了显示,该步骤是要封装一个引擎库方便注册和查询
创建一个c++类,继承QObeject
包含头文件FaceEngine.h,该头文件如果找不到的话去
将其复制一份
在构造函数中初始化引擎库模型
在析构函数中将new的空间释放掉,防止内存泄漏
人脸注册
人脸查找
人脸库中只保存了人脸信息与人脸id的对应关系,当注册时,simage中保存的人脸信息在人脸库中如果没有,就进行注册,id和人脸信息对应,而这个人脸信息只包含图像信息,而个人的姓名,性别信息,需要我们自己创建一个数据库来保存这些
三个模型下载链接
链接
在该链接中的readme.md文件里面
11.Qt数据库和表格创建
上一主题创建的人脸库中只有人脸库和人脸id,我们还要创建两个数据库来更完善员工信息,第一个是员工信息表,第二个为考勤表,员工信息表中包含下面内容
考勤表包括下面内容
在.pro中记得加sql
在调用界面的时候就开始创建这两个数据库
我们可以使用sqlite expert软件看一下建表情况
点击file
打开该路径下的server.db
创建成功
12.员工信息注册界面设计
13.员工信息录入到数据库
重置按钮的实现:
将所以的输入框内容全部都清除对按钮转到槽,
实现对所有的输入框全部清除
添加头像按钮实现:
使用QFiledialog中的getOpenFileName获取头像路径放在QString中,然后通过setText函数将头像路径显示出来,然后通过QPixmap进行显示在标签上
注册按钮的实现
在注册按钮中需要实现以下步骤
1.通过照片,结合qobjectface模块得到faceid,并且把所以注册进人脸库中的人脸图片都保存在当前目录下的data命令下
对应的代码为
2.将个人信息存储到 数据库中employee表
QSqlTableModel用来充当一个表模型,该表使用数据库中的哪个表,QSqlRecord作为要插入表数据的记录,然后将记录插入到数据库表中,如果成功就进行提交插入记录,即可在数据库表中查看到记录
对应代码如下
问题1图片路径中不能有中文,如果有中文的话就读不到图片使用imread,imwrite函数,导致识别不到人脸,注册就会返回-1
问题2在构造函数需要加载人脸库,要不然每次注册人脸库,人脸库就是空的
返回0,并且注册失败
问题3如果注册的时候只返回1的话,可能是封装好的注册函数没有return
效果演示:
员工信息插入数据库
14.员工信息注册模块头像采集
该部分包括打开摄像头按键实现以及拍照按键的实现
打开摄像头按键实现思路,当按下一次摄像头时,该按键上的字修改为关闭摄像头,使用opencv中的cv::VideoCapture来打开摄像头,并且启动定时器,定时器里完成(),当按下该按钮(此时按钮上的字为关闭摄像头),按钮上的字变成打开摄像头,关闭摄像头,关闭定时器,显示图片的地方清除掉
定时器的中断函数中需要完成获取摄像头一帧图像,然后把opencv里面的Mat格式数据(BGR)转化为qt中的Qimage(RGB),通过QPixmap显示在标签上
拍照按键的实现:
实现思路,将cv::Mat image变量定义为类内私有变量,当点击拍照的时候,定义图片要保存的路径,将image保存到该路径下,关闭摄像头,关闭定时器,将保存路径显示在图片路径dir下
演示:
员工信息注册模块头像采集
15.接收客户端人脸数据并且识别出人脸id

在之前我们已经将从客户端接收到的编码过的图片信息放在data中,此时我们需要对data进行解码,然后调用封装好的face_query函数即可。
根据这个构建我们要填的参数
flag的话和imread的flag是一样的
这里使用查找函数速度会非常的慢,会占用服务端的主线程,导致很卡,后面优化将该查找函数用多线程来完成。
16.识别人脸ID查询数据个人信息
上一个步骤已经查找出人脸ID,这一步我们根据人脸ID在数据库中查找该人脸ID对应的基本信息,并且返回到客户端,
使用#include <QSqlTableModel> #include <QSqlRecord>
这两个头文件
需要发送给客户端这几个信息
发送信息给客户端
客户端接收该信息:
信息打印出来
识别并接收到数据

17.考勤机人脸采集发送次数优化
在之前说过在服务端将客户端传过来的人脸进行在人脸库中查找时会很费时间,并且出现阻塞,因为考勤机人脸每次捕捉到人脸的话,就会发送到服务端,就直接查找,如果我们能减少发送次数的话就会减少查找次数,来进一步优化
通过定义一个变量来表示识别到人脸的次数
客户端:
对flag赋值
18.服务器优化用线程实现人脸识别
因为查找函数很费时间,如果在主线程中完成的话,就会造成卡顿,所以创建一个线程来进行查找
1.创建一个线程,并把能使用人脸查找的对象传到创建的线程中去
2.创建一个信号
如果this发出调用查找函数的信号的话,收到信号的就可以去执行查找函数
使用connect进行关联
调用该函数
该函数如何将faceid返回回去呢?
也可以通过信号
当识别成功了并且人脸辨识度大于你设置的值
19.考勤机终端json数据接收与json解析和显示
之前已经debug出该人脸的需要显示的信息,现在我们只需要通过json进行解析即可
需要的头文件
先隐藏认证成功

还要显示图片
我们可以在发送图片到服务端的时候,将图片保存在当前目录下,也就是在下面这个地方
演示:
json解析
20.考勤信息和员工信息查询模块设计与实现
服务端新添加一个qt设计师类
使用数据库使用下面头文件
21.考勤数据实时录入到数据库
当服务端调用线程去查找人脸时,如果返回faceid大于0,我们就返回其相关信息,同时往考勤表中插入数据步骤如下
注意:这里识别一个人的人脸只需要进行一次打卡
修改flag=-2
考勤数据库演示:
22.服务端用QTabWidget整合

注释掉注册界面和查询界面
界面这样设置
将注册和考勤提升,类名为对应qt设计界面的类名即可
整体联调:
整体联调
后面可以在板子上跑,等我买板子!!!!!!!