OpenCV3.3深度學習模組(DNN)應用-影象分類
DNN模組介紹
在OpenCV3.3版本釋出中把DNN模組從擴充套件模組移到了OpenCV正式釋出模組中,當前DNN模組最早來自Tiny-dnn,可以載入預先訓練好的Caffe模型資料,OpenCV做了近一步擴充套件支援所有主流的深度學習框架訓練生成與匯出模型資料載入,常見的有如下:
-
Caffe
-
TensorFlow
-
Torch/PyTorch
OpenCV中DNN模組已經支援與測試過這些常見的網路模組
-
AlexNet
-
GoogLeNet v1 (also referred to as Inception-5h)
-
ResNet-34/50/...
-
SqueezeNet v1.1
-
VGG-based FCN (semantical segmentation network)
-
ENet (lightweight semantical segmentation network)
-
VGG-based SSD (object detection network)
-
MobileNet-based SSD (light-weight object detection network)
一:GoogleNet Caffe模型資料說明
OpenCV通過支援載入這些預先訓練好的模型,實現影象分類、物件檢測、語義分割、風格遷移等功能。支援Android/iOS等移動端平臺開發。下面我們就以OpenCV3.3 使用Caffe的GoogleNet資料模型為例,實現對影象常見分類,OpenCV3.3的DNN模組使用的模型支援1000種常見影象分類、googlenet深度學習網路模型是2014影象分類比賽的冠軍、首先是下載相關的資料模型檔案
-
bvlc_googlenet.caffemodel
-
bvlc_googlenet.prototxt
其中prototxt是一個文字的JSON檔案、一看就明白啦,另外一個檔案二進位制檔案。文字檔案只有你下載了OpenCV3.3解壓縮之後就會在對應的目錄發現。模型檔案需要從以下地址下載即可: http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel
二:程式設計實現
首先我們需要載入它官方指定的一張測試影象space_shuttle.jpg 是一張太空梭的圖片、OpenCV中載入影象的程式碼如下:
Mat testImage = imread(
"D:/vcprojects/images/dnn/football.jpg");
if (testImage.empty()) {
printf("could not load image...\n");
return -1;
}
然後我們需要宣告模型資料的路徑與標記資料路徑,載入建立網路模型,程式碼實現如下:
// create googlenet with caffemodel text and bin
Net net = dnn::readNetFromCaffe(modelTxt, modelBin);
if (net.empty())
{
std::cerr << "Can't load network by using the following files: " << std::endl;
std::cerr << "prototxt: " << modelTxt << std::endl;
std::cerr << "caffemodel: " << modelBin << std::endl;
return -1;
}
// 讀取分類資料
vector<String> labels = readClasslabels();
//GoogLeNet accepts only 224x224 RGB-images
Mat inputBlob = blobFromImage(testImage, 1, Size(224, 224), Scalar(104, 117, 123));
然後開始分類預測,根據prototxt中的開始的要求,我們需要輸入迭代10次,輸出預測分類的結果,程式碼實現如下:
// 支援1000個影象分類檢測
Mat prob;
// 迴圈10+
for (int i = 0; i < 10; i++)
{
// 輸入
net.setInput(inputBlob, "data");
// 分類預測
prob = net.forward("prob");
}
// 讀取分類索引,最大與最小值
Mat probMat = prob.reshape(1, 1); //reshape the blob to 1x1000 matrix // 1000個分類
Point classNumber;
double classProb;
minMaxLoc(probMat, NULL, &classProb, NULL, &classNumber); // 可能性最大的一個
int classIdx = classNumber.x; // 分類索引號
printf("\n current image classification : %s, possible : %.2f \n", labels.at(classIdx).c_str(), classProb);
putText(testImage, labels.at(classIdx), Point(20, 20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 0, 255), 2, 8);
imshow("Image Category", testImage);
其中讀取影象分類索引與文字描述的方法程式碼如下:
vector<String> readClasslabels() {
std::vector<String> classNames;
std::ifstream fp(labelFile);
if (!fp.is_open())
{
std::cerr << "File with classes labels not found: " << labelFile << std::endl;
exit(-1);
}
std::string name;
while (!fp.eof())
{
std::getline(fp, name);
if (name.length())
classNames.push_back(name.substr(name.find(' ') + 1));
}
fp.close();
return classNames;
}