由於項目需要,需要在QT中進行圖片分類,準備用opencv自帶的dnn模塊,調用訓練好的模型。
win7/64+QT5.11.1+opencv3.4.1
1.QTCreator配置opencv
先測試是否可用,QTCreator的pro文件先添加opencv庫。(默認系統環境變量已添加opencv的bin目錄)
CONFIG(debug,debug|release) {
TARGET = $$join(TARGET,,,_d)
}
Debug {
contains(QMAKE_COMPILER_DEFINES, _WIN64) {
LIBS += -LH:/opencv/opencv/newbuild/install/x64/vc15/lib -lopencv_img_hash341d
LIBS += -LH:/opencv/opencv/newbuild/install/x64/vc15/lib -lopencv_world341d
DESTDIR = ./Bin/x64
}
else {
}
}
else {
contains(QMAKE_COMPILER_DEFINES, _WIN64) {
LIBS += -LH:/opencv/opencv/newbuild/install/x64/vc15/lib -lopencv_img_hash341
LIBS += -LH:/opencv/opencv/newbuild/install/x64/vc15/lib -lopencv_world341
DESTDIR = ./Bin/x64
}
else {
}
}
INCLUDEPATH += \
H:/opencv/opencv/newbuild/install/include\
H:/opencv/opencv/newbuild/install/include/opencv\
H:/opencv/opencv/newbuild/install/include/opencv2\
測試opencv是否可用
2.百度上找一張直升飛機的圖片,修改main函數,打開圖片,測試opencv庫是否配置成功
#include "opencvmat.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Mat src = cv::imread("F:/DahuaSDKC++/opencvtest/airplane.jpg");
cv::namedWindow("input", CV_WINDOW_AUTOSIZE);
cv::imshow("input", src);
cv::waitKey(0);
//opencvMat w;
//w.show();
return a.exec();
}
這裏之前用的相對路徑,讀取有的圖片成功,有的有問題,出過一個opencv錯誤:斷言失敗的問題,後來查了之後改成絕對路徑就好了。
參考:https://blog.csdn.net/lijinshanba/article/details/78888159
3.準備模型
oepncv沒問題就可以準備模型文件了,參考很多案例,下了一堆模型,出現問題好像都是因爲.pb和.pbtxt文件不匹配之類的,蛋疼。
後來找到一個案例:https://blog.csdn.net/qq_35054151/article/details/82916424
1.首先我們需要下載訓練好的googlenet權重模型bvlc_googlenet .caffemodel(二進制文件),模型下載地址爲
http://dl.caffe.berkeleyvision.org/
2.然後導入模型描述文件,地址爲H:\opencv\opencv\sources\samples\data\dnn(這裏具體路徑看自己opencv的路徑)
把打勾的兩個文件拷過去
4.測試程序
修改main函數如下:我這裏都是用的絕對路徑
#include "opencvmat.h"
#include <QApplication>
#include <iostream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;
using namespace dnn;
String model_file = "F:/DahuaSDKC++/opencvtest/bvlc_googlenet.caffemodel";
String model_txtfile = "F:/DahuaSDKC++/opencvtest/bvlc_googlenet.prototxt";
String labels_file = "F:/DahuaSDKC++/opencvtest/synset_words.txt";
vector<String>readLabels();
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Mat src = cv::imread("F:/DahuaSDKC++/opencvtest/airplane.jpg");
namedWindow("input", CV_WINDOW_AUTOSIZE);
cv::imshow("input", src);
//讀取模型的類別(文本)
vector<String> labels = readLabels();
//讀取google_net的模型和描述文件
Net net = readNetFromCaffe(model_txtfile, model_file);
if (net.empty()) {
printf("read caffee model data failure\n");
return -1;
}
//將圖像轉爲google_net網絡輸入的對象,由描述文件可知,圖像尺寸統一爲224*224
Mat inputBlob = blobFromImage(src, 1.0, Size(224, 224), Scalar(104, 117, 123));
//進行前向傳播,由描述文件可知,第一層用了10個卷積層,提取圖像10種不同的特徵
Mat prob;
for (int i = 0; i < 10; i++) {
net.setInput(inputBlob, "data");
prob = net.forward("prob");//最後一層的輸出爲“prob”
}
//輸出
//得到的概率值爲1行1000列的
Mat promat = prob.reshape(1, 1);
Point classLoc;
double classProb;
minMaxLoc(promat, NULL, &classProb, NULL, &classLoc);
printf("current image classification: %s,probablity %f\n", labels.at(classLoc.x).c_str(), classProb);
putText(src, labels.at(classLoc.x), Point(20, 20), FONT_HERSHEY_COMPLEX, 1.0, Scalar(0, 0, 255), 2);
imshow("output", src);
waitKey(0);
//opencvMat w;
//w.show();
return a.exec();
}
//讀取模型的類別(文本)
vector<String>readLabels() {
vector<String>classNames;
ifstream fp(labels_file);//打開文件
if (!fp.is_open()) {//文件沒打開
printf("could not open the file ");
exit(-1);
}
string name;
while (!fp.eof()) {//文件沒讀到結尾
getline(fp, name);//得到每一行,放到name中
if (name.length()) {//非空行
classNames.push_back(name.substr(name.find(' ') + 1));//
}
}
fp.close();
return classNames;
}