30 案例:实施人脸检测

30 案例:实施人脸检测

opencv知识点:

  • 创建和操作综合人工神经网络 - dnn::Net
  • 读取以TensorFlow框架格式存储的网络模型 - readNetFromTensorflow
  • 从图像创建4维blob - blobFromImage
  • 设置网络的新输入值- Net::setInput
  • 运行正向传递以计算指定层的输出 - Net::forward

本课所解决的问题:

  • 如何运行opencv4提供的人脸检测模型

1.OpenCV 4

本节课的内容主要基于opencv 4 实现,开始我们先了解一下opencv4

OpenCV4.x发布以来,其依靠良好的接口代码、系统级别的优化、更加通用易学的函数调用,集成OpenVINO与tensorflowcaffe等模型加速推断、实现了从传统的图像处理到基于深度学习的视觉处理路线图的完整拓展。

OpenCV4 毫无疑问是一个OpenCV发展历史的一个重要里程碑之作。
官方的宣传口号 OpenCV4 is more than OpenCV
也充分说明OpenCV4 是整合深度学习的新一代计算机视觉开发框架!

本课将介绍一种opencv4自带的,一个进行人脸检测的模型

2.下载人脸检测模型和

为了方便,我们不采用视频的方式,我们就直接去下载课程源码zip了

下载地址:OpenCV学堂 / OpenCV课程资料

下载完之后到图中目录:opencv_tutorial_data-master → models → face_detector

7ed97a6c96de472989ecafc2d3cd3967

目标文件夹:安装opencv目录下的sources → samples → dnn → face_detector

77232f0964cf46048e16f4f8bf63f0d6

3.人脸检测模型演示

开始前,我们可以先把头文件命名空间补上

6d6dd01b35c944c196e54dc0c60ca4e4

这里提一下,当我们使用Net导入模型时,关于模型的各种参数可以从这个文档查看

70628773207c4383a88e1d42bb833e5e

在运行这个人脸检测模型之前,我们需要先来了解几个API

  • dnn::Net类
  • readNetFromTensorflow
  • blobFromImage
  • Net::setInput方法
  • Net::forward方法
  • Mat::ptr

具体介绍如下

dnn::Net类

dnn::Net类
	创建和操作综合人工神经网络
		
		神经网络表示为有向无环图 (DAG),其中顶点是层实例,边指定层输入和输出之间的关系。
		
		每个网络层在其网络内都有唯一的整数id 和唯一的字符串名称。LayerId 可以存储图层名称或图层ID。
		
		此类支持其实例的引用计数,即副本指向同一个实例。

readNetFromTensorflow

readNetFromTensorflow
	读取以TensorFlow框架格式存储的网络模型
		共2个参数
			第1个参数 pb文件路径
			第2个参数 pbtxt文件路径

blobFromImage

blobFromImage
	从图像创建4维blob(斑点,深度学习相关知识)
		共7个参数
			第1个参数 输入
			第2个参数 图像空间大小(默认1.0,即图像仍保持在0~255色彩空间)
			第3个参数 size
			第4个参数 均值
			第5个参数 是否交换RB通道(默认false)
			第6个参数 调整图像大小后是否剪切(默认false)
			第7个参数 输出的blob深度(默认CV_32F)
	
	returns
		按照NCHW(数量,通道,高度,宽度)顺序的4维Mat,blob就是这个4维Mat

Net::setInput方法

setInput
	设置网络的新输入值
		共4个参数
			第1个参数 输入斑点
			第2个参数 输入层名称(默认为空“”)
			第3个参数 可选的标准化比列
			第4个参数 可选的平均值

Net::forward方法

forward
	运行正向传递以计算名为 outputName 的层的输出。
		共1个参数
			第1个参数 需要输出的层的名称
	returns
		返回也有四个值
			第1个维度 表示有多少张图像,并且每个图像有一个编号。imageId
			第2个维度 图像的批次。batchId
			第3个维度 有多少个框(行)
			第4个维度 每个框有7个值(列)
							前两个值 标明类型 + index
							第3个值 得分(得分越高,越有可能是人脸)
							后四个值 矩形左上角和右下角的坐标							

Mat::ptr

二维单通道元素可以用MAT::at(i,j),i是行号,j是列号

但对于多通道的非uchar类型矩阵来说,以上方法不适用
可以用Mat::ptr()来获得指行某行元素的指针,在通过行数与通道数计算相应点的指针

演示如下:

//函数定义
void face_detection_demo();

//函数实现
void QuickDemo::face_detection_demo() {

	//文件夹路径
	string root_dir = "D:/meta/opencv/opencv-4.5.5/sources/samples/dnn/face_detector/";

	//读取以TensorFlow框架格式存储的网络模型
	dnn::Net net = dnn::readNetFromTensorflow(root_dir + "opencv_face_detector_uint8.pb", root_dir + "opencv_face_detector.pbtxt");

	//对摄像头进行人脸检测
	VideoCapture cap(0);
	Mat frame;
	while (true) {

		cap.read(frame);//frame为输出,read是将捕获到的视频一帧一帧的传入frame
		
		if (frame.empty()) {
			break;
		}

		flip(frame, frame, 1);//左右翻转

		//准备深度学习模型需要的数据 (blob-斑点)
		Mat blob = dnn::blobFromImage(frame, 1.0, Size(300, 300), Scalar(104, 177, 123), false, false);
		net.setInput(blob);
		
		//完成推理
		Mat probs = net.forward();

		Mat detectionMat(probs.size[2], probs.size[3], CV_32F, probs.ptr<float>());

		//解析结果
		for (int i = 0; i < detectionMat.rows; i++) {

			float confidence = detectionMat.at<float>(i, 2);//第三个值 得分
			
			if (confidence > 0.5) {

				//因为预测来的值为[0,1]范围的数,我们还需要*原图像的宽度和长度
				int x1 = static_cast<int>(detectionMat.at<float>(i, 3) * frame.cols);
				int y1 = static_cast<int>(detectionMat.at<float>(i, 4) * frame.rows);
				int x2 = static_cast<int>(detectionMat.at<float>(i, 5) * frame.cols);
				int y2 = static_cast<int>(detectionMat.at<float>(i, 6) * frame.rows);

				Rect rect(x1, y1, x2 - x1, y2 - y1);
				rectangle(frame, rect, Scalar(0, 0, 255), 2, 8, 0);

			}
		}

		imshow("人脸检测",frame);

		int c = waitKey(1);
		if (c == 27) {
			break;
		}
	}
	cap.release();

}

此处需要补一个结果视频的gif文件

本课所用API查阅

1.dnn::Net

2.dnn::readNetFromTensorflow

3.dnn::blobFromImage

4.Net::setInput

5.Net::forward

posted @ 2023-01-15 14:52  L707  阅读(94)  评论(0编辑  收藏  举报