一、前言
以下为使用caffe的C++接口提取某层的特征向量,作下记录,一下两种方式耗时基本相同。
二、方式一
//CaffeExFeat.h
#ifndef CAFFEEXFEAT_H
#define CAFFEEXFEAT_H
#include "caffe/caffe.hpp"
#include
#include
#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 > net_;
cv::Size input_geometry_;
int num_channels_;
cv::Mat mean_;
Blob* 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* input_channels);
void preprocess(const cv::Mat& img,std::vector* 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 >(new caffe::Net(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 input_channels;
wrapInputLayer(&input_channels);
preprocess(img, &input_channels);
net_->ForwardPrefilled();
boost::shared_ptr > 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 */
Blob mean_blob;
mean_blob.FromProto(blob_proto);
/* The format of the mean file is planar 32-bit float BGR or grayscale. */
std::vector 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* input_channels) {
Blob* 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* 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
#include
#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 > net;
Blob* 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 >(new caffe::Net(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(h);
int img_index = 0;
for(int w=0; w(ptr[img_index++])-meanData[blob_index])*scale_;
}
}
}
net->ForwardPrefilled();
boost::shared_ptr > 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 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 vec;
vec.push_back(v1);
vec.push_back(v2);
vec.push_back(v3);
for(int c=0; c 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
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`