您的位置:首页 > Web前端

caffe接口中python代码和c++代码的转换

2018-01-31 14:59 423 查看
caffe使用别人训练好的模型

我觉得都是一样的套路,不管是python还是c++

掌握好步骤流程就行

加载网络结构流程

_1、设置gpu或者cpu模式

2、设置gpu设备号

3、加载网络结构,caffeModel和prototxt文件

4、处理输入图片,例如减去均值和归一化操作

5、前向传播

6、处理计算之后的结果_

#python代码
#ssd mobileNet检测图片

import numpy as np
import sys,os
import cv2
caffe_root = '/home/ssd/caffe/'
sys.path.insert(0, caffe_root + 'python')
import caffe
import time

net_file= 'deploy.prototxt'
caffe_model= 'tr.caffemodel'
test_dir = "/home/qwe/Desktop/12"

if not os.path.exists(caffe_model):
print("MobileNetSSD_deploy.affemodel does not exist,")
print("use merge_bn.py to generate it.")
exit()
caffe.set_mode_gpu()
caffe.set_device(0)
net = caffe.Net(net_file,caffe_model,caffe.TEST)

CLASSES = ('background', 'obj')

def preprocess(src):
img = cv2.resize(src, (512,256))
img = img - 127.5
img = img * 0.007843
return img

def postprocess(img, out):
h = img.shape[0]
w = img.shape[1]
box = out['detection_out'][0,0,:,3:7] * np.array([w, h, w, h])

cls = out['detection_out'][0,0,:,1]
conf = out['detection_out'][0,0,:,2]

return (box.astype(np.int32), conf, cls)

def detect(imgfile):
origimg = cv2.imread(imgfile)

img = preprocess(origimg)

img = img.astype(np.float32)
img = img.transpose((2, 0, 1))

start_time = time.time()
net.blobs['data'].data[...] = img
out = net.forward()
box, conf, cls = postprocess(origimg, out)
pro_time = time.time() - start_time
print('use time: ' + str(pro_time) + 's')

for i in range(len(box)):
p1 = (box[i][0], box[i][1])
p2 = (box[i][2], box[i][3])
cv2.rectangle(origimg, p1, p2, (0,255,0))
p3 = (max(p1[0], 15), max(p1[1], 15))
title = "%s:%.2f" % (CLASSES[int(cls[i])], conf[i])
cv2.putText(origimg, title, p3, cv2.FONT_ITALIC, 0.6, (0, 255, 0), 1)
cv2.imshow("SSD", origimg)

k = cv2.waitKey(0) & 0xff
#Exit if ESC pressed
if k == 27 : return False
return True

for f in os.listdir(test_dir):
if detect(test_dir + "/" + f) == False:
break


|——————————————————————————

|—–从上面的python代码中可以看出完整的加载模型流程

|—–而使用c++会有几点需要注意的地方

|——————————————————————————

//-------ssd.h

class Detector
{
public:
Detector(const string& model_file,const string& weights_file);

std::vector<std::vector<float> > Detect(const cv::Mat& _img);

private:
boost::shared_ptr<Net<float> > net_;
};


//------ssd.cpp

Detector::Detector(const string &model_file, const string &weights_file)
{
#ifdef CPU_ONLY
Caffe::set_mode(Caffe::CPU);
#else
Caffe::set_mode(Caffe::GPU);
#endif

/* Load the network. */
net_.reset(new Net<float>(model_file, TEST));
net_->CopyTrainedLayersFrom(weights_file);

}

std::vector<std::vector<float> >Detector::Detect(const cv::Mat &_img)
{
cv::Mat img = _img.clone();

Blob<float>* inputBlob = net_->input_blobs()[0];
int width = inputBlob->width();            //网络规定的输入图片的宽度和高度
int height = inputBlob->height();
cv::resize(img,img,cv::Size(width,height));//将测试图片进行调整大小
img.convertTo(img, CV_32FC3);   //转为浮点图
img = (img - 127.5) * 0.007843;

float* data = inputBlob->mutable_cpu_data();   //将图片的像素值,复制进网络的输入Blob
for (int k = 0; k<3; ++k){
for (int i = 0; i<height; ++i){
for (int j = 0; j<width; ++j){
int index = (k*height + i)*width + j;  //获取偏移量
data[index] = img.at<Vec3f>(i, j)[k];
}
}
}

vector<Blob<float>* > inputs(1, inputBlob);
//const vector<Blob<float>* >& outputBlobs = net_->Forward(inputs);   //进行前向传播,并返回最后一层的blob
const vector<Blob<float>* >& outputBlobs = net_->Forward();   //进行前向传播,并返回最后一层的blob

Blob<float>* outputBlob = outputBlobs[0];      //输出blob
const float* result = outputBlob->cpu_data();

vector<vector<float> > detections;
for (int i = 0; i<outputBlob->count(); ++i)       //将输出blob里的特征数值,拷贝到vector里并返回
{
if (result[0] == -1) {
// Skip invalid detection.
result += 7;
continue;
}
vector<float> detection(result, result + 7);
detections.push_back(detection);
result += 7;
}
return detections;
}


几个不同的地方

_1,将待测试图片加载进网络中

2,运算完成之后取出数据_

python中写法比较简单,按照套路直接写

加载待测图片

#python 代码
#----------------------------
#加载待测图片
origimg = cv2.imread(imgfile)
#将图片减去均值,归一化处理
img = cv2.resize(src, (512,256))
img = img - 127.5
img = img * 0.007843
#将图片转换成float类型
img = img.astype(np.float32)
img = img.transpose((2, 0, 1))
#将图片内容送进网络中进行前向传播
net.blobs['data'].data[...] = img
#前向传播
out = net.forward()


/*c++代码
-------------------------------------*/
//opencv 读取图片文件
cv::Mat img = cv::imread(fileName);

Blob<float>* inputBlob = net_->input_blobs()[0];
//网络规定的输入图片的宽度和高度
int width = inputBlob->width();
int height = inputBlob->height();
cv::resize(img,img,cv::Size(width,height));//将测试图片进行调整大小
img.convertTo(img, CV_32FC3);   //转为浮点图
img = (img - 127.5) * 0.007843; //减去均值,归一化图像
/*减均值也可以使用cv::subtract函数,例如:
cv::Mat mean(height,width,image.type(),cv::Scalar(102.9801,115,122.77);
cv::Mat normalized;
cv::subtract(image,mean,normalized);
*/
//------
//将图片加载进网络结构前向传播
float* data = inputBlob->mutable_cpu_data();  //将图片的像素值,复制进网络的输入Blob
for (int k = 0; k<3; ++k)
{
for (int i = 0; i<height; ++i){
for (int j = 0; j<width; ++j){
int index = (k*height + i)*width + j;  //获取偏移量
data[index] = img.at<Vec3f>(i, j)[k];
}
}
}
/*也可以写成下面的形式
std::vector<cv::Mat> input_channels;
float* input_data = inputBlob->mutable_cpu_data();
for (int i = 0; i < inputBlob->channels(); ++i)
{
cv::Mat channel(height, width, CV_32FC1, input_data);
input_channels->push_back(channel);
input_data += width * height;
}
cv::split(img, input_channels);
*/
//前向传播,直接取最后一层输出结果
const vector<Blob<float>* >& outputBlobs = net_->Forward();
//这样的写法要注意网络结构最后是否有多个分支,如果是多个分支,则会导致最后的结果将多个分支的结果融合在一起,不好区分。


从前向传播之后取最后的检测结果

#python代码
#------------------------
#out = net.forward()
h = img.shape[0] #待测图片的高
w = img.shape[1] #待测图片的宽
#取出out中的detection_out的blob中的数据,按照blob名字取数据。
#detection_out中的是包含7个float数据,从第4个到第7个分别代表位置坐标
#由于要还原到原来的图片中的实际位置,所以分别乘以原图中的宽高
box = out['detection_out'][0,0:3,7] * np.array([w,h,w,h)
cls = out['detection_out'][0,0,:,1] #第二个位置是分类结果
conf = out['detection_out'][0,0,:,2]#第三个位置是分类置信度


/*C++代码
----------------------------*/
const vector<Blob<float>* >& outputBlobs = net_->Forward();
Blob<float>* outputBlob = outputBlobs[0];      //输出blob
const float* result = outputBlob->cpu_data();

vector<vector<float> > detections;
//注意这里 outputBlob->count() 和 outputBlob->height()的数值也许是不一样的
for (int i = 0; i<outputBlob->count(); ++i)
{
if (result[0] == -1) {
// Skip invalid detection.
result += 7;
continue;
}
vector<float> detection(result, result + 7);
detections.push_back(detection);
result += 7;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: