当前位置: 首页 > news >正文

基于Ubuntu22.04和OpenCV4.5.4的物联网人脸识别考勤机

前言:本人已有Ubuntu22.04的相关开发环境配置,并且默认C++和机器学习基础,这里直接从安装opencv开始,完整代码在最后。具体情况具体分析,请以实际为主。

视频参考:【大厂敲门砖】从0到1做一个物联网人脸识别考勤机项目!(附源码)_哔哩哔哩_bilibili

博客参考:做一个人脸识别考勤机项目(利用OpenCV)_基于opencv的人脸识别考勤-CSDN博客


目录

1.OpenCV配置

1.1安装OpenCV

1.2OpenCV使用的官方在线帮助文档

2.C++和OpenCV初步编程

2.1连接摄像头

2.2使用OpenCV库

2.3打开摄像头

2.4图像采集和优化处理

2.5人脸检测

2.6人脸截取及图片编码与解码

3.对接百度智能云平台

3.1注册账号

3.2创建人脸库

3.3SDK环境搭建

3.4百度云平台的接入

4.优化数据处理与分析

4.1Json数据解析

4.2记录考勤时间

4.3显示考勤信息

5.最终结果汇总


1.OpenCV配置

OpenCV是一个开源的计算机视觉和机器学习软件库其使用一系列C语言函数和少量C++类实现,内部实现了很多图像处理和计算机视觉的通用算法。

OpenCV可以运行在Linux系统上,且其轻量、高效所以在嵌入式领域得到广泛的应用。

1.1安装OpenCV

在终端输入:(注意联网)(以下使用 apt 也可)

sudo apt-get install libopencv-dev

如果出现错误无法安装(已经联网),进行更新软件包索引:

sudo apt-get update

PS:连不了网图标还不见的进行以下操作,删除NetworkManager缓存文件,重启网络服务(Ubuntu22.04的特别处理)

sudo service NetworkManager stop 
sudo rm /var/lib/NetworkManager/NetworkManager.state 
sudo service NetworkManager start

验证是否安装成功:

dpkg -s libopencv-dev

1.2OpenCV使用的官方在线帮助文档

网址:OpenCV - Open Computer Vision Library

找对应版本的文档:

用什么直接搜吧:

2.C++和OpenCV初步编程

2.1连接摄像头

需要让虚拟机使用本机的摄像头,选择USB3.1的兼容性:

之后可以找到摄像头设备,点击连接,之后点击确定 x2:

也可以直接在右下角连接:

PS:如果还是找不到可用的摄像头,win+R:services.msc,在服务页面找到“VMUSBArbService”服务,又发现无法启动,那么多半是因为之前卸载过VMWare且卸载不干净。解决如下:

控制面板 —> 程序与功能 —> 找到VMWare,右键点击更改 —> 点击修复 —> 重启

2.2使用OpenCV库

使用的总的头文件:

include "opencv2/opencv.hpp"

加上命名空间的声明:

using namespace cv;

因为这个头文件的是在opencv4目录下的,注意编译的时添加链接库路径,告诉编译器在指定的路径中查找头文件:(示例)

g++ main.cpp -o main -I/usr/include/opencv4

2.3打开摄像头

:VideoCapture

头文件:videoio.hpp

作用:从视频文件、图像序列或摄像头捕获视频

VideoCapture cap(0, CAP_V4L2); //创建对象并打开默认摄像头,CAP_V4L2有自动调整参数
//cap.set(CAP_PROP_FRAME_WIDTH, 1000);//宽度 
//cap.set(CAP_PROP_FRAME_HEIGHT, 960);//高度if(!cap.isOpened()){cout << "Camera opened failed." << endl;return -1;
}
cout << "Camera opened successfully." << endl;

PS:VideoCapture cap(0, CAP_V4L2)已经创建并打开了摄像头,因此检测是否打开不能用open()。另外为摄像头选择一个后端,否则会有一个不影响运行的警告。而查看启用了哪些后端可使用命令:

opencv_version -v

2.4图像采集和优化处理

:Mat

:core

作用:表示图像或矩阵,用于存储图像数据

函数:cvtColor()

:imgproc

作用:用于将图像从一种颜色空间转换为另一种颜色空间

函数:imshow()

:highgui

作用:用于在窗口中显示图像;第一个参数是窗口名称,第二个参数是图像矩阵

函数:equalizeHist()

:imgproc

作用: 用于对灰度图像进行直方图均衡化,增强清晰度和对比度

函数:waitKey() 

:highgui

作用:用于控制图像显示窗口的关闭或循环退出

Mat ColorImage; //定义一个Mat类型的容器变量frame,用于存储视频帧
Mat GrayImage; //存储灰度图
for(;;){cap >> ColorImage; //从视频流中读取下一帧并将其存储到colorImage中cvtColor(ColorImage,GrayImage,COLOR_BGR2GRAY); //转换灰度图equalizeHist(GrayImage,GrayImage); //均衡化灰度图 (清晰度)imshow("实时视频", GrayImage); //显示帧if(waitKey(7) >= 0) break; //暂停7ms,等待用户按下按键
}

提供阶段编译测试的命令:此时编译速度已经比较慢

g++ main.cpp -o main -I/usr/include/opencv4 -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_videoio

阶段效果:

2.5人脸检测

:cv::CascadeClassifier(级联分类器)

:objdetect - Object Detection(对象检测)

作用:用于加载预先训练好的级联分类器,并用于在图像中检测特定的对象;级联分类器通过一系列的弱分类器组合而成,能够在图像中快速定位和识别目标对象。

OpenCV已经自带一些训练好的模型,输入以下命令可以查看模型文件:

cd /usr/share/opencv4/haarcascades
ls

选择以下这个人脸识别模型: 

pwd获取当前目录,创建对象实例:

CascadeClassifier Classifier("/usr/share/opencv4/haarcascades/haarcascade_frontalface_alt2.xml");

函数:CascadeClassifier::detectMultiScale()

:objdetect

作用:从输入图像中检测出不同尺寸的对象,并返回一个矩形框框住识别目标

使用detectMultiScale()需要创建vector< Rect >类型的对象:

vector<Rect> AllFace;

在显示循环中加入:

Classifier.detectMultiScale(GrayImage,AllFace); //选中识别对象

函数:rectangle()

:core

作用:在图像上绘制一个矩形框

注意一个rectangle()只能显示一个人脸的框框,并且为了防止没检测到脸时出错,加一个检测:

if(AllFace.size()){rectangle(GrayImage,AllFace[0],Scalar(255,255,255)); //只能显示一张图片,显示了第一个检测到的人脸
}

此时编译命令:

g++ main.cpp -o main -I/usr/include/opencv4 -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_videoio -lopencv_objdetect

结果:

2.6人脸截取及图片编码与解码

函数:imencode(函数编码)

:imgcodecs

作用:从内存中的图像数据解码为 OpenCV 的 Mat 对象;用于处理从网络传输的图像数据或从文件中读取的图像数据

使用Mat容器就可以完成截取图像,但是发送给百度只能云平台的图片还需要格式处理(转为.jpg、.png等):

Mat MatFace;
vector<uchar> JpgFace;...if(AllFace.size()){ //防止没检测到脸时出错rectangle(GrayImage, AllFace[0], Scalar(255,255,255)); //只能显示一张图像MatFace = GrayImage(AllFace[0]); //截取图像imencode(".jpg", MatFace, JpgFace); //格式转换}
...

此时编译验证:

g++ main.cpp -o main -I/usr/include/opencv4 -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_videoio -lopencv_objdetect -lopencv_imgcodecs

3.对接百度智能云平台

3.1注册账号

百度智能云官网:百度智能云-云智一体深入产业

下拉,选择人脸搜索:

点击立即使用,登陆账号(可以使用百度其他产品账号来登陆):

再勾选协议、同意协议之后可以使用:

3.2创建人脸库

找到概览的应用数,点击数字,再点击创建应用:

给应用起名,默认已经选择人脸识别的接口,应用归属选择个人,并填写语言描述:

完成后单击立即创建:

返回应用列表之后就会看到已经创建的应用:

报表里会记录使用这个应用的情况;免费的次数:每秒提交2张识别;以下是使用说明:

可知首先需要将“公司内员工的人脸上传”,点击新建应用的【查看人脸库】,点击新建组,注意选择通用版类型,再上传人脸(尽量找正面清晰的):

完成人脸库创建:

3.3SDK环境搭建

SDK简介:SDK(Software Development Kit,软件开发工具包)是一种用于开发软件的工具集合,一般是软件工程师为特定的软件包、软件框架、硬件平台,操作系统等建立的应用于软件开发和部署的工具集合,通常包括编译器、代码库、API(应用程序编程接口)文档、示例代码等。

搭建原因:百度智能云发回来的识别结果包含各种信息,提前内容的写的代码相关繁琐,而外面可以直接使用百度写好的SDK这个库来简化处理。

在人脸识别的概况中,找到技术文档打开:

在SDK文档中的第一项里选择C++-SDK:

使用最新版本:

点击官方链接,下载C++SDK压缩包,一步步按照指示完成:

官方链接:SDK下载_文字识别SDK_语音识别SDK-百度AI开放平台

好家伙竟然已经变成C了: 点这个C HTTP SDK下载

解压下载的压缩包后,需要搬到Linux里使用(当然也可以直接在Linux的火狐浏览器下载):

依赖库libcurl(HTTP协议相关)、openssl(加密相关)、jsoncpp(提取信息)安装:

sudo apt-get install libcurl4-openssl-dev
dpkg -s libcurl4-openssl-devsudo apt-get install openssl
dpkg -s opensslsudo apt-get install libjsoncpp-dev
dpkg -s libjsoncpp-devsudo apt-get install libssl-dev //为了使用openssl/evp.h
dpkg -s libssl-dev

在写的文件中添加:

#include "face.h"
using namespace aip;

把我们写的和百度SDK的代码放在同一个文件夹里一起编译:

现在要对 base.h 和 http.h 文件中 json 头文件目录位置进行修改(根据我们安装的目录):

#include "jsoncpp/json/json.h" 或 #include <jsoncpp/json/json.h>

进入目录编译测试:

g++ main.cpp -o main -I/usr/include/opencv4 -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_videoio -lopencv_objdetect -lopencv_imgcodecs -std=c++11 -lcurl -lcrypto -ljsoncpp

此时出现一个错误:

将 long long int 类型的变量 log_id 赋值给 Json::Value 类型的 data["log_id"] 时,编译器无法确定如何将 long long int 转换为 Json::Value。以下报错详细列出了 Json::Value 各种重载的版本:

解释原因:Json::Value 的构造函数有多种重载版本,编译器无法确定使用哪一个。long long int 是一个 64 位的整数类型,但它并不是 Json::Value 的直接支持类型。Json::Value 提供了 Int64 和 UInt64 类型,但它们与 long long int 不完全匹配,上面那些都可以转换。

在 face.h 中错误的行数修改:对 log_id 赋值这一行进行修改,明确指定类型转换,以消除歧义。

保存,重新编译即可成功。

3.4百度云平台的接入

现在需要创建一个客户端然后使用百度云平台的服务。以下是百度官方的参考代码

// 设置APPID/AK/SK
std::string app_id = "你的 App ID";
std::string api_key = "你的 Api key";
std::string secret_key = "你的 Secret Key";aip::Face client(app_id, api_key, secret_key);

在上面代码中,常量APP_ID在百度云控制台中创建,常量API_KEY与SECRET_KEY是在创建完毕应用后,系统分配给用户的,均为字符串,用于标识用户,为访问做签名验证,可在AI服务控制台中的应用列表中查看。 在之前的代码基础上添加代码或者直接用最后一行就可以了。

回到应用列表,将以下三个对应的key复制到代码中绑定:

本次项目使用的接口是人脸搜索,按需添加对应代码(以下是百度官方提供的参考):

Json::Value result;std::string image = "取决于image_type参数,传入BASE64字符串或URL字符串或FACE_TOKEN字符串";std::string image_type = "BASE64";std::string group_id_list = "3,2";// 调用人脸搜索
result = client.face_search_v3(image, image_type, group_id_list, aip::json_null);// 如果有可选参数
std::map<std::string, std::string> options;
options["match_threshold"] = "70";
options["quality_control"] = "NORMAL";
options["liveness_control"] = "LOW";
options["user_id"] = "233451";
options["max_user_num"] = "3";// 带参数调用人脸搜索
result = client.face_search_v3(image, image_type, group_id_list, options);

参数规定:

image :图片信息(总数据大小应小于10M)

image_type:图片类型 BASE64(不超过2M),图片的 URL 地址,FACE_TOKEN人脸图片的唯一标识。

group_id_list:从指定的group中进行查找用逗号分隔,上限10个

这里选择转换成 BASE64 格式。在下载的SDK中的base64.h文件中,可以查看到已经给出的转换函数:

写入自己的代码:

string Base64Face; //定义转换完成的base64格式图片
Json::Value result; //获取返回结果的容器
...
//编码成base64
Base64Face = base64_encode((char *)JpgFace.data(), JpgFace.size());
//调用人脸搜索
result = client.face_search_v3(Base64Face, "BASE64", "learning", json_null);
cout << result << endl;

编译测试:如果你出现了以下结果,表示“Open API QPS 请求限制已达到”

去查看发现:原来收到限制了,可恶

解决:去个人实名认证,领取500次调用机会,抠啊。。不过也够了

运行效果:返回Json格式的结果

返回数据说明:

{"face_token": "fid", //人脸标志"user_list": [{"group_id" : "test1", //用户所属组别"user_id": "u333333", //用户的id,名"user_info": "Test User", //说明"score": 99.3 //匹配分数}]
}

4.优化数据处理与分析

4.1Json数据解析

要获取的百度所给的返回数据目标是人脸所对应的人的信息,所以需要从数据中提取特定信息:

①判断是否检测到人脸

opencv所给模型不太精确,会将疑似为人脸的物体也上传。百度会进行第二次检测是否有人脸。如果返回为空则不打印信息

②判断人脸匹配得分

匹配得分很低说明只是有人脸;百度会返回得分最高的人,即使得分很低(没有这个人脸的资料库),所以结果会不准确。所以要控制得分在一定的高分(70-90)以上才返回信息。

③只返回人脸所匹配的人的名字

增加代码:

//判断是否检测到人脸(opencv所给模型不一定准确,百度会进行第二次检测是否有人脸)
if(!result["result"].isNull())
{//判断人脸匹配得分是否大于80if(result["result"]["user_list"][0]["score"].asInt() >= 80){cout<<result["result"]["user_list"][0]["user_id"]<<endl; //输出人名}
}

运行效果:

4.2记录考勤时间

利用Linux本身提供的时间获取函数 

时间容器time_t 

说明:获取 (从1970.1.1 0:0:0到现在的秒数) time(NULL);

时间转换(转换为正常时间)函数ctime()

增加代码:

time_t sec;
...
sec = time(NULL);
cout << ctime(&sec) << endl;

运行效果:

4.3显示考勤信息

记录考勤信息:运行程序时将信息定向到文本文件中

./main >> log.txt

问题:这样执行就只会将信息存在log.txt中,不再从终端窗口显示

解决:改为从摄像头窗口的人脸识别框上直接显示人名和时间

函数:putText (图像上写字)

:core

原型:void putText(Mat& img, const string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness=1, int lineType=8, bool bottomLeftOrigin=false ) 

        img:要写字的图像

        text:要写的字

        org:字在图像上的坐标

        fontFace:图像的字体(具体看官方文档)

        fontScale:字的大小

        color:字的颜色

添加代码:

putText(GrayImage, result["result"]["user_list"][0]["user_id"].asString(), Point(0,50), FONT_HERSHEY_SIMPLEX, 1, Scalar(255,255,255));
putText(GrayImage, ctime(&sec), Point(0,100), FONT_HERSHEY_SIMPLEX, 1, Scalar(255,255,255));

运行后的文件中:

识别效果:

5.最终结果汇总

main.cpp完整代码:

#include <iostream>
#include "opencv2/opencv.hpp"
#include "face.h"using namespace std;
using namespace cv;
using namespace aip;int main(){VideoCapture cap(0, CAP_V4L2); //创建对象并打开默认摄像头cap.set(CAP_PROP_FRAME_WIDTH, 1000); //宽度 //cap.set(CAP_PROP_FRAME_HEIGHT, 960); //高度if(!cap.isOpened()){cout << "Camera opened failed." << endl;return -1;}cout << "Camera opened successfully." << endl;Mat ColorImage; //定义一个Mat类型的容器变量frame,用于存储视频帧Mat GrayImage;  //存储灰度图Mat MatFace;    //保存截取的人脸图像vector<Rect> AllFace;  //获取识别的人脸vector<uchar> JpgFace; //保存改格式后的人脸CascadeClassifier Classifier("/usr/share/opencv4/haarcascades/haarcascade_frontalface_alt2.xml"); //加载人脸识别模型Face client("***", "***", "***"); //客户端和人脸库绑定关系string Base64Face;  //定义转换完成的base64格式图片Json::Value result; //获取返回结果的容器time_t sec; //时间容器for(;;){cap >> ColorImage; //从视频流中读取下一帧并将其存储到colorImage中(采集图像)cvtColor(ColorImage, GrayImage, COLOR_BGR2GRAY); //转换灰度图equalizeHist(GrayImage, GrayImage); //均衡化灰度图 (清晰)Classifier.detectMultiScale(GrayImage, AllFace); //选中识别对象//防止没检测到脸时出错if(AllFace.size()){rectangle(GrayImage, AllFace[0], Scalar(255,255,255)); //只能显示一张图像MatFace = GrayImage(AllFace[0]); //截取图像imencode(".jpg", MatFace, JpgFace); //格式转换Base64Face = base64_encode((char *)JpgFace.data(), JpgFace.size()); //编码成base64result = client.face_search_v3(Base64Face, "BASE64", "learning", json_null); //传输到百度,获取返回结果//cout << result << endl;//判断是否检测到人脸(opencv所给模型不一定准确,百度会进行第二次检测是否有人脸)if(!result["result"].isNull()){//判断人脸匹配得分是否大于80if(result["result"]["user_list"][0]["score"].asInt() >= 80){sec = time(NULL); //获取(从1970.1.1 0:0:0到现在的秒数)cout << ctime(&sec) << endl; //输出时间信息cout << result["result"]["user_list"][0]["user_id"] << endl; //输出人名//显示考勤信息putText(GrayImage, result["result"]["user_list"][0]["user_id"].asString(), Point(0,70), FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 255, 255));putText(GrayImage,ctime(&sec), Point(0,100), FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 255, 255));}}}imshow("实时视频", GrayImage); //显示帧waitKey(40); //暂停40ms}return 0;
}

编译:

g++ main.cpp -o main -I/usr/include/opencv4 -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_videoio -lopencv_objdetect -lopencv_imgcodecs -std=c++11 -lcurl -lcrypto -ljsoncpp

运行:

./main >> log.txt

效果:

相关文章:

  • SpringBoot私人西服系统开发与设计
  • FreeRTOS任务通知
  • linux如何手动设置域名与 IP 地址的映射关系
  • iOS 冷启动时间监控:启动起点有哪些选择?
  • 从零构建 Vue3 登录页:结合 Vant 组件与 Axios 实现完整登录功能
  • 【Datawhale Al春训营】气象预测(AI+航空安全)竞赛笔记
  • ProjectChrono安装
  • Oracle 19c部署之手工建库(四)
  • Axios的使用
  • 选择 iOS 按键精灵无根有根越狱辅助工具的理由
  • 【Spring Boot】MyBatis入门:连接Mysql数据库、测试单元、连接的常见错误
  • PyTorch深度学习框架60天进阶学习计划 - 第45天:神经架构搜索(二)
  • Netlink套接字
  • Starrocks 数据均衡DiskAndTabletLoadReBalancer的实现
  • DBeaver连接hive
  • DasViewer是什么?如何安装?
  • AI 组件库是什么?如何影响UI的开发?
  • 华为OD机试真题——最长的顺子(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
  • PyTorch 浮点数精度全景:从 float16/bfloat16 到 float64 及混合精度实战
  • PyTorch分布式训练调试方法(跟踪调用过程)
  • 全球首台环形CT直线加速器在沪正式开机,系我国自主研发
  • 马上评丨马拉松“方便门”被处罚,是一针清醒剂
  • 大家聊中国式现代化|郑崇选:提升文化软实力,打造文化自信自强的上海样本
  • 可移动可变形的新型超材料问世
  • 经济日报:美离间国际关系注定徒劳无功
  • 拖车10公里收1900元?货车司机质疑收费过高,潮州饶平县市监局已介入