使用OpenCV DNN模块进行人脸检测

内容的一部分来源于贾志刚的《opencv4应用开发、入门、进阶与工程化实践》。这本书我大概看了一下,也就后面几章比较感兴趣,但是内容很少,并没有想像的那种充实。不过学习还是要学习的。

在实际工程项目中,并不是说我们将神经网络训练好拿来就直接落地,事实上,一个深度学习网络的落地在训练验证好才是开始的第一步,剩下为了部署网络,需要考虑场景问题,硬件配置,软件配置。需要对网络进行蒸馏,剪枝,轻量化,是模型大小适宜硬件配置,此外为了更好,更快速的推理,还需要将模型转成不同的模型格式,使其更加适配软件推理。目前使用较多推理加速工具英特尔的OpenVINO,Nvidia的TensorRT,都是目前主流的加速推理引擎软件,后期会继续学习。

OpenCV DNN模块在OpenCV3系列就已经正式发布,该模块是一个深度学习网络库,它支持多种预训练的深度学习模型,并可以用于多种图像和视频分析任务,如面部识别、对象检测、图像分类等。这个模块使得在OpenCV中使用深度学习模型变得相对简单,因为它可以加载由不同深度学习框架(如TensorFlow、Caffe、Torch/PyTorch等)训练的模型。其不仅可以基于CPU推理,也可基于GPU加速推理。使用方便。

使用dnn模块时,一般的步骤如下:

  1. 加载模型:使用cv2.dnn.readNetFrom*系列函数(例如readNetFromCaffereadNetFromTensorflow等)加载预训练模型。

  2. 准备输入:对输入图像进行必要的预处理(如缩放、中心化、标准化等),并将其转换为网络所需的格式。

  3. 前向传播:将处理后的图像传入网络进行前向传播,得到输出。

  4. 解析输出:根据模型的特性和应用需求,解析模型的输出,以得到最终的结果。

 Opencv samples 提供了基于resnet的SSD人脸检测模型示例,有基于caffe生成的,也有基于Tensorflow生成的。如果你安装opencv时是编译源码安装,则可以去源码位置处看看opencv4.6\opencv\sources\samples下有各类的示例,dnn文件夹下的face_detector下就有需要的网络权重文件与网络配置文件。

网络配置文件描述了一个神经网络的架构和结构。它包含了网络中的各层(如卷积层、池化层、全连接层等)的定义,以及这些层的参数(如核大小、步长、填充等)。此文件不包含训练后的模型权重,只定义了模型的结构。

这种文件通常是一个文本文件,可以使用JSON、XML、YAML或特定框架的专用格式(如Caffe的.prototxt文件)编写。在不同的深度学习框架中,配置文件的格式可能会有所不同。

网络权重文件包含了神经网络在训练过程中学习到的权重和偏置参数。这些参数是通过训练数据集上的反向传播过程优化得到的,它们决定了模型对新数据的预测能力。

权重文件通常是一个二进制文件,包含了数值型的参数数据。这种文件的格式也取决于使用的深度学习框架,常见格式包括TensorFlow的.ckpt、PyTorch的.pt.pth、Caffe的.caffemodel等。

如果你找不到,也可以在链接:https://pan.baidu.com/s/1suEmF7zgmgamnJbToegQ6Q?pwd=gcxy   提取码:gcxy 这里下载。

好了有了这些,那我还想实现一个视频检测,但是又没有摄像头,那没办法了,也可以整一个显示桌面窗口的。由于本人这里又两个显示屏,所以在将电脑显示屏窗口的一个内容获得,可以在另外一个窗口中用opencv的imshow观察。

下面提供一些重要代码。

1.window_capture

#include <opencv2/opencv.hpp>
#include <Windows.h>
#include <iostream>using namespace std;
using namespace cv;Mat hwnd2mat(HWND hwnd)
{HDC hwindowDC, hwindowCompatibleDC;int height, width, srcheight, srcwidth;HBITMAP hbwindow;Mat src;BITMAPINFOHEADER  bi;hwindowDC = GetDC(hwnd);hwindowCompatibleDC = CreateCompatibleDC(hwindowDC);SetStretchBltMode(hwindowCompatibleDC, COLORONCOLOR);RECT windowsize;    // get the height and width of the screenGetClientRect(hwnd, &windowsize);srcheight = windowsize.bottom;srcwidth = windowsize.right;height = windowsize.bottom / 1;  //change this to whatever size you want to resize towidth = windowsize.right / 1;src.create(height, width, CV_8UC4);// create a bitmaphbwindow = CreateCompatibleBitmap(hwindowDC, width, height);bi.biSize = sizeof(BITMAPINFOHEADER);    //http://msdn.microsoft.com/en-us/library/windows/window/dd183402%28v=vs.85%29.aspxbi.biWidth = width;bi.biHeight = -height;  //this is the line that makes it draw upside down or notbi.biPlanes = 1;bi.biBitCount = 32;bi.biCompression = BI_RGB;bi.biSizeImage = 0;bi.biXPelsPerMeter = 0;bi.biYPelsPerMeter = 0;bi.biClrUsed = 0;bi.biClrImportant = 0;// use the previously created device context with the bitmapSelectObject(hwindowCompatibleDC, hbwindow);// copy from the window device context to the bitmap device contextStretchBlt(hwindowCompatibleDC, 0, 0, width, height, hwindowDC, 0, 0, srcwidth, srcheight, SRCCOPY); //change SRCCOPY to NOTSRCCOPY for wacky colors !GetDIBits(hwindowCompatibleDC, hbwindow, 0, height, src.data, (BITMAPINFO*)&bi, DIB_RGB_COLORS);  //copy from hwindowCompatibleDC to hbwindow// avoid memory leakDeleteObject(hbwindow);DeleteDC(hwindowCompatibleDC);ReleaseDC(hwnd, hwindowDC);//src是BGRA 4通道显示return src;
}

有几个需要注意的问题,windows.h头文件需要在iostream或者其他C++标准库的前面,至于问什么就是如果写反了,windows会对一个量报重定义的错误,没法解决,应该是个冲突。

此外这段代码是将hwindowCompatibleDC的数据传给Mat类src,这里传入的输入是4通道的即RGBA类型,在 OpenCV 中处理图像时,一个常见的格式是 RGBA,其中包括四个通道:红色(R)、绿色(G)、蓝色(B)和 Alpha(A)。Alpha 通道代表透明度,其中值 0 表示完全透明,255 表示完全不透明。 这里非常重要,因为我们后续的处理时将一幅3通道的图传入网络进行推理,传入的数据格式错误就会报错。所以需要后期将RGBA格式转为RGB格式。

哦对了,这里再提一嘴,以上只是为了方便,说成RGB。在opencv中,彩色图像时BGR格式的,所以读入的4通道也是BGRA格式。

2.face_detect

void face_detect(Mat& image, Net& net) {int h = image.rows;int w = image.cols;cv::Mat inputBlob = cv::dnn::blobFromImage(image, 1.0, cv::Size(300, 300),Scalar(104.0, 177.0, 123.0), false, false);net.setInput(inputBlob, "data");cv::Mat detection = net.forward("detection_out");cv::Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());for (int i = 0; i < detectionMat.rows; i++){float confidence = detectionMat.at<float>(i, 2);if (confidence > 0.125){int x1 = static_cast<int>(detectionMat.at<float>(i, 3) * w);int y1 = static_cast<int>(detectionMat.at<float>(i, 4) * h);int x2 = static_cast<int>(detectionMat.at<float>(i, 5) * w);int y2 = static_cast<int>(detectionMat.at<float>(i, 6) * h);cv::rectangle(image, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(0, 255, 0),2, 8);}}namedWindow("人脸检测演示", WINDOW_NORMAL);imshow("人脸检测演示", image);}

 这段代码就是推理的主要流程,其中几个比较重要的点就是blobFromImage函数是将待预测的图片转成网络输入的格式,一般网络的图像输入格式为N,C,H,W。N就是batch数,在推理时一般为1,C即通道数,H,W即为图像的高宽,除此之外这个函数还可缩放图像的像素值,默认1.0表示不变,也可以resize图像宽高,这里缩放到(300X300)为网络的输入。还有是否互换图像的R与B通道,数据类型(默认为浮点数)等。

然后将图像传入网络,前向推理获得结果,该网络的输出层是“detection_out”需要加输出层名称获得输出结果,我们这里是将结果用一个Mat类 detection获得。

该结果中输出格式为Nx7,N表示检测到的对象数目,7分别表示,批次,类别,得分,检测狂的左上角与右下角坐标。所以可以采用上面的代码对推理结果进行解析。这里根据置信度得分,筛选符合的条件,并将其绘制在图像显示。

3.整体流程

void screen_capture_facedetection(bool tf) {const std::string caffe_config = model_dir + "face_detector/deploy.prototxt";const std::string caffe_weight = model_dir + "face_detector/res10_300x300_ssd_iter_140000_fp16.caffemodel";const std::string tf_config = model_dir + "face_detector/opencv_face_detector.pbtxt";const std::string tf_weight = model_dir + "face_detector/opencv_face_detector_uint8.pb";Net net;if (tf) {net = cv::dnn::readNetFromTensorflow(tf_weight, tf_config);}else {net = cv::dnn::readNetFromCaffe(caffe_config, caffe_weight);}HWND hwndDesktop = GetDesktopWindow();//namedWindow("window", WINDOW_NORMAL);while (true) {Mat frame = hwnd2mat(hwndDesktop);if (frame.empty()) {break;}//从窗口获得的图像是BGRA4通道显示,可以将其转为3通道显示Mat frame3Channel;cvtColor(frame, frame3Channel, COLOR_BGRA2BGR);//imshow("window", frame3Channel);//cout << frame3Channel.channels() << endl;//break;face_detect(frame3Channel, net);char c = waitKey(10);if (c == 27) {break;}}
}

可以看到这里使用cvtColor将4通道转为3通道。

在int main 中调用即可,注意bool tf 选择caffee model,或者tensorflow model即可。推出,在显示窗口中按ESC即可退出。

后期当然也可以使用opencv的video writer,将视频录制下来。这里就不接着做了,感兴趣的可以试一下。

一下是一些效果。

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

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

相关文章

【Unity】【WebRTC】如何用Unity而不是浏览器接收远程画面

【背景】 之前几篇我们讨论了如何设置信令服务器&#xff0c;如何发送画面给远端以及如何用浏览器查看同步画面&#xff0c;今天来讨论如何实现Unity内部接收画面。 看本篇之前请先看过之前将web服务器设置和基本远程画面功能的几篇博文。&#xff08;同专栏下查看&#xff09…

el-select如何去掉placeholder属性

功能要求是&#xff1a;当el-select的disabled属性为true的时候不展示“请选择”字样 1、要去掉 el-select 元素的 placeholder 属性&#xff0c;可以在代码中将其设置为空字符串。 <el-select placeholder"" ...></el-select> 注意&#xff1a;这种方…

Linux目录切换相关命令@cd/pwd

目录 基础指令 cd命令原型命令的搭配以及效果命令本身cd cd 指定目录 基础指令 pwd命令原型pwd 总结&#xff1a; 基础指令 cd cd 取自英文 Change Directory 的首字母组成。 英文的中文翻译为&#xff1a;更改目录。 很明显该指令是用来更改目录的。 命令原型 cd [Linux路径…

Java设计模式之单例模式以及如何防止通过反射破坏单例模式

单例模式 单例模式使用场景 ​ 什么是单例模式&#xff1f;保障一个类只能有一个对象&#xff08;实例&#xff09;的代码开发模式就叫单例模式 ​ 什么时候使用&#xff1f; 工具类&#xff01;&#xff08;一种做法&#xff0c;所有的方法都是static&#xff0c;还有一种单…

27. 过滤器

Filter(过滤器)简介 Filter 的基本功能是对 Servlet 容器调用 Servlet 的过程进行拦截&#xff0c;从而在 Servlet 进行响应处理的前后实现一些特殊的功能。在 Servlet API 中定义了三个接口类来开供开发人员编写 Filter 程序&#xff1a;Filter, FilterChain, FilterConfigFi…

【数据结构】队列的使用|模拟实现|循环队列|双端队列|面试题

一、 队列(Queue) 1.1 概念 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出FIFO(First In First Out) 入队列&#xff1a;进行插入操作的一端称为队尾&#xff08;Tail/Rear&#xff09; 出队列…

TSINGSEE青犀可视化视频云平台JT/T1078接入能力在智慧物流中的应用

一、引言 随着科技的快速发展和全球贸易的蓬勃发展&#xff0c;智慧物流成为了现代物流业的重要发展方向。智慧物流通过引入先进的信息技术&#xff0c;实现了物流过程的自动化、智能化和信息化&#xff0c;从而提高了物流效率和准确性。在这个过程中&#xff0c;JT/T1078接入…

【分享】4个方法打开PDF文件

PDF是很多人工作中经常使用的电子文档格式&#xff0c;但是可能有些刚接触的小伙伴不知道用什么工具来打开PDF文件&#xff0c;今天小编就来分享一下4种常用的工具。 1. 使用浏览器 只要有电脑基本都会安装一到两款浏览器&#xff0c;其实浏览器也可以用来打开PDF文件。 只需…

在x64上构建智能家居(home assistant)(二)(新版Debain12)连接Postgresql数据库

新版数据库安装基本和旧版相同,大部分可以参考旧版本在x64上构建智能家居(home assistant)&#xff08;二&#xff09;连接Postgresql数据库_homeassist 数据库-CSDN博客 新版本的home assistant系统安装,我在原来写的手顺上直接修改了,需要的可以查看在x64上构建智能家居(home…

探索未来交通!空客、宝马开启新一轮“量子计算挑战赛”

12月6日&#xff0c;空中客车公司和宝马集团共同发起了一项名为 “量子交通探索”的全球量子计算挑战赛&#xff0c;以应对航空和汽车领域最紧迫的挑战——这些挑战对于传统计算机而言仍然是难以克服的。 这项挑战是首创性的&#xff0c;它将两个全球行业领导者聚集在一起&…

Wavesurfer.js绘制波形图

HTML使用Wavesurfer.js 要使用wavesurfer.js&#xff0c;首先需要在HTML文件中引入Wavesurfer.js库&#xff0c;然后创建一个音频元素并将其添加到页面中。接下来&#xff0c;初始化Wavesurfer实例并配置相关选项。以下是一个简单的示例&#xff1a; 在HTML文件中引入Wavesurf…

jvm内存模型

1、简介 JVM在执行Java程序时&#xff0c;会把它管理的内存划分为若干个的区域&#xff0c;每个区域都有自己的用途和创建销毁时间。如下图所示&#xff0c;可以分为两大部分&#xff0c;线程私有区和共享区。下图是根据自己理解画的一个JVM内存模型架构图&#xff1a; 2、线程…

LeetCode刷题--- 电话号码的字母组合

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 http://t.csdnimg.cn/6AbpV 数据结构与算法 http://t.csdnimg.cn/hKh2l 前言&#xff1a;这个专栏主要讲述递归递归、搜…

机器学习算法(12) — 集成技术(Boosting — Xgboost 分类)

一、说明 时间这是集成技术下的第 4 篇文章&#xff0c;如果您想了解有关集成技术的更多信息&#xff0c;您可以参考我的第 1 篇集成技术文章。 机器学习算法&#xff08;9&#xff09; - 集成技术&#xff08;装袋 - 随机森林分类器和...... 在这篇文章中&#xff0c;我将解释…

LangChain入门指南:定义、功能和工作原理

LangChain入门指南&#xff1a;定义、功能和工作原理 引言LangChain是什么&#xff1f;LangChain的核心功能LangChain的工作原理LangChain实际应用案例如何开始使用LangChain 引言 在人工智能的浪潮中&#xff0c;语言模型已成为推动技术革新的重要力量。从简单的文本生成到复…

ChatGPT一周年:开源语言大模型的冲击

自2022年末发布后&#xff0c;ChatGPT给人工智能的研究和商业领域带来了巨大变革。通过有监督微调和人类反馈的强化学习&#xff0c;模型可以回答人类问题&#xff0c;并在广泛的任务范围内遵循指令。在获得这一成功之后&#xff0c;人们对LLM的兴趣不断增加&#xff0c;新的LL…

《每天一分钟学习C语言·七》指针、字节对齐等

1、 对于二维数组如a[3][4]可以当做有三个元素的一维数组&#xff0c;每个元素包含四个小元素。 2、 printf(“%-5d”, i); //负号表示左对齐&#xff0c;5d表示空五个光标的位置 3、 栈&#xff1a;先进后出&#xff0c;堆&#xff1a;先进先出 4、 &#xff08;1&#xff…

yolo-nas无人机高空红外热数据小目标检测(教程+代码)

前言 YOLO-NAS是目前最新的YOLO目标检测模型。从一开始&#xff0c;它就在准确性方面击败了所有其他 YOLO 模型。与之前的 YOLO 模型相比&#xff0c;预训练的 YOLO-NAS 模型能够以更高的准确度检测更多目标。但是我们如何在自定义数据集上训练 YOLO NAS&#xff1f; 这将是我…

基于ERC20代币协议实现的去中心化应用平台

文章目录 内容简介设计逻辑ERC20TokenLoanPlatform 合约事件结构体状态变量函数 Remix 运行实现部署相关智能合约存款和取款贷款和还款 源码地址 内容简介 使用 solidity 实现的基于 ERC20 代币协议的借贷款去中心化应用平台(极简版)。实现存款、取款、贷款、还款以及利息计算的…

[Angular] 笔记 7:模块

Angular 中的模块(modules) 是代码在逻辑上的最大划分&#xff0c;它类似于C, C# 中的名字空间&#xff1a; module 可分为如下几种不同的类型&#xff1a; 使用模块的第一个原因是要对代码进行逻辑上的划分&#xff0c;第二个非常重要的原因是为了实现懒惰加载(lazy loading)&…