OpenCv-C++-深度神经网络(DNN)模块-使用SSD模型实现对象检测

版权声明:本文为博主原创文章,转载请附上博文链接! https://blog.csdn.net/Daker_Huang/article/details/86740019

首先我们要搞明白图像分类和对象检测的区别:
1、图像分类:
在这里插入图片描述
图像分类就是将这幅图像归为某一类,图像中的对象尽量要单一。
2、对象检测:
在这里插入图片描述
对象检测就是将不同的对象用框圈出来并规定为某一类,对象可以多个。
首先需要下载SSD模型,可以去github上下载,也可以使用自己训练的模型,这里我使用官网训练的caffe模型。
在这里插入图片描述
在这里插入图片描述
一个是二进制模型文件,一个是描述文件。这两个文件可以在这里下载:https://download.csdn.net/download/daker_huang/10960936
我们来看看描述文件,它的开头是这样的:
在这里插入图片描述
可以看到,该模型所需要的图像文件的维度是3通道,300*300的大小,所以我们先来定义一下宽高:

const size_t width = 300;
const size_t height = 300;//定义图像文件宽高

从上面的文件中我们可以知道ssd模型接受的图像文件是3通道的,这里需要将图像通道数转成3通道的:

Mat frame;
src.copyTo(frame);
if (frame.channels() == 4)
	{
		cvtColor(frame, frame, COLOR_BGRA2BGR);//将4通道转为3通道
	}

	if (frame.channels() == 1)
	{
		cvtColor(frame, frame,COLOR_GRAY2BGR );//将单通道转为3通道

	}

OpenCv-C++ -深度神经网络(DNN)模块-使用goolenet模型实现图像分类中读caffe模型使用的是dnn模块中的"readNet",在这篇文章中,依旧使用dnn模块中的"readNet"读取caffe模型。

string deploy_file = "D:/test/ssd/deploy.prototxt";  //读取描述文件
string model_file = "D:/test/ssd/VGG_VOC0712Plus_SSD_300x300_iter_240000.caffemodel";//模型文件
......
Net net = readNetFromCaffe(deploy_file, model_file);

图片中检测输出的结果需要标注,而我们有标签文件,在一开始就已经导入:
在这里插入图片描述
这里放上标签文件:

0,0,background
5,1,aeroplane
2,2,bicycle
15,3,bird
9,4,boat
40,5,bottle
6,6,bus
3,7,car
16,8,cat
57,9,chair
20,10,cow
61,11,diningtable
17,12,dog
18,13,horse
4,14,motorbike
1,15,person
59,16,pottedplant
19,17,sheep
58,18,sofa
7,19,train
63,20,tvmonitor

这里总共21种分类物体,不多,其实我们可以把每行英文名称前面的两个数字去掉,但是如果比较多就行不通了。这里我们用定义一个函数读取每行的英文名称:

vector<String> labels()
  {
	vector<String>objNames;
	
	
	ifstream fp(label_file);//打开输入流,读入文件
	if (!fp.is_open())
	{
		printf("文件读入失败!!!\n");
		exit(-1);//直接退出

	}
	string name;//标签文件中都有对应的名字
	while (!fp.eof())//当文件没有读到结尾
	{
		getline(fp, name);//读取每一行
		if (name.length())
		{
			string temp1 = name.substr(name.find(",") + 1);   //找到每行第一个逗号,从逗号后面开始取数据
			string temp2 = temp1.substr(temp1.find(",") + 1);//找到新的(第二个)逗号,从逗号后面开始取数据
			objNames.push_back(temp2);
		}
	}
	/*for (vector<string>::iterator iter = objNames.begin(); iter != objNames.end(); ++iter)
	{
		//输出*iter才是输出那些字符串
		cout << *iter << endl;
	}*/
	return objNames;
}

对象检测并画框:

float confidence_threshold = 0.2;
	
	for (int i = 0; i < detectionMat.rows; i++)
	{
		float confidence = detectionMat.at<float>(i, 2);    //置信度
		if (confidence > confidence_threshold) {
			size_t objIndex = (size_t)(detectionMat.at<float>(i, 1));  //标签文件的索引号
			float tl_x = detectionMat.at<float>(i, 3) * frame.cols;  //矩形框左上横坐标点
			float tl_y = detectionMat.at<float>(i, 4) * frame.rows;  //矩形框左上纵坐标点
			float br_x = detectionMat.at<float>(i, 5) * frame.cols;  //矩形框右下横坐标点
			float br_y = detectionMat.at<float>(i, 6) * frame.rows;  //矩形框右下纵坐标点

			Rect object_box((int)tl_x, (int)tl_y, (int)(br_x - tl_x), (int)(br_y - tl_y));
			rectangle(frame, object_box, Scalar(0, 0, 255), 2, 8, 0);
			putText(frame, format("%s", objnames[objIndex].c_str()), Point(tl_x+1, tl_y+1),FONT_HERSHEY_PLAIN, 2.0, Scalar(255, 0, 0), 2);
		    // cout << objIndex << endl;
		

完整代码:

#include<opencv2/opencv.hpp>
#include<opencv2/dnn.hpp>
#include<iostream>

using namespace cv;
using namespace std;
using namespace cv::dnn;

const size_t width = 300;
const size_t height = 300;//定义图像文件宽高

vector<String> labels();

string label_file = "D:/test/ssd/labelmap.txt";
string deploy_file = "D:/test/ssd/deploy.prototxt";
string model_file = "D:/test/ssd/VGG_VOC0712Plus_SSD_300x300_iter_240000.caffemodel";



int main(int argc, char **argv)
{
	Mat src = imread("D:/test/dnn_ssd.jpeg.jpg");
	if (src.empty())
	{
	
		cout << "图像未找到!!!" << endl; 
		return -1;
	}
	vector<String>  objnames = labels();
	namedWindow("input image", WINDOW_AUTOSIZE);
	imshow("input image",src);
	Net net = readNetFromCaffe(deploy_file, model_file);
	Mat frame;
	src.copyTo(frame);
	if (frame.channels() == 4)
	{
		cvtColor(frame, frame, COLOR_BGRA2BGR);//将4通道转为3通道
	}

	if (frame.channels() == 1)
	{
		cvtColor(frame, frame,COLOR_GRAY2BGR );//将单通道转为3通道

	}
	
	Mat blob_Img = blobFromImage(frame, 1.0f, Size(width, height), Scalar(104, 117, 123), false, false);
	net.setInput(blob_Img, "data");//开始层
	Mat detection=net.forward("detection_out");//最后一层

	Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());
	/*
	detection.size[2]表示宽度
	detection.size[3]表示高度
	*/

	float confidence_threshold = 0.2;
	
	for (int i = 0; i < detectionMat.rows; i++)
	{
		float confidence = detectionMat.at<float>(i, 2);    //置信度
		if (confidence > confidence_threshold) {
			size_t objIndex = (size_t)(detectionMat.at<float>(i, 1));  //标签文件的索引号
			float tl_x = detectionMat.at<float>(i, 3) * frame.cols;  //矩形框左上横坐标点
			float tl_y = detectionMat.at<float>(i, 4) * frame.rows;  //矩形框左上纵坐标点
			float br_x = detectionMat.at<float>(i, 5) * frame.cols;  //矩形框右下横坐标点
			float br_y = detectionMat.at<float>(i, 6) * frame.rows;  //矩形框右下纵坐标点

			Rect object_box((int)tl_x, (int)tl_y, (int)(br_x - tl_x), (int)(br_y - tl_y));
			rectangle(frame, object_box, Scalar(0, 0, 255), 2, 8, 0);
			putText(frame, format("%s", objnames[objIndex].c_str()), Point(tl_x+1, tl_y+1),FONT_HERSHEY_PLAIN, 2.0, Scalar(255, 0, 0), 2);
		    //cout << objIndex << endl;
		}
	}
	imshow("output image", frame);

	waitKey(0);
	return 0;

}

vector<String> labels()
  {
	vector<String>objNames;
	
	
	ifstream fp(label_file);//打开输入流,读入文件
	if (!fp.is_open())
	{
		printf("文件读入失败!!!\n");
		exit(-1);//直接退出

	}
	string name;//标签文件中都有对应的名字
	while (!fp.eof())//当文件没有读到结尾
	{
		getline(fp, name);//读取每一行
		if (name.length())
		{
			string temp1 = name.substr(name.find(",") + 1);   //找到每行第一个逗号,从逗号后面开始取数据
			string temp2 = temp1.substr(temp1.find(",") + 1);//找到新的(第二个)逗号,从逗号后面开始取数据
			objNames.push_back(temp2);
		}
	}
	/*for (vector<string>::iterator iter = objNames.begin(); iter != objNames.end(); ++iter)
	{
		//输出*iter才是输出那些字符串
		cout << *iter << endl;
	}*/
	return objNames;
}

运行结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Daker_Huang/article/details/86740019