[置顶] Windows下用VS2013加载caffemodel做图像分类

  本文假设你已经安装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中的内容为:
[置顶] Windows下用VS2013加载caffemodel做图像分类_第1张图片
!!!然后,需要将bin文件夹加入环境变量中。

   当然,如果嫌麻烦,下载我解压好的文件就行,跳过以上过程,下载该文件,下载地址: 点击这里。

1.4 开始编译

双击caffe-windows-master\src\caffe\proto\extract_proto.bat,生成caffe.pb.hcaffe.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版本,就可以正常打开了。
 右键caffe项目,C/C++ ——> 常规,附加包含目录修改如下(CUDA路径按自己的修改):
../../3rdparty/include
../../src
../../include
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\include
链接器 ——> 常规,附加库目录修改如下(CUDA路径按自己的修改)
../../3rdparty/lib
..\..\bin
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\lib\x64

设置好之后,右键解决方案,重新生成。编译结束后会出现失败**个,因为我们没有配置matlab接口和python接口等,所以这些编译失败,但是我们没用到,所以无所谓。如果需要matlab和python接口,可参考如下设置(路径按自己的设置):

Matcaffe项目:

附加包含目录:

../../3rdparty/include
../../src
../../include
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\include
D:\Program Files\MATLAB\R2014a\extern\include

附加库目录:

../../3rdparty/lib
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\lib\x64
D:\Program Files\MATLAB\R2014a\extern\lib\win64\microsoft

Pycaffe项目:

附加包含目录:

../../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

附加库目录:

../../3rdparty/lib
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\lib\x64
D:\Python27\libs

2.修改classification.cpp代码

右键caffelib,添加现有项,将caffe-windows-master\examples\cpp_classification中的classification.cpp添加进来,修改classification.cpp代码(可以参考我修改的代码):

#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 <fstream>  
  
using namespace caffe;  
using std::string;  
  
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  
  
    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());  
  
    SetMean(mean_file);  
  
    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;  
}  
  
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;  
}  
  
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;  
}  
  
void Classifier::SetMean(const string& mean_file) {  
    BlobProto blob_proto;  
    ReadProtoFromBinaryFileOrDie(mean_file.c_str(), &blob_proto);  
  
    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.";  
  
    std::vector<cv::Mat> channels;  
    float* data = mean_blob.mutable_cpu_data();  
    for (int i = 0; i < num_channels_; ++i) {  
        cv::Mat channel(mean_blob.height(), mean_blob.width(), CV_32FC1, data);  
        channels.push_back(channel);  
        data += mean_blob.height() * mean_blob.width();  
    }  
  
    cv::Mat mean;  
    cv::merge(channels, mean);  
  
    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);  
    net_->Reshape();  
  
    std::vector<cv::Mat> input_channels;  
    WrapInputLayer(&input_channels);  
  
    Preprocess(img, &input_channels);  
  
    net_->ForwardPrefilled();  
  
    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);  
}  
  
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) {  
    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);  
  
    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.";  
}  
  
int main(int argc, char** argv) {  
#ifdef _MSC_VER  
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )  
#endif  
    ::google::InitGoogleLogging(argv[0]);  
  
    string model_file = "C:\\Users\\Desktop\\classification\\ResNet\\deploy.prototxt";  
    string trained_file = "C:\\Users\\Desktop\\classification\\ResNet\\ResNet_iter_150000.caffemodel";  
    string mean_file = "C:\\Users\\Desktop\\classification\\ResNet\\my_mean.binaryproto";  
    string label_file = "C:\\Users\\Desktop\\classification\\ResNet\\car_words.txt";  
    string picture_path = "C:\\Users\\Desktop\\classification\\car.jpg";  
  
    Classifier classifier(model_file, trained_file, mean_file, label_file);  
    cv::Mat img = cv::imread(picture_path, -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 / (float)sz.width) : (300 / (float)sz.height);  
    sz.width *= scal;  
    sz.height *= scal;  
    resize(img, img2, sz, 0, 0, CV_INTER_LINEAR); 
	
	/*********************用FreeType库输出中文***********************/
	string text = p.first;
	char buff[20];
	_gcvt(p.second, 4, buff);
	text = text + ":" + buff;
		
	CvxText mytext("../../model/simhei.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(50, 50), cvScalar(0, 0, 255, NULL));
	/*********************************************************/
	
    IplImage* show = cvCreateImage(sz, IPL_DEPTH_8U, 3);  
    cvCopy(&(IplImage)img2, show);  
    cvNamedWindow("结果展示");  
    cvShowImage("结果展示", show);  
    int c = cvWaitKey();  
    cvDestroyWindow("结果展示");  
    cvReleaseImage(&show);  
    return 0;  
}  

上面代码中的路径改成自己的就行,由于我的标签是中文,所以用到了Freetype库在图片上显示中文。(英文的标签用opencv自带的函数就可以)

3.修改caffe项目中的caffe.cpp代码

将caffe.cpp中的main函数注释掉就可以了。

4.结果


最后,可以删除那些不需要的文件或文件夹,如我的caffe-windows-master内只留下:

[置顶] Windows下用VS2013加载caffemodel做图像分类_第2张图片




你可能感兴趣的:(windows,分类,caffe,图像分类,caffemodel)