生活随笔
收集整理的這篇文章主要介紹了
Windows下用VS2013加载caffemodel做图像分类
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
本文假設你已經安裝CUDA,CUDA版本是7.5。
1.編譯caffe的Windows版本
happynear的博客已經介紹了如何在windows下編譯caffe,這里把我自己編譯的過程記錄下來,也算是做做筆記,方便以后查看。
1.1下載caffe-windows-master
下載地址:caffe-windows-master
1.2下載第三方庫
下載地址:
3rdparty
1.3 解壓
解壓第三方庫3rdparty,解壓到caffe-windows-master中的3rdparty文件夾中,即caffe-windows-master/3rdparty中的內容為:
!!!然后,需要將bin文件夾加入環(huán)境變量中。
當然,如果嫌麻煩,下載我解壓好的文件就行,跳過以上過程,下載該文件,下載地址:點擊這里。
1.4 開始編譯
雙擊caffe-windows-master\src\caffe\proto\extract_proto.bat,生成caffe.pb.h和caffe.pb.cc兩個c++文件,和caffe_pb2.py這個python使用的文件。然后,用vs2013打開./buildVS2013/MainBuilder.sln,打開之后切換編譯模式至Release X64模式。如果你的CUDA版本不是7.5,打開之后可能顯示加載失敗,這時就要用記事本打開./buildVS2013/MSVC/MainBuilder.vcxproj,搜索CUDA 7.5,把這個7.5換成你自己的CUDA版本,就可以正常打開了。
?右鍵caffelib項目,配置屬性——>常規(guī),將配置類型修改為應用程序(.exe),目標文件擴展名修改為.exe;接著:
C/C++ ——> 常規(guī),附加包含目錄修改如下(CUDA路徑按自己的修改):
[plain]?view plaincopy
../../3rdparty/include?? ../../src?? ../../include?? C:\Program?Files\NVIDIA?GPU?Computing?Toolkit\CUDA\v7.5\include?? 鏈接器 ——> 常規(guī),附加庫目錄修改如下(CUDA路徑按自己的修改):
[plain]?view plaincopy
../../3rdparty/lib?? [plain]?view plaincopy
C:\Program?Files\NVIDIA?GPU?Computing?Toolkit\CUDA\v7.5\lib\x64??
鏈接器——>輸入;將cudnn64_65.lib修改成cudnn.lib
如果需要matlab和python接口,可參考如下設置(路徑按自己的設置):
Matcaffe項目:
附加包含目錄:
[plain]?view plaincopy
../../3rdparty/include?? ../../src?? ../../include?? C:\Program?Files\NVIDIA?GPU?Computing?Toolkit\CUDA\v7.5\include?? D:\Program?Files\MATLAB\R2014a\extern\include??
附加庫目錄:
[plain]?view plaincopy
../../3rdparty/lib?? C:\Program?Files\NVIDIA?GPU?Computing?Toolkit\CUDA\v7.5\lib\x64?? D:\Program?Files\MATLAB\R2014a\extern\lib\win64\microsoft?? Pycaffe項目:
附加包含目錄:
[plain]?view plaincopy
../../3rdparty/include?? ../../src?? ../../include?? C:\Program?Files\NVIDIA?GPU?Computing?Toolkit\CUDA\v7.5\include?? D:\Python27\include?? D:\Python27\Lib\site-packages\numpy\core\include??
附加庫目錄:
[plain]?view plaincopy
../../3rdparty/lib?? C:\Program?Files\NVIDIA?GPU?Computing?Toolkit\CUDA\v7.5\lib\x64?? D:\Python27\libs?? 2.修改classification.cpp代碼
右鍵caffelib,添加新建項classification.cpp,classification.cpp代碼可參考如下:
該代碼逐張讀取文件夾下的圖像并將分類結果顯示在圖像左上角,空格下一張。
結果顯示在左上角,有英文和中文兩種標簽可選,如果顯示中文,需要使用Freetype庫,請自行百度。
[plain]?view plaincopy
#include?<caffe/caffe.hpp>?? #include?<opencv2/core/core.hpp>?? #include?<opencv2/highgui/highgui.hpp>?? #include?<opencv2/imgproc/imgproc.hpp>?? #include?<iosfwd>?? #include?<memory>?? #include?<utility>?? #include?<vector>?? #include?<iostream>?? #include?<string>?? #include?<sstream>?? #include?"CvxText.h"?//英文標簽去掉該頭文件?? ?? using?namespace?caffe;??//?NOLINT(build/namespaces)?? using?std::string;?? /*?Pair?(label,?confidence)?representing?a?prediction.?*/?? typedef?std::pair<string,?float>?Prediction;?? ?? class?Classifier?{?? public:?? ????Classifier(const?string&?model_file,?? ????????const?string&?trained_file,?? ????????const?string&?mean_file,?? ????????const?string&?label_file);?? ?? ????std::vector<Prediction>?Classify(const?cv::Mat&?img,?int?N?=?5);?? ?? private:?? ????void?SetMean(const?string&?mean_file);?? ?? ????std::vector<float>?Predict(const?cv::Mat&?img);?? ?? ????void?WrapInputLayer(std::vector<cv::Mat>*?input_channels);?? ?? ????void?Preprocess(const?cv::Mat&?img,?? ????????std::vector<cv::Mat>*?input_channels);?? ?? private:?? ????shared_ptr<Net<float>?>?net_;?? ????cv::Size?input_geometry_;?? ????int?num_channels_;?? ????cv::Mat?mean_;?? ????std::vector<string>?labels_;?? };?? ?? Classifier::Classifier(const?string&?model_file,?? ????const?string&?trained_file,?? ????const?string&?mean_file,?? ????const?string&?label_file)?{?? #ifdef?CPU_ONLY?? ????Caffe::set_mode(Caffe::CPU);?? #else?? ????Caffe::set_mode(Caffe::GPU);?? #endif?? ?? ????/*?Load?the?network.?*/?? ????net_.reset(new?Net<float>(model_file,?TEST));?? ????net_->CopyTrainedLayersFrom(trained_file);?? ?? ????CHECK_EQ(net_->num_inputs(),?1)?<<?"Network?should?have?exactly?one?input.";?? ????CHECK_EQ(net_->num_outputs(),?1)?<<?"Network?should?have?exactly?one?output.";?? ?? ????Blob<float>*?input_layer?=?net_->input_blobs()[0];?? ????num_channels_?=?input_layer->channels();?? ????CHECK(num_channels_?==?3?||?num_channels_?==?1)?? ????????<<?"Input?layer?should?have?1?or?3?channels.";?? ????input_geometry_?=?cv::Size(input_layer->width(),?input_layer->height());?? ?? ????/*?Load?the?binaryproto?mean?file.?*/?? ????SetMean(mean_file);?? ?? ????/*?Load?labels.?*/?? ????std::ifstream?labels(label_file);?? ????CHECK(labels)?<<?"Unable?to?open?labels?file?"?<<?label_file;?? ?????? ????string?line;?? ????while?(std::getline(labels,?line))?? ????????labels_.push_back(string(line));?? ?? ????Blob<float>*?output_layer?=?net_->output_blobs()[0];?? ????CHECK_EQ(labels_.size(),?output_layer->channels())?? ????????<<?"Number?of?labels?is?different?from?the?output?layer?dimension.";?? }?? ?? static?bool?PairCompare(const?std::pair<float,?int>&?lhs,?? ????const?std::pair<float,?int>&?rhs)?{?? ????return?lhs.first?>?rhs.first;?? }?? ?? /*?Return?the?indices?of?the?top?N?values?of?vector?v.?*/?? static?std::vector<int>?Argmax(const?std::vector<float>&?v,?int?N)?{?? ????std::vector<std::pair<float,?int>?>?pairs;?? ????for?(size_t?i?=?0;?i?<?v.size();?++i)?? ????????pairs.push_back(std::make_pair(v[i],?i));?? ????std::partial_sort(pairs.begin(),?pairs.begin()?+?N,?pairs.end(),?PairCompare);?? ?? ????std::vector<int>?result;?? ????for?(int?i?=?0;?i?<?N;?++i)?? ????????result.push_back(pairs[i].second);?? ????return?result;?? }?? ?? /*?Return?the?top?N?predictions.?*/?? std::vector<Prediction>?Classifier::Classify(const?cv::Mat&?img,?int?N)?{?? ????std::vector<float>?output?=?Predict(img);?? ?? ????std::vector<int>?maxN?=?Argmax(output,?N);?? ????std::vector<Prediction>?predictions;?? ????for?(int?i?=?0;?i?<?N;?++i)?{?? ????????int?idx?=?maxN[i];?? ????????predictions.push_back(std::make_pair(labels_[idx],?output[idx]));?? ????}?? ?? ????return?predictions;?? }?? ?? /*?Load?the?mean?file?in?binaryproto?format.?*/?? void?Classifier::SetMean(const?string&?mean_file)?{?? ????BlobProto?blob_proto;?? ????ReadProtoFromBinaryFileOrDie(mean_file.c_str(),?&blob_proto);?? ?? ????/*?Convert?from?BlobProto?to?Blob<float>?*/?? ????Blob<float>?mean_blob;?? ????mean_blob.FromProto(blob_proto);?? ????CHECK_EQ(mean_blob.channels(),?num_channels_)?? ????????<<?"Number?of?channels?of?mean?file?doesn't?match?input?layer.";?? ?? ????/*?The?format?of?the?mean?file?is?planar?32-bit?float?BGR?or?grayscale.?*/?? ????std::vector<cv::Mat>?channels;?? ????float*?data?=?mean_blob.mutable_cpu_data();?? ????for?(int?i?=?0;?i?<?num_channels_;?++i)?{?? ????????/*?Extract?an?individual?channel.?*/?? ????????cv::Mat?channel(mean_blob.height(),?mean_blob.width(),?CV_32FC1,?data);?? ????????channels.push_back(channel);?? ????????data?+=?mean_blob.height()?*?mean_blob.width();?? ????}?? ?? ????/*?Merge?the?separate?channels?into?a?single?image.?*/?? ????cv::Mat?mean;?? ????cv::merge(channels,?mean);?? ????/*?Compute?the?global?mean?pixel?value?and?create?a?mean?image?? ????*?filled?with?this?value.?*/?? ????cv::Scalar?channel_mean?=?cv::mean(mean);?? ????mean_?=?cv::Mat(input_geometry_,?mean.type(),?channel_mean);?? }?? std::vector<float>?Classifier::Predict(const?cv::Mat&?img)?{?? ????Blob<float>*?input_layer?=?net_->input_blobs()[0];?? ????input_layer->Reshape(1,?num_channels_,?? ????????input_geometry_.height,?input_geometry_.width);?? ????/*?Forward?dimension?change?to?all?layers.?*/?? ????net_->Reshape();?? ????std::vector<cv::Mat>?input_channels;?? ????WrapInputLayer(&input_channels);?? ?? ????Preprocess(img,?&input_channels);?? ?? ????net_->ForwardPrefilled();?? ?? ????/*?Copy?the?output?layer?to?a?std::vector?*/?? ????Blob<float>*?output_layer?=?net_->output_blobs()[0];?? ????const?float*?begin?=?output_layer->cpu_data();?? ????const?float*?end?=?begin?+?output_layer->channels();?? ????return?std::vector<float>(begin,?end);?? }?? ?? /*?Wrap?the?input?layer?of?the?network?in?separate?cv::Mat?objects?? *?(one?per?channel).?This?way?we?save?one?memcpy?operation?and?we?? *?don't?need?to?rely?on?cudaMemcpy2D.?The?last?preprocessing?? *?operation?will?write?the?separate?channels?directly?to?the?input?? *?layer.?*/?? void?Classifier::WrapInputLayer(std::vector<cv::Mat>*?input_channels)?{?? ????Blob<float>*?input_layer?=?net_->input_blobs()[0];?? ?? ????int?width?=?input_layer->width();?? ????int?height?=?input_layer->height();?? ????float*?input_data?=?input_layer->mutable_cpu_data();?? ????for?(int?i?=?0;?i?<?input_layer->channels();?++i)?{?? ????????cv::Mat?channel(height,?width,?CV_32FC1,?input_data);?? ????????input_channels->push_back(channel);?? ????????input_data?+=?width?*?height;?? ????}?? }?? ?? void?Classifier::Preprocess(const?cv::Mat&?img,?? ????std::vector<cv::Mat>*?input_channels)?{?? ????/*?Convert?the?input?image?to?the?input?image?format?of?the?network.?*/?? ????cv::Mat?sample;?? ????if?(img.channels()?==?3?&&?num_channels_?==?1)?? ????????cv::cvtColor(img,?sample,?CV_BGR2GRAY);?? ????else?if?(img.channels()?==?4?&&?num_channels_?==?1)?? ????????cv::cvtColor(img,?sample,?CV_BGRA2GRAY);?? ????else?if?(img.channels()?==?4?&&?num_channels_?==?3)?? ????????cv::cvtColor(img,?sample,?CV_BGRA2BGR);?? ????else?if?(img.channels()?==?1?&&?num_channels_?==?3)?? ????????cv::cvtColor(img,?sample,?CV_GRAY2BGR);?? ????else?? ????????sample?=?img;?? ?? ????cv::Mat?sample_resized;?? ????if?(sample.size()?!=?input_geometry_)?? ????????cv::resize(sample,?sample_resized,?input_geometry_);?? ????else?? ????????sample_resized?=?sample;?? ?? ????cv::Mat?sample_float;?? ????if?(num_channels_?==?3)?? ????????sample_resized.convertTo(sample_float,?CV_32FC3);?? ????else?? ????????sample_resized.convertTo(sample_float,?CV_32FC1);?? ?? ????cv::Mat?sample_normalized;?? ????cv::subtract(sample_float,?mean_,?sample_normalized);?? ?? ????/*?This?operation?will?write?the?separate?BGR?planes?directly?to?the?? ????*?input?layer?of?the?network?because?it?is?wrapped?by?the?cv::Mat?? ????*?objects?in?input_channels.?*/?? ????cv::split(sample_normalized,?*input_channels);?? ?? ????CHECK(reinterpret_cast<float*>(input_channels->at(0).data)?? ????????==?net_->input_blobs()[0]->cpu_data())?? ????????<<?"Input?channels?are?not?wrapping?the?input?layer?of?the?network.";?? }?? //獲取路徑path下的文件,并保存在files容器中?? void?getFiles(string?path,?vector<string>&?files)?? {?? ????//文件句柄?? ????long???hFile?=?0;?? ????//文件信息?? ????struct?_finddata_t?fileinfo;?? ????string?p;?? ????if?((hFile?=?_findfirst(p.assign(path).append("\\*").c_str(),?&fileinfo))?!=?-1)?? ????{?? ????????do?? ????????{?? ????????????if?((fileinfo.attrib?&??_A_SUBDIR))?? ????????????{?? ????????????????if?(strcmp(fileinfo.name,?".")?!=?0?&&?strcmp(fileinfo.name,?"..")?!=?0)?? ????????????????????getFiles(p.assign(path).append("\\").append(fileinfo.name),?files);?? ????????????}?? ????????????else?? ????????????{?? ????????????????files.push_back(p.assign(path).append("\\").append(fileinfo.name));?? ????????????}?? ????????}?while?(_findnext(hFile,?&fileinfo)?==?0);?? ????????_findclose(hFile);?? ????}?? }?? ?? int?main(int?argc,?char**?argv)?{?? ????//caffe的準備工作?? #ifdef?_MSC_VER?? #pragma?comment(?linker,?"/subsystem:\"windows\"?/entry:\"mainCRTStartup\""?)?? #endif?? ????//::google::InitGoogleLogging(argv[0]);?? ????string?model_file("../../model/deploy.prototxt");?? ????string?trained_file("../../model/type.caffemodel");?? ????string?mean_file("../../model/type_mean.binaryproto");?? ????string?label_file("../../model/labels.txt");?? ????string?picture_path("../../type");?? ?? ????Classifier?classifier(model_file,?trained_file,?mean_file,?label_file);?? ????vector<string>?files;?? ????getFiles(picture_path,?files);?? ?? ?????? ????for?(int?i?=?0;?i?<?files.size();?i++)?? ????{?? ????????cv::Mat?img?=?cv::imread(files[i],?-1);?? ????????cv::Mat?img2;?? ?? ????????std::vector<Prediction>?predictions?=?classifier.Classify(img);?? ????????Prediction?p?=?predictions[0];?? ?????????? ????????CvSize?sz;?? ????????sz.width?=?img.cols;?? ????????sz.height?=?img.rows;?? ????????float?scal?=?0;?? ????????scal?=?sz.width?>?sz.height???(300.0?/?(float)sz.height)?:?(300.0?/?(float)sz.width);?? ????????sz.width?*=?scal;?? ????????sz.height?*=?scal;?? ????????resize(img,?img2,?sz,?0,?0,?CV_INTER_LINEAR);?? ????????IplImage*?show?=?cvCreateImage(sz,?IPL_DEPTH_8U,?3);?? ?????????? ????????string?text?=?p.first;?? ????????char?buff[20];?? ????????_gcvt(p.second,?4,?buff);?? ????????text?=?text?+?":"?+?buff;?? ?? ????????/************************輸出中文(用到Freetype庫)****************************/?? ????????/*CvxText?mytext("../../STZHONGS.TTF");//?字體文件????? ????????const?char?*msg?=?text.c_str();?? ????????CvScalar?size;?? ????????size.val[0]?=?26;?? ????????size.val[1]?=?0.5;?? ????????size.val[2]?=?0.1;?? ????????size.val[3]?=?0;?? ????????mytext.setFont(NULL,&size,?NULL,?NULL);???//?設置字體大小?? ????????mytext.putText(&IplImage(img2),?msg,?cvPoint(10,?30),?cvScalar(0,?0,?255,?NULL));?? ????????//輸出圖像名?? ????????text?=?files[i].substr(files[i].find_last_of("\\")+1);?? ????????msg?=?text.c_str();?? ????????mytext.putText(&IplImage(img2),?msg,?cvPoint(10,?55),?cvScalar(0,?0,?255,?NULL));?? ????????cvCopy(&(IplImage)img2,?show);*/?? ????????/*******************************************************************************/?? ?? ????????/***************************輸出英文標簽*****************************************/?? ????????cvCopy(&(IplImage)img2,?show);?? ????????CvFont?font;?? ????????cvInitFont(&font,?CV_FONT_HERSHEY_COMPLEX,?1.0,?1.0,?0,?2,?8);??//初始化字體?? ????????cvPutText(show,?text.c_str(),?cvPoint(10,?30),?&font,?cvScalar(0,?0,?255,?NULL));?? ?? ????????text?=?files[i].substr(files[i].find_last_of("\\")+1);?? ????????cvPutText(show,?text.c_str(),?cvPoint(10,?55),?&font,?cvScalar(0,?0,?255,?NULL));?? ????????/**********************************************************************************/?? ?????????? ????????cvNamedWindow("結果展示");?? ????????cvShowImage("結果展示",?show);?? ????????int?c?=?cvWaitKey();?? ????????cvDestroyWindow("結果展示");?? ????????cvReleaseImage(&show);?? ?????????? ????????if?(c?==?27)?? ????????{?? ????????????return?0;?? ????????}?? ????}?? ????return?0;?? }??
3.生成
設置好之后,右鍵caffelib,生成。
4.結果
左邊是中文標簽,右邊是英文標簽。
最后,可以刪除那些不需要的文件或文件夾,如我的caffe-windows-master內只留下:
也可以下載我封裝好的代碼,可通過鏈接下載:http://download.csdn.net/detail/sinat_30071459/9568131? 是一個txt文件,因為csdn上傳限制,代碼上傳到了百度云,txt里面有百度云鏈接。下載解壓后將Classification\CLassificationDLL\bin加入環(huán)境變量,然后加入你的模型文件即可。
總結
以上是生活随笔為你收集整理的Windows下用VS2013加载caffemodel做图像分类的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。