caffe 提取特征C++接口

一、前言

     以下为使用caffe的C++接口提取某层的特征向量,作下记录,一下两种方式耗时基本相同。

二、方式一

//CaffeExFeat.h
#ifndef CAFFEEXFEAT_H 
#define CAFFEEXFEAT_H

#include "caffe/caffe.hpp"
#include <string>
#include <vector>
#include "opencv2/opencv.hpp"


using namespace caffe;

class CaffeExFeat
{
	public:
		 explicit CaffeExFeat(std::string proto,std::string model,char* nameLayer,std::string meanFile,float scale=-1);
		 explicit CaffeExFeat(std::string proto,std::string model,char* nameLayer,float v1=0.0,float v2=0.0,float v3=0.0,float scale=-1);
		 ~CaffeExFeat();

		double*extractFeat(const cv::Mat& img);
		double calSimilarity(const cv::Mat& img1 ,const cv::Mat& img2);
	private:
		unsigned int blob_id_;
		boost::shared_ptr< Net<float> > net_;
		cv::Size input_geometry_;
		int num_channels_;
		cv::Mat mean_;
		Blob<float>* input_blobs_;
		unsigned int featNum_;
		float scale_;

		void init(std::string proto,std::string model,float scale);
	    void getMeanData(std::string mean_file);
	    void getMeanData(float v1,float v2,float v3 );
		unsigned int get_blob_index( char *query_blob_name);
		void wrapInputLayer(std::vector<cv::Mat>* input_channels);
		void preprocess(const cv::Mat& img,std::vector<cv::Mat>* input_channels);

};

#endif
//CaffeExFeat.cpp
#include "CaffeExFeat.h"

CaffeExFeat::CaffeExFeat(std::string proto,std::string model, char* nLayer,std::string meanFile,
	float scale)
{
	init(proto,model,scale);
	getMeanData(meanFile);
    blob_id_ = get_blob_index(nLayer);
}

CaffeExFeat::CaffeExFeat(std::string proto,std::string model, char* nLayer,float v1,float v2,float v3,
	float scale)
{
	init(proto,model,scale);
	getMeanData(v1,v2,v3);
    blob_id_ = get_blob_index(nLayer);
}

void CaffeExFeat::init(std::string proto,std::string model,float scale)
{
	scale_=scale;
	Phase phase = TEST;
	Caffe::set_mode(Caffe::CPU);
	net_ = boost::shared_ptr< Net<float> >(new caffe::Net<float>(proto, phase));
	net_->CopyTrainedLayersFrom(model);

	input_blobs_ = net_->input_blobs()[0];
	num_channels_ = input_blobs_->channels();
	input_geometry_ = cv::Size(input_blobs_->width(),input_blobs_->height());
	input_blobs_->Reshape(1, num_channels_,input_geometry_.height, input_geometry_.width); //难道可输入多张图
	
	net_->Reshape();  //维度改变
	
}

CaffeExFeat::~CaffeExFeat()
{
	
}

double* CaffeExFeat::extractFeat(const cv::Mat& img)
{
	std::vector<cv::Mat> input_channels;
	wrapInputLayer(&input_channels);
	preprocess(img, &input_channels);

    net_->ForwardPrefilled();
	boost::shared_ptr<Blob<float> > featBlob = net_->blobs()[blob_id_];
	featNum_ = featBlob->count();
    const float *featData = (const float *) featBlob->cpu_data();
    
    double* out = new double[featNum_];
    for(int k=0;k<featNum_;++k) out[k]=featData[k];

	return out;
}

double CaffeExFeat::calSimilarity(const cv::Mat& img1 ,const cv::Mat& img2)
{
	double* feat_1 = extractFeat(img1);
	double* feat_2 = extractFeat(img2);

	double sim = cblas_ddot(featNum_,feat_1,1,feat_2,1)/(std::sqrt(cblas_ddot(featNum_,feat_1,1,feat_1,1))*std::sqrt(cblas_ddot(featNum_,feat_2,1,feat_2,1)));
    delete []feat_1;
	delete []feat_2;

	return sim;
}

void CaffeExFeat::getMeanData(std::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);  
  
  /* 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);  
}

void CaffeExFeat::getMeanData(float v1,float v2, float v3)
{
	cv::Scalar channel_mean(v1,v2,v3);
	mean_ = cv::Mat(input_geometry_,CV_32FC3,channel_mean );
}

unsigned int CaffeExFeat::get_blob_index( char *query_blob_name)
{
    std::string str_query(query_blob_name);    
    vector< string > const & blob_names = net_->blob_names();
    for( unsigned int i = 0; i != blob_names.size(); ++i ) 
    { 
        if( str_query == blob_names[i] ) 
        { 
            return i;
        } 
    }
    LOG(FATAL) << "Unknown blob name: " << str_query;
}

void CaffeExFeat::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 CaffeExFeat::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);
  
  if(scale_!=-1){
  	cv::multiply(scale_ ,sample_normalized,sample_normalized);  
  }
  
  cv::split(sample_normalized, *input_channels);
}

三、方式二

#ifndef CAFFEEXFEAT_H 
#define CAFFEEXFEAT_H

#include "caffe/caffe.hpp"
#include <string>
#include <vector>
#include "opencv2/opencv.hpp"


using namespace caffe;

class CaffeExFeat
{
	public:
		 explicit CaffeExFeat(std::string proto,std::string model,char* nameLayer,std::string meanFile,float scale=1.);
		 explicit CaffeExFeat(std::string proto,std::string model,char* nameLayer,float v1=0.0,float v2=0.0,float v3=0.0,float scale=1.);
		 ~CaffeExFeat();

		double*extractFeat(const cv::Mat& img);
		double calSimilarity(const cv::Mat& img1 ,const cv::Mat& img2);
	private:
		unsigned int blob_id;
		boost::shared_ptr< Net<float> > net;
		Blob<float>* input_blobs;
		int channel,width,height;
		unsigned int featNum;
		float *meanData;
		float scale_;

		void init(std::string proto,std::string model,float scale);
	    void getMeanData(std::string meanFile);
	    void getMeanData(float v1,float v2,float v3 );
		unsigned int get_blob_index( char *query_blob_name);
};

#endif
#include "CaffeExFeat.h"

CaffeExFeat::CaffeExFeat(std::string proto,std::string model, char* nLayer,std::string meanFile,float scale)
{
	init(proto,model,scale);
	getMeanData(meanFile);
    blob_id = get_blob_index(nLayer);
}

CaffeExFeat::CaffeExFeat(std::string proto,std::string model, char* nLayer,float v1,float v2,float v3,float scale)
{
	init(proto,model,scale);
	getMeanData(v1,v2,v3);
    blob_id = get_blob_index(nLayer);
}

void CaffeExFeat::init(std::string proto,std::string model,float scale)
{
	scale_=scale;
	Phase phase = TEST;
	Caffe::set_mode(Caffe::CPU);
	net = boost::shared_ptr< Net<float> >(new caffe::Net<float>(proto, phase));
	net->CopyTrainedLayersFrom(model);

	input_blobs = net->input_blobs()[0];
	channel = input_blobs->channels();
	width = input_blobs->width();
	height = input_blobs->height();
}

CaffeExFeat::~CaffeExFeat()
{
	delete meanData;
}

 double* CaffeExFeat::extractFeat(const cv::Mat& img)
{
	cv::Mat resizedImg;
	cv::resize(img , resizedImg, cv::Size(height,width)); //缩放和去均值
	float *input_data = input_blobs->mutable_cpu_data();
	
	for(int h=0;h<height; ++h){
		const uchar* ptr = img.ptr<uchar>(h);
		int img_index = 0;
		for(int w=0; w<width ;++w){
			for(int c=0;c<channel ;++c){
				int blob_index = (c*height+h)*width +w ;
				input_data[blob_index] =(static_cast<float>(ptr[img_index++])-meanData[blob_index])*scale_;
			}
		}
	}  

	net->ForwardPrefilled();
	boost::shared_ptr<Blob<float> > featBlob = net->blobs()[blob_id];

	featNum = featBlob->count(); 
	const float *featData = (const float *) featBlob->cpu_data();
	
	double* out = new double[featNum];
	for(int k=0;k<featNum;++k) out[k]=featData[k];

	return out;
}

double CaffeExFeat::calSimilarity(const cv::Mat& img1 ,const cv::Mat& img2)
{
	double* feat_1 = extractFeat(img1);
	double* feat_2 = extractFeat(img2);

	double sim = cblas_ddot(featNum,feat_1,1,feat_2,1)/(std::sqrt(cblas_ddot(featNum,feat_1,1,feat_1,1)
				)*std::sqrt(cblas_ddot(featNum,feat_2,1,feat_2,1)));
    delete []feat_1;
	delete []feat_2;

	return sim;
}


void CaffeExFeat::getMeanData(std::string meanFile)
{
	Blob<float> image_mean;  
	BlobProto blob_proto;  
	const float *mean_ptr;  
	unsigned int num_pixel;  
	  
	bool succeed = ReadProtoFromBinaryFile(meanFile, &blob_proto);  
	if (succeed)  
	{  
    	image_mean.FromProto(blob_proto);  
    	num_pixel = image_mean.count(); /* NCHW=1x3x256x256=196608 */  
    	mean_ptr = (const float *) image_mean.cpu_data();  
		meanData = new float[num_pixel];
		memcpy(meanData,mean_ptr,num_pixel*sizeof(float));
	}
}

void CaffeExFeat::getMeanData(float v1,float v2, float v3)
{
	int wh = width*height;
    meanData = new float[channel*wh];

	std::vector<float> vec;
	vec.push_back(v1);
	vec.push_back(v2);
	vec.push_back(v3);

	for(int c=0; c<channel ; ++c){
		for(int k=0;k<wh ;++k){
				meanData[k+c*wh] = vec[c];
		}
	}

}

unsigned int CaffeExFeat::get_blob_index( char *query_blob_name)
{
    std::string str_query(query_blob_name);    
    vector< string > const & blob_names = net->blob_names();
    for( unsigned int i = 0; i != blob_names.size(); ++i ) 
    { 
        if( str_query == blob_names[i] ) 
        { 
            return i;
        } 
    }
    LOG(FATAL) << "Unknown blob name: " << str_query;
}
//main.cpp
#include "CaffeExFeat.h"

#include <iostream>

int main(int argc,char**argv)
{

    caffe::GlobalInit(&argc,&argv);  //关掉Log
    std::string proto = "***.prototxt";
    std::string model = "***.caffemodel";
	
    CaffeExFeat exFeater(proto,model,(char*)"fc5", 127.5,127.5,127.5 ,1./128);

 
    cv::Mat img_1 = cv::imread(path);  
  double* feat = extractFeat(img_1);
   delete[] feat;
   return 0;
}

四、编译下

g++ CaffeExFeat.cpp main.cpp -o main -D CPU_ONLY -I /home/trainer/Jyang/caffe-intel/include -L /home/trainer/Jyang/caffe-intel/build/lib -lcblas -lpthread  -lcaffe -lboost_system -lglog `pkg-config opencv --libs --cflags`


阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭