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:本人的註釋比較雜,既有自己的心得體會也有網上查閱資料時摘抄下的知識內容,所以如有雷同,純屬我向前輩學習的致敬,如果有前輩覺得我的筆記內容侵犯了您的知識產權,請和我聯繫,我會將涉及到的博文內容刪除,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章