Qt音视频开发41-人脸识别嵌入式
一、前言
大概几年前搞过一套嵌入式linux上的人脸识别程序,当然人脸识别的核心算法并不是自己开发的,关于人脸识别算法这一块,虽然有众多的开源库可以用,甚至还可以用opencv搞算法训练深度学习之类的,个人认为始终达不到准确度的要求,尤其是人脸比对的准确度,这个需要专业的人脸训练模型才行。目前市面上绝大部分的人脸识别库提供的都是X86的或者安卓ios的库,并没有嵌入式linux的库,估计一方面因为嵌入式linux跑的板子性能比较低,还有一个就是依赖特定编译器,版本众多难以提供,市场也小,所以大部分的厂家都没有提供嵌入式linux的开发包,这个就比较鸡肋,所以很多终端厂家最终弃用linux而选用安卓作为载体系统,这样就可以用上高大上的人脸识别库了,比如萤火虫开发板,RK3288 RK3399等。
记得当时还特意搞了一整套的非常详细的通信协议,产品也初步成型,大概的设备有人脸识别终端、双目门禁、人工访客机、自助访客机、人脸比对服务器等,也试运行了一些小区,效果还行,不过在抗逆光和晚上的情况下效果不是很好,当然这是所有人脸识别设备的通病,必须依赖补光或者调整安装位置增加抗逆光摄像机来处理,这样一来对施工就有要求了增加了复杂度,设备成本也上来了,对于小终端厂商来说,这个要选择一个平衡点才行,只有用户愿意付出对应的成本才提供对应的版本。
通信方式及端口:
- 客户端和服务端等设备统一提供web访问修改配置,端口6660。
- 人工访客机客户端与人工访客机服务端通信采用TCP短连接,通信端口6661。
- 自助访客机客户端与自助访客机服务端通信采用TCP长连接,通信端口6661。
- 人脸识别比对数据库服务器采用TCP长连接,通信端口6662。
- 服务端与数据库服务器通信采用TCP长连接,通信端口6666。
- 数据库服务器下发人脸通行证数据采用TCP短连接,通信端口6667。
- 电脑PC端下发配置到双目门禁采用TCP短连接,通信端口6668。
- 双目门禁与数据库服务器通信采用TCP长连接,通信端口6669。
- 双目门禁电脑客户端升级通信采用TCP短连接,通信端口6670。
- 检测测试与手机app或者其他客户端通信采用TCP长连接,通信端口6671。
二、功能特点
- 支持的功能包括人脸识别、人脸比对、人脸搜索、活体检测等。
- 在线版还支持身份证、驾驶证、行驶证、银行卡等识别。
- 在线版的协议支持百度、旷视,离线版的支持百度,可定制。
- 除了支持X86架构,还支持嵌入式linux比如contex-A9、树莓派等。
- 每个功能的执行除了返回结果还返回执行用时时间。
- 多线程处理,通过type控制当前处理类型。
- 支持单张图片检索相似度最高的图片。
- 支持指定目录图片用来生成人脸特征值文件。
- 可设置等待处理图片队列中的数量。
- 每次执行都有成功或者失败的信号返回。
- 人脸搜索的返回结果包含了原图+最大相似度图+相似度等。
- 人脸比对同时支持两张图片和两个特征值比对。
- 相关功能自定义一套协议用于客户端和服务端,可以通过TCP通信进行交互。
- 自定义人脸识别协议非常适用于中心一台服务器,现场若干设备请求的场景。
- 每个模块全部是独立的一个类,代码整洁、注释完善。
三、效果图

四、相关站点
- 国内站点:https://gitee.com/feiyangqingyun/QWidgetDemo
- 国际站点:https://github.com/feiyangqingyun/QWidgetDemo
- 个人主页:https://blog.csdn.net/feiyangqingyun
- 知乎主页:https://www.zhihu.com/people/feiyangqingyun/
- 体验地址:https://blog.csdn.net/feiyangqingyun/article/details/97565652
五、核心代码
void FaceLocalArm::imgToBgr(const QImage &img, quint8 *bgr, int w, int h)
{
for (int i = 0; i < h; ++i) {
const quint8 *scanline = img.scanLine(i);
for (int j = 0; j < w; ++j) {
*bgr++ = scanline[j * 3 + 0];
*bgr++ = scanline[j * 3 + 1];
*bgr++ = scanline[j * 3 + 2];
}
}
}
void FaceLocalArm::bgrToYuv(quint8 *yuv, const quint8 *bgr, int w, int h)
{
int b, g, r;
for (int i = 0; i < w * h; ++i) {
b = bgr[3 * i + 0];
g = bgr[3 * i + 1];
r = bgr[3 * i + 2];
yuv[i] = (quint8)((r * 30 + g * 59 + b * 11 + 50) / 100);
}
}
void FaceLocalArm::init()
{
//如果已经正常则无需初始化
if (isOk) {
return;
}
#ifdef __arm__
int res = CRface::FaceDetect_Init_ColorReco(sdkPath.toStdString());
if (res != 1) {
qDebug() << TIMEMS << QString("FaceDetect_Init_ColorReco error: %1").arg(res);
} else {
qDebug() << TIMEMS << "FaceDetect_Init_ColorReco ok";
res = CRface::FaceReco_Init_ColorReco(sdkPath.toStdString());
if (res != 1) {
qDebug() << TIMEMS << QString("FaceReco_Init_ColorReco error: %1").arg(res);
} else {
isOk = true;
qDebug() << TIMEMS << "FaceReco_Init_ColorReco ok";
}
}
emit sdkInitFinsh(isOk);
#endif
}
bool FaceLocalArm::getFaceRect(const QString &flag, const QImage &img, QRect &rect, int &msec)
{
if (!isOk) {
return false;
}
#ifdef __arm__
//qDebug() << TIMEMS << flag << "getFaceRect";
QTime time;
if (countTime) {
time.start();
}
int w = img.width();
int h = img.height();
//这里有隐患,如果图片像素特别大会崩溃,应该改为quint8 *bgr=(quint8 *)calloc(w * h * 3, 1);然后后面free(bgr);
quint8 yuv[w * h];
quint8 bgr[w * h * 3];
imgToBgr(img, bgr, w, h);
int facebox[32 * 5];
bgrToYuv(yuv, bgr, w, h);
facebox[0] = 0;
int result = 0;
if (findFast) {
result = CRface::FaceDetect_Fast_ColorReco(yuv, w, h, facebox, true);
} else {
result = CRface::FaceDetect_Normal_ColorReco(yuv, w, h, facebox, true, w / percent);
}
if (result == 1) {
rect = QRect(facebox[1], facebox[2], facebox[3], facebox[4]);
msec = getTime(time);
return true;
}
#endif
return false;
}
bool FaceLocalArm::getFaceFeature(const QString &flag, const QImage &img, QList<float> &feature, int &msec)
{
if (!isOk) {
return false;
}
#ifdef __arm__
//qDebug() << TIMEMS << flag << "getFaceFeature" << img.width() << img.height() << img.size();
QTime time;
if (countTime) {
time.start();
}
int w = img.width();
int h = img.height();
//这里有隐患,如果图片像素特别大会崩溃,应该改为quint8 *bgr=(quint8 *)calloc(w * h * 3, 1);然后后面free(bgr);
quint8 yuv[w * h];
quint8 bgr[w * h * 3];
imgToBgr(img, bgr, w, h);
int facebox[32 * 5];
bgrToYuv(yuv, bgr, w, h);
facebox[0] = 0;
int result = 0;
if (findFast) {
result = CRface::FaceDetect_Fast_ColorReco(yuv, w, h, facebox, true);
} else {
result = CRface::FaceDetect_Normal_ColorReco(yuv, w, h, facebox, true, w / percent);
}
if (result == 1) {
QRect rect = QRect(facebox[1], facebox[2], facebox[3], facebox[4]);
msec = getTime(time);
emit receiveFaceRect(flag, rect, msec);
float fea[256];
int result = CRface::FaceReco_Extract_ColorReco(bgr, w, h, facebox + 1, fea);
if (result == 256) {
feature.clear();
for (int i = 0; i < 256; i++) {
feature.append(fea[i]);
}
msec = getTime(time);
return true;
}
} else {
emit receiveFaceRectFail(flag);
}
#endif
return false;
}
float FaceLocalArm::getFaceCompare(const QString &flag, const QList<float> &feature1, const QList<float> &feature2)
{
if (!isOk) {
return 0;
}
#ifdef __arm__
//qDebug() << TIMEMS << flag << "getFaceCompareXXX";
float fea1[256], fea2[256];
for (int i = 0; i < 256; i++) {
fea1[i] = feature1.at(i);
fea2[i] = feature2.at(i);
}
float result = CRface::FaceReco_Match_ColorReco(fea1, fea2);
result = result * 100;
//过滤非法的值
result = result > 100 ? 0 : result;
return result;
#endif
return 0;
}
Qt音视频开发41-人脸识别嵌入式的更多相关文章
- Android IOS WebRTC 音视频开发总结(八十五)-- 使用WebRTC广播网络摄像头视频(下)
本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...
- WebRTC 音视频开发
WebRTC 音视频开发 webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译 ...
- 转:Android IOS WebRTC 音视频开发总结 (系列文章集合)
随笔分类 - webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译和整理的,译 ...
- Python音视频开发:消除抖音短视频Logo的图形化工具实现
☞ ░ 前往老猿Python博文目录 ░ 一.引言 在<Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解>节介绍了怎么通过Python+Moviepy+OpenCV实现 ...
- Python音视频开发:消除抖音短视频Logo和去电视台标
☞ ░ 前往老猿Python博文目录 ░ 一.引言 对于带Logo(如抖音Logo.电视台标)的视频,有三种方案进行Logo消除: 直接将对应区域用对应图像替换: 直接将对应区域模糊化: 通过变换将要 ...
- Moviepy音视频开发:视频转gif动画或jpg图片exe图形化工具开发案例
☞ ░ 前往老猿Python博文目录 ░ 一.引言 老猿之所以学习和研究Moviepy的使用,是因为需要一个将视频转成动画的工具,当时在网上到处搜索查找免费使用工具,结果找了很多自称免费的工具,但转完 ...
- 【秒懂音视频开发】02_Windows开发环境搭建
音视频开发库的选择 每个主流平台基本都有自己的音视频开发库(API),用以处理音视频数据,比如: iOS:AVFoundation.AudioUnit等 Android:MediaPlayer.Med ...
- Android音视频开发(1):H264 基本原理
前言 H264 视频压缩算法现在无疑是所有视频压缩技术中使用最广泛,最流行的.随着 x264/openh264 以及 ffmpeg 等开源库的推出,大多数使用者无需再对H264的细节做过多的研究,这大 ...
- Android IOS WebRTC 音视频开发总结(八十三)-- 使用WebRTC广播网络摄像头视频(上)
本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...
- Android IOS WebRTC 音视频开发总结(四六)-- 从另一个角度看国内首届WebRTC大会
文章主要从开发者角度谈国内首届WebRTC大会,支持原创,文章来自博客园RTC.Blacker,支持原创,转载必须说明出处,更多详见www.rtc.help. -------------------- ...
随机推荐
- day16-break,continue,goto
break,continue,goto break在任何循环语句的主体部分,均可用break控制循环的流程.break用于强行退出循环,不执行循环中剩余的语句.(break语句也在switch选择语句 ...
- Windows 如何启用 Administrator 账户
Windows 默认安装的时候需要自己定义一个账户,不是管理员账户,不能操作某些目录,有时很不方便.不过我们可以手动打开,像盗版一样默认使用 Administrator 账户: 按下Win + R, ...
- 多元/多维高斯/正态分布概率密度函数推导 (Derivation of the Multivariate/Multidimensional Normal/Gaussian Density)
各种维度正态分布公式: 一维正态分布 二维正态分布/多维正态分布 各向同性正态分布 注:即方差都是一样的,均值不一样,方差的值可以单独用标量表示. 多元/多维高斯/正态分布概率密度函数推导 (Deri ...
- Linux基础常识
1 什么是shell shell是Linux系统的用户界面,提供了用户与内核交互的一种接口,它接收用户输入的命令并到送到内核去执行,因此也被称为Linux的命令解释器. 显示系统当前使用的shell ...
- 设计卷积神经网络CNN为什么不是编程?
上一篇:<搞清楚这个老六的真面目!逐层'剥开'人工智能中的卷积神经网络(CNN)> 序言:现在让我们开始走进卷积神经网络(CNN)的世界里.和传统编程完全不同,在人工智能的程序代码里,您看 ...
- 一文彻底熟练掌握并使用Java的NIO操作
一.基本概念 Java NIO 是 Java 1.4 引入的,用于处理高速.高并发的 I/O 操作.与传统的阻塞 I/O 不同,NIO 支持非阻塞 I/O 和选择器,可以更高效地管理多个通道. 二.核 ...
- 如何看待:以色列在真主党订购的5000台寻呼机中放了TNT
日常生活等关键物品的生产必须要有国内完全掌握,美国.日本.以色列等国惯用的这种暗杀方法.如果不能在本国国内做到自主可控的产品生产,那么无疑是把自己的脑袋交给敌人来保护,随时都有丢命的可能. 同时,这也 ...
- 记录一个opencv的imread方法无法读取成功的问题,【设计到visual studio和静态库(lib)匹配的问题】
一.为什么会遇到这个问题 公司需要对多图进行拼接,经过多番查找发现了OpenStitching这个库.可以实现多图拼接.在python段尝试了之后感觉效果不错,所以使用Visual Studio进行C ...
- DDCA —— 缓存(Cache):缓存体系结构、缓存操作
1. 存储器层次(The Memory Hierarchy) 1.1 现代系统中的存储器 其中包括L1.L2.L3和DRAM 1.2 存储器的局限 理想存储器的需求如下: 零延迟 容量无限 零成本 带 ...
- isObject:判断数据是不是引用类型的数据 (例如: arrays, functions, objects, regexes, new Number(0),以及 new String(''))
function isObject(value) { let type = typeof value; return value != null && (type == 'object ...