OpenCV4深度神经网络DNN实战教程

2024-08-28 01:04

本文主要是介绍OpenCV4深度神经网络DNN实战教程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

OpenCV4深度神经网络DNN实战教程

  • 1-概述与环境配置
  • 2-卷积神经网络概述
  • 3-加载网络模型与设置
    • 3.1 所需的模型下载
    • 3.2 所使用的模型(googlenet)
    • 3.3 Net介绍
    • 3.4 代码输出网络结构信息
    • 3.5 计算后台设置
    • 3.6 所有代码
  • 4-图像分类网络inception的使用
  • 5-读取分类标签文件显示分类
  • 6-对象检测网络介绍
  • 7-SSD对象检测网络加载与执行
  • 8-SSD对象检测推理输出解释与显示
  • 9-Faster RCNN对象检测模型使用
    • 解决无法打开RAW的问题
  • 10-YOLOv3对象检测模型推理使用
  • 11-OpenCV DNN配置加速组件IE支持

1-概述与环境配置

OpenCV DNN模块
传统的HAAR级联人脸检测器不可靠到DNN的高可靠

各种操作
,如何将TensorFlow训练出来的模型导入到,实现很好的调用

OpenCVDNN模块可以解决

OpenCV4不再是单纯的计算机视觉库,还有深度学习推理库
OpenCV4后与神经网络

扩展模块
在3.3中放到了release版本中

旧的教程下线有瑕疵
此时已经很成熟了,通过IE加速(推理引擎,7、8倍的效率提升)
OpenCV4模型数很多

OpenCVgithub官方网站https://github.com/opencv/opencv
点击wiki
https://github.com/opencv/opencv/wiki/Deep-Learning-in-OpenCV
有很多关于深度学习的介绍

OpenCV face detector已经做的非常好了,模型只有几兆,但检测,完全可以抛弃级联检测方式

整个目录围绕模型展开。
在这里插入图片描述

色彩,风格迁移

OpenCV 的DNN如何使用,在应用层
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2-卷积神经网络概述

如何还用OpenCV的API加载神经网络各个层次
卷积神经网络框架中,有paddle填充模式,sim是输入3232大小,输出还是3232大小。而value输入3232,输出则变为2828.。

重叠池化的步长永远是1

局部池化,步长是其大小

最大值池化、均值池化,根据数据
在这里插入图片描述

3-加载网络模型与设置

https://www.pianshen.com/article/9895277588/
在这里插入图片描述

如何加载一个网络,网络有输入,输入是图像,c通道数,h高度,w宽度,N一般为1,表示1张图像的预测,也可以多张图像

获取输出层有个api
在这里插入图片描述

3.1 所需的模型下载

opencv_tutorial-master文件是从Google下载的,下载路径为实际上下载的东西在贾老师的GitHub上就有,
https://github.com/gloomyfish1998/opencv_tutorial/
将下载好的文件保存在了D:\OpenCV\project\下

3.2 所使用的模型(googlenet)

D:\OpenCV\project\opencv_tutorial-master\data\models\googlenet
在这里插入图片描述

bvlc_googlenet.caffemodel这是个caffe模型,在OpenCV中支持离线加载,不依赖caffe,这是模型的权重文件
bvlc_googlenet.prototxt这是模型的描述文件
Imagenet支持1000个分类,分类类别在classification_classes_ILSVRC2012.txt可以看到,使用editplus可以看到一直到1000行
//有了模型的权重和描述文件就可以加载模型了

3.3 Net介绍

(1)在OpenCV中加载模型要通过readNetWork函数
(2)readNet函数有三个参数,参数1加载网络(caffe、TensorFlow等),参数2,3为权重路径和描述文件
(3)或者readNetFromCaffe(TensorFlow、darknet、ONNX等),意思为读进来的必须是caffe模型,此外还支持TensorFlow等模型,只有两个参数
(4)还有readNetFromModelOptimizer从dnn模型优化器中读取模型优化后的模型

Net net = readNetFromCaffe(protxt, bin_model);	//此处只能加载caffe的

3.4 代码输出网络结构信息

#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>			//包含dnn模块的头文件
#include <iostream>using namespace cv;
using namespace cv::dnn;			//包含dnn的命名空间
using namespace std;int main() {string bin_model = "D:/OpenCV/project/opencv_tutorial-master/data/models/googlenet/bvlc_googlenet.caffemodel";		//定义模型权重文件的加载路径string protxt = "D:/OpenCV/project/opencv_tutorial-master/data/models/googlenet/bvlc_googlenet.prototxt";			//定义模型描述文件的加载路径//Imagenet支持1000个分类,分类类别在classification_classes_ILSVRC2012.txt可以看到,一直到1000//有了模型的权重和描述文件就可以加载模型了//在OpenCV中加载模型要通过readNetWork,//readNet函数有三个参数,参数1加载网络(caffe、TensorFlow等),参数2,权重路径,参数3,描述文件//或者readNetFromCaffe(TensorFlow、darknet、ONNX等),意思为读进来的必须是caffe模型,此外还支持TensorFlow等模型,只有两个参数//还有readNetFromModelOptimizer从dnn模型优化器中读取模型优化后的模型Net net = readNetFromCaffe(protxt, bin_model);vector<string> layer_names = net.getLayerNames();		//此时我们就可以获取所有层的名称了,有了这些可以将其ID取出for (int i = 0; i < layer_names.size(); i++) {int id = net.getLayerId(layer_names[i]);			//通过name获取其idauto layer = net.getLayer(id);						//通过id获取layerprintf("layer id:%d,type:%s,name:%s\n", id, layer->type.c_str(), layer->name.c_str());	//将每一层的id,类型,姓名打印出来(可以明白此网络有哪些结构信息了)}waitKey(0);return 0;
}

在这里插入图片描述
在这里插入图片描述

我们知道这个网络有142层,Convolution卷积层,relu激活函数,pooling池化层,此时就搞清楚网络结构了

现在去搞其他的网络的层等信息也就清楚了

3.5 计算后台设置

//设置计算后台(OpenCVdnn模块支持设置不同的计算后台和在不同的设备上进行)net.setPreferableBackend(DNN_BACKEND_OPENCV);				//setPreferableBackend实际计算后台,default默认是DNN_BACKEND_OPENCV作为计算后台,使用此就行(也有加速后台ENGINE)net.setPreferableTarget(DNN_TARGET_CPU);						//设置在什么设备上进行计算(opencl(需要有interl图形卡)、FPGA、CPU)//当上面两个设置之后,他在执行网络进行推算时就会执行此计算后台进行计算(不同的计算后台有不同的效果,速度也有差别)

本节课学习了如何加载一个网络,此网络是Googlenet的,下节会讲如何使用此网络实现图像的分类预测

3.6 所有代码

#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>			//包含dnn模块的头文件
#include <iostream>using namespace cv;
using namespace cv::dnn;			//包含dnn的命名空间
using namespace std;int main() {string bin_model = "D:/OpenCV/project/opencv_tutorial-master/data/models/googlenet/bvlc_googlenet.caffemodel";		//定义模型权重文件的加载路径string protxt = "D:/OpenCV/project/opencv_tutorial-master/data/models/googlenet/bvlc_googlenet.prototxt";			//定义模型描述文件的加载路径//Imagenet支持1000个分类,分类类别在classification_classes_ILSVRC2012.txt可以看到,一直到1000//有了模型的权重和描述文件就可以加载模型了//在OpenCV中加载模型要通过readNetWork,//readNet函数有三个参数,参数1加载网络(caffe、TensorFlow等),参数2,权重路径,参数3,描述文件//或者readNetFromCaffe(TensorFlow、darknet、ONNX等),意思为读进来的必须是caffe模型,此外还支持TensorFlow等模型,只有两个参数//还有readNetFromModelOptimizer从dnn模型优化器中读取模型优化后的模型Net net = readNetFromCaffe(protxt, bin_model);//设置计算后台(OpenCVdnn模块支持设置不同的计算后台和在不同的设备上进行)net.setPreferableBackend(DNN_BACKEND_OPENCV);				//setPreferableBackend实际计算后台,default默认是DNN_BACKEND_OPENCV作为计算后台,使用此就行(也有加速后台ENGINE)net.setPreferableTarget(DNN_TARGET_CPU);						//设置在什么设备上进行计算(opencl(需要有interl图形卡)、FPGA、CPU)//当上面两个设置之后,他在执行网络进行推算时就会执行此计算后台进行计算(不同的计算后台有不同的效果,速度也有差别)//获取各层信息vector<string> layer_names = net.getLayerNames();		//此时我们就可以获取所有层的名称了,有了这些可以将其ID取出for (int i = 0; i < layer_names.size(); i++) {int id = net.getLayerId(layer_names[i]);			//通过name获取其idauto layer = net.getLayer(id);						//通过id获取layerprintf("layer id:%d,type:%s,name:%s\n", id, layer->type.c_str(), layer->name.c_str());	//将每一层的id,类型,姓名打印出来(可以明白此网络有哪些结构信息了)}waitKey(0);return 0;
}

4-图像分类网络inception的使用

池化层降维,卷积层提取特征,
利用已经训练好的模型在OpenCV中进行离线的调用

之前加载caffe模型,各个层次读取
图像分类识别
在这里插入图片描述
在这里插入图片描述

此图像分类模型主要来自谷歌,在CVPR2015发表
与之前的相比发表了inception模型

此模型可以对1000个类别进行分类
在这里插入图片描述

在OpenCV官方网站有关于模型中通道是BGR还是RGB的说明
https://github.com/opencv/opencv/wiki/Deep-Learning-in-OpenCV

https://github.com/opencv/opencv/blob/master/samples/dnn/models.yml
有个配置文件,配置说明文件,就说了各个模型调用的时候有哪些需要输入的参数。通过此模型给出的参数 进行设置

Googlenet是RGB的通道顺序
最后一层是softmax
基于imagenet数据集的
它的类有
D:\OpenCV\project\opencv_tutorial-master\data\models\googlenet中的
classification_classes_ILSVRC2012.txt

构建输入可以参考OpenCV自带的配置文件,根据此文件进行构建输入
D:\OpenCV\opencv-4.4.0-vc14_vc15\opencv\sources\samples\dnn\models.yml
打开文件可以看到,上方链接为模型的下载链接,下方参数为构建输入,进行图像预处理时的参数
在这里插入图片描述

当我们需要继续对其分类时

#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>			//包含dnn模块的头文件
#include <iostream>using namespace cv;
using namespace cv::dnn;			//包含dnn的命名空间
using namespace std;int main() {string bin_model = "D:/OpenCV/project/opencv_tutorial-master/data/models/googlenet/bvlc_googlenet.caffemodel";		//定义模型权重文件的加载路径string protxt = "D:/OpenCV/project/opencv_tutorial-master/data/models/googlenet/bvlc_googlenet.prototxt";			//定义模型描述文件的加载路径//Imagenet支持1000个分类,分类类别在classification_classes_ILSVRC2012.txt可以看到,一直到1000//有了模型的权重和描述文件就可以加载模型了//在OpenCV中加载模型要通过readNetWork,//readNet函数有三个参数,参数1加载网络(caffe、TensorFlow等),参数2,权重路径,参数3,描述文件//或者readNetFromCaffe(TensorFlow、darknet、ONNX等),意思为读进来的必须是caffe模型,此外还支持TensorFlow等模型,只有两个参数//还有readNetFromModelOptimizer从dnn模型优化器中读取模型优化后的模型Net net = readNetFromCaffe(protxt, bin_model);//设置计算后台(OpenCVdnn模块支持设置不同的计算后台和在不同的设备上进行)net.setPreferableBackend(DNN_BACKEND_OPENCV);				//setPreferableBackend实际计算后台,default默认是DNN_BACKEND_OPENCV作为计算后台,使用此就行(也有加速后台ENGINE)net.setPreferableTarget(DNN_TARGET_CPU);						//设置在什么设备上进行计算(opencl(需要有interl图形卡)、FPGA、CPU)//当上面两个设置之后,他在执行网络进行推算时就会执行此计算后台进行计算(不同的计算后台有不同的效果,速度也有差别)//获取各层信息vector<string> layer_names = net.getLayerNames();		//此时我们就可以获取所有层的名称了,有了这些可以将其ID取出for (int i = 0; i < layer_names.size(); i++) {int id = net.getLayerId(layer_names[i]);			//通过name获取其idauto layer = net.getLayer(id);						//通过id获取layerprintf("layer id:%d,type:%s,name:%s\n", id, layer->type.c_str(), layer->name.c_str());	//将每一层的id,类型,姓名打印出来(可以明白此网络有哪些结构信息了)//printf("name2:%s\n", layer_names[i].c_str());}Mat src = imread("G:/OpenCV/opencv笔记所用图片/plane.jpg");imshow("src", src);因为googlenet的通道类型是RGB通道的,而OpenCVread读取的是BGR通道的,要进行通道转换(实际在后面的blobFromImage就能进行通道转换,此处无需转换)//Mat rgb;	//cvtColor(src, rgb, COLOR_BGR2RGB);//构建输入//使用blobFromImage函数对单张图像进行预处理,使其符合网络的输入//对于网络来说原始输入层的时候都有指定的输入大小int w = 224;int h = 224;
Mat inputBlob = blobFromImage(src, 1.0, Size(w, h),Scalar(104, 117, 123), false,false);	//我们要将图像resize成224*224的才是我们神经网络可以接受的宽高//参数1:输入图像,参数2:默认1.0表示0-255范围的,参数3:设置输出的大小,参数4:均值对所有数据中心化预处理,参数5:是否进行通道转换,参数6:,参数7:默认深度为浮点型//设置输入//前面已经将图像预处理完成,就可以执行分类了//现在要将其输入到创建的网络中net.setInput(inputBlob);//进行推断得到输出//让网络执行得到output,调用forward可以得到一个结果//此处不给参数,得到的是最后一层的结果,也可以输入层数得到任何一层的输出结果Mat probMat = net.forward();	//通过前面的输出层看最后一层,可以知道输出100个分类,每个分类的得分是多少//softmax层出来的总和为1,找到max值对应的index就知道对应的分类了,在classification_classes_ILSVRC2012.txt可以知道具体名称//上方得到的probMat是1000*1*1(有imagewatch得到)//要解析输出(forward得到的)//对数据进行序列化(变成1行n列的,可以在后面进行方便的知道是哪个index了)Mat prob = probMat.reshape(1, 1);		//reshape函数可以进行序列化,(输出为1通道1行的数据,参数1:1个通道,参数2:1行)将输出结果变成1行n列的,但前面probMat本身就是1000*1*1//实际结果probMat和prob相同//当其他网络probMat需要序列化的时候,reshape就可以了//此时找到最大的那个Point classNum;double classProb;minMaxLoc(prob, NULL, &classProb, NULL, &classNum);//此时只获取最大值及最大值位置,最小值不管他int index = classNum.x;		//此时得到的是最大值的列坐标。就是其类的索引值,就可以知道其类名了printf("\n current index=%d,possible:%2f\n",index,classProb);	// current index=812,possible:0.999675,用editplus打开classification_classes_ILSVRC2012.txt,找到第813行(因为812+1)就是结果//这样自己在classification_classes_ILSVRC2012.txt找答案挺麻烦的,我们使用程序打开此文件,得到类名即可waitKey(0);return 0;
}

5-读取分类标签文件显示分类

一般对于自然场景的图像可以进行较精确的分类,利于后期图像查找等

输出层解析:主要讲其变为我们能接收的对象,找出最大可能性及其对于index
标签匹配:读入txt文件使其与index一一对应,最终得到类名

#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>			//包含dnn模块的头文件
#include <iostream>
#include <fstream>				//文件流进行txt文件读取using namespace cv;
using namespace cv::dnn;			//包含dnn的命名空间
using namespace std;vector<string> readLabels();		//将类名的txt文件读取到容器中int main() {string bin_model = "D:/OpenCV/project/opencv_tutorial-master/data/models/googlenet/bvlc_googlenet.caffemodel";		//定义模型权重文件的加载路径string protxt = "D:/OpenCV/project/opencv_tutorial-master/data/models/googlenet/bvlc_googlenet.prototxt";			//定义模型描述文件的加载路径//Imagenet支持1000个分类,分类类别在classification_classes_ILSVRC2012.txt可以看到,一直到1000vector<string> names = readLabels();		//使用自定义函数读取特定文件中的类名到names中,在后面输出对应名称时会用到//有了模型的权重和描述文件就可以加载模型了//在OpenCV中加载模型要通过readNetWork,//readNet函数有三个参数,参数1加载网络(caffe、TensorFlow等),参数2,权重路径,参数3,描述文件//或者readNetFromCaffe(TensorFlow、darknet、ONNX等),意思为读进来的必须是caffe模型,此外还支持TensorFlow等模型,只有两个参数//还有readNetFromModelOptimizer从dnn模型优化器中读取模型优化后的模型Net net = readNetFromCaffe(protxt, bin_model);//设置计算后台(OpenCVdnn模块支持设置不同的计算后台和在不同的设备上进行)net.setPreferableBackend(DNN_BACKEND_OPENCV);				//setPreferableBackend实际计算后台,default默认是DNN_BACKEND_OPENCV作为计算后台,使用此就行(也有加速后台ENGINE)net.setPreferableTarget(DNN_TARGET_CPU);						//设置在什么设备上进行计算(opencl(需要有interl图形卡)、FPGA、CPU)//当上面两个设置之后,他在执行网络进行推算时就会执行此计算后台进行计算(不同的计算后台有不同的效果,速度也有差别)//获取各层信息vector<string> layer_names = net.getLayerNames();		//此时我们就可以获取所有层的名称了,有了这些可以将其ID取出for (int i = 0; i < layer_names.size(); i++) {int id = net.getLayerId(layer_names[i]);			//通过name获取其idauto layer = net.getLayer(id);						//通过id获取layerprintf("layer id:%d,type:%s,name:%s\n", id, layer->type.c_str(), layer->name.c_str());	//将每一层的id,类型,姓名打印出来(可以明白此网络有哪些结构信息了)//printf("name2:%s\n", layer_names[i].c_str());}Mat src = imread("G:/OpenCV/opencv笔记所用图片/plane.jpg");imshow("src", src);因为googlenet的通道类型是RGB通道的,而OpenCVread读取的是BGR通道的,要进行通道转换(实际在后面的blobFromImage就能进行通道转换,此处无需转换)//Mat rgb;	//cvtColor(src, rgb, COLOR_BGR2RGB);//构建输入//使用blobFromImage函数对单张图像进行预处理,使其符合网络的输入//对于网络来说原始输入层的时候都有指定的输入大小int w = 224;int h = 224;Mat inputBlob = blobFromImage(src, 1.0, Size(w, h),Scalar(104, 117, 123), false,false);	//我们要将图像resize成224*224的才是我们神经网络可以接受的宽高//参数1:输入图像,参数2:默认1.0表示0-255范围的,参数3:设置输出的大小,参数4:均值对所有数据中心化预处理,参数5:是否进行通道转换,参数6:,参数7:默认深度为浮点型//设置输入//前面已经将图像预处理完成,就可以执行分类了//现在要将其输入到创建的网络中net.setInput(inputBlob);//进行推断得到输出//让网络执行得到output,调用forward可以得到一个结果//此处不给参数,得到的是最后一层的结果,也可以输入层数得到任何一层的输出结果Mat probMat = net.forward();	//通过前面的输出层看最后一层,可以知道输出100个分类,每个分类的得分是多少//softmax层出来的总和为1,找到max值对应的index就知道对应的分类了,在classification_classes_ILSVRC2012.txt可以知道具体名称//上方得到的probMat是1000*1*1(有imagewatch得到)//要解析输出(forward得到的)//对数据进行序列化(变成1行n列的,可以在后面进行方便的知道是哪个index了)Mat prob = probMat.reshape(1, 1);		//reshape函数可以进行序列化,(输出为1通道1行的数据,参数1:1个通道,参数2:1行)将输出结果变成1行n列的,但前面probMat本身就是1000*1*1//实际结果probMat和prob相同//当其他网络probMat需要序列化的时候,reshape就可以了//此时找到最大的那个Point classNum;double classProb;minMaxLoc(prob, NULL, &classProb, NULL, &classNum);//此时只获取最大值及最大值位置,最小值不管他int index = classNum.x;		//此时得到的是最大值的列坐标。就是其类的索引值,就可以知道其类名了printf("\n current index=%d,possible:%2f,name=%s\n",index,classProb,names[index].c_str());	// current index=812,possible:0.999675,用editplus打开classification_classes_ILSVRC2012.txt,找到第813行(因为812+1)就是结果//这样自己在classification_classes_ILSVRC2012.txt找答案挺麻烦的,我们使用程序打开此文件,得到类名即可//此时可以将名称打印到图片上去putText(src, names[index].c_str(), Point(50, 50), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 0, 255), 2, 8);imshow("result", src);waitKey(0);return 0;
}vector<string> readLabels() {string label_map_txt = "D:/OpenCV/project/opencv_tutorial-master/data/models/googlenet/classification_classes_ILSVRC2012.txt";vector<string> classNames;ifstream fp(label_map_txt);if (!fp.is_open()) {printf("could not find the file \n");exit(-1);}std::string name;while (!fp.eof()) {		//当没有结束时就一直读取getline(fp, name);	//每次读取一行if (name.length()) {classNames.push_back(name);}}fp.close();		//关闭文件输入流return classNames;
}

6-对象检测网络介绍

前面学习了如何通过DNN实现图像的分类,
图像分类的预训练模型googlenet,哪些层,输入,输出哪些看到
怎么去set到网络中,forward得到输出,可以forward任意一层,默认最后一层

对网络进行加载,相关后台设备,网络分类。

OpenCV的DNN模块只能进行推理,不能执行训练,训练是有各个深度学习的框架完成的,
这节课学习对象检测模型。

在计算机视觉中对象检测,常见模型及其输出层格式不同。

对象检测模型进行应用的代码演示。
在这里插入图片描述

前面的是分类,现在要检测:

图像的分类加对象位置信息就是对象检测
在这里插入图片描述

前面的googlenet只是得到分类信息就可以了

而检测还需要得到位置信息,长宽高等位置,得到位置信息再进行矩形
Image classification 图像分类
Object detection 对象检测
在这里插入图片描述

这些模型都有一些结构性的不同
在这里插入图片描述

卷积提取特征,RPN区域推荐网络,输出会产生很多ROI区域,可以对ROI区域分类,有了分类信息和位置信息

RCNN分类,位置回归,对象在什么位置,可能性是多少
在这里插入图片描述
在这里插入图片描述

SSD缺点,如果目标太小就检测不到了,对小物体检测效果不太好。

非最大抑制,可能会在不同的层次匹配到对象
在这里插入图片描述

SSD全是卷积的神经网络,训练,速度快,很多时候使用

YOLO也慢慢变成全卷积的网络了
在这里插入图片描述

Scale都是有阈值的,大于0.5的保留,小于的去掉

YOLOV3多尺度输出
在这里插入图片描述

YOLOV3输出的是其中心位置和宽高,解析方式与faster RCNN不同
在这里插入图片描述

YOLO最后一层的输出方式
11N7 N是多少张图,7个值,1,bumbox,index,scale,4个位置信息
1
1N(5+score) 矩形信息和得分

不同网络最后一层输出方式不同,代码使用也不同

7-SSD对象检测网络加载与执行

SSD一次就能检测出多个box
SSD基础网络不一样,导出权重大小不一样的离线模型文件
在这里插入图片描述

数据集都是室内常见的物体,书,车,人,狗等类别

得分越高,在此数据集的表现越好
在这里插入图片描述

Scale是2/255

上面是模型的相关介绍
在这里插入图片描述

推断预测,结果解析,
data就是参数层的名称

CV_WRAP void setInput(InputArray blob, const String& name = "",double scalefactor = 1.0, const Scalar& mean = Scalar());/** @brief Sets the new value for the learned param of the layer.*  @param layer name or id of the layer.*  @param numParam index of the layer parameter in the Layer::blobs array.*  @param blob the new value.*  @see Layer::blobs*  @note If shape of the new blob differs from the previous shape,*  then the following forward pass may fail.*/

Forward 最终输出层就是detection_out
detection_out这一层出来的就是117的

D:\OpenCV\opencv-4.4.0-vc14_vc15\opencv\sources\samples\dnn在其下方的moduls.yml文件中有关于各个模型的参数配置,
在这里插入图片描述
在这里插入图片描述

而其labelmap_det.txt文件中内容有点多,实际可以总结出
如下

String objNames[] = { "background",
"aeroplane","bicycle","bird","boat",
"bottle","bus","car","cat","chair",
"cow","diningtable","dog","horse",
"motorbike","person","pottedplant",
"sheep","sofa","train","tvmonitor" };

输入层就是data

获取的层信息发现,最后一层就是detection_out

在这里插入图片描述
在这里插入图片描述

8-SSD对象检测推理输出解释与显示

加载输入,解析输出,后面会有针对视频的对象检测

#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>			//包含dnn模块的头文件
#include <iostream>
#include <fstream>				//文件流进行txt文件读取using namespace cv;
using namespace cv::dnn;			//包含dnn的命名空间
using namespace std;String objNames[] = { "background",
"aeroplane","bicycle","bird","boat",
"bottle","bus","car","cat","chair",
"cow","diningtable","dog","horse",
"motorbike","person","pottedplant",
"sheep","sofa","train","tvmonitor" };int main() {string bin_model = "D:/OpenCV/project/opencv_tutorial-master/data/models/ssd/MobileNetSSD_deploy.caffemodel";		//定义模型权重文件的加载路径string protxt = "D:/OpenCV/project/opencv_tutorial-master/data/models/ssd/MobileNetSSD_deploy.prototxt";			//定义模型描述文件的加载路径//load DNN modelNet net = readNetFromCaffe(protxt, bin_model);//设置计算后台(OpenCVdnn模块支持设置不同的计算后台和在不同的设备上进行)net.setPreferableBackend(DNN_BACKEND_OPENCV);				//setPreferableBackend实际计算后台,default默认是DNN_BACKEND_OPENCV作为计算后台,使用此就行(也有加速后台ENGINE)net.setPreferableTarget(DNN_TARGET_CPU);						//设置在什么设备上进行计算(opencl(需要有interl图形卡)、FPGA、CPU)//获取各层信息vector<string> layer_names = net.getLayerNames();		//此时我们就可以获取所有层的名称了,有了这些可以将其ID取出for (int i = 0; i < layer_names.size(); i++) {int id = net.getLayerId(layer_names[i]);			//通过name获取其idauto layer = net.getLayer(id);						//通过id获取layerprintf("layer id:%d,type:%s,name:%s\n", id, layer->type.c_str(), layer->name.c_str());	//将每一层的id,类型,姓名打印出来(可以明白此网络有哪些结构信息了)}Mat src = imread("G:/OpenCV/opencv笔记所用图片/gou.jpg");	//planeif (src.empty()) {cout << "could not load image.." << endl;getchar();return -1;}imshow("src", src);//构建输入(根据models.yml)Mat blob = blobFromImage(src, 0.007843, Size(300, 300), Scalar(127.5, 127.5, 127.5), false, false);	//交换通道false,是否剪切falsenet.setInput(blob, "data");		//输入层名称就是data,通过描述文件也可以看到输入层名称//推测结果Mat detection = net.forward("detection_out");	//将名称为detection_out的层的结果返回,不输入名称默认也是返回最后一层,输入可以返回特定层的结果//上方得到的detection宽高为0(使用imagewatch查看,原因是其为tensen,它的宽高维度等信息都存在size结构中,所以要在下方通过size获取)//重新定义一个Mat对象接收Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());		//此处是初始化一个行为size[2],列为size[3]大小,深度为浮点型,数据从detection中获取//使用imagewatch可以看到7*100的数组,单通道32F深度//获取浮点型数据后就可以进行数据的解析了float confidence_threshold = 0.5;		//在后面通过此判断合适的结果进行保存//解析输出数据//上方获取的detectionMat是100行,7列的,每行对应一个对象//输出结果[1x1xNx7], 其中输出的七个维度浮点数如下://[image_id, label, conf, x_min, y_min, x_max, y_max]for (int i = 0; i < detectionMat.rows; i++) {float score = detectionMat.at<float>(i, 2);			//此处获取的是conf(i, 2),也就是得分if (score > confidence_threshold) {					//如果获取的score大于0.5,就将box保存,不要扔掉size_t objIndex = (size_t)(detectionMat.at<float>(i, 1));		//此处获取的是label(i, 2),就是索引//得到四个点的矩形框位置float tl_x = detectionMat.at<float>(i, 3)*src.cols;		//x_min(此处detectionMat.at<float>(i, 3)得到的是一个图像的比例值不是真实值,需要变换)float tl_y = detectionMat.at<float>(i, 4)*src.rows;		//y_minfloat br_x = detectionMat.at<float>(i, 5)*src.cols;		//x_maxfloat br_y = detectionMat.at<float>(i, 6)*src.rows;		//y_max//得到boxRect box((int)tl_x, (int)tl_y, (int)br_x - tl_x, (int)br_y - tl_y);//画矩形rectangle(src, box, Scalar(0, 0, 255), 2, 8, 0);//写文字(在box的做上角写文字)putText(src, format("score:%2f,%s",score,objNames[objIndex].c_str()), box.tl(), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(255, 0, 0), 2, 8);}}imshow("ssd-detection-demo", src);waitKey(0);return 0;
}

9-Faster RCNN对象检测模型使用

前面是SSD对象检测网络实现离线运行进行检测

加载模型,推理,输出,解析,输出格式是11N*7
至于网络中间部分训练时会关心,而推测评估时,只需知道输入输出,解析输出结果即可,
也可以获取卷积各层信息

Faster-RCNN是TensorFlow对象检测,TensorFlow object API

怎么将TensorFlow支持的对象拿出来
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一定不要将其拷贝代码

将下载的描述文件复制到此文件目录下
在这里插入图片描述

上面的很多网络都是来自TensorFlow的预训练框架,已经训练好了,只需要将其权重及描述文件下载下来即可离线使用
点击进入,点击row另存为,不要拷贝会破坏格式。

本处下载的是faster-RCNN resnet50的权重文件及配置文件

下载的配置文件,后缀会有.txt, 重命名将多余的.txt删除

解决无法打开RAW的问题

Windows上可以这样办:
上https://www.ipaddress.com查一下raw.githubusercontent.com的ipv4地址,比如我现在查到的是199.232.68.133。
使用管理员权限打开C:\Windows\System32\drivers\etc\hosts文件,添加到最后一行

199.232.68.133 raw.githubusercontent.com 

或者管理员权限开或者给个用户写入权限。然后差不多就行了,可能要重启。不过本人使用editplus将其打开并输入后再打开raw.githubusercontent.com就成功了。
在这里插入图片描述

D:\OpenCV\project\opencv_tutorial-master\data\models\mscoco_label_map.pbtxt
数据集的类名有80个,在上面的文件内

80个类别定义数组太麻烦,直接采用读取读取.pbtxt文件的方式将类名导入进来
在这里插入图片描述

上面的格式
在这里插入图片描述

D:\OpenCV\project\opencv_tutorial-master\data\models\TensorFlow\faster_rcnn_resnet50_coco_2018_01_28
frozen_inference_graph.pb
faster_rcnn_resnet50_coco_2018_01_28.pbtxt

在这里插入图片描述

有时检测对象不多,将confidence值调低一些如0.5变为0.3如下所示可以检测出(但可能有些出错,一般以0.5即可)
在这里插入图片描述

此网络模型要比SSD耗时多

10-YOLOv3对象检测模型推理使用

Faster-RCNN来自TensorFlow的object detection即对象检测框架,此框架也有其他的对象检测网络,可以也被OpenCV4的DNN模块接收,并且数据设置与faster-RCNN类似

SSD来自caffe
Faster-RCNN来自TensorFlow
YOLO来自darknet框架,是C语言的框架,主要为YOLO服务
在这里插入图片描述

COCO数据集支持80个分类
常用的物体基本在其内

配置文件与权重
https://pjreddie.com/darknet/yolo/
在这里插入图片描述

YOLOV3-416 表示宽高416

YOLO有多个输出层,不像faster-RCNN、SSD只有一个输出层

YOLO有多个输出层,在这个层发现,另一个层也发现了,需要调用NMS将所有输出层结果合并
在这里插入图片描述
在这里插入图片描述

输出
NMS去掉重复box
Yolo有几个输出层,可能在好几个层都检测到了然后输出

NMS
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>			//包含dnn模块的头文件
#include <iostream>
#include <fstream>				//文件流进行txt文件读取using namespace cv;
using namespace cv::dnn;			//包含dnn的命名空间
using namespace std;string label_map = "D:/OpenCV/project/opencv_tutorial-master/data/models/YOLO3/object_detection_classes_yolov3.txt";int main() {string weight_file = "D:/OpenCV/project/opencv_tutorial-master/data/models/YOLO3/yolov3.weights";		//定义模型权重文件的加载路径string cfg_file = "D:/OpenCV/project/opencv_tutorial-master/data/models/YOLO3/yolov3.cfg";			//定义模型描述文件的加载路径//load DNN modelNet net = readNetFromDarknet(cfg_file, weight_file);vector<String> outNames = net.getUnconnectedOutLayersNames();	//获取多个输出层for (int k = 0; k < outNames.size(); k++) {printf("output layer name:%s \n", outNames[k].c_str());}//设置计算后台(OpenCVdnn模块支持设置不同的计算后台和在不同的设备上进行)net.setPreferableBackend(DNN_BACKEND_OPENCV);				//setPreferableBackend实际计算后台,default默认是DNN_BACKEND_OPENCV作为计算后台,使用此就行(也有加速后台ENGINE)net.setPreferableTarget(DNN_TARGET_CPU);						//设置在什么设备上进行计算(opencl(需要有interl图形卡)、FPGA、CPU)//获取各层信息vector<string> layer_names = net.getLayerNames();		//此时我们就可以获取所有层的名称了,有了这些可以将其ID取出for (int i = 0; i < layer_names.size(); i++) {int id = net.getLayerId(layer_names[i]);			//通过name获取其idauto layer = net.getLayer(id);						//通过id获取layerprintf("layer id:%d,type:%s,name:%s\n", id, layer->type.c_str(), layer->name.c_str());	//将每一层的id,类型,姓名打印出来(可以明白此网络有哪些结构信息了)}Mat src = imread("G:/OpenCV/opencv笔记所用图片/gou.jpg");	//planeif (src.empty()) {cout << "could not load image.." << endl;getchar();return -1;}imshow("src", src);Mat blob = blobFromImage(src, 0.00392, Size(416, 416), Scalar(), true, false);net.setInput(blob);//推理输出vector<Mat> outs;net.forward(outs, layer_names);	//将三个输出层的结果都得到vector<Rect> boxes;		//三个输出层的box信息接收vector<int> classIds;	//接收三个类的信息vector<float> confidences;	//接收三个得分信息for (int i = 0; i < outs.size(); i++) {//开始解析每个输出blobfloat *data = (float*)outs[i].data;for (int j = 0; j < outs[i].rows; j++,data+=outs[i].cols) {			//加入data+=outs[i].cols是为了跳到下一行去,data相当于指针,指针到下一行使用此种方式Mat scores = outs[i].row(j).colRange(5, outs[i].cols);Point classIdPoint;double confidence;minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);//[C, center_x, center_y, width, height]if (confidence > 0.5) {int centerx = (int)(data[0] * src.cols);int centery = (int)(data[1] * src.rows);int width = (int)(data[2] * src.cols);int height = (int)(data[3] * src.rows);int left = centerx - width / 2;int top = centery - height / 2;classIds.push_back(classIdPoint.x);boxes.push_back(Rect(left, top, width, height));rectangle(src, Rect(left, top, width, height), Scalar(0, 0, 255), 2, 8);}}}imshow("result", src);waitKey(0);return 0;
}

发现有多个框,这是没有做非最大抑制出现的。
OpenCVDNN模块已经提供了非最大抑制的API

Yolov3tiny 也可以尝试一下,速度较快,只有30M左右,精度较低
但对于实时性较高的场景,还是不错的

NMS可以去掉重复的检测框,但需要调试,根据结果选择调试

11-OpenCV DNN配置加速组件IE支持

代码演示部分,每层都有box框

对象检测,图像分类都用了,但他们的速度太慢

使用IE加速我们对模块的推理

英特尔发布的深度学习加速工具包,开源的
其中最重要的组件有IE

• OpenVINO中的IE加速组件介绍
• 设置IE为计算后台,加速执行
• 代码演示
注意在官方下载的是无加速的,需要自己编译,才能得到支持OpenCV版本的,此种方式较麻烦

我们无需编译,只需要安装openVINO就可以得到一个支持IE加速的版本

OpenVINO中的IE加速组件介绍
• 下载与安装IE支持的OpenCV版本
• 重新配置OpenCV
• 安装依赖(VS2015/VS2017+CMake3.14+Python3.6.5)
• https://software.intel.com/en-us/openvino-toolkit/choose-download

注意要有CMAKE3.14,的环境变量要配置,python3.6.5也要配置到环境变量中去
在这里插入图片描述

注意openvino只会从默认的安装目录去找,所以前面的不要自定义安装,默认安装即可

OpenCVvino路径是可以改的,可以改到
将OpenCVvino中的OpenCV的lib,include等配置好

C:\Program Files (x86)\IntelSWTools\openvino_2020.4.287

只有通过OpenCVvino安装好后,才可以设置计算后台如下,否则会报错
net.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE);
net.setPreferableTarget(DNN_TARGET_CPU);

可能对图片时,发现无法明显加速,前期是在加载模型,初始化权重方法,但一旦推断forward速度就会非常快
在这里插入图片描述

前面的caffe、TensorFlow、mxnet等平台的离线模型都可以通过OpenCV的DNN模块加载,加载开始计算时使用OpenCVDNN作为加载后台,现在有了opencvvino,就可以使用inference ENgine作为后台支持,而此后台又支持CPU\GPU\VPU加速,英伟达的GPU天生不支持,支持的是英特尔的图形卡的计算方式,如果想要支持需要自己想办法编译。
获得优化后可以得到5到10倍的加速,一秒钟可能5帧,现在就25帧了

代码实现
• 设置IE为计算后台
• 加速执行
• 支持网络与模型
• 关于转换IR与更多知识…

安装完成后需要测验一下

加速组件

https://cmake.org/files/v3.14/
https://www.python.org/downloads/release/python-365/

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意cmake和python3.6.5要默认路径安装,
Openvino可以更改路径安装
下面的路径就是推算引擎
C:\Program Files (x86)\IntelSWTools\openvino_2020.4.287\inference_engine

我们的是debug模式,要将下方的路径添加到环境变量
C:\Program Files (x86)\IntelSWTools\openvino_2020.4.287\inference_engine\bin\intel64\Debug

此处有OpenCV
C:\Program Files (x86)\IntelSWTools\openvino_2020.4.287\opencv
之前如何配置这里就怎么配置
OpenCV配置好后,此处就可以使用了

如何检测是否安装好了
C:\Program Files (x86)\IntelSWTools\openvino_2020.4.287\deployment_tools\demo
进入文件下,双击运行demo_security_barrier_camera.bat
等到最后弹出车牌检测图,说明所有安装都没有问题

在这里插入图片描述

使用openvino的OpenCV的属性配置,看能否
net.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE);运行。

opencv_calib3d440d.lib
opencv_core440d.lib
opencv_dnn440d.lib
opencv_features2d440d.lib
opencv_flann440d.lib
opencv_gapi440d.lib
opencv_highgui440d.lib
opencv_imgcodecs440d.lib
opencv_imgproc440d.lib
opencv_ml440d.lib
opencv_objdetect440d.lib
opencv_photo440d.lib
opencv_stitching440d.lib
opencv_video440d.lib
opencv_videoio440d.libinference_engine_c_apid.lib
inference_engine_ir_readerd.lib
inference_engine_legacyd.lib
inference_engine_lp_transformationsd.lib
inference_engine_onnx_readerd.lib
inference_engine_preprocd.lib
inference_engine_transformationsd.lib
inference_engined.lib

这篇关于OpenCV4深度神经网络DNN实战教程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1113283

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}

滚雪球学Java(87):Java事务处理:JDBC的ACID属性与实战技巧!真有两下子!

咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE啦,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~ 🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!! 环境说明:Windows 10

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(五):Blender锥桶建模

前言 本系列教程旨在使用UE5配置一个具备激光雷达+深度摄像机的仿真小车,并使用通过跨平台的方式进行ROS2和UE5仿真的通讯,达到小车自主导航的目的。本教程默认有ROS2导航及其gazebo仿真相关方面基础,Nav2相关的学习教程可以参考本人的其他博客Nav2代价地图实现和原理–Nav2源码解读之CostMap2D(上)-CSDN博客往期教程: 第一期:基于UE5和ROS2的激光雷达+深度RG

韦季李输入法_输入法和鼠标的深度融合

在数字化输入的新纪元,传统键盘输入方式正悄然进化。以往,面对实体键盘,我们常需目光游离于屏幕与键盘之间,以确认指尖下的精准位置。而屏幕键盘虽直观可见,却常因占据屏幕空间,迫使我们在操作与视野间做出妥协,频繁调整布局以兼顾输入与界面浏览。 幸而,韦季李输入法的横空出世,彻底颠覆了这一现状。它不仅对输入界面进行了革命性的重构,更巧妙地将鼠标这一传统外设融入其中,开创了一种前所未有的交互体验。 想象