深度神经网络模型DNN--使用SSD模型实现目标检测

一、深度神经网络模型

  • openCV DNN支持的功能:图像分类、对象检测、图像分割、场景文字检测、人脸检测与识别

  • openCV DNN支持的对象检测网络:Faster-RCNN、SSD(VGG/mobile-net backbone)、YOLO(YOLOv3/YOLOv3-tiny/YOLOv4)

                输入------------------>黑盒------------------------>输出
    

二、OpenCV使用训练好的网络模型

三、SSD(Single Shot MultiBox Detector)

Opencv支持很多的深度学习框架,且有很多开源深度网络模型,以SSD模型为例:
MobileNetSSD_deploy.caffemodel

openCV支持的模型描述文件汇总:Site Unreachable

# Caffe implementation of SSD model from https://github.com/chuanqi305/MobileNet-SSD //模型来源地址
ssd_caffe:
load_info:
url: "https://drive.google.com/uc?export=download&id=0B3gersZ2cHIxRm5PMWRoTkdHdHc"
sha1: "994d30a8afaa9e754d17d2373b2d62a7dfbaaf7a"
model: "MobileNetSSD_deploy.caffemodel" //模型二进制文件名
config: "MobileNetSSD_deploy.prototxt"  //模型描述文件名 ,二者均在模型来源地址下载
mean: [127.5, 127.5, 127.5]
scale: 0.007843
width: 300
height: 300
rgb: false
classes: "object_detection_classes_pascal_voc.txt"
sample: "object_detection"

模型描述文件

name: "MobileNet-SSD"
input: "data" //输入层名称
input_shape {
    
     //输入参数格式
dim: 1 //每次接受一张图片
dim: 3 //三通道
dim: 300
dim: 300  //图像尺寸300*300
}
.....//中间省略网络各层描述
layer {
    
     
name: "detection_out"
type: "DetectionOutput"
bottom: "mbox_loc"
bottom: "mbox_conf_flatten"
bottom: "mbox_priorbox"
top: "detection_out"    //最后一层描述示例
include {
    
    
phase: TEST
}
detection_output_param {
    
    
num_classes: 21
share_location: true
background_label_id: 0
nms_param {
    
    
nms_threshold: 0.45
top_k: 100
}
  • 输入: [ 1 × 3 × 300 × 300 ] [ 1\times3\times300\times300] [1×3×300×300]
  • 输出: [ 1 × 1 × 100 × 7 ] [ 1\times1\times100\times7] [1×1×100×7] ,7对应的浮点数据如下:[image_id, label, conf, x_min, y_min, x_max, y_max]
  • 示例:

四、OpenCV网络使用流程

参考资料:OpenCv-C+±深度神经网络(DNN)模块-使用goolenet模型实现图像分类

1. 加载网络模型

openCV支持的模型描述文件:Site Unreachable

Net cv::dnn::readNet(const String& model, //模型的二进制文件
					 const String& config="", //模型的配置参数,通常在模型的voc文件夹下寻找
					 const String& framework="" //具体的框架名
					 )

2. 计算后端

OpenCV dnn module支持设置不同的计算后端,在指定目标设备上进行。

void cv::dnn::Net::setPreferableBackend(int backendId);
void cv::dnn::Net::setPreferableTarget(int targetId);

3. 构建输入

Mat cv::dnn::blobFromImage(InputArray image,
						   double scalefactor = 1.0,
						   const Size & size = Size(),
						   const Scalar & mean = Scalar(),
						   bool swapRB = false,
						   bool crop = false,
						   int ddepth = CV_32F 
						   )

4. 执行推理inference

Mat cv::dnn::Net::forward(const String& outputName=String())

5.解析输出

使用 detection函数

五、完整代码

参考资料:深度神经网络(DNN)之二(使用SSD进行对象检测)

#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>			//包含dnn模块的头文件
#include <iostream>

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 model
	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获取其id
		auto layer = net.getLayer(id);						//通过id获取layer
		printf("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");	//plane
	if (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,是否剪切false
	net.setInput(blob, "data");		//输入层名称就是data,通过描述文件也可以看到输入层名称

	//推测结果
	Mat detection = net.forward("detection_out");	//将名称为detection_out的层的结果返回,不输入名称默认也是返回最后一层,输入可以返回特定层的结果
	//上方得到的detection宽高为0(使用imagewatch查看,原因是其为tensor,它的宽高维度等信息都存在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_min
			float br_x = detectionMat.at<float>(i, 5)*src.cols;		//x_max
			float br_y = detectionMat.at<float>(i, 6)*src.rows;		//y_max
			//得到box
			Rect 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;
}

六、TensorFlow Object Detection API

上述介绍的是Caff框架下的SSD模型,同理亦可以使用TensorFlow框架下的模型如YOLO

猜你喜欢

转载自blog.csdn.net/weixin_43949950/article/details/126341068