由于我的目標就是用Caffe來做圖像的分類,而且是要用C++來做圖像的分類。那么,目前最重要的事就是要驗證一下能不能用Caffe做這件事,以及Caffe是怎么做這件事的。看到官網上提供了一個例子:Classifying ImageNet: using the C++ API。那我們就從這里開始吧。](http://caffe.berkeleyvision.org/gathered/examples/cpp_classification.html)。那我們就從這里開始吧。)
Caffe, at its core, is written in C++. It is possible to use the C++ API of Caffe to implement an image classification application similar to the Python code presented in one of the Notebook examples. To look at a more general-purpose example of the Caffe C++ API, you should study the source code of the command line tool caffe in tools/caffe.cpp.
A simple C++ code is proposed in examples/cpp_classification/classification.cpp.
也就是,官網說Caffe是完全可以用C++接口進行調用的。要想知道怎么調用,可以研究一下tools/caffe.cpp和examples/cpp_classification/classification.cpp這兩個文件。按我目前的理解,tools/caffe.cpp是用來訓練的,而classification.cpp則是教我們如何用已經訓練好的模型進行分類。其實,對于caffe可以訓練這件事是毋庸置疑的,只不過還沒有深入了解。但現在最重要的,是要看看當模型訓練完成之后,如何調用C++ API函數對圖像進行識別。所以,本文章僅對examples/cpp_classification/classification.cpp這個文件感興趣。網上已經有一個大神寫了一篇關于這個議題的文章了,因此,我就只是在Windows系統上來重新實驗一下吧。
目標
在Windows 7上實驗對小貓圖片(examples\images\cat.jpg
)進行分類。
準備
我們需要準備三個文件:
- caffemodel文件:可以直接在此地址下載,下載后放到models\bvlc_reference_caffenet文件夾下。
- 均值文件: notepad++打開data/ilsvc12/get_ilsvrc_aux.sh,“編輯”->“文檔格式轉換”->“轉換為UNIX格式”。在caffe目錄下執行
data/ilsvc12/get_ilsvrc_aux.sh
執行并下載后,均值文件放在 data/ilsvrc12/ 文件夾里。
-
synset_words.txt文件
在調用腳本文件下載均值的時候,這個文件也一并下載好了。里面放的是1000個類的名稱。
C++實現
用Visual Studio打開Caffe.sln。生成examples\classification。如果生成的是Release版本,則生成的exe程序會在caffe\build\examples\cpp_classification\Release中。在控制臺運行classification.exe,出現了Usage解釋:
Usage: classification.exe deploy.prototxt network.caffemodel mean.binaryproto la
bels.txt img.jpg
也就是說一共需要五個參數:
- deploy.prototxt
- network.caffemodel
- mean.binaryproto
- labels.txt
- img.jpg
> cd caffe
> build\examples\cpp_classification\Release\classification.exe ^
models\bvlc_reference_caffenet\deploy.prototxt ^
models\bvlc_reference_caffenet\bvlc_reference_caffenet.caffemodel ^
data\ilsvrc12\imagenet_mean.binaryproto ^
data\ilsvrc12\synset_words.txt ^
examples\images\cat.jpg
輸出結果
---------- Prediction for examples\images\cat.jpg ----------
0.3134 - "n02123045 tabby, tabby cat"
0.2380 - "n02123159 tiger cat"
0.1235 - "n02124075 Egyptian cat"
0.1003 - "n02119022 red fox, Vulpes vulpes"
0.0715 - "n02127052 lynx, catamount"
即有0.3134的概率為tabby cat, 有0.2380的概率為tiger cat ......
OK,到此為止,說明用C++寫程序來預測某一張圖像屬于哪個類是可用的。但如果真的自己要寫的話,還是得仔細看一下classification.cpp
。它一共有265行,我們就先來看一下它的main函數吧。
int main(int argc, char** argv) {
if (argc != 6) {
std::cerr << "Usage: " << argv[0]
<< " deploy.prototxt network.caffemodel"
<< " mean.binaryproto labels.txt img.jpg" << std::endl;
return 1;
}
::google::InitGoogleLogging(argv[0]);
string model_file = argv[1];
string trained_file = argv[2];
string mean_file = argv[3];
string label_file = argv[4];
Classifier classifier(model_file, trained_file, mean_file, label_file);
string file = argv[5];
std::cout << "---------- Prediction for "
<< file << " ----------" << std::endl;
cv::Mat img = cv::imread(file, -1);
CHECK(!img.empty()) << "Unable to decode image " << file;
std::vector<Prediction> predictions = classifier.Classify(img);
/* Print the top N predictions. */
for (size_t i = 0; i < predictions.size(); ++i) {
Prediction p = predictions[i];
std::cout << std::fixed << std::setprecision(4) << p.second << " - \""
<< p.first << "\"" << std::endl;
}
}
line# 2-7: 顯示用法信息
line# 9: 初始化glog……很慚愧,還沒有使用過glog
line# 15: 初始化classifier對象。Classifier類是關鍵,也是在這個文件中定義的。
line# 22: 用OpenCV庫讀取圖像
line# 24: 調用classifier的方法Classify,對剛剛讀取的圖像進行識別,并將結果存儲在Prediction數組中,其中,Prediction的定義為
typedef std::pair<string, float> Prediction;
是<label,score>鍵值對。
line# 27-31: 輸出結果。
cpp除了main以外的其它地方就干了一件事:定義Classifier。等到真正要用的時候,我們可以把Classifier類直接拿來用。因此,暫時就不展開分析了。
總結
如果我們有了caffemodel文件,均值文件和synset_words.txt文件,則借助** Classifier類**,就可以實現簡單地對OpenCV Mat圖像預測,給出前n個預測結果。