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

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;
}
发布了65 篇原创文章 · 获赞 63 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/qq_17278169/article/details/79217411