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

使用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,将视频录制下来。这里就不接着做了,感兴趣的可以试一下。

一下是一些效果。

相关文章:

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

内容的一部分来源于贾志刚的《opencv4应用开发、入门、进阶与工程化实践》。这本书我大概看了一下&#xff0c;也就后面几章比较感兴趣&#xff0c;但是内容很少&#xff0c;并没有想像的那种充实。不过学习还是要学习的。 在实际工程项目中&#xff0c;并不是说我们将神经网络…...

C#中使用OpenCV的常用函数

以下是一些C#中使用OpenCV的常用函数例子&#xff1a; 1. 加载图像&#xff1a; using OpenCvSharp;Mat image Cv2.ImRead("path_to_your_image.jpg", ImreadModes.Color); 2. 显示图像&#xff1a; Cv2.NamedWindow("Image Window", WindowFlags.Nor…...

使用Swift Package Manager (SPM)实现xcframework分发

Swift Package Manager (SPM) 是苹果官方提供的用于管理 Swift 项目的依赖关系和构建过程的工具。它是一个集成在 Swift 编程语言中的包管理器&#xff0c;用于解决在开发过程中管理和构建包依赖项的需求。 1、上传xcframework.zip到服务端 压缩xcframeworks成一个zip包&…...

非阻塞 IO(NIO)

文章目录 非阻塞 IO(NIO)模型驱动程序应用程序模块使用 非阻塞 IO(NIO) 上一节中 https://blog.csdn.net/tyustli/article/details/135140523&#xff0c;使用等待队列头实现了阻塞 IO 程序使用时&#xff0c;阻塞 IO 和非阻塞 IO 的区别在于文件打开的时候是否使用了 O_NONB…...

Android应用-flutter使用Positioned将控件定位到底部中间

文章目录 场景描述示例解释 场景描述 要将Positioned定位到屏幕底部中间的位置&#xff0c;你可以使用MediaQuery来获取屏幕的高度&#xff0c;然后设置Positioned的bottom属性和left或right属性&#xff0c;一般我们left和right都会设置一个值让控制置于合适的位置&#xff0…...

Django 简单图书管理系统

一、图书需求 1. 书籍book_index.html中有超链接&#xff1a;查看所有的书籍列表book_list.html页面 2. 书籍book_list.html中显示所有的书名&#xff0c;有超链接&#xff1a;查看本书籍详情book_detail.html(通过书籍ID)页面 3. 书籍book_detail.html中书的作者和出版社&…...

C++内存管理和模板初阶

C/C内存分布 请看代码&#xff1a; int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] { 1, 2, 3, 4 };char char2[] "abcd";const char* pChar3 "abcd";int* ptr1 (int*)mallo…...

QtRO(Qt Remote Objects)分布式对象远程通信

一、什么是QtRO Qt Remote Objects&#xff08;QRO&#xff09;是Qt提供的一种用于实现远程对象通信的机制。 QtRO支持两种类型的通信&#xff1a;RPC&#xff08;远程过程调用&#xff09;和LPC&#xff08;本地进程通信&#xff09;。 RPC&#xff08;远程过程调用&#xf…...

【K8s】1# 使用kuboard-spray安装K8s集群

文章目录 搭建k8s集群1.推荐配置1.1.服务器配置1.2.软件版本 2.使用Kuboard-Spray安装k8s集群2.1.配置要求2.2.操作系统兼容性2.3.安装 Kuboard-Spray2.4.加载离线资源包2.5.规划并安装集群2.6.安装成功2.7.访问集群 3.涉及的命令3.1.linux 4.问题汇总Q1&#xff1a;启动离线集…...

leetCode算法—12. 整数转罗马数字

12. 整数转罗马数字 难度&#xff1a;中等 ** 罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如&#xff0c; 罗马数字 2 写做 II &#xff0c;即…...

使用OpenCV4实现工业缺陷检测的六种方法

目录 1 机器视觉2 缺陷检测3 工业上常见缺陷检测方法 1 机器视觉 机器视觉是使用各种工业相机&#xff0c;结合传感器跟电气信号实现替代传统人工&#xff0c;完成对象识别、计数、测量、缺陷检测、引导定位与抓取等任务。其中工业品的缺陷检测极大的依赖人工完成&#xff0c;…...

Excel 获取当前行的行数

ROW() 获取当前行 ROW()1 获取当前行然后支持二次开发...

R语言【stringr】——str_detect 检测是否存在字符串的匹配项

Package stringr version 1.5.1 str_detect(string, pattern, negate FALSE) 参数【string】&#xff1a;输入向量。既可以是字符向量&#xff0c;也可以是强制作为一个字符向量。 参数【pattern】&#xff1a;要寻找的模式。默认解释为正则表达式&#xff0c;如 vignette(&…...

【SpringMVC】SpringMVC的请求与响应

文章目录 0. Tomcat环境的配置1. PostMan工具介绍创建WorkSpace建立新的请求 2. 请求映射路径案例结构与代码案例结构案例代码 案例存在问题解决方案方法方法升级版——配置请求路径前缀注解总结 3. Get请求与Post请求案例结构与案例代码案例结构案例代码 Get请求Post请求接收中…...

Spring Boot3通过GraalVM生成exe执行文件

一、安装GraalVM 1、官网&#xff1a;https://www.graalvm.org/downloads/ 2、配置环境变量 2.1、环境变量必须使用JAVA_HOME&#xff0c;否则会出现问题 2.2、在系统变量配置Path,%JAVA_HOME%\bin&#xff0c;注意必须放在顶部第一位 2.3、配置jdk的环境变量&#xff0c;在P…...

【Amazon 实验②】使用缓存策略及源请求策略,用于控制边缘缓存的行为及回源行为

文章目录 1. 了解缓存策略和源请求策略1.1 使用缓存键和缓存策略 实验&#xff1a;使用CloudFront缓存策略和缓存键控制缓存行为 接上一篇文章【Amazon 实验①】使用 Amazon CloudFront加速Web内容分发&#xff0c;我们现在了解和配置如何使用缓存策略及源请求策略&#xff0c;…...

达梦数据对比工具的部署与使用

1、拷贝达梦软件bin目录到Oracle服务器&#xff08;root用户&#xff09; 压缩Linux rh6 x86版本的达梦数据库bin目录&#xff0c;例如压缩文件为dmbin.tar.gz&#xff0c;将文件拷贝到Oracle服务器指定目录并解压&#xff08;如&#xff1a;/home/oracle/dmbin&#xff09;&a…...

TLC2543(12位A/D转换器)实现将输入的模拟电压显示到数码管上

代码&#xff1a; #include <reg51.h> #define uchar unsigned char #define uint unsigned int// 数码管0-9 unsigned char seg[] {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; sbit SDO P1^0; sbit SDI P1^1; sbit CS P1^2; sbit CLK P1^3; s…...

npm的使用技巧

以下是一些NPM&#xff08;Node Package Manager&#xff09;的使用技巧&#xff1a; 1. **获取帮助**&#xff1a; - 使用 npm help 或者 npm <command> --help 可以获取关于特定命令的帮助信息。 2. **命令自动完成**&#xff1a; - 在 Bash、Zsh 等 shell 中&…...

MySQL 5.6的新特性

MySQL 5.6是一个主要的版本发布&#xff0c;它在性能、可伸缩性、可靠性和可用性方面引入了多项重要改进和新特性。它在2013年发布&#xff0c;相比于它的前身MySQL 5.5&#xff0c;MySQL 5.6带来了以下关键升级&#xff1a; 优化的InnoDB存储引擎&#xff1a;MySQL 5.6中的Inn…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

OD 算法题 B卷【正整数到Excel编号之间的转换】

文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的&#xff1a;a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...