C++ DNN Opencv3.4 实现人脸计数和人脸检测

前言

OpenCV 3.3正式发布后,对深度学习(dnn模块)提供了更好的支持,dnn模块目前支持Caffe、TensorFlow、Torch、PyTorch等深度学习框架。

另外,新版本中使用预训练深度学习模型的API同时兼容C++和Python,让系列操作变得非常简便

  • 从硬盘加载模型;
  • 对输入图像进行预处理;
  • 将图像输入网络,获取输出的分类。

当然,我们不能、也不该用OpenCV训练深度学习模型,但这个新版本让我们能把用深度学习框架训练好了的模型拿来,高效地用在OpenCV之中。

在很久很久以前,用Opencv2.4x跟Opencv3.0进行人脸检测的时候,都是基于HAAR级联,但是我测试过HAAR级联,明显不太准,而且速度慢。但是现在2020年啦,深度学习的快速发展,使人脸检测 越来越精准,在Opencv4发布以来,官方支持的人脸检测方法已经转换为支持深度学习的快准狠的方法了,就连HAAR级联训练的工具都在Opencv4中除名了,其实已经有了支持深度学习的人脸检测算法,并且准确率和速度都比HAAR好,那再学HAAR级联无疑是浪费时间和精力了,要学会跟着时代的步伐嘛,所以与时俱进很重要的。

注意:本文不涉及任何原理,只讲具体的应用。

一、下载模型文件

在OpenCV的\sources\samples\dnn\face_detector目录下,有一个download_weights.py脚本文件,首先运行一下,下载模型文件。下载的模型文件分别为:
Caffe模型:

res10_300x300_ssd_iter_140000_fp16.caffemodel
deploy.prototxt

tensorflow模型:

opencv_face_detector_uint8.pb
opencv_face_detector.pbtxt

pb文件的能够保存tensorflow计算图中的操作节点以及对应的各张量,方便我们日后直接调用之前已经训练好的计算图。

其中tensorflow的模型OpenCV官方对它进行了量化处理,大小只有2MB左右,非常适合在各种场景下使用。

如果没有安装python,我将这几个模型文件上传到了网盘,直接下载下来就可以了。

链接:https://pan.baidu.com/s/19XUTKXBriInd9goHWBwLSg 
提取码:fye8

二、演示代码

1.读入模型文件

String modelDesc = "D:/VC projects/dnn_face_detection-model/opencv_face_detector.pbtxt";
String modelBinary = "D:/VC projects/dnn_face_detection-model/opencv_face_detector_uint8.pb";
  • 1
  • 2

2.初始化网络,读入权重和网络结构,调用cv::dnn对应的后端设置函数

dnn::Net net = readNetFromTensorflow(modelBinary, modelDesc);
net.setPreferableBackend(DNN_BACKEND_OPENCV);
net.setPreferableTarget(DNN_TARGET_CPU);
  • 1
  • 2
  • 3

这样子程序再运行dnn计算时,用CPU运行。
当然也可以用GPU加速:

// when using opencv 4 and data > 20191022, the cuda is support
net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);
net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
  • 1
  • 2
  • 3

3.对输入数据进行调整。

Mat inputBlob = blobFromImage(frame, inScaleFactor, Size(inWidth, inHeight), meanVal, false, false);
  • 1

4.输入、输出

net.setInput(inputBlob, "data");
//detection返回值标签、置信度、目标位置的4个坐标信息[xmin ymin xmax ymax]
Mat detection = net.forward("detection_out");
  • 1
  • 2
  • 3

完整代码:

#include <opencv2/dnn.hpp>
#include <opencv2/opencv.hpp>using namespace cv;
using namespace cv::dnn;#include <iostream>
#include <cstdio>
using namespace std;const size_t inWidth = 300;
const size_t inHeight = 300;
const double inScaleFactor = 1.0;
//为了减去平均值(mean):为了消除同一场景下不同光照的图片,对我们最终的分类或者神经网络的影响,我们常常对图片的R、G、B通道的像素求一个平均值,然后将每个像素值减去我们的平均值,这样就可以得到像素之间的相对值,就可以排除光照的影响。
const Scalar meanVal(104.0, 177.0, 123.0);
const float confidenceThreshold = 0.7;
void face_detect_dnn();
void mtcnn_demo();
int main(int argc, char** argv) {face_detect_dnn();waitKey(0);return 0;
}
void face_detect_dnn() {//读入模型路径//String modelDesc = "D:/VC projects/dnn_face_detection-model/deploy.prototxt";//String modelBinary = "D:/VC projects/dnn_face_detection-model/res10_300x300_ssd_iter_140000_fp16.caffemodel";String modelDesc = "D:/VC projects/dnn_face_detection-model/opencv_face_detector.pbtxt";String modelBinary = "D:/VC projects/dnn_face_detection-model/opencv_face_detector_uint8.pb";//初始化网络//dnn::Net net = readNetFromCaffe(modelDesc, modelBinary);dnn::Net net = readNetFromTensorflow(modelBinary, modelDesc);net.setPreferableBackend(DNN_BACKEND_OPENCV);net.setPreferableTarget(DNN_TARGET_CPU);if (net.empty()) {printf("could not load net...\n");return;}//打开摄像头//VideoCapture capture("D:/images/video/Boogie_Up.mp4");VideoCapture capture(0);if (!capture.isOpened()) {printf("Could not load camera...\n");return;}Mat frame;int count = 0;while (capture.read(frame)) {//用于返回从操作系统启动到当前所经的计时周期数int64 start = getTickCount();if (frame.empty()) break;//水平镜像调整//flip(frame, frame, 1);imshow("input", frame);if (frame.channels() == 4) cvtColor(frame, frame, COLOR_BGRA2BGR);//输入数据调整/*深度学习或图片分类的预处理blobFromImage1.整体像素值减去平均值(mean)2.通过缩放系数(scalefactor)对图片像素值进行缩放*/Mat inputBlob = blobFromImage(frame, inScaleFactor, Size(inWidth, inHeight), meanVal, false, false);net.setInput(inputBlob, "data");//人脸检测Mat detection = net.forward("detection_out");//detection返回值标签、置信度、目标位置的4个坐标信息[xmin ymin xmax ymax]vector<double> layersTimings;//用于返回CPU的频率,也就是一秒内重复的次数//1000 *总次数/一秒内重复的次数= 时间(ms)double freq = getTickFrequency() / 1000;double time = net.getPerfProfile(layersTimings) / freq;Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());ostringstream ss;for (int i = 0; i < detectionMat.rows; ++i) {//置信度0-1之间float  confidence = detectionMat.at<float>(i, 2);if (confidence > confidenceThreshold) {count++;//坐标int xLeftBottom = static_cast<int>(detectionMat.at<float>(i, 3)*frame.cols);int yLeftBottom = static_cast<int>(detectionMat.at<float>(i, 4) * frame.rows);int xRightTop = static_cast<int>(detectionMat.at<float>(i, 5) * frame.cols);int yRightTop = static_cast<int>(detectionMat.at<float>(i, 6) * frame.rows);//画框Rect object((int)xLeftBottom, (int)yLeftBottom,(int)(xRightTop - xLeftBottom),(int)(yRightTop - yLeftBottom));rectangle(frame, object, Scalar(0, 255, 0));ss << confidence;//添加标签String conf(ss.str());String label = "Face: " + conf;int baseLine = 0;Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);rectangle(frame, Rect(Point(xLeftBottom, yLeftBottom - labelSize.height),Size(labelSize.width, labelSize.height + baseLine)),Scalar(255, 255, 255), FILLED);putText(frame, label, Point(xLeftBottom, yLeftBottom),FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0));}}float fps = getTickFrequency() / (getTickCount() - start);ss.str("");ss << "FPS:" << fps << ";inference time: " << time << " ms";putText(frame, ss.str(), Point(20, 20), 0, 0.75, Scalar(0, 0, 255), 2, 8);imshow("dnn_face_detect", frame);if (waitKey(1) >= 0) break;}printf("total face: %d\n", count);
}

任何程序错误,以及技术疑问或需要解答的,请添加

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/546846.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

几种php 删除数组元素方法

看一完整删除重复数组实例 代码如下复制代码 //删除数组中的一个元素 function array_remove_value(&$arr, $var){ foreach ($arr as $key > $value) { if (is_array($value)) { array_remove_value($arr[$key], $var); } else { $value trim($value); if ($value $va…

Modbus通信协议之CRC16冗余循环校验函数

Modbus 通信协议详解&#xff1a;https://www.cnblogs.com/txwtech/p/11104428.html Modbus 通信协议详解 下面是在QT5 C控制台测试程序。 #include <QCoreApplication> #include <QTextStream> #include <stdio.h>//然后&#xff0c;在使用cin、cout、cer…

C++ SVM Opencv3.4实现人脸检测

很通俗的来说&#xff0c;haar算法计算特征就是用一块区域内黑色的值减去白色的值。但是一张图片像素点是非常多的&#xff0c;如果用普通的方法去计算一块区域的值&#xff0c;效率相当低下。这里有一种加速计算的方法--积分图&#xff1a;定义如下&#xff1a;&#xff08;维…

Spring Boot(十四)RabbitMQ延迟队列

一、前言 延迟队列的使用场景&#xff1a;1.未按时支付的订单&#xff0c;30分钟过期之后取消订单&#xff1b;2.给活跃度比较低的用户间隔N天之后推送消息&#xff0c;提高活跃度&#xff1b;3.过1分钟给新注册会员的用户&#xff0c;发送注册邮件等。 实现延迟队列的方式有…

bzoj 2121 DP

首先如果我们能处理出来i,j段能不能消掉&#xff0c;这样就可以直接dp转移了&#xff0c;设w[i]为前i为最少剩下多少&#xff0c;那么w[i]w[j-1] (flag[j][i])。 现在我们来求flag[i][j]&#xff0c;首先我们可以把字符串组建立trie然后处理在串L中从left位置开始的所有的flag&…

三、Win10 64位PyCharm下打包.py程序为可执行exe文件且兼容32位和64位

WIN10 64位下Pycharm打包.py程序为可执行文件exe 上面衔接WIN10 64位下Pycharm打包.py程序为可执行文件exe,存在不兼容32位和64位的情况。 下面Win10 64位PyCharm下打包.py程序为可执行exe文件且兼容32位和64位说明: 前提条件 python3.8.2 32 位;注意:原来有 64 位 Pyth…

Java核心(一)线程Thread详解

一、概述 在开始学习Thread之前&#xff0c;我们先来了解一下 线程和进程之间的关系&#xff1a; 线程(Thread)是进程的一个实体&#xff0c;是CPU调度和分派的基本单位。 线程不能够独立执行&#xff0c;必须依存在应用程序中&#xff0c;由应用程序提供多个线程执行控制。 线…

Jetson Nano配置与使用(5)cuda测试及tensorflow gpu安装

Jetson Nano利用官方镜像进行安装后&#xff0c;系统已经安装好了JetPack&#xff0c;cuda&#xff0c;cudaa&#xff0c;OpenCV等组件&#xff0c;不过需要修改下环境变量才可以使用。 1.修改环境变量 利用vim打开 ~ 路径下.bashrc文件&#xff1a; sudo vi ~./bashrc文件的…

工作方法

刚入职场的年轻人&#xff0c;总不喜欢写工作汇报&#xff0c;想来有如下原因:觉得每天都在做同样的事情&#xff0c;没有多少有趣新鲜的素材好写觉得这是领导对自己的监控&#xff0c;写了会有不少工作疏漏落在领导手上不太知道如何将本日工作进行总结其实每日工作汇报是非常重…

Python弹窗提示警告框MessageBox

需要安装pywin32模块&#xff0c;pip install pywin32 # pip install pywin32 import win32api import win32con# 提醒OK消息框 win32api.MessageBox(0, "这是一个测试提醒OK消息框", "提醒",win32con.MB_OK)# 是否信息框 win32api.MessageBox(0, "这…

一次失败的蛋疼的设计

需求&#xff1a;当一个用户上传一条记录之后&#xff0c;通知某一个组或者某几个组的用户查看。用户可以属于多个组。 分析&#xff1a;当用户登录之后&#xff0c;判断自己所在的组是否属于通知组&#xff0c;是&#xff0c;则提醒。 SQL&#xff1a; select * from newsGro…

Java核心(二)深入理解线程池ThreadPool

本文你将获得以下信息&#xff1a; 线程池源码解读线程池执行流程分析带返回值的线程池实现延迟线程池实现 为了方便读者理解&#xff0c;本文会由浅入深&#xff0c;先从线程池的使用开始再延伸到源码解读和源码分析等高级内容&#xff0c;读者可根据自己的情况自主选择阅读…

XCOPY不是内部或外部命令,也不是可运行程序 修复

系统常用命令无法识别 解决 1.进入系统安装目录的system32中&#xff0c;一般目录为C:\Windows\System32&#xff0c;找一下可执行文件是否存在&#xff0c;是否可以运行&#xff08;如ipconfig&#xff0c;直接点击会出现一个命令行窗口&#xff0c;一闪而逝&#xff09;&…

Jetson Nano安装pytorch 基于torch1.6和torchvision0.7

需要注意的是&#xff0c;博主使用的是win10主机&#xff0c;通过局域网连接的jetson nano&#xff0c; 其中jetson nano的预制CUDA版本为10.2 Jetpack 4.1.1 分别执行以下命令&#xff0c;即可查看自己的jetson nano 预搭载的CUDA版本 sudo pip3 install jetson-stats sudo …

SEO之基础篇(一)

1、关键字的竞争你能应对吗&#xff1f;那些每索20W次的关键字你能做到吗&#xff1f;因此我们选择关键字要适合自己的。你是单枪匹马还是团队&#xff0c;要考虑清楚。 2、找到适合自己的关键字。新站长最好选择1~2个关键字&#xff0c;切忌不要太多。等网站流量上去了后再…

Python获取硬件信息(硬盘序列号,CPU序列号)

原文衔接 https://www.cnblogs.com/blog-rui/p/12108072.html pip install wmi pip install pywin32import wmic wmi.WMI()# # 硬盘序列号 for physical_disk in c.Win32_DiskDrive():print(physical_disk.SerialNumber)# CPU序列号 for cpu in c.Win32_Processor():print(cp…

Java核心(三)并发中的线程同步与锁

乐观锁、悲观锁、公平锁、自旋锁、偏向锁、轻量级锁、重量级锁、锁膨胀…难理解&#xff1f;不存的&#xff01;来&#xff0c;话不多说&#xff0c;带你飙车。 上一篇介绍了线程池的使用&#xff0c;在享受线程池带给我们的性能优势之外&#xff0c;似乎也带来了另一个问题&a…

【Jetson-Nano】2.Tensorflow和Pytorch的安装

文章目录 1、Tensorflow多版本安装 1.1 Protobuf 安装1.2 安装依赖包及tensorflow1.151.3 安装其它常用库1.4 测试python包是否安装成功1.5 TensorRT和Opencv的安装1.6 pycuda和onnx安装1.7 Tensorflow2.3安装2、Pytorch安装 2.1 安装pytroch和torchvision2.2 安装环境验证参考…

Spring Boot 终极清单

一、Spring Boot 终极清单诞生原因我上学那会主要学的是 Java 和 .Net 两种语言&#xff0c;当时对于语言分类这事儿没什么概念&#xff0c;恰好在2009年毕业那会阴差阳错的先找到了 .Net 的工作&#xff0c;此后就开始了漫长的 .Net 编程之旅&#xff0c;说实话最初的“编程思…

Python SHA1加密算法

SHA1 加密 SHA1的全称是Secure Hash Algorithm(安全哈希算法) 。SHA1基于MD5&#xff0c;加密后的数据长度更长&#xff0c; 它对长度小于264的输入&#xff0c;产生长度为160bit的散列值。比MD5多32位。 因此&#xff0c;比MD5更加安全&#xff0c;但SHA1的运算速度就比MD5…