#define CPU_ONLY
#include<vector>
#include<iostream>
#include<caffe/caffe.hpp>
#include<opencv2/opencv.hpp>
#include "caffe_reg.h"
#include<mat.h>
using namespace caffe;
using namespace std;
using namespace cv;
Mat read_mat_file(string file_path, int cross_id,bool isShow)
{
MATFile *mean_pmat = NULL; // .mat file for mean_file
mxArray *mean_var_cell = NULL; // mean variable in .mat file
MATFile *std_pmat = NULL;
mxArray *std_var_cell = NULL;
const char ** var_names;// variable names in .mat file
int nvars;// the number of variables in .mat file
// read .mat file
mean_pmat = matOpen(file_path.c_str(), "r");
if (mean_pmat == NULL)
{
cout << "cannot open *.mat file!" << endl;
exit(-1);
}
// read the varaibles in .mat file
var_names = (const char **)matGetDir(mean_pmat, &nvars);
if (var_names == NULL)
{
cout << "The .mat file contarin 0 variable, please perform checking!" << endl;
exit(-1);
}
// output the number of variable in .mat file
cout << "The numboer of variable in.mat file is : " << nvars << endl;
cout << " The name for all variables:";
for (int i = 0; i < nvars; i++) cout << string(var_names[i]) << endl;
// get the "mean_file_cross" ( a cell) variable from .mat file
// because we only have one variable in .mat file , so the index of var_names is set as 0
mean_var_cell = matGetVariable(mean_pmat, var_names[0]);
// get the size of mean_var_cell: M: rows, N :cols
int mean_cell_M = (int)mxGetM(mean_var_cell);
int mean_cell_N = (int)mxGetN(mean_var_cell);
//int cross_id = 1; // the cross_id for cross validation experiments
// mxGetCell(cell_name,count) , "count" is a accumuative number , column as main direction
// The above statement should be further checked.
mxArray * mean_file = mxGetCell(mean_var_cell, cross_id - 1); // start from 0
cout << " The dimension of mean_file: " << (int)mxGetNumberOfDimensions(mean_file) << endl;
double *data = (double*)mxGetData(mean_file);// get data from mxArray file
// mean_file is color image ,so mxGetM, mxGetN is instead by mxGetDimensios,
const size_t * dims = mxGetDimensions(mean_file);
int M = dims[0];
int N = dims[1];
int C = dims[2];
double *ptr_data = (double*)mxGetPr(mean_file);
cout << "The shape of mean_file: " << "(" << M << "," << N << "," << C << ")" << endl;
Mat mean_file_mat;
if (mxGetNumberOfDimensions(mean_file) == 3)
{
mean_file_mat.create(M, N, CV_8UC3);
}
else
{
mean_file_mat.create(M, N, CV_8UC1);
}
size_t subs[3];
// note that: row,cols,c
for (int i = 0; i < M; i++)
{
subs[0] = i;
for (int j = 0; j < N; j++)
{
subs[1] = j;
for (int k = 0; k < C; k++)
{
subs[2] = k;
int index = mxCalcSingleSubscript(mean_file, 3, subs);
mean_file_mat.at<Vec3b>(subs[0], subs[1])[k] = ptr_data[index];
}
}
}
// matlab: RGB opencv: BGR
Mat mean_file_img;
cvtColor(mean_file_mat, mean_file_img, CV_RGB2BGR);
// show for debug
if (isShow)
{
imshow(file_path, mean_file_img);
waitKey(0);
}
return mean_file_img;
}
// 共享内存,仅用来演示
void check_warp_op()
{ // change the values in p-pointer, the values in mat will also changes
// They share the same memory.
float * p = new float[10];
cout << "before warp: " << endl;
for (int i = 0; i < 10; i++)
{
p[i] = i;
cout << p[i] << " ";
}
cout << endl;
Mat wap_mat(1, 10, CV_32FC1, p);
wap_mat.at<float>(0, 1) = 10;
wap_mat.at<float>(0, 2) = 10;
wap_mat.at<float>(0, 3) = 10;
cout << "mat: " << endl;
cout << wap_mat << endl;
cout << "after warp: " << endl;
for (int i = 0; i < 10; i++)
{
cout << p[i] << " ";
}
cout << endl;
}
/* Return the indices of the top N values of vector v. */
// Argmax function and Paricompare(weici) are copied from caffe example
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], static_cast<int>(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;
}
int main(void)
{
// for test
string deploy_proto = "ZOO_VGG16/deploy.prototxt";
string pre_trained_weight = "ZOO_VGG16/vgg__iter_10000.caffemodel";
Net<float> * net = new Net<float>(deploy_proto, caffe::Phase::TEST, 0);
net->CopyTrainedLayersFrom(pre_trained_weight);
cout << "number of input and output:";
cout << net->num_inputs() << " " << net->num_outputs() << endl;
// mean_file
// std_file
string lfw_data_path = "E:/xlh/eclipse_workplace/hello_world/data/lfw/";
string mean_file_path = lfw_data_path + "mean_file_cross224_10fold.mat";
string std_file_path = lfw_data_path + "std_file_cross224_10fold.mat";
string one_img = lfw_data_path + "/imgs224/Aaron_Eckhart_0001.jpg";
int cross_id = 1;
Mat mean_file = read_mat_file(mean_file_path, cross_id, false);
Mat std_file = read_mat_file(std_file_path, cross_id, false);
Mat input_img = imread(one_img);
// only for CPU
Caffe::set_mode(Caffe::CPU);
Mat norm_img; //H W C(brg)
cv::subtract(input_img, mean_file, norm_img);
cv::divide(norm_img, std_file, norm_img);
//
bool isShow = false;
// all the values are very small, so is black
if (isShow)
{
Mat show_img;
norm_img.convertTo(show_img, CV_8UC3);
imshow("normalize", show_img);
waitKey(0);
}
//
Blob<float> * input_layer = net->input_blobs()[0];
// or Blob<float> * input_layer = net->blobs["data"];
int num_channels = input_layer->channels();
cout << "channels: " << num_channels << endl;
int npose = 5; // for lfw dataset
Blob<float> *output_layer = net->output_blobs()[0];
cout << "label size: " << npose << "; num_channels of output: " << output_layer->channels() << endl;
//check_warp_op(); a faster method ,dont need copy
// for details, please refer to classification.cpp in caffe
cout << "input_layer.shape: ";
for (int i = 0; i < input_layer->shape().size(); i++)
{
cout << input_layer->shape()[i] << " ";
}
cout << endl;
// an idiot method
// input_blob.shape: [1,3,224,224]; nsample * channels * height * width
// input_blob.shape: [3,224,224];
float * data = input_layer->mutable_cpu_data();
int nrows = input_layer->shape()[2];
int ncols = input_layer->shape()[3];
int nchannels = input_layer->shape()[1];
int num = 0;
float *p = data;
for (int i = 0; i < nchannels; i++)
{
for (int j = 0; j < nrows; j++)
{
for (int k = 0; k < ncols; k++)
{
p[num] = norm_img.at<Vec3b>(j, k)[i];
num += 1;
}
}
}
net->Forward();
//
const float* begin = output_layer->cpu_data();
const float* end = begin + output_layer->channels();
vector<float> output(begin, end);
cout << "the probabilites for each class: ";
for (int i = 0; i < output.size(); i++)
{
cout << output[i] << " ";
}
cout << endl;
vector<int> class_id = Argmax(output, npose);
// left profile, left ,front ,right ,right profile
cout << "predict label is : " << class_id[0] -2 << endl; // change from[0,4] to [-2,2]
// free memory
delete(net);
}
参考文献:
1. http://blog.csdn.net/jnulzl/article/details/49623121
2. http://blog.csdn.net/shaoxiaohu1/article/details/8269690