aspcms 生成网站地图,深圳品牌女装前十名,定制网站开发一般多少钱,网站开发需要什么工具逃离舒适区 项目源代码放在我的仓库中#xff0c;有需要自取 项目地址
https://gitcode.com/hujiahangdewa/Face_recognition.git 文章目录 一、项目结构分析二、服务器的搭建三、客户端的搭建四、人脸识别库的申请五、基于人脸识别库的识别判断六、QT人脸识别----调用百度ai… 逃离舒适区 项目源代码放在我的仓库中有需要自取 项目地址
https://gitcode.com/hujiahangdewa/Face_recognition.git 文章目录 一、项目结构分析二、服务器的搭建三、客户端的搭建四、人脸识别库的申请五、基于人脸识别库的识别判断六、QT人脸识别----调用百度ai接口七、如何在Qt中添加图片素材八、项目总结 本项目需要准备到的工具qt6.8.0、VMware17、Ubuntu24.10、百度AI人脸识别库的密钥、摄像头(笔记本电脑自带即可) 一、项目结构分析 本项目选用Linux系统来搭建服务器首先我们要明白一点就是在Linux系统中一切 皆文件我们的客户端使用QT来搭建本项目中的客户端与服务器之间的通信采用TCP/IP协议人脸识别算法采用了百度AI中的人脸识别库(免费)
二、服务器的搭建
首先先检查我们的虚拟机的USB功能有没有启用 windowsR调出这个窗口输入以下命令 找到VMware USB Arbitration Service将其启动 启动虚拟机将摄像头连入虚拟机) 检查摄像头是否连接成功唤起命令行输入cheese即可检查结构分析 总的来说就是服务器端打开摄像头将摄像头拍摄的数据传输到客户端中显示出来。 接下来我们来看看关于摄像头的头文件的结构
#ifndef CAMERA_H
#define CAMERA_H#include stddef.h // for size_t#define BUFFER_COUNT 4struct camera
{void *start;size_t length;
};struct buffer_info
{int index;char *pic_buf;int length;
};extern struct camera buffer[BUFFER_COUNT];
extern struct v4l2_buffer buf;
extern struct buffer_info buf_info;/*** brief 初始化摄像头** param pathname 摄像头设备的路径。* return 成功时返回文件描述符失败时返回 -1。*/
int camera_init(const char *pathname);/*** brief 启动摄像头采集** param fd 摄像头设备的文件描述符。* return 成功时返回 0失败时返回 -1。*/
int camera_start(int fd);/*** brief 获取一帧数据** param fd 摄像头设备的文件描述符。* param pic_buf 指向图像数据的指针。* param length 图像数据的长度。* return 成功时返回 0失败时返回 -1。*/
int camera_get(int fd, char **pic_buf, int *length);/*** brief 将已处理的缓冲区重新放入缓存队列** param fd 摄像头设备的文件描述符。* return 成功时返回 0失败时返回 -1。*/
int camera_input(int fd);/*** brief 停止摄像头流** param fd 摄像头设备的文件描述符。*/
void camera_stop(int fd);#endif // CAMERA_H
服务器的具体实现(代码)
#include stdio.h
#include stdlib.h
#include string.h
#include sys/types.h
#include sys/socket.h
#include netinet/in.h
#include netinet/ip.h
#include arpa/inet.h
#include unistd.h
#include camera.hint main(int argc, char *argv[])
{// 创建socket套接字int sockfd socket(AF_INET, SOCK_STREAM, 0);if (sockfd 0){perror(socket);return -1;}printf(create socket success!\n);// 设置地址信息struct sockaddr_in addr;addr.sin_family AF_INET; // 地址协议族IPv4addr.sin_port htons(65432); // 端口号addr.sin_addr.s_addr inet_addr(0.0.0.0); // IP地址socklen_t addrlen sizeof(addr);// bind绑定地址信息 端口号int bind_info bind(sockfd, (const struct sockaddr *)addr, addrlen);if (bind_info 0){perror(bind);return -1;}printf(bind socket success!\n);// listen监听if (listen(sockfd, 5) 0){perror(listen);return -1;}printf(listen socket success!\n);// 摄像头的初始化int camera_fd camera_init(/dev/video0);if (camera_fd 0){printf(camera init failed\n);return -1;}printf(camera_init success\n);// 服务器搭建完毕保证服务器不停while (1){struct sockaddr_in c_addr;socklen_t c_addrlen sizeof(c_addr);int conn_fd accept(sockfd, (struct sockaddr *)c_addr, c_addrlen);if (conn_fd 0){perror(accept);continue;}printf(client connect success! conn_fd:%d\n, conn_fd);// 开启摄像头-----------摄像头开始获取数据if (camera_start(camera_fd) 0){printf(camera start failed\n);return -1;}// 连接成功保证服务程序持续运行while (1){// 服务程序---发送视频信息// 采集(获取)一帧图像char *pic_buf NULL; // 定义存放图像数据的指针int length 0; // 定义保存图像大小的变量if (camera_get(camera_fd, pic_buf, length) 0){printf(camera get failed\n);continue;}// 1.先发送图像的大小char len[8] {0};sprintf(len, %d, length);write(conn_fd, len, 8);// 2.发送图像的数据write(conn_fd, pic_buf, length);// 清除存放图像的缓冲区if (camera_input(camera_fd) 0){printf(camera_input close failed\n);continue;}}}// 摄像头停止工作camera_stop(camera_fd);// 关闭文件描述符close(camera_fd);// 关闭通信的套接字close(sockfd);return 0;
}以上服务器代码中的第55行中由于设备的不同我们需要进行更换如果以上代码出现摄像头无法显示的问题将/dev/video0修改为dev/video1即可解决。 接下来编译这个服务器文件使用gcc来编译
gcc server.c -o app -L ./ -lcamera
其中lcamera是摄像头的一些驱动库启动服务器 这即是服务器启动成功之后的界面如若启动失败在评论区留下错误原因。
三、客户端的搭建
创建项目
打开我们的QT软件创建一个qt项目具体如何创建可参考这个文章https://blog.csdn.net/hujiahangdewa/article/details/143915238?spm1001.2014.3001.5501 我们需要在项目文件的.pro文件中添加以下模块这里面含有tcp/ip协议的构造函数 QT network2.设计ui界面 点击左侧的widget.ui即可进入到ui界面的设计 从左侧的控件栏中拖出三个按钮(Push Button)根据需要可以进行更名如下 那我们用什么来显示摄像头传输给我们的图像数据呢---------使用label或者TextEdit 这里我们就使用label来显示我们的图像数据 我们还需要两个文本框来输入我们服务器的IP地址和端口号 在控件栏中拖出两个LineEdit即可如下
ui界面的简单布局就是这样美化的事情可以后期再做。 接下来我们要理解一个很重要的一个QT的核心理念就是----信号与槽 当我们点击登录按钮就是一个鼠标的点击事件。
按钮槽函数的设计 (1)登录按钮的槽函数 我们先选中登录按钮右键转到槽在弹出的提示框中选择clicked()
void Widget::on_pushButton_clicked()
{QString IPui-lineEdit-text(); //获取IP地址int PORTui-lineEdit_2-text().toInt(); //获取端口号client-connectToHost(IP,PORT);//连接到服务器前提是服务器是启动状态
}接下来就是当我们登录成功之后在label框中实时显示我们摄像头拍摄的数据 我们来到widget.cpp这个文件中新建一个recv函数
void Widget::recv()
{static int flag0;//第一次读取图像的大小//第二次读取图像的数据if(flag0){//判断数据是否有效if(client-bytesAvailable()8){return;}length client-read(8).toInt();flag1;}else if(flag1){//判断数据是否有效if(client-bytesAvailable()length)//说明图片没有传完{return;}pic client-read(length);QPixmap pix;//定义一个图片类型变量pix.loadFromData(pic);//显示图像ui-label_3-setPixmap(pix);ui-label_3-setScaledContents(true);flag0;}
}
然后我们需要在Widget的构造函数中进行信号和槽的绑定
//实例化客户端对象通信协议clientnew QTcpSocket;
//接收信号与接收槽函数的绑定//信号对象 信号 槽函数对象 对象connect(client, QTcpSocket::readyRead, this, Widget::recv);同时启动服务器和客户端在客户端输入服务器的IP和端口号登陆成功之后我们的label框中会显示摄像头拍摄到的数据。如下 (2)注册人脸信息按钮的槽函数
//人脸信息的注册
void Widget::on_pushButton_3_clicked()
{QPixmap pix;//定义一个图片类型变量pix.loadFromData(pic);//显示图像ui-label_4-setPixmap(pix);ui-label_4-setScaledContents(true);//上传的人脸信息QImage image;image.loadFromData(pic);//获取用户的组QString group_id ui-lineEdit_3-text();//获取用户的IDQString user_id ui-lineEdit_4-text();//进行人脸信息的注册AI-insert_user(image,group_id,user_id);}(3)打卡按钮的槽函数
//打卡的槽函数
void Widget::on_pushButton_2_clicked()
{QPixmap pix;//定义一个图片类型变量pix.loadFromData(pic);//显示图像ui-label_4-setPixmap(pix);ui-label_4-setScaledContents(true);//上传的人脸信息QImage image;image.loadFromData(pic);//获取用户的组QString group_id ui-lineEdit_3-text();//进行人脸检测AI-search_face(image,group_id);}//绑定信号与槽//1.绑定识别成功的信号与槽connect(AI, face::recv_nub, this, Widget::face_success);//人脸识别成功的槽函数
void Widget::face_success(QString user_id,double number)
{QString data 打卡成功,欢迎 user_id 业主回家! 相似度为QString::number(number);ui-textEdit-setText(data);}四、人脸识别库的申请
接下来我们将教大家如何申请 首先进入到百度AI的控制台 https://console.bce.baidu.com/#/index/overview 在这个界面中在人工智能的那一列找到人脸识别点击应用列表点击创建应用根据提示完成创建。然后在返回到应用列表界面 这里的API KEY和Secret Key很重要是我们调用百度ai的密钥
返回到我们的qt软件 来到widget.cpp在widget的构造函数中初始化百度ai以及输入密钥
//实例化一个百度ai对象AI new face(API_KEY,SECRET_KEY); //API_KEY SECRET_KEY五、基于人脸识别库的识别判断
识别失败识别成功 //绑定信号与槽//1.绑定识别成功的信号与槽connect(AI, face::recv_nub, this, Widget::face_success);//2.绑定识别失败的信号与槽connect(AI, face::recv_dis, this, Widget::face_failure); //连接人脸识别失败信号到新的槽函数connect(AI, face::recv_error_msg, this, Widget::showErrorMsg); // 连接接收错误信息信号到显示错误信息的槽函数//人脸识别成功的槽函数
void Widget::face_success(QString user_id,double number)
{QString data 打卡成功,欢迎 user_id 业主回家! 相似度为QString::number(number);ui-textEdit-setText(data);
}void Widget::face_failure()
{QMessageBox::warning(this, 打卡失败, 人脸识别未通过请重新尝试打卡。);
}//显示错误信息的槽函数弹出提示框显示具体错误消息
void Widget::showErrorMsg(QString errorMsg)
{QMessageBox::critical(this, 错误, 发生错误 errorMsg);
}六、QT人脸识别----调用百度ai接口
我们注册的人脸信息将会保存在百度AI的人脸库中每隔一个月会消除一次。 以下代码就是调用这个接口的具体实现
#ifndef FACE_H
#define FACE_H#include QObject
#include QNetworkAccessManager
#include QNetworkRequest
#include QNetworkReply
#include QJsonDocument
#include QJsonObject
#include QJsonArray
#include QImage
#include QBuffer
#include QDebug
#include QPixmapclass face : public QObject
{Q_OBJECT
public:explicit face(QObject *parent nullptr);//构造face类需要传递api_key值和secret_keyface(QString,QString);/********************************************************************************************** 进行人脸库搜索* 参数说明* 1.图像内容为Qimage类型* 2.查询的用户组*********************************************************************************************/void search_face(QImage,QString);/********************************************************************************************** 添加用户信息即实现用户人脸注册当用户存在时添加用户图片用户不存在添加用户和图片* 参数说明* 1.图像内容为Qimage类型* 2.添加的用户组* 3.添加到的用户名id*********************************************************************************************/void insert_user(QImage,QString,QString);/********************************************************************************************** 添加用户组* 参数说明* 添加的用户*********************************************************************************************/void insert_group(QString);/**********************************************************************************************获取access_token值* api_key和secret_key来自于构造该对象时传的参数*********************************************************************************************/void get_access_token();signals:/********************************************************************************************** 该对象的信号触发该信号返回人脸搜索的用户名id和对比度得分* 触发条件人脸对比与用户信息阈值超过80则触发*********************************************************************************************/void recv_nub(QString,double);/********************************************************************************************** 触发条件人脸对比与用户信息阈值低于80则触发*********************************************************************************************/void recv_dis();//用于返回错误码的信号该信号触发返回错误信息void recv_error_msg(QString);public slots://接收由networkaccessmanager发起的网络请求的网络返回数据并解析void recv_json(QNetworkReply*);private:QNetworkAccessManager *my_access_manager;QString api_key;QString secret_key;QString access_token;QString user_id;double score;
};#endif // FACE_H
#include face.hface::face(QObject *parent) : QObject(parent)
{}face::face(QString ak,QString sk)
{api_key ak;secret_key sk;//实例化网络请求管理工具my_access_manager new QNetworkAccessManager;//关联信号与槽connect(my_access_manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(recv_json(QNetworkReply*)));get_access_token();}
//获取access_token值,发起网络请求
void face::get_access_token()
{QNetworkRequest req;req.setUrl(QUrl(QString(https://aip.baidubce.com/oauth/2.0/token?grant_typeclient_credentialsclient_id%0client_secret%1).arg(api_key).arg(secret_key)));req.setHeader(QNetworkRequest::ContentTypeHeader,Content-Type:application/json);QByteArray buf;my_access_manager-post(req,buf);
}
//发起人脸检测的网络请求
void face::search_face(QImage image,QString group_id)
{//将接收到的image类型转化为qpixmap类QPixmap pic QPixmap::fromImage(image);//存储图像数据到字节数组内QByteArray buf;QBuffer b(buf);b.open(QIODevice::ReadWrite);pic.save(b,jpg);b.close();//封装百度api请求需要的json格式类型数据QJsonObject obj;//图像数据格式要求base64格式obj.insert(image,QString(buf.toBase64()));obj.insert(image_type,BASE64);obj.insert(group_id_list,group_id);//实例化网络请求QNetworkRequest req;//表明网络请求发起的请求地址req.setUrl(QUrl(QString(https://aip.baidubce.com/rest/2.0/face/v3/search?access_token%0).arg(access_token)));//设置网络请求头req.setHeader(QNetworkRequest::ContentTypeHeader,Content-Type:application/json);//发起post网络请求my_access_manager-post(req,QJsonDocument(obj).toJson());
}
//发起添加用户的网络请求
void face::insert_user(QImage image,QString group_id,QString user_id)
{QPixmap pic QPixmap::fromImage(image);QByteArray buf;QBuffer b(buf);b.open(QIODevice::ReadWrite);pic.save(b,jpg);b.close();//封装数据内添加需要增加到的用户组用户id以及该用户的图像数据QJsonObject obj;obj.insert(image,QString(buf.toBase64()));obj.insert(image_type,BASE64);obj.insert(group_id,group_id);obj.insert(user_id,user_id);obj.insert(action_type,APPEND);QNetworkRequest req;req.setUrl(QUrl(QString(https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add?access_token%0).arg(access_token)));req.setHeader(QNetworkRequest::ContentTypeHeader,Content-Type:application/json);my_access_manager-post(req,QJsonDocument(obj).toJson());
}
//发起添加用户组的网络请求
void face::insert_group(QString group_id)
{//封装组idQJsonObject obj;obj.insert(group_id,group_id);QNetworkRequest req;req.setUrl(QUrl(QString(https://aip.baidubce.com/rest/2.0/face/v3/faceset/group/add?access_token%0).arg(access_token)));req.setHeader(QNetworkRequest::ContentTypeHeader,Content-Type:application/json);my_access_manager-post(req,QJsonDocument(obj).toJson());
}
//解析接收到的网络请求的返回数据
void face::recv_json(QNetworkReply *rep)
{//读取网络请求后的返回数据QByteArray replay rep-readAll();//将数据转化为json文档QJsonDocument doc QJsonDocument::fromJson(replay);if(doc.isObject()){//将json文档转化为json对象QJsonObject replay_obj doc.object();//判定json数据内所包含的字样并获取字样对应的数据值if(replay_obj.contains(result)){QJsonValue val replay_obj.value(result);if(val.isObject()){QJsonObject replay_obj val.toObject();if(replay_obj.contains(user_list)){QJsonValue val replay_obj.value(user_list);if(val.isArray()){QJsonArray arr val.toArray();QJsonValue val arr.at(0);if(val.isObject()){QJsonObject replay_obj val.toObject();if(replay_obj.contains(user_id))//解析用户id{user_id replay_obj.value(user_id).toString();}if(replay_obj.contains(score))//解析人脸比对的阈值{score replay_obj.value(score).toDouble();if(score 80)//比对得分超过80认为是同一个人可以触发信号返回用户id和对比值{qDebug()score;emit this-recv_nub(user_id,score);}else{emit this-recv_dis();}}}}}}}//解析access_token值if(replay_obj.contains(access_token)){access_token replay_obj.value(access_token).toString();}//解析错误码if(replay_obj.contains(error_msg)){QString error_msg replay_obj.value(error_msg).toString();if(error_msg!SUCCESS){//触发信号返回错误信息emit this-recv_error_msg(error_msg);}}//解析access_token值的错误码else if(replay_obj.contains(error_description)){QString error_description replay_obj.value(error_description).toString();emit this-recv_error_msg(error_description);}}
} 完成以上之后我们的项目基本完成剩下的就是美化工作我们可以根据自己的喜好来进行美化。 七、如何在Qt中添加图片素材 在这个界面中选择Qt然后选择Qt Resource File
取一个名字存放位置建议默认也可根据情况而修改接下来的设置默认就可。 完成以上步骤之后会出现这样一个界面点击添加前缀 建议是设置成以下这样 然后点击添加文件我们就可以自由的添加图片文件了。我们的文件列表中会出现一个.prc的资源文件
八、项目总结