OpenCV4学习笔记(62)——dnn模块之调用inception5h模型实现图像分类

本次笔记要整理的内容是:通过OpenCV的dnn模块来调用OpenCV自带的inception5h模型,并实现物体识别。该模型可识别的类别总共有1000类,包含动物、日常用品、交通工具等等,范围非常广泛。下面通过代码逐步整理。

首先,我们需要加载模型,并设置计算后台和目标设备。

	//加载opencv自带的tenserflow模型实现图像分类
	const string tf_net_model_path = "D:\\opencv_c++\\opencv_tutorial\\data\\models\\inception5h\\tensorflow_inception_graph.pb";
	const string labels_txt_path = "D:\\opencv_c++\\opencv_tutorial\\data\\models\\inception5h\\imagenet_comp_graph_label_strings.txt";
	//加载tf模型
	dnn::Net tf_net = dnn::readNetFromTensorflow(tf_net_model_path);
	tf_net.setPreferableBackend(DNN_BACKEND_OPENCV);			//设置计算后台,DNN_BACKEND_INFERENCE_ENGINE表示使用openVINO进行加速计算,但是一些模型上使用会报错;DNN_BACKEND_OPENCV表示使用opencv自带的dnn后台进行计算
	tf_net.setPreferableTarget(DNN_TARGET_CPU);		//设置计算目标设备
	if (tf_net.empty())
	{
		cout << "read model file fail" << endl;
	}

然后从文件中加载、并组织成可以索引类别的标签集。

	//读取分类标签集
	ifstream fp(labels_txt_path);
	vector<string>class_labels;
	if (!fp.is_open())
	{
		cout << "labels file can't open" << endl;
		exit(-1);
	}
	while (!fp.eof())				//如果指针不位于文件末尾,就继续读取文件
	{
		string class_name;
		getline(fp, class_name);			//读取文件中的每一行数据
		if (0 != class_name.length())				//如果不是空行,就将这一行的数据保存起来
		{
			class_labels.push_back(class_name);
		}
	}

然后读取测试图像。

	//读取测试图像
	Mat test_image = imread("D:\\opencv_c++\\opencv_tutorial\\data\\images\\pig.jpg");
	resize(test_image, test_image, Size(700, 700));
	imshow("test_image", test_image);

接着是非常重要的一步,就是将输入神经网络的图像进行预处理,将图像转化为一个4维的blob。

	Mat inputBlob = dnn::blobFromImage(test_image, 1.0, Size(224, 224), Scalar(117,117,117), true, false, 5);

APIblobFromImage()的参数含义如下:
(1)参数image:要输入神经网络进行处理或者分类的图片;
(2)参数scalefactor:将图像减去平均值之后,对每个像素点的像素值进行一定的尺度缩放,它的默认值是1;例如当scalefactor=1/2,则对图像进行减均值操作后,再对每个像素点的像素值乘1/2;
(3)参数size:神经网络(模型)在训练的时候要求输入的图片尺寸,由所使用的模型来决定;
(4)参数mean:对图像减去的平均值,如果我们需要对RGB图片的三个通道分别减去不同的值,那么可以使用3组平均值,如果只使用一组,那么就默认对三个通道减去一样的值。
对图片的R、G、B三通道求取平均像素值,然后将每个像素点减去平均值,就可以得到像素点之间的相对值,可以消除同一场景下不同光照情况的图片对最终分类的影响。该值由训练模型时所使用的数据集决定。
(5)参数swapRB:OpenCV中图像的通道顺序是BGR,但是有些神经网络的输入图像其通道顺序是RGB;当测试图像和神经网络要求的输入图像的通道顺序不同时,则将swapRB=true,即交换输入图像的R、B通道;该值由所使用的神经网络的输入图像要求所决定;
(6)参数crop:表示是否对要输入神经网络的测试图像进行裁剪,一般默认为false;
(7)参数depth:返回的blob的深度。

接着就可以将处理好的blob传入神经网络中进行前向传播了,并得到预测结果。

	Mat prob;
	//设置神经网络的输入,可以指定为某一层的输入,默认第一层神经层为输入层
	tf_net.setInput(inputBlob);
	//对神经网络进行前向传播,得到一个预测结果;具体结构由所使用的神经网络输出层决定
	prob = tf_net.forward();

得到预测结果后,需要将结果做一定的处理,也就是把结果矩阵转换为1行多列的矩阵,其中每一列就是一个类别的置信度。我们获取其中数值最大的一列,那么该列的x坐标在标签集中对应的类别就是输出的预测类别。

	//将预测结果转化为一行多列的单通道Mat对象,每一列为一个标签的置信度
	Mat prob_mat = prob.reshape(1, 1);
	//寻找预测结果中置信度最大的某个分类,即为输入测试图像的预测分类
	double maxval;
	Point maxloc;
	minMaxLoc(prob_mat, NULL, &maxval, NULL, &maxloc);
	int classID = maxloc.x;
	maxval = maxval * 100;

最后对预测结果进行可视化输出。

	//输出预测结果
	string confidence = to_string(maxval);
	string img_class = class_labels[classID];
	putText(test_image, img_class+confidence+"%", Point(50, 50), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 255, 0), 2, LINE_AA);
	imshow("retult", test_image);
	cout <<"运行时间: "<< run_time << "s" << endl;

运行结果如下:


在这里插入图片描述

到这里,我们就实现了在OpenCV中dnn模块来调用inception5h模型来进行图像分类的功能,那么本次笔记到此结束啦。

PS:本人的注释比较杂,既有自己的心得体会也有网上查阅资料时摘抄下的知识内容,所以如有雷同,纯属我向前辈学习的致敬,如果有前辈觉得我的笔记内容侵犯了您的知识产权,请和我联系,我会将涉及到的博文内容删除,谢谢!

你可能感兴趣的:(学习笔记,opencv,dnn,c++,计算机视觉)