环境:win10 x64,vs2013, caffe(带有psroipooling层)

测试代码已经传到百度网盘:链接:https://pan.baidu.com/s/1Yy2gnd_g3Jj0uV1NV5eqPg 
提取码:vp3t 
复制这段内容后打开百度网盘手机App,操作更方便哦

备注:这份代码主要是想在vs2013中调用matlab中训练好的RFCN模型来计算一张图像中各个ROI的概率,后面将bbox显示出来这些没做,目的不在此。

1、main.cpp

int main()
{

	Caffe_Predefine();

	Mat img = imread("images/001852.jpg");
	//这个例子图像经过rpn网络得到了226个propasals
	const int row = 226;
	const int col = 5;

	//这里的第一列必须为0,否则会报错
	float rois[row*col] = 
	{
		0, 0, 0, 87, 265,
		0, 0, 0, 88, 121,
		0, 0, 0, 129, 179,
		0, 0, 0, 175, 123,
		0, 0, 0, 188, 85,
        ......,
        ......,
        0, 569, 373, 798, 598,
		0, 581, 263, 798, 598,
		0, 601, 66, 798, 598,
		0, 609, 0, 798, 373,
		0, 648, 0, 798, 598,
		0, 773, 0, 798, 64
	};
    vector<aboxes> bboxes;

	for (int i = 0; i < row; i++)
	{
		aboxes box = { rois[i*col + 0], rois[i*col + 1], rois[i*col + 2], rois[i*col + 3], rois[i*col + 4] };
		bboxes.push_back(box);
	}

	vector<float> ft = GetProb(img, bboxes);
	for (int i = 0; i < ft.size(); i++)
	{
		if (i % 21 == 0)
		{
			cout << endl;
		}
		cout << fixed << setprecision(4) << ft[i] <<" ";
	}
	
	return 0;
}

测试图片为001852.jpg:

Rois就是经过RPN 网络得到的propasals,这个图片对应的是226个,这里我的rois矩阵有5列,是因为训练好的模型中的ROI输入是[1,5,1,1]维度的。

input: "rois"
input_dim: 1 # to be changed on-the-fly to num ROIs
input_dim: 5 # [batch ind, x1, y1, x2, y2] zero-based indexing
input_dim: 1
input_dim: 1

将图片和rois作为参数,输入到getProb函数中。

2、getprob.cpp

//通过RFCN网络获得每个roi的输出概率
std::vector<float> GetProb(Mat Img,vector<aboxes> rois)
{
	caffe::Caffe::set_mode(caffe::Caffe::GPU);
	/*
		数据层输入
	*/
	Mat Imgnew=Img.clone();

	//转成float型
	Mat Img_float;
	Imgnew.convertTo(Img_float, CV_32FC3); //3通道的float型
	//减去均值
	cv::Scalar channel_mean = cv::mean(Img_float);
	Mat mean = cv::Mat(Imgnew.rows, Imgnew.cols, Img_float.type(), channel_mean);
	Mat Img_normalized;
	subtract(Img_float, mean, Img_normalized);
	//缩放
	cv::resize(Img_normalized, Img_normalized, Size(800, 600));

	/*imshow("Img_resized", Img_normalized);
	waitKey(0);*/
	caffe::Blob<float> *input_ptr1=net->input_blobs()[0]; //data
	//输入data层的大小和通道
	input_ptr1->Reshape(1, Img_normalized.channels(),Img_normalized.rows, Img_normalized.cols);
	net->Reshape();
	std::vector<cv::Mat> input_channels;
	float* input_data = input_ptr1->mutable_cpu_data();
	for (int i = 0; i < input_ptr1->channels(); ++i) 
	{
		cv::Mat channel(Img_normalized.rows, Img_normalized.cols, CV_32FC1, input_data);
		input_channels.push_back(channel);
		input_data += Img_normalized.rows*Img_normalized.cols;
	}
	//将预处理后的图像切分成通道,放进input_channels
	cv::split(Img_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.";
	

	/*
	    Rois输入
	*/
	caffe::Blob<float> *input_ptr2 = net->input_blobs()[1]; // rois

	int num_rois = rois.size();
	//int num_rois = rois.rows;
	cout << "rois num:" << num_rois << endl;
	input_ptr2->Reshape(num_rois, 5, 1, 1);
	//input_ptr2->set_cpu_data((float*)rois.data);
	float* input_rois = input_ptr2->mutable_cpu_data();
	int num = 0;
	vector<aboxes>::iterator iter;
	for (iter = rois.begin(); iter != rois.end(); iter++)
	{
		input_rois[num * 5 + 0] = iter->batch_ind;
		input_rois[num * 5 + 1] = iter->x1;
		input_rois[num * 5 + 2] = iter->y1;
		input_rois[num * 5 + 3] = iter->x2;
		input_rois[num * 5 + 4] = iter->y2;
		num++;
	}
	std::vector<float> feature_value;
	
	net->Forward();

	boost::shared_ptr<caffe::Blob<float>> feature_layer = net->blob_by_name("cls_prob");

	cout << "feature layer count" << feature_layer->count()<< endl;
	int dim_features = feature_layer->count() / feature_layer->num(); //H*W*C
	cout << "dim_features=" << dim_features << endl;
	const float* pstart = (const float *)feature_layer->cpu_data();
	feature_value.clear();
	feature_value.assign(pstart, pstart + feature_layer->count());
	return feature_value;
}

RFCN中两个输入:data和rois:

input: "data"
input_dim: 1
input_dim: 3
input_dim: 224
input_dim: 224

#----------------------------------------------------------------
input: "rois"
input_dim: 1 # to be changed on-the-fly to num ROIs
input_dim: 5 # [batch ind, x1, y1, x2, y2] zero-based indexing
input_dim: 1
input_dim: 1

data是输入到resNet中用于产生featuremap的,rois是和featuremap一起输入到psroiopooling的。所以两个输入要单独处理。首先对输入图像进行一系列预处理:数据类型转换、减去均值,缩放(放大1.6倍,RFCN中就是这样的),然后就是难点,折腾了好几天的地方,就是怎么把数据从cv矩阵放到caffe输入层:

//新建一个指向数据输入层的指针,因为输入层有两个,所以
//这里的[0]指的是data,如果是[1]就指的是rois
caffe::Blob<float> *input_ptr1=net->input_blobs()[0]; //data
//data层的大小和通道(按照预处理后的图像的大小reshape)
input_ptr1->Reshape(1, Img_normalized.channels(),Img_normalized.rows, Img_normalized.cols);
//整个网络reshape
net->Reshape();
//定义一个存放图像各个通道的容器
std::vector<cv::Mat> input_channels;
//定义指向数据的指针
float* input_data = input_ptr1->mutable_cpu_data();
for (int i = 0; i < input_ptr1->channels(); ++i) 
{
    //指针指向三个通道的每一个通道
	cv::Mat channel(Img_normalized.rows, Img_normalized.cols, CV_32FC1, input_data);
    //叠加通道
	input_channels.push_back(channel);
    //指向下一个通道
	input_data += Img_normalized.rows*Img_normalized.cols;
}
//将预处理后的图像切分成三个通道,放进input_channels
cv::split(Img_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.";

接下来是rois输入的处理:

/*
	Rois输入
*/
//新建指向rois输入层的指针
caffe::Blob<float> *input_ptr2 = net->input_blobs()[1]; // rois
//roi的个数
int num_rois = rois.size();
//将网络中rois输入层的输入reshape成多个roi的形式,而不是[1,5,1,1]
input_ptr2->Reshape(num_rois, 5, 1, 1);
//新建指向数据的指针
float* input_rois = input_ptr2->mutable_cpu_data();
int num = 0;
vector<aboxes>::iterator iter;
//将rois的5个值一个个放在rois的输入数据中
for (iter = rois.begin(); iter != rois.end(); iter++)
{
	input_rois[num * 5 + 0] = iter->batch_ind;
	input_rois[num * 5 + 1] = iter->x1;
	input_rois[num * 5 + 2] = iter->y1;
	input_rois[num * 5 + 3] = iter->x2;
	input_rois[num * 5 + 4] = iter->y2;
	num++;
}

然后就可以net->Forward()了,可以输出所有rois的分类概率,共有21个类:

matlab中输出的原始概率(没有经过过滤)为:

 0           1              16        17        18        19        20
0.3239    0.0000   ...    0.0000    0.6733    0.0000    0.0000    0.0000
0.9935    0.0000   ...    0.0000    0.0064    0.0000    0.0000    0.0000
0.5869    0.0000   ...    0.0000    0.4126    0.0000    0.0000    0.0000
0.9981    0.0000   ...    0.0000    0.0016    0.0000    0.0000    0.0000
0.2755    0.0000   ...    0.0000    0.7229    0.0000    0.0000    0.0000
0.0309    0.0000   ...    0.0000    0.9673    0.0000    0.0000    0.0000
0.9205    0.0000   ...    0.0000    0.0794    0.0000    0.0000    0.0000

c++中输出的概率(没有经过过滤)为:

   0      1         16      17    18     19     20
0.9929 0.0000 ... 0.0000 0.0070 0.0000 0.0000 0.0000
0.5486 0.0000 ... 0.0000 0.4509 0.0000 0.0000 0.0000
0.9984 0.0000 ... 0.0000 0.0014 0.0000 0.0000 0.0000
0.2857 0.0000 ... 0.0000 0.7130 0.0000 0.0000 0.0000
0.0256 0.0000 ... 0.0000 0.9727 0.0000 0.0000 0.0000
0.9279 0.0000 ... 0.0000 0.0720 0.0000 0.0000 0.0000
0.9986 0.0000 ... 0.0002 0.0008 0.0000 0.0000 0.0000

可见,大多数roi的第一列值很大,接近1,因为第一列表示的是背景这一类,所有的rois中背景占绝大部分,其他的就是看哪一列值比较大,那么表示这一列代表的类出现的可能性很大,比如这里的倒数第四列有些值为0.9几,倒数第四列表示的是sheep这一类,这说明对应的框中很可能是绵羊这个目标。再来看看原来的图片,发现结果是正确的,图片中有两只绵羊。

可以成功的在vs中计算出分类概率,接下来就可以训练MOTDT中的评分网络,然后在vs中计算评分分数了。


版权声明:本文为sinat_33486980原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/sinat_33486980/article/details/96157908