纯C++版的Faster-Rcnn(通过caffe自定义RPN层实现)

这里介绍的是通过添加自定义层(RPN层)代替python层,实现c++版的faster-rcnn,因为去掉python了,所以部署时不会因为牵扯到python库等其它的莫名其妙的错误,使用起来就跟单纯的caffe一样,更简单方便。 核心代码,借鉴的是这篇博客,这里的话,我们不扣具体的代码细节(比如rpn层是怎么产出候选框啊,非极大值抑制是具体怎么实现的等等),有兴趣的可以自己查下资料,所以主要是走一个步骤,从而完成c++版faster-rcnn的配置。

http://blog.csdn.net/u010327085/article/details/54342070

        步入正题,步骤和上面那篇博客大致一样,但它有一些细节地方直接忽略了,代码也有几处小bug,所以我把具体的流程给说下。

      (1) 添加自定义层 rpn_layer.hpp  把它放在 caffe/include/caffe/layers/  目录下

[cpp]  view plain  copy
  1. #ifndef CAFFE_RPN_LAYER_HPP_  
  2. #define CAFFE_RPN_LAYER_HPP_  
  3.   
  4. #include <vector>  
  5.   
  6. #include "caffe/blob.hpp"  
  7. #include "caffe/layer.hpp"  
  8. #include "caffe/proto/caffe.pb.h"  
  9. //#include"opencv2/opencv.hpp"  
  10.   
  11. #define mymax(a,b) ((a)>(b))?(a):(b)  
  12. #define mymin(a,b) ((a)>(b))?(b):(a)  
  13. namespace caffe {  
  14.   
  15.     /** 
  16.     * @brief implement RPN layer for faster rcnn 
  17.     */  
  18.   
  19.     template <typename Dtype>  
  20.     class RPNLayer : public Layer<Dtype> {  
  21.     public:  
  22.         explicit RPNLayer(const LayerParameter& param)  
  23.             : Layer<Dtype>(param) {  
  24.                 m_score_.reset(new Blob<Dtype>());  
  25.                 m_box_.reset(new Blob<Dtype>());  
  26.                 local_anchors_.reset(new Blob<Dtype>());  
  27.             }  
  28.         virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,  
  29.             const vector<Blob<Dtype>*>& top);  
  30.         virtual void Reshape(const vector<Blob<Dtype>*>& bottom,  
  31.             const vector<Blob<Dtype>*>& top){}  
  32.         virtual inline const char* type() const { return "RPN"; }  
  33.   
  34.         struct abox{  
  35.             Dtype batch_ind;  
  36.             Dtype x1;  
  37.             Dtype y1;  
  38.             Dtype x2;  
  39.             Dtype y2;  
  40.             Dtype score;  
  41.             bool operator <(const abox&tmp) const{  
  42.                 return score < tmp.score;  
  43.             }  
  44.         };  
  45.   
  46.     protected:  
  47.         virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,  
  48.             const vector<Blob<Dtype>*>& top);  
  49.         //virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,  
  50.             //const vector<Blob<Dtype>*>& top);  
  51.         virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,  
  52.             const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom){};  
  53.   
  54.           
  55.         int feat_stride_;  
  56.         int base_size_;  
  57.         int min_size_;  
  58.         int pre_nms_topN_;  
  59.         int post_nms_topN_;  
  60.         float nms_thresh_;  
  61.         vector<int> anchor_scales_;  
  62.         vector<float> ratios_;  
  63.   
  64.   
  65.         vector<vector<float> > gen_anchors_;  
  66.         int *anchors_;  
  67.         int anchors_nums_;  
  68.         int src_height_;  
  69.         int src_width_;  
  70.         float src_scale_;  
  71.         int map_width_;  
  72.         int map_height_;  
  73.           
  74.         shared_ptr<Blob<Dtype> > m_score_;  
  75.         shared_ptr<Blob<Dtype> > m_box_;  
  76.         shared_ptr<Blob<Dtype> >local_anchors_;  
  77.         void generate_anchors();  
  78.         vector<vector<float> > ratio_enum(vector<float>);  
  79.         vector<float> whctrs(vector<float>);  
  80.         vector<float> mkanchor(float w,float h,float x_ctr,float y_ctr);  
  81.         vector<vector<float> > scale_enum(vector<float>);  
  82.           
  83.         //cv::Mat proposal_local_anchor(int width, int height);  
  84.         void proposal_local_anchor();  
  85.         void bbox_tranform_inv();  
  86.         cv::Mat bbox_tranform_inv(cv::Mat local_anchors, cv::Mat boxs_delta);  
  87.         void nms(std::vector<abox> &input_boxes, float nms_thresh);  
  88.         void filter_boxs(cv::Mat& pre_box, cv::Mat& score, vector<abox>& aboxes);  
  89.         void filter_boxs(vector<abox>& aboxes);  
  90.     };  
  91. }  // namespace caffe  
  92.   
  93. #endif  // CAFFE_RPN_LAYER_HPP_  
  然后是源文件 rpn_layer.cpp  放在 caffe/src/caffe/layers/  目录下

[cpp]  view plain  copy
  1. #include <algorithm>  
  2. #include <vector>  
  3.   
  4. #include "caffe/layers/rpn_layer.hpp"  
  5. #include "caffe/util/math_functions.hpp"  
  6. #include <opencv2/opencv.hpp>  
  7.   
  8. int debug = 0;  
  9. int  tmp[9][4] = {  
  10.     { -83, -39, 100, 56 },  
  11.     { -175, -87, 192, 104 },  
  12.     { -359, -183, 376, 200 },  
  13.     { -55, -55, 72, 72 },  
  14.     { -119, -119, 136, 136 },  
  15.     { -247, -247, 264, 264 },  
  16.     { -35, -79, 52, 96 },  
  17.     { -79, -167, 96, 184 },  
  18.     { -167, -343, 184, 360 }  
  19. };  
  20. namespace caffe {  
  21.   
  22.     template <typename Dtype>  
  23.     void RPNLayer<Dtype>::LayerSetUp(  
  24.         const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {  
  25.         anchor_scales_.clear();  
  26.         ratios_.clear();  
  27.         feat_stride_ = this->layer_param_.rpn_param().feat_stride();  
  28.         base_size_ = this->layer_param_.rpn_param().basesize();  
  29.         min_size_ = this->layer_param_.rpn_param().boxminsize();  
  30.         pre_nms_topN_ = this->layer_param_.rpn_param().per_nms_topn();  
  31.         post_nms_topN_ = this->layer_param_.rpn_param().post_nms_topn();  
  32.         nms_thresh_ = this->layer_param_.rpn_param().nms_thresh();  
  33.         int scales_num = this->layer_param_.rpn_param().scale_size();  
  34.         for (int i = 0; i < scales_num; ++i)  
  35.         {  
  36.             anchor_scales_.push_back(this->layer_param_.rpn_param().scale(i));  
  37.         }  
  38.         int ratios_num = this->layer_param_.rpn_param().ratio_size();  
  39.         for (int i = 0; i < ratios_num; ++i)  
  40.         {  
  41.             ratios_.push_back(this->layer_param_.rpn_param().ratio(i));  
  42.         }  
  43.           
  44.           
  45.         //anchors_nums_ = 9;  
  46.         //anchors_ = new int[anchors_nums_ * 4];  
  47.         //memcpy(anchors_, tmp, 9 * 4 * sizeof(int));  
  48.           
  49.         generate_anchors();  
  50.   
  51.         anchors_nums_ = gen_anchors_.size();  
  52.         anchors_ = new int[anchors_nums_ * 4];  
  53.         for (int i = 0; i<gen_anchors_.size(); ++i)  
  54.         {  
  55.             for (int j = 0; j<gen_anchors_[i].size(); ++j)  
  56.             {  
  57.                 anchors_[i*4+j] = gen_anchors_[i][j];  
  58.             }  
  59.         }  
  60.         top[0]->Reshape(1, 5, 1, 1);  
  61.         if (top.size() > 1)  
  62.         {  
  63.             top[1]->Reshape(1, 1, 1, 1);  
  64.         }  
  65.     }  
  66.   
  67.     template <typename Dtype>  
  68.     void RPNLayer<Dtype>::generate_anchors(){  
  69.         //generate base anchor  
  70.         vector<float> base_anchor;  
  71.         base_anchor.push_back(0);  
  72.         base_anchor.push_back(0);  
  73.         base_anchor.push_back(base_size_ - 1);  
  74.         base_anchor.push_back(base_size_ - 1);  
  75.         //enum ratio anchors  
  76.         vector<vector<float> >ratio_anchors = ratio_enum(base_anchor);  
  77.         for (int i = 0; i < ratio_anchors.size(); ++i)  
  78.         {  
  79.             vector<vector<float> > tmp = scale_enum(ratio_anchors[i]);  
  80.             gen_anchors_.insert(gen_anchors_.end(), tmp.begin(), tmp.end());  
  81.         }  
  82.     }  
  83.   
  84.     template <typename Dtype>  
  85.     vector<vector<float> > RPNLayer<Dtype>::scale_enum(vector<float> anchor){  
  86.         vector<vector<float> > result;  
  87.         vector<float> reform_anchor = whctrs(anchor);  
  88.         float x_ctr = reform_anchor[2];  
  89.         float y_ctr = reform_anchor[3];  
  90.         float w = reform_anchor[0];  
  91.         float h = reform_anchor[1];  
  92.         for (int i = 0; i < anchor_scales_.size(); ++i)  
  93.         {  
  94.             float ws = w * anchor_scales_[i];  
  95.             float hs = h *  anchor_scales_[i];  
  96.             vector<float> tmp = mkanchor(ws, hs, x_ctr, y_ctr);  
  97.             result.push_back(tmp);  
  98.         }  
  99.         return result;  
  100.     }  
  101.   
  102.   
  103.     template <typename Dtype>  
  104.     vector<vector<float> > RPNLayer<Dtype>::ratio_enum(vector<float> anchor){  
  105.         vector<vector<float> > result;  
  106.         vector<float> reform_anchor = whctrs(anchor);  
  107.         float x_ctr = reform_anchor[2];  
  108.         float y_ctr = reform_anchor[3];  
  109.         float size = reform_anchor[0] * reform_anchor[1];  
  110.         for (int i = 0; i < ratios_.size(); ++i)  
  111.         {  
  112.             float size_ratios = size / ratios_[i];  
  113.             float ws = round(sqrt(size_ratios));  
  114.             float hs = round(ws*ratios_[i]);  
  115.             vector<float> tmp = mkanchor(ws, hs, x_ctr, y_ctr);  
  116.             result.push_back(tmp);  
  117.         }  
  118.         return result;  
  119.     }  
  120.   
  121.     template <typename Dtype>  
  122.     vector<float> RPNLayer<Dtype>::mkanchor(float w, float h, float x_ctr, float y_ctr){  
  123.         vector<float> tmp;  
  124.         tmp.push_back(x_ctr - 0.5*(w - 1));  
  125.         tmp.push_back(y_ctr - 0.5*(h - 1));  
  126.         tmp.push_back(x_ctr + 0.5*(w - 1));  
  127.         tmp.push_back(y_ctr + 0.5*(h - 1));  
  128.         return tmp;  
  129.     }  
  130.     template <typename Dtype>  
  131.     vector<float> RPNLayer<Dtype>::whctrs(vector<float> anchor){  
  132.         vector<float> result;  
  133.         result.push_back(anchor[2] - anchor[0] + 1); //w  
  134.         result.push_back(anchor[3] - anchor[1] + 1); //h  
  135.         result.push_back((anchor[2] + anchor[0]) / 2); //ctrx  
  136.         result.push_back((anchor[3] + anchor[1]) / 2); //ctry  
  137.         return result;  
  138.     }  
  139.       
  140.   
  141.     /*template <typename Dtype> 
  142.     cv::Mat RPNLayer<Dtype>::proposal_local_anchor(int width, int height) 
  143.     { 
  144.         Blob<float> shift; 
  145.         cv::Mat shitf_x(height, width, CV_32SC1); 
  146.         cv::Mat shitf_y(height, width, CV_32SC1); 
  147.         for (size_t i = 0; i < width; i++) 
  148.         { 
  149.             for (size_t j = 0; j < height; j++) 
  150.             { 
  151.                 shitf_x.at<int>(j, i) = i * feat_stride_; 
  152.                 shitf_y.at<int>(j, i) = j * feat_stride_; 
  153.             } 
  154.         } 
  155.         shift.Reshape(anchors_nums_, width*height, 4,  1); 
  156.         float *p = shift.mutable_cpu_diff(), *a = shift.mutable_cpu_data(); 
  157.         for (int i = 0; i < height*width; i++) 
  158.         { 
  159.             for (int j = 0; j < anchors_nums_; j++) 
  160.             { 
  161.                 size_t num = i * 4 + j * 4 * height*width; 
  162.                 p[num + 0] = -shitf_x.at<int>(i / shitf_x.cols, i % shitf_x.cols); 
  163.                 p[num + 2] = -shitf_x.at<int>(i / shitf_x.cols, i % shitf_x.cols); 
  164.                 p[num + 1] = -shitf_y.at<int>(i / shitf_y.cols, i % shitf_y.cols); 
  165.                 p[num + 3] = -shitf_y.at<int>(i / shitf_y.cols, i % shitf_y.cols); 
  166.                 a[num + 0] = anchors_[j * 4 + 0]; 
  167.                 a[num + 1] = anchors_[j * 4 + 1]; 
  168.                 a[num + 2] = anchors_[j * 4 + 2]; 
  169.                 a[num + 3] = anchors_[j * 4 + 3]; 
  170.             } 
  171.         } 
  172.         shift.Update(); 
  173.         cv::Mat loacl_anchors(anchors_nums_ * height*width, 4, CV_32FC1); 
  174.         size_t num = 0; 
  175.         for (int i = 0; i < height; ++i) 
  176.         { 
  177.             for (int j = 0; j < width; ++j) 
  178.             { 
  179.                 for (int c = 0; c < anchors_nums_; ++c) 
  180.                 { 
  181.                     for (int k = 0; k < 4; ++k) 
  182.                     { 
  183.                         loacl_anchors.at<float>((i*width + j)*anchors_nums_+c, k)= shift.data_at(c, i*width + j, k, 0); 
  184.                     } 
  185.                 } 
  186.             } 
  187.         } 
  188.         return loacl_anchors; 
  189.     }*/  
  190.   
  191.     template <typename Dtype>  
  192.     void RPNLayer<Dtype>::proposal_local_anchor(){  
  193.         int length = mymax(map_width_, map_height_);  
  194.         int step = map_width_*map_height_;  
  195.         int *map_m = new int[length];  
  196.         for (int i = 0; i < length; ++i)  
  197.         {  
  198.             map_m[i] = i*feat_stride_;  
  199.         }  
  200.         Dtype *shift_x = new Dtype[step];  
  201.         Dtype *shift_y = new Dtype[step];  
  202.         for (int i = 0; i < map_height_; ++i)  
  203.         {  
  204.             for (int j = 0; j < map_width_; ++j)  
  205.             {  
  206.                 shift_x[i*map_width_ + j] = map_m[j];  
  207.                 shift_y[i*map_width_ + j] = map_m[i];  
  208.             }  
  209.         }  
  210.         local_anchors_->Reshape(1, anchors_nums_ * 4, map_height_, map_width_);  
  211.         Dtype *a = local_anchors_->mutable_cpu_data();  
  212.         for (int i = 0; i < anchors_nums_; ++i)  
  213.         {  
  214.             caffe_set(step, Dtype(anchors_[i * 4 + 0]), a + (i * 4 + 0) *step);  
  215.             caffe_set(step, Dtype(anchors_[i * 4 + 1]), a + (i * 4 + 1) *step);  
  216.             caffe_set(step, Dtype(anchors_[i * 4 + 2]), a + (i * 4 + 2) *step);  
  217.             caffe_set(step, Dtype(anchors_[i * 4 + 3]), a + (i * 4 + 3) *step);  
  218.             caffe_axpy(step, Dtype(1), shift_x, a + (i * 4 + 0)*step);  
  219.             caffe_axpy(step, Dtype(1), shift_x, a + (i * 4 + 2)*step);  
  220.             caffe_axpy(step, Dtype(1), shift_y, a + (i * 4 + 1)*step);  
  221.             caffe_axpy(step, Dtype(1), shift_y, a + (i * 4 + 3)*step);  
  222.         }  
  223.     }  
  224.   
  225.     template<typename Dtype>  
  226.     void RPNLayer<Dtype>::filter_boxs(cv::Mat& pre_box, cv::Mat& score, vector<abox>& aboxes)  
  227.     {  
  228.         float localMinSize=min_size_*src_scale_;  
  229.         aboxes.clear();  
  230.           
  231.         for (int i = 0; i < pre_box.rows; i++)  
  232.         {  
  233.             int widths = pre_box.at<float>(i, 2) - pre_box.at<float>(i, 0) + 1;  
  234.             int heights = pre_box.at<float>(i, 3) - pre_box.at<float>(i, 1) + 1;  
  235.             if (widths >= localMinSize || heights >= localMinSize)  
  236.             {  
  237.                 abox tmp;  
  238.                 tmp.x1 = pre_box.at<float>(i, 0);  
  239.                 tmp.y1 = pre_box.at<float>(i, 1);  
  240.                 tmp.x2 = pre_box.at<float>(i, 2);  
  241.                 tmp.y2 = pre_box.at<float>(i, 3);  
  242.                 tmp.score = score.at<float>(i, 0);  
  243.                 aboxes.push_back(tmp);  
  244.             }  
  245.         }  
  246.     }  
  247.   
  248.     template<typename Dtype>  
  249.     void RPNLayer<Dtype>::filter_boxs(vector<abox>& aboxes)  
  250.     {  
  251.         float localMinSize = min_size_*src_scale_;  
  252.         aboxes.clear();  
  253.         int map_width = m_box_->width();  
  254.         int map_height = m_box_->height();  
  255.         int map_channel = m_box_->channels();  
  256.         const Dtype *box = m_box_->cpu_data();  
  257.         const Dtype *score = m_score_->cpu_data();  
  258.   
  259.         int step = 4 * map_height*map_width;  
  260.         int one_step = map_height*map_width;  
  261.         int offset_w, offset_h, offset_x, offset_y, offset_s;  
  262.   
  263.         for (int h = 0; h < map_height; ++h)  
  264.         {  
  265.             for (int w = 0; w < map_width; ++w)  
  266.             {  
  267.                 offset_x = h*map_width + w;  
  268.                 offset_y = offset_x + one_step;  
  269.                 offset_w = offset_y + one_step;  
  270.                 offset_h = offset_w + one_step;  
  271.                 offset_s = one_step*anchors_nums_+h*map_width + w;  
  272.                 for (int c = 0; c < map_channel / 4; ++c)  
  273.                 {  
  274.                     Dtype width = box[offset_w], height = box[offset_h];  
  275.                     if (width < localMinSize || height < localMinSize)  
  276.                     {  
  277.                     }  
  278.                     else  
  279.                     {  
  280.                         abox tmp;  
  281.                         tmp.batch_ind = 0;  
  282.                         tmp.x1 = box[offset_x] - 0.5*width;  
  283.                         tmp.y1 = box[offset_y] - 0.5*height;  
  284.                         tmp.x2 = box[offset_x] + 0.5*width;  
  285.                         tmp.y2 = box[offset_y] + 0.5*height;  
  286.                         tmp.x1 = mymin(mymax(tmp.x1, 0), src_width_);  
  287.                         tmp.y1 = mymin(mymax(tmp.y1, 0), src_height_);  
  288.                         tmp.x2 = mymin(mymax(tmp.x2, 0), src_width_);  
  289.                         tmp.y2 = mymin(mymax(tmp.y2, 0), src_height_);  
  290.                         tmp.score = score[offset_s];  
  291.                         aboxes.push_back(tmp);  
  292.                     }  
  293.                     offset_x += step;  
  294.                     offset_y += step;  
  295.                     offset_w += step;  
  296.                     offset_h += step;  
  297.                     offset_s += one_step;  
  298.                 }  
  299.             }  
  300.         }  
  301.     }  
  302.   
  303.     template<typename Dtype>  
  304.     void RPNLayer<Dtype>::bbox_tranform_inv(){  
  305.         int channel = m_box_->channels();  
  306.         int height = m_box_->height();  
  307.         int width = m_box_->width();  
  308.         int step = height*width;  
  309.         Dtype * a = m_box_->mutable_cpu_data();  
  310.         Dtype * b = local_anchors_->mutable_cpu_data();  
  311.         for (int i = 0; i < channel / 4; ++i)  
  312.         {  
  313.             caffe_axpy(2*step, Dtype(-1), b + (i * 4 + 0)*step, b + (i * 4 + 2)*step);  
  314.             caffe_add_scalar(2 * step, Dtype(1), b + (i * 4 + 2)*step);  
  315.             caffe_axpy(2*step, Dtype(0.5), b + (i * 4 + 2)*step, b + (i * 4 + 0)*step);  
  316.               
  317.             caffe_mul(2 * step, b + (i * 4 + 2)*step, a + (i * 4 + 0)*step, a + (i * 4 + 0)*step);  
  318.             caffe_add(2 * step, b + (i * 4 + 0)*step, a + (i * 4 + 0)*step, a + (i * 4 + 0)*step);  
  319.   
  320.             caffe_exp(2*step, a + (i * 4 + 2)*step, a + (i * 4 + 2)*step);  
  321.             caffe_mul(2 * step, b + (i * 4 + 2)*step, a + (i * 4 + 2)*step, a + (i * 4 + 2)*step);  
  322.         }  
  323.     }  
  324.   
  325.   
  326.       
  327.   
  328.     template<typename Dtype>  
  329.     void RPNLayer<Dtype>::nms(std::vector<abox> &input_boxes, float nms_thresh){  
  330.         std::vector<float>vArea(input_boxes.size());  
  331.         for (int i = 0; i < input_boxes.size(); ++i)  
  332.         {  
  333.             vArea[i] = (input_boxes.at(i).x2 - input_boxes.at(i).x1 + 1)  
  334.                 * (input_boxes.at(i).y2 - input_boxes.at(i).y1 + 1);  
  335.         }  
  336.         for (int i = 0; i < input_boxes.size(); ++i)  
  337.         {  
  338.             for (int j = i + 1; j < input_boxes.size();)  
  339.             {  
  340.                 float xx1 = std::max(input_boxes[i].x1, input_boxes[j].x1);  
  341.                 float yy1 = std::max(input_boxes[i].y1, input_boxes[j].y1);  
  342.                 float xx2 = std::min(input_boxes[i].x2, input_boxes[j].x2);  
  343.                 float yy2 = std::min(input_boxes[i].y2, input_boxes[j].y2);  
  344.                 float w = std::max(float(0), xx2 - xx1 + 1);  
  345.                 float   h = std::max(float(0), yy2 - yy1 + 1);  
  346.                 float   inter = w * h;  
  347.                 float ovr = inter / (vArea[i] + vArea[j] - inter);  
  348.                 if (ovr >= nms_thresh)  
  349.                 {  
  350.                     input_boxes.erase(input_boxes.begin() + j);  
  351.                     vArea.erase(vArea.begin() + j);  
  352.                 }  
  353.                 else  
  354.                 {  
  355.                     j++;  
  356.                 }  
  357.             }  
  358.         }  
  359.     }  
  360.   
  361.     template <typename Dtype>  
  362.     void RPNLayer<Dtype>::Forward_cpu(  
  363.         const vector<Blob<Dtype>*>& bottom,  
  364.         const vector<Blob<Dtype>*>& top) {  
  365.           
  366.         map_width_ = bottom[1]->width();  
  367.         map_height_ = bottom[1]->height();  
  368.         //int channels = bottom[1]->channels();  
  369.           
  370.           
  371.         //get boxs_delta,向右。  
  372.         m_box_->CopyFrom(*(bottom[1]), falsetrue);  
  373.         /*cv::Mat boxs_delta(height*width*anchors_nums_, 4, CV_32FC1); 
  374.         for (int i = 0; i < height; ++i) 
  375.         { 
  376.             for (int j = 0; j < width; ++j) 
  377.             { 
  378.                 for (int k = 0; k < anchors_nums_; ++k) 
  379.                 { 
  380.                     for (int c = 0; c < 4; ++c) 
  381.                     { 
  382.                         boxs_delta.at<float>((i*width + j)*anchors_nums_ + k, c) = bottom[1]->data_at(0, k*4 + c, i, j); 
  383.                     } 
  384.                 } 
  385.             } 
  386.         }*/  
  387.   
  388.           
  389.   
  390.         //get sores 向右,前面anchors_nums_个位bg的得分,后面anchors_nums_为fg得分,我们需要的是后面的。  
  391.         m_score_->CopyFrom(*(bottom[0]),false,true);  
  392.           
  393.         /*cv::Mat scores(height*width*anchors_nums_, 1, CV_32FC1); 
  394.         for (int i = 0; i < height; ++i) 
  395.         { 
  396.             for (int j = 0; j < width; ++j) 
  397.             { 
  398.                 for (int k = 0; k < anchors_nums_; ++k) 
  399.                 { 
  400.                     scores.at<float>((i*width + j)*anchors_nums_+k, 0) = bottom[0]->data_at(0, k + anchors_nums_, i, j); 
  401.                 } 
  402.             } 
  403.         }*/  
  404.   
  405.         //get im_info  
  406.   
  407.         src_height_ = bottom[2]->data_at(0, 0,0,0);  
  408.         src_width_ = bottom[2]->data_at(0, 1,0,0);  
  409.         src_scale_ = bottom[2]->data_at(0, 2, 0, 0);  
  410.   
  411.         //gen local anchors 向右  
  412.           
  413.         proposal_local_anchor();  
  414.         //cv::Mat local_anchors = proposal_local_anchor(width, height);  
  415.           
  416.   
  417.         //Convert anchors into proposals via bbox transformations  
  418.           
  419.         bbox_tranform_inv();  
  420.           
  421.         /*for (int i = 0; i < pre_box.rows; ++i) 
  422.         { 
  423.             if (pre_box.at<float>(i, 0) < 0)   pre_box.at<float>(i, 0) = 0; 
  424.             if (pre_box.at<float>(i, 0) > (src_width_ - 1))    pre_box.at<float>(i, 0) = src_width_ - 1; 
  425.             if (pre_box.at<float>(i, 2) < 0)   pre_box.at<float>(i, 2) = 0; 
  426.             if (pre_box.at<float>(i, 2) > (src_width_ - 1))    pre_box.at<float>(i, 2) = src_width_ - 1; 
  427.  
  428.             if (pre_box.at<float>(i, 1) < 0)   pre_box.at<float>(i, 1) = 0; 
  429.             if (pre_box.at<float>(i, 1) > (src_height_ - 1))   pre_box.at<float>(i, 1) = src_height_ - 1; 
  430.             if (pre_box.at<float>(i, 3) < 0)   pre_box.at<float>(i, 3) = 0; 
  431.             if (pre_box.at<float>(i, 3) > (src_height_ - 1))   pre_box.at<float>(i, 3) = src_height_ - 1; 
  432.         }*/  
  433.         vector<abox>aboxes;  
  434.           
  435.         filter_boxs(aboxes);  
  436.           
  437.         //clock_t start, end;  
  438.         //start = clock();  
  439.         std::sort(aboxes.rbegin(), aboxes.rend()); //降序  
  440.         if (pre_nms_topN_ > 0)  
  441.         {  
  442.             int tmp = mymin(pre_nms_topN_, aboxes.size());  
  443.             aboxes.erase(aboxes.begin() + tmp, aboxes.end());  
  444.         }  
  445.           
  446.         nms(aboxes,nms_thresh_);  
  447.         //end = clock();  
  448.         //std::cout << "sort nms:" << (double)(end - start) / CLOCKS_PER_SEC << std::endl;  
  449.         if (post_nms_topN_ > 0)  
  450.         {  
  451.             int tmp = mymin(post_nms_topN_, aboxes.size());  
  452.             aboxes.erase(aboxes.begin() + tmp, aboxes.end());  
  453.         }  
  454.         top[0]->Reshape(aboxes.size(),5,1,1);  
  455.         Dtype *top0 = top[0]->mutable_cpu_data();  
  456.         for (int i = 0; i < aboxes.size(); ++i)  
  457.         {  
  458.             //caffe_copy(aboxes.size() * 5, (Dtype*)aboxes.data(), top0);  
  459.             top0[0] = aboxes[i].batch_ind;  
  460.             top0[1] = aboxes[i].x1;  
  461.             top0[2] = aboxes[i].y1;   
  462.             top0[3] = aboxes[i].x2;  
  463.             top0[4] = aboxes[i].y2;  
  464.             top0 += top[0]->offset(1);  
  465.         }  
  466.         if (top.size()>1)  
  467.         {  
  468.             top[1]->Reshape(aboxes.size(), 1,1,1);  
  469.             Dtype *top1 = top[1]->mutable_cpu_data();  
  470.             for (int i = 0; i < aboxes.size(); ++i)  
  471.             {  
  472.                 top1[0] = aboxes[i].score;  
  473.                 top1 += top[1]->offset(1);  
  474.             }  
  475.         }     
  476.     }  
  477.   
  478. #ifdef CPU_ONLY  
  479.         STUB_GPU(RPNLayer);  
  480. #endif  
  481.   
  482.     INSTANTIATE_CLASS(RPNLayer);  
  483.     REGISTER_LAYER_CLASS(RPN);  
  484.   
  485. }  // namespace caffe<strong>  
  486. </strong>  

(2) 添加自定义层 roi_pooling_layer.hpp  把它放在 caffe/include/caffe/layers/  目录下

[cpp]  view plain  copy
  1. <span style="font-size:10px;">#ifndef CAFFE_ROI_POOLING_LAYER_HPP_  
  2. #define CAFFE_ROI_POOLING_LAYER_HPP_  
  3.   
  4. #include <vector>  
  5.   
  6. #include "caffe/blob.hpp"  
  7. #include "caffe/common.hpp"  
  8. #include "caffe/layer.hpp"  
  9. #include "caffe/proto/caffe.pb.h"  
  10.   
  11. namespace caffe {  
  12.   
  13. /**  
  14.  * @brief Perform max pooling on regions of interest specified by input, takes 
  15.  *        as input N feature maps and a list of R regions of interest. 
  16.  * 
  17.  *   ROIPoolingLayer takes 2 inputs and produces 1 output. bottom[0] is 
  18.  *   [N x C x H x W] feature maps on which pooling is performed. bottom[1] is 
  19.  *   [R x 5] containing a list R ROI tuples with batch index and coordinates of 
  20.  *   regions of interest. Each row in bottom[1] is a ROI tuple in format 
  21.  *   [batch_index x1 y1 x2 y2], where batch_index corresponds to the index of 
  22.  *   instance in the first input and x1 y1 x2 y2 are 0-indexed coordinates 
  23.  *   of ROI rectangle (including its boundaries). 
  24.  * 
  25.  *   For each of the R ROIs, max-pooling is performed over pooled_h x pooled_w 
  26.  *   output bins (specified in roi_pooling_param). The pooling bin sizes are 
  27.  *   adaptively set such that they tile ROI rectangle in the indexed feature 
  28.  *   map. The pooling region of vertical bin ph in [0, pooled_h) is computed as 
  29.  * 
  30.  *    start_ph (included) = y1 + floor(ph * (y2 - y1 + 1) / pooled_h) 
  31.  *    end_ph (excluded)   = y1 + ceil((ph + 1) * (y2 - y1 + 1) / pooled_h) 
  32.  * 
  33.  *   and similar horizontal bins. 
  34.  * 
  35.  * @param param provides ROIPoolingParameter roi_pooling_param, 
  36.  *        with ROIPoolingLayer options: 
  37.  *  - pooled_h. The pooled output height. 
  38.  *  - pooled_w. The pooled output width 
  39.  *  - spatial_scale. Multiplicative spatial scale factor to translate ROI 
  40.  *  coordinates from their input scale to the scale used when pooling. 
  41.  * 
  42.  * Fast R-CNN 
  43.  * Written by Ross Girshick 
  44.  */  
  45.   
  46. template <typename Dtype>  
  47. class ROIPoolingLayer : public Layer<Dtype> {  
  48.  public:  
  49.   explicit ROIPoolingLayer(const LayerParameter& param)  
  50.       : Layer<Dtype>(param) {}  
  51.   virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,  
  52.       const vector<Blob<Dtype>*>& top);  
  53.   virtual void Reshape(const vector<Blob<Dtype>*>& bottom,  
  54.       const vector<Blob<Dtype>*>& top);  
  55.   
  56.   virtual inline const char* type() const { return "ROIPooling"; }  
  57.   
  58.   virtual inline int MinBottomBlobs() const { return 2; }  
  59.   virtual inline int MaxBottomBlobs() const { return 2; }  
  60.   virtual inline int MinTopBlobs() const { return 1; }  
  61.   virtual inline int MaxTopBlobs() const { return 1; }  
  62.   
  63.  protected:  
  64.   virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,  
  65.       const vector<Blob<Dtype>*>& top);  
  66.   virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,  
  67.       const vector<Blob<Dtype>*>& top);  
  68.   virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,  
  69.       const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);  
  70.   virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,  
  71.       const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);  
  72.   
  73.   int channels_;  
  74.   int height_;  
  75.   int width_;  
  76.   int pooled_height_;  
  77.   int pooled_width_;  
  78.   Dtype spatial_scale_;  
  79.   Blob<int> max_idx_;  
  80. };  
  81.   
  82. }  // namespace caffe  
  83.   
  84. #endif  // CAFFE_ROI_POOLING_LAYER_HPP_</span><span style="font-size:18px;"><strong>  
  85. </strong></span>  
  然后是源文件 roi_pooling_layer.cpp 以及cuda版的roi_pooling_layer.cu  放在 caffe/src/caffe/layers/  目录下
[cpp]  view plain  copy
  1. #include <algorithm>  
  2. #include <cfloat>  
  3. #include <vector>  
  4.   
  5. #include "caffe/layers/roi_pooling_layer.hpp"  
  6.   
  7. using std::max;  
  8. using std::min;  
  9. using std::floor;  
  10. using std::ceil;  
  11.   
  12. namespace caffe {  
  13.   
  14. template <typename Dtype>  
  15. void ROIPoolingLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,  
  16.       const vector<Blob<Dtype>*>& top) {  
  17.   ROIPoolingParameter roi_pool_param = this->layer_param_.roi_pooling_param();  
  18.   CHECK_GT(roi_pool_param.pooled_h(), 0)  
  19.       << "pooled_h must be > 0";  
  20.   CHECK_GT(roi_pool_param.pooled_w(), 0)  
  21.       << "pooled_w must be > 0";  
  22.   pooled_height_ = roi_pool_param.pooled_h();  
  23.   pooled_width_ = roi_pool_param.pooled_w();  
  24.   spatial_scale_ = roi_pool_param.spatial_scale();  
  25.   LOG(INFO) << "Spatial scale: " << spatial_scale_;  
  26. }  
  27.   
  28. template <typename Dtype>  
  29. void ROIPoolingLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,  
  30.       const vector<Blob<Dtype>*>& top) {  
  31.   channels_ = bottom[0]->channels();  
  32.   height_ = bottom[0]->height();  
  33.   width_ = bottom[0]->width();  
  34.   top[0]->Reshape(bottom[1]->num(), channels_, pooled_height_,  
  35.       pooled_width_);  
  36.   max_idx_.Reshape(bottom[1]->num(), channels_, pooled_height_,  
  37.       pooled_width_);  
  38. }  
  39.   
  40. template <typename Dtype>  
  41. void ROIPoolingLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,  
  42.       const vector<Blob<Dtype>*>& top) {  
  43.   const Dtype* bottom_data = bottom[0]->cpu_data();  
  44.   const Dtype* bottom_rois = bottom[1]->cpu_data();  
  45.   // Number of ROIs  
  46.   int num_rois = bottom[1]->num();  
  47.   int batch_size = bottom[0]->num();  
  48.   int top_count = top[0]->count();  
  49.   Dtype* top_data = top[0]->mutable_cpu_data();  
  50.   caffe_set(top_count, Dtype(-FLT_MAX), top_data);  
  51.   int* argmax_data = max_idx_.mutable_cpu_data();  
  52.   caffe_set(top_count, -1, argmax_data);  
  53.   
  54.   // For each ROI R = [batch_index x1 y1 x2 y2]: max pool over R  
  55.   for (int n = 0; n < num_rois; ++n) {  
  56.     int roi_batch_ind = bottom_rois[0];  
  57.     int roi_start_w = round(bottom_rois[1] * spatial_scale_);  
  58.     int roi_start_h = round(bottom_rois[2] * spatial_scale_);  
  59.     int roi_end_w = round(bottom_rois[3] * spatial_scale_);  
  60.     int roi_end_h = round(bottom_rois[4] * spatial_scale_);  
  61.     CHECK_GE(roi_batch_ind, 0);  
  62.     CHECK_LT(roi_batch_ind, batch_size);  
  63.   
  64.     int roi_height = max(roi_end_h - roi_start_h + 1, 1);  
  65.     int roi_width = max(roi_end_w - roi_start_w + 1, 1);  
  66.     const Dtype bin_size_h = static_cast<Dtype>(roi_height)  
  67.                              / static_cast<Dtype>(pooled_height_);  
  68.     const Dtype bin_size_w = static_cast<Dtype>(roi_width)  
  69.                              / static_cast<Dtype>(pooled_width_);  
  70.   
  71.     const Dtype* batch_data = bottom_data + bottom[0]->offset(roi_batch_ind);  
  72.   
  73.     for (int c = 0; c < channels_; ++c) {  
  74.       for (int ph = 0; ph < pooled_height_; ++ph) {  
  75.         for (int pw = 0; pw < pooled_width_; ++pw) {  
  76.           // Compute pooling region for this output unit:  
  77.           //  start (included) = floor(ph * roi_height / pooled_height_)  
  78.           //  end (excluded) = ceil((ph + 1) * roi_height / pooled_height_)  
  79.           int hstart = static_cast<int>(floor(static_cast<Dtype>(ph)  
  80.                                               * bin_size_h));  
  81.           int wstart = static_cast<int>(floor(static_cast<Dtype>(pw)  
  82.                                               * bin_size_w));  
  83.           int hend = static_cast<int>(ceil(static_cast<Dtype>(ph + 1)  
  84.                                            * bin_size_h));  
  85.           int wend = static_cast<int>(ceil(static_cast<Dtype>(pw + 1)  
  86.                                            * bin_size_w));  
  87.   
  88.           hstart = min(max(hstart + roi_start_h, 0), height_);  
  89.           hend = min(max(hend + roi_start_h, 0), height_);  
  90.           wstart = min(max(wstart + roi_start_w, 0), width_);  
  91.           wend = min(max(wend + roi_start_w, 0), width_);  
  92.   
  93.           bool is_empty = (hend <= hstart) || (wend <= wstart);  
  94.   
  95.           const int pool_index = ph * pooled_width_ + pw;  
  96.           if (is_empty) {  
  97.             top_data[pool_index] = 0;  
  98.             argmax_data[pool_index] = -1;  
  99.           }  
  100.   
  101.           for (int h = hstart; h < hend; ++h) {  
  102.             for (int w = wstart; w < wend; ++w) {  
  103.               const int index = h * width_ + w;  
  104.               if (batch_data[index] > top_data[pool_index]) {  
  105.                 top_data[pool_index] = batch_data[index];  
  106.                 argmax_data[pool_index] = index;  
  107.               }  
  108.             }  
  109.           }  
  110.         }  
  111.       }  
  112.       // Increment all data pointers by one channel  
  113.       batch_data += bottom[0]->offset(0, 1);  
  114.       top_data += top[0]->offset(0, 1);  
  115.       argmax_data += max_idx_.offset(0, 1);  
  116.     }  
  117.     // Increment ROI data pointer  
  118.     bottom_rois += bottom[1]->offset(1);  
  119.   }  
  120. }  
  121.   
  122. template <typename Dtype>  
  123. void ROIPoolingLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,  
  124.       const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {  
  125.   if (propagate_down[1]) {  
  126.     LOG(FATAL) << this->type()  
  127.                << " Layer cannot backpropagate to roi inputs.";  
  128.   }  
  129.   if (!propagate_down[0]) {  
  130.     return;  
  131.   }  
  132.   const Dtype* bottom_rois = bottom[1]->cpu_data();  
  133.   const Dtype* top_diff = top[0]->cpu_diff();  
  134.   Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();  
  135.   caffe_set(bottom[0]->count(), Dtype(0.), bottom_diff);  
  136.   const int* argmax_data = max_idx_.cpu_data();  
  137.   const int num_rois = top[0]->num();  
  138.   
  139.   // Accumulate gradient over all ROIs  
  140.   for (int roi_n = 0; roi_n < num_rois; ++roi_n) {  
  141.     int roi_batch_ind = bottom_rois[roi_n * 5];  
  142.     // Accumulate gradients over each bin in this ROI  
  143.     for (int c = 0; c < channels_; ++c) {  
  144.       for (int ph = 0; ph < pooled_height_; ++ph) {  
  145.         for (int pw = 0; pw < pooled_width_; ++pw) {  
  146.           int offset_top = ((roi_n * channels_ + c) * pooled_height_ + ph)  
  147.               * pooled_width_ + pw;  
  148.           int argmax_index = argmax_data[offset_top];  
  149.           if (argmax_index >= 0) {  
  150.             int offset_bottom = (roi_batch_ind * channels_ + c) * height_  
  151.                 * width_ + argmax_index;  
  152.             bottom_diff[offset_bottom] += top_diff[offset_top];  
  153.           }  
  154.         }  
  155.       }  
  156.     }  
  157.   }  
  158. }  
  159.   
  160.   
  161. #ifdef CPU_ONLY  
  162. STUB_GPU(ROIPoolingLayer);  
  163. #endif  
  164.   
  165. INSTANTIATE_CLASS(ROIPoolingLayer);  
  166. REGISTER_LAYER_CLASS(ROIPooling);  
  167.   
  168. }  // namespace caffe<strong>  
  169. </strong>  
  

[cpp]  view plain  copy
  1. #include <algorithm>  
  2. #include <cfloat>  
  3. #include <vector>  
  4.   
  5. #include "caffe/layers/roi_pooling_layer.hpp"  
  6.   
  7.   
  8. using std::max;  
  9. using std::min;  
  10.   
  11. namespace caffe {  
  12.   
  13. template <typename Dtype>  
  14. __global__ void ROIPoolForward(const int nthreads, const Dtype* bottom_data,  
  15.     const Dtype spatial_scale, const int channels, const int height,  
  16.     const int width, const int pooled_height, const int pooled_width,  
  17.     const Dtype* bottom_rois, Dtype* top_data, int* argmax_data) {  
  18.   CUDA_KERNEL_LOOP(index, nthreads) {  
  19.     // (n, c, ph, pw) is an element in the pooled output  
  20.     int pw = index % pooled_width;  
  21.     int ph = (index / pooled_width) % pooled_height;  
  22.     int c = (index / pooled_width / pooled_height) % channels;  
  23.     int n = index / pooled_width / pooled_height / channels;  
  24.   
  25.     bottom_rois += n * 5;  
  26.     int roi_batch_ind = bottom_rois[0];  
  27.     int roi_start_w = round(bottom_rois[1] * spatial_scale);  
  28.     int roi_start_h = round(bottom_rois[2] * spatial_scale);  
  29.     int roi_end_w = round(bottom_rois[3] * spatial_scale);  
  30.     int roi_end_h = round(bottom_rois[4] * spatial_scale);  
  31.   
  32.     // Force malformed ROIs to be 1x1  
  33.     int roi_width = max(roi_end_w - roi_start_w + 1, 1);  
  34.     int roi_height = max(roi_end_h - roi_start_h + 1, 1);  
  35.     Dtype bin_size_h = static_cast<Dtype>(roi_height)  
  36.                        / static_cast<Dtype>(pooled_height);  
  37.     Dtype bin_size_w = static_cast<Dtype>(roi_width)  
  38.                        / static_cast<Dtype>(pooled_width);  
  39.   
  40.     int hstart = static_cast<int>(floor(static_cast<Dtype>(ph)  
  41.                                         * bin_size_h));  
  42.     int wstart = static_cast<int>(floor(static_cast<Dtype>(pw)  
  43.                                         * bin_size_w));  
  44.     int hend = static_cast<int>(ceil(static_cast<Dtype>(ph + 1)  
  45.                                      * bin_size_h));  
  46.     int wend = static_cast<int>(ceil(static_cast<Dtype>(pw + 1)  
  47.                                      * bin_size_w));  
  48.   
  49.     // Add roi offsets and clip to input boundaries  
  50.     hstart = min(max(hstart + roi_start_h, 0), height);  
  51.     hend = min(max(hend + roi_start_h, 0), height);  
  52.     wstart = min(max(wstart + roi_start_w, 0), width);  
  53.     wend = min(max(wend + roi_start_w, 0), width);  
  54.     bool is_empty = (hend <= hstart) || (wend <= wstart);  
  55.   
  56.     // Define an empty pooling region to be zero  
  57.     Dtype maxval = is_empty ? 0 : -FLT_MAX;  
  58.     // If nothing is pooled, argmax = -1 causes nothing to be backprop'd  
  59.     int maxidx = -1;  
  60.     bottom_data += (roi_batch_ind * channels + c) * height * width;  
  61.     for (int h = hstart; h < hend; ++h) {  
  62.       for (int w = wstart; w < wend; ++w) {  
  63.         int bottom_index = h * width + w;  
  64.         if (bottom_data[bottom_index] > maxval) {  
  65.           maxval = bottom_data[bottom_index];  
  66.           maxidx = bottom_index;  
  67.         }  
  68.       }  
  69.     }  
  70.     top_data[index] = maxval;  
  71.     argmax_data[index] = maxidx;  
  72.   }  
  73. }  
  74.   
  75. template <typename Dtype>  
  76. void ROIPoolingLayer<Dtype>::Forward_gpu(const vector<Blob<Dtype>*>& bottom,  
  77.       const vector<Blob<Dtype>*>& top) {  
  78.   const Dtype* bottom_data = bottom[0]->gpu_data();  
  79.   const Dtype* bottom_rois = bottom[1]->gpu_data();  
  80.   Dtype* top_data = top[0]->mutable_gpu_data();  
  81.   int* argmax_data = max_idx_.mutable_gpu_data();  
  82.   int count = top[0]->count();  
  83.   // NOLINT_NEXT_LINE(whitespace/operators)  
  84.   ROIPoolForward<Dtype><<<CAFFE_GET_BLOCKS(count), CAFFE_CUDA_NUM_THREADS>>>(  
  85.       count, bottom_data, spatial_scale_, channels_, height_, width_,  
  86.       pooled_height_, pooled_width_, bottom_rois, top_data, argmax_data);  
  87.   CUDA_POST_KERNEL_CHECK;  
  88. }  
  89.   
  90. template <typename Dtype>  
  91. __global__ void ROIPoolBackward(const int nthreads, const Dtype* top_diff,  
  92.     const int* argmax_data, const int num_rois, const Dtype spatial_scale,  
  93.     const int channels, const int height, const int width,  
  94.     const int pooled_height, const int pooled_width, Dtype* bottom_diff,  
  95.     const Dtype* bottom_rois) {  
  96.   CUDA_KERNEL_LOOP(index, nthreads) {  
  97.     // (n, c, h, w) coords in bottom data  
  98.     int w = index % width;  
  99.     int h = (index / width) % height;  
  100.     int c = (index / width / height) % channels;  
  101.     int n = index / width / height / channels;  
  102.   
  103.     Dtype gradient = 0;  
  104.     // Accumulate gradient over all ROIs that pooled this element  
  105.     for (int roi_n = 0; roi_n < num_rois; ++roi_n) {  
  106.       const Dtype* offset_bottom_rois = bottom_rois + roi_n * 5;  
  107.       int roi_batch_ind = offset_bottom_rois[0];  
  108.       // Skip if ROI's batch index doesn't match n  
  109.       if (n != roi_batch_ind) {  
  110.         continue;  
  111.       }  
  112.   
  113.       int roi_start_w = round(offset_bottom_rois[1] * spatial_scale);  
  114.       int roi_start_h = round(offset_bottom_rois[2] * spatial_scale);  
  115.       int roi_end_w = round(offset_bottom_rois[3] * spatial_scale);  
  116.       int roi_end_h = round(offset_bottom_rois[4] * spatial_scale);  
  117.   
  118.       // Skip if ROI doesn't include (h, w)  
  119.       const bool in_roi = (w >= roi_start_w && w <= roi_end_w &&  
  120.                            h >= roi_start_h && h <= roi_end_h);  
  121.       if (!in_roi) {  
  122.         continue;  
  123.       }  
  124.   
  125.       int offset = (roi_n * channels + c) * pooled_height * pooled_width;  
  126.       const Dtype* offset_top_diff = top_diff + offset;  
  127.       const int* offset_argmax_data = argmax_data + offset;  
  128.   
  129.       // Compute feasible set of pooled units that could have pooled  
  130.       // this bottom unit  
  131.   
  132.       // Force malformed ROIs to be 1x1  
  133.       int roi_width = max(roi_end_w - roi_start_w + 1, 1);  
  134.       int roi_height = max(roi_end_h - roi_start_h + 1, 1);  
  135.   
  136.       Dtype bin_size_h = static_cast<Dtype>(roi_height)  
  137.                          / static_cast<Dtype>(pooled_height);  
  138.       Dtype bin_size_w = static_cast<Dtype>(roi_width)  
  139.                          / static_cast<Dtype>(pooled_width);  
  140.   
  141.       int phstart = floor(static_cast<Dtype>(h - roi_start_h) / bin_size_h);  
  142.       int phend = ceil(static_cast<Dtype>(h - roi_start_h + 1) / bin_size_h);  
  143.       int pwstart = floor(static_cast<Dtype>(w - roi_start_w) / bin_size_w);  
  144.       int pwend = ceil(static_cast<Dtype>(w - roi_start_w + 1) / bin_size_w);  
  145.   
  146.       phstart = min(max(phstart, 0), pooled_height);  
  147.       phend = min(max(phend, 0), pooled_height);  
  148.       pwstart = min(max(pwstart, 0), pooled_width);  
  149.       pwend = min(max(pwend, 0), pooled_width);  
  150.   
  151.       for (int ph = phstart; ph < phend; ++ph) {  
  152.         for (int pw = pwstart; pw < pwend; ++pw) {  
  153.           if (offset_argmax_data[ph * pooled_width + pw] == (h * width + w)) {  
  154.             gradient += offset_top_diff[ph * pooled_width + pw];  
  155.           }  
  156.         }  
  157.       }  
  158.     }  
  159.     bottom_diff[index] = gradient;  
  160.   }  
  161. }  
  162.   
  163. template <typename Dtype>  
  164. void ROIPoolingLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,  
  165.       const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {  
  166.   if (!propagate_down[0]) {  
  167.     return;  
  168.   }  
  169.   const Dtype* bottom_rois = bottom[1]->gpu_data();  
  170.   const Dtype* top_diff = top[0]->gpu_diff();  
  171.   Dtype* bottom_diff = bottom[0]->mutable_gpu_diff();  
  172.   const int count = bottom[0]->count();  
  173.   caffe_gpu_set(count, Dtype(0.), bottom_diff);  
  174.   const int* argmax_data = max_idx_.gpu_data();  
  175.   // NOLINT_NEXT_LINE(whitespace/operators)  
  176.   ROIPoolBackward<Dtype><<<CAFFE_GET_BLOCKS(count), CAFFE_CUDA_NUM_THREADS>>>(  
  177.       count, top_diff, argmax_data, top[0]->num(), spatial_scale_, channels_,  
  178.       height_, width_, pooled_height_, pooled_width_, bottom_diff, bottom_rois);  
  179.   CUDA_POST_KERNEL_CHECK;  
  180. }  
  181.   
  182. INSTANTIATE_LAYER_GPU_FUNCS(ROIPoolingLayer);  
  183.   
  184. }  // namespace caffe  

(3) 好了,代码添加完毕,现在在caffe/src/caffe/proto/caffe.proto 中声明这两个类

根据你自己的可用ID 在message Layer中添加这两个类,我的已经添加了,大概是这样的,千万记住大小写!

[cpp]  view plain  copy
  1. // NOTE  
  2. // Update the next available ID when you add a new LayerParameter field.  
  3. // LayerParameter next available layer-specific ID: 152 (last added: rpn_param roi_pooling_param)  
[cpp]  view plain  copy
  1. optional RPNParameter rpn_param = 150;                  //    
  2. optional ROIPoolingParameter roi_pooling_param = 151;       // roi pooling  Faster-Rcnn  
这里写好后,因为这两个层都有内置的参数,还得在这个文件的最末尾,定义具体的参数

[cpp]  view plain  copy
  1. message ROIPoolingParameter {  
  2.   optional uint32 pooled_h = 1 [default = 0];  
  3.   optional uint32 pooled_w = 2 [default = 0];  
  4.   optional float spatial_scale = 3 [default = 1];  
  5. }  
  6. message RPNParameter {  
  7.   optional uint32 feat_stride = 1;  
  8.   optional uint32 basesize = 2;  
  9.   repeated uint32 scale = 3;  
  10.   repeated float ratio = 4;  
  11.   optional uint32 boxminsize =5;  
  12.   optional uint32 per_nms_topn = 9;  
  13.   optional uint32 post_nms_topn = 11;  
  14.   optional float nms_thresh = 8;  
  15. }  

(4) 因为自定义层使用了RPN层,为了以后程序中各处都能使用该层,所以得在common.hpp和common.cpp文件的最末尾,添加对应的代码,注意这里的namespace RPN是和namespace caffe同一级的

头文件common.hpp里添加

[cpp]  view plain  copy
  1. namespace RPN{  
  2.     struct abox  
  3.     {  
  4.         float x1;  
  5.         float y1;  
  6.         float x2;  
  7.         float y2;  
  8.         float score;  
  9.         bool operator <(const abox&tmp) const{  
  10.             return score < tmp.score;  
  11.         }  
  12.    };  
  13.     void nms(std::vector<abox>& input_boxes,float nms_thresh);  
  14.     cv::Mat bbox_tranform_inv(cv::Mat, cv::Mat);  
  15. // namespace RPN  

源文件common.cpp里,为了防止说找不到cv::Mat类型的错误,添加opencv头文件

 #include<opencv2/opencv.hpp>

using namespace cv;


[cpp]  view plain  copy
  1. namespace RPN{  
  2.     cv::Mat bbox_tranform_inv(cv::Mat local_anchors, cv::Mat boxs_delta){  
  3.         cv::Mat pre_box(local_anchors.rows, local_anchors.cols, CV_32FC1);  
  4.         for (int i = 0; i < local_anchors.rows; i++)  
  5.         {  
  6.             double pred_ctr_x, pred_ctr_y, src_ctr_x, src_ctr_y;  
  7.             double dst_ctr_x, dst_ctr_y, dst_scl_x, dst_scl_y;  
  8.             double src_w, src_h, pred_w, pred_h;  
  9.             src_w = local_anchors.at<float>(i, 2) - local_anchors.at<float>(i, 0) + 1;  
  10.             src_h = local_anchors.at<float>(i, 3) - local_anchors.at<float>(i, 1) + 1;  
  11.             src_ctr_x = local_anchors.at<float>(i, 0) + 0.5 * src_w;  
  12.             src_ctr_y = local_anchors.at<float>(i, 1) + 0.5 * src_h;  
  13.   
  14.             dst_ctr_x = boxs_delta.at<float>(i, 0);  
  15.             dst_ctr_y = boxs_delta.at<float>(i, 1);  
  16.             dst_scl_x = boxs_delta.at<float>(i, 2);  
  17.             dst_scl_y = boxs_delta.at<float>(i, 3);  
  18.             pred_ctr_x = dst_ctr_x*src_w + src_ctr_x;  
  19.             pred_ctr_y = dst_ctr_y*src_h + src_ctr_y;  
  20.             pred_w = exp(dst_scl_x) * src_w;  
  21.             pred_h = exp(dst_scl_y) * src_h;  
  22.   
  23.             pre_box.at<float>(i, 0) = pred_ctr_x - 0.5*pred_w;  
  24.             pre_box.at<float>(i, 1) = pred_ctr_y - 0.5*pred_h;  
  25.             pre_box.at<float>(i, 2) = pred_ctr_x + 0.5*pred_w;  
  26.             pre_box.at<float>(i, 3) = pred_ctr_y + 0.5*pred_h;  
  27.         }  
  28.         return pre_box;  
  29.     }  
  30.     void nms(std::vector<abox> &input_boxes, float nms_thresh){  
  31.         std::vector<float>vArea(input_boxes.size());  
  32.         for (int i = 0; i < input_boxes.size(); ++i)  
  33.         {  
  34.             vArea[i] = (input_boxes.at(i).x2 - input_boxes.at(i).x1 + 1)  
  35.                 * (input_boxes.at(i).y2 - input_boxes.at(i).y1 + 1);  
  36.         }  
  37.         for (int i = 0; i < input_boxes.size(); ++i)  
  38.         {  
  39.             for (int j = i + 1; j < input_boxes.size();)  
  40.             {  
  41.                 float xx1 = std::max(input_boxes[i].x1, input_boxes[j].x1);  
  42.                 float yy1 = std::max(input_boxes[i].y1, input_boxes[j].y1);  
  43.                 float xx2 = std::min(input_boxes[i].x2, input_boxes[j].x2);  
  44.                 float yy2 = std::min(input_boxes[i].y2, input_boxes[j].y2);  
  45.                 float w = std::max(float(0), xx2 - xx1 + 1);  
  46.                 float   h = std::max(float(0), yy2 - yy1 + 1);  
  47.                 float   inter = w * h;  
  48.                 float ovr = inter / (vArea[i] + vArea[j] - inter);  
  49.                 if (ovr >= nms_thresh)  
  50.                 {  
  51.                     input_boxes.erase(input_boxes.begin() + j);  
  52.                     vArea.erase(vArea.begin() + j);  
  53.                 }  
  54.                 else  
  55.                 {  
  56.                     j++;  
  57.                 }  
  58.             }  
  59.         }  
  60.     }  
  61. }  

(5)好了,配置弄完了,回到caffe根目录下,

make clean

make all -j

开始编译吧!

可能会出现什么找不到pb.h文件什么的,那就继续执行 make -j5  可能是因为编译的线程太多导致先后顺序什么的。 我也是猜的,反正我是这么解决的。


(6)环境已经配置好了,现在我们再加个类,用来对图片进行检测吧!编写头文件ObjectDetector.hpp

[cpp]  view plain  copy
  1. <span style="font-size:10px;">#ifndef OBJECTDETECTOR_H  
  2. #define OBJECTDETECTOR_H  
  3.   
  4. #define INPUT_SIZE_NARROW  600  
  5. #define INPUT_SIZE_LONG  1000  
  6.   
  7. #include <string>  
  8. #include <caffe/net.hpp>  
  9. #include <caffe/common.hpp>  
  10. #include <opencv2/core/core.hpp>  
  11. #include <iostream>  
  12. #include <memory>  
  13. #include <map>  
  14.   
  15. using namespace std;  
  16.   
  17. class ObjectDetector  
  18. {  
  19. public:  
  20.   
  21.       ObjectDetector(const std::string &model_file, const std::string &weights_file);  //构造函数  
  22.     //对一张图片,进行检测,将结果保存进map数据结构里,分别表示每个类别对应的目标框,如果需要分数信息,则计算分数  
  23.       map<int,vector<cv::Rect> > detect(const cv::Mat& image, map<int,vector<float> >* score=NULL);     
  24.   
  25. private:  
  26.     boost::shared_ptr< caffe::Net<float> > net_;  
  27.     int class_num_;     //类别数+1   ,官方给的demo 是20+1类  
  28. };  
  29.   
  30. #endif<strong>  
  31. </strong></span>  
源文件ObjectDetector.cpp

[cpp]  view plain  copy
  1. #include "ObjectDetector.hpp"  
  2. #include <opencv2/highgui/highgui.hpp>  
  3. #include <opencv2/imgproc/imgproc.hpp>  
  4. #include <vector>  
  5. #include <fstream>  
  6.   
  7. using std::string;  
  8. using std::vector;  
  9. using namespace caffe;  
  10. using  std::max;  
  11. using std::min;  
  12.   
  13.   
  14. ObjectDetector::ObjectDetector(const std::string &model_file,const std::string &weights_file){  
  15. #ifdef CPU_ONLY  
  16.     Caffe::set_mode(Caffe::CPU);  
  17. #else  
  18.     Caffe::set_mode(Caffe::GPU);  
  19. #endif   
  20.     net_.reset(new Net<float>(model_file, TEST));  
  21.     net_->CopyTrainedLayersFrom(weights_file);  
  22.     this->class_num_ = net_->blob_by_name("cls_prob")->channels();  //求得类别数+1  
  23. }  
  24.   
  25. //对一张图片,进行检测,将结果保存进map数据结构里,分别表示每个类别对应的目标框,如果需要分数信息,则计算分数  
  26. map<int,vector<cv::Rect> > ObjectDetector::detect(const cv::Mat& image,map<int,vector<float> >* objectScore){  
  27.   
  28.     if(objectScore!=NULL)   //如果需要保存置信度  
  29.         objectScore->clear();  
  30.   
  31.     float CONF_THRESH = 0.8;  //置信度阈值  
  32.     float NMS_THRESH = 0.3;   //非极大值抑制阈值  
  33.     int max_side = max(image.rows, image.cols);   //分别求出图片宽和高的较大者  
  34.     int min_side = min(image.rows, image.cols);  
  35.     float max_side_scale = float(max_side) / float(INPUT_SIZE_LONG);    //分别求出缩放因子  
  36.     float min_side_scale = float(min_side) / float(INPUT_SIZE_NARROW);  
  37.     float max_scale = max(max_side_scale, min_side_scale);  
  38.   
  39.     float img_scale = float(1) / max_scale;  
  40.     int height = int(image.rows * img_scale);  
  41.     int width = int(image.cols * img_scale);  
  42.   
  43.     int num_out;  
  44.     cv::Mat cv_resized;  
  45.     image.convertTo(cv_resized, CV_32FC3);  
  46.     cv::resize(cv_resized, cv_resized, cv::Size(width, height));   
  47.     cv::Mat mean(height, width, cv_resized.type(), cv::Scalar(102.9801, 115.9465, 122.7717));  
  48.     cv::Mat normalized;  
  49.     subtract(cv_resized, mean, normalized);  
  50.   
  51.     float im_info[3];  
  52.     im_info[0] = height;  
  53.     im_info[1] = width;  
  54.     im_info[2] = img_scale;  
  55.     shared_ptr<Blob<float> > input_layer = net_->blob_by_name("data");  
  56.     input_layer->Reshape(1, normalized.channels(), height, width);  
  57.     net_->Reshape();  
  58.     float* input_data = input_layer->mutable_cpu_data();  
  59.     vector<cv::Mat> input_channels;  
  60.     for (int i = 0; i < input_layer->channels(); ++i) {  
  61.         cv::Mat channel(height, width, CV_32FC1, input_data);  
  62.         input_channels.push_back(channel);  
  63.         input_data += height * width;  
  64.     }  
  65.     cv::split(normalized, input_channels);  
  66.     net_->blob_by_name("im_info")->set_cpu_data(im_info);  
  67.     net_->Forward();                                       //进行网络前向传播  
  68.   
  69.   
  70.     int num = net_->blob_by_name("rois")->num();    //产生的 ROI 个数,比如为 13949个ROI  
  71.     const float *rois_data = net_->blob_by_name("rois")->cpu_data();    //维度比如为:13949*5*1*1  
  72.     int num1 = net_->blob_by_name("bbox_pred")->num();   //预测的矩形框 维度为 13949*84  
  73.     cv::Mat rois_box(num, 4, CV_32FC1);  
  74.     for (int i = 0; i < num; ++i)  
  75.     {  
  76.         rois_box.at<float>(i, 0) = rois_data[i * 5 + 1] / img_scale;  
  77.         rois_box.at<float>(i, 1) = rois_data[i * 5 + 2] / img_scale;  
  78.         rois_box.at<float>(i, 2) = rois_data[i * 5 + 3] / img_scale;  
  79.         rois_box.at<float>(i, 3) = rois_data[i * 5 + 4] / img_scale;  
  80.     }  
  81.   
  82.     shared_ptr<Blob<float> > bbox_delt_data = net_->blob_by_name("bbox_pred");   // 13949*84  
  83.     shared_ptr<Blob<float> > score = net_->blob_by_name("cls_prob");             // 3949*21  
  84.   
  85.     map<int,vector<cv::Rect> > label_objs;    //每个类别,对应的检测目标框  
  86.     for (int i = 1; i < class_num_; ++i){     //对每个类,进行遍历  
  87.         cv::Mat bbox_delt(num, 4, CV_32FC1);  
  88.         for (int j = 0; j < num; ++j){  
  89.             bbox_delt.at<float>(j, 0) = bbox_delt_data->data_at(j, i * 4 + 0, 0, 0);  
  90.             bbox_delt.at<float>(j, 1) = bbox_delt_data->data_at(j, i * 4 + 1, 0, 0);  
  91.             bbox_delt.at<float>(j, 2) = bbox_delt_data->data_at(j, i * 4 + 2, 0, 0);  
  92.             bbox_delt.at<float>(j, 3) = bbox_delt_data->data_at(j, i * 4 + 3, 0, 0);  
  93.         }  
  94.         cv::Mat box_class = RPN::bbox_tranform_inv(rois_box, bbox_delt);  
  95.   
  96.         vector<RPN::abox> aboxes;   //对于 类别i,检测出的矩形框保存在这  
  97.         for (int j = 0; j < box_class.rows; ++j){  
  98.             if (box_class.at<float>(j, 0) < 0)  box_class.at<float>(j, 0) = 0;  
  99.             if (box_class.at<float>(j, 0) > (image.cols - 1))   box_class.at<float>(j, 0) = image.cols - 1;  
  100.             if (box_class.at<float>(j, 2) < 0)  box_class.at<float>(j, 2) = 0;  
  101.             if (box_class.at<float>(j, 2) > (image.cols - 1))   box_class.at<float>(j, 2) = image.cols - 1;  
  102.   
  103.             if (box_class.at<float>(j, 1) < 0)  box_class.at<float>(j, 1) = 0;  
  104.             if (box_class.at<float>(j, 1) > (image.rows - 1))   box_class.at<float>(j, 1) = image.rows - 1;  
  105.             if (box_class.at<float>(j, 3) < 0)  box_class.at<float>(j, 3) = 0;  
  106.             if (box_class.at<float>(j, 3) > (image.rows - 1))   box_class.at<float>(j, 3) = image.rows - 1;  
  107.             RPN::abox tmp;  
  108.             tmp.x1 = box_class.at<float>(j, 0);  
  109.             tmp.y1 = box_class.at<float>(j, 1);  
  110.             tmp.x2 = box_class.at<float>(j, 2);  
  111.             tmp.y2 = box_class.at<float>(j, 3);  
  112.             tmp.score = score->data_at(j, i, 0, 0);  
  113.             aboxes.push_back(tmp);  
  114.         }  
  115.         std::sort(aboxes.rbegin(), aboxes.rend());  
  116.         RPN::nms(aboxes, NMS_THRESH);  //与非极大值抑制消除对于的矩形框  
  117.         for (int k = 0; k < aboxes.size();){  
  118.             if (aboxes[k].score < CONF_THRESH)  
  119.                 aboxes.erase(aboxes.begin() + k);  
  120.             else  
  121.                 k++;  
  122.         }  
  123.         //################ 将类别i的所有检测框,保存  
  124.         vector<cv::Rect> rect(aboxes.size());    //对于类别i,检测出的矩形框  
  125.         for(int ii=0;ii<aboxes.size();++ii)  
  126.             rect[ii]=cv::Rect(cv::Point(aboxes[ii].x1,aboxes[ii].y1),cv::Point(aboxes[ii].x2,aboxes[ii].y2));  
  127.         label_objs[i]=rect;     
  128.         //################ 将类别i的所有检测框的打分,保存  
  129.         if(objectScore!=NULL){           //################ 将类别i的所有检测框的打分,保存  
  130.             vector<float> tmp(aboxes.size());       //对于 类别i,检测出的矩形框的得分  
  131.             for(int ii=0;ii<aboxes.size();++ii)  
  132.                 tmp[ii]=aboxes[ii].score;  
  133.             objectScore->insert(pair<int,vector<float> >(i,tmp));  
  134.         }  
  135.     }  
  136.     return label_objs;  
  137. }  

这里的代码,是在参考博客中的代码,我改了下,加了自己的需求。这里的函数返回的是一个map对象,每一个键(类别label),对应一个矩形框向量。比如,一个20类检测任务,而一张图片里有3个人(标签是1),和2辆车(标签是5),那函数会返回一个map,其中有两个键值对,键1对应的值是一个3维的矩形框向量,分别代表着3个人的矩形框;键5对应的值是一个2维的矩形框向量,分别代表的是2辆车的矩形框。同时,函数还接受一个可选参数,可以返回每个矩形框各自对应的置信度。

Ok,现在我们写个主函数,测试下效果吧,我们建个文件夹,首先把网络描述文件test.prototxt拷贝过来,这里我用的是VGG16的,end2end的网络,路径是py-faster-rcnn/models/pascal_voc/VGG16/faster_rcnn_end2end/test.prototxt,Ok,拷贝过来,因为我们不需要python层了,那我们打开这个文件,定位到 Python层,

[cpp]  view plain  copy
  1. layer {  
  2.    name: 'proposal'  
  3.    type: 'Python'  
  4.    bottom: 'rpn_cls_prob_reshape'  
  5.    bottom: 'rpn_bbox_pred'  
  6.    bottom: 'im_info'  
  7.    top: 'rois'  
  8.    python_param {  
  9.      module: 'rpn.proposal_layer'  
  10.      layer: 'ProposalLayer'  
  11.     param_str: "'feat_stride': 16"  
  12.    }  
  13. }  
把它修改为

[cpp]  view plain  copy
  1. layer {  
  2.    name: "proposal"  
  3.    type: "RPN"  
  4.    bottom: "rpn_cls_prob_reshape"  
  5.    bottom: "rpn_bbox_pred"  
  6.    bottom: "im_info"  
  7.    top: "rois"  
  8.    rpn_param {  
  9.        feat_stride : 16  
  10.        basesize : 16  
  11.        scale : 8  
  12.        scale : 16  
  13.        scale : 32  
  14.        ratio : 0.5  
  15.        ratio : 1  
  16.        ratio : 2  
  17.        boxminsize :16  
  18.        per_nms_topn : 0;  
  19.        post_nms_topn : 0;  
  20.        nms_thresh : 0.3  
  21.    }  
  22. }  
是的,这里的一系列参数,可以自己设置的,大家可以尝试下

然后,我们需要一个已经训练好的检测caffemodel,这里我直接拿示例的20类demo的caffemodel,也把它拷贝到我们的文件夹下,万事俱备,只欠东风了! 赶紧编写个主函数进行测试吧,我的示例如下:

[cpp]  view plain  copy
  1. #include "ObjectDetector.hpp"  
  2. #include<opencv2/opencv.hpp>  
  3. #include<iostream>  
  4. #include<sstream>  
  5. using namespace cv;  
  6. using namespace std;  
  7. string num2str(float i){  
  8.     stringstream ss;  
  9.     ss<<i;  
  10.     return ss.str();  
  11. }  
  12.   
  13. int main(int argc,char **argv){  
  14.   ::google::InitGoogleLogging(argv[0]);  
  15. #ifdef CPU_ONLY  
  16.   cout<<"Use CPU\n";  
  17. #else  
  18.   cout<<"Use GPU\n";  
  19. #endif  
  20.   
  21.   ObjectDetector detect("test.prototxt","1.caffemodel");  
  22.   
  23.   Mat img=imread("1.jpg");  
  24.   map<int,vector<float> > score;  
  25.   map<int,vector<Rect> > label_objs=detect.detect(img,&score);  //目标检测,同时保存每个框的置信度  
  26.   
  27.   for(map<int,vector<Rect> >::iterator it=label_objs.begin();it!=label_objs.end();it++){  
  28.       int label=it->first;  //标签  
  29.       vector<Rect> rects=it->second;  //检测框  
  30.       for(int j=0;j<rects.size();j++){  
  31.           rectangle(img,rects[j],Scalar(0,0,255),2);   //画出矩形框  
  32.           string txt=num2str(label)+" : "+num2str(score[label][j]);  
  33.           putText(img,txt,Point(rects[j].x,rects[j].y),CV_FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,255,0)); //标记 类别:置信度  
  34.       }  
  35.   }  
  36.   imshow("", img);  
  37.   waitKey();  
  38.   return 0;  
  39. }  

好了,这里网络描述文件是 test.prototxt,调用的是caffemodel是官方示例的model,我这为了简单,改名1.caffemodel了, 对图片1.jpg进行测试, 现在编译main.cpp 文件,命令如下:
[cpp]  view plain  copy
  1. app.bin: main.cpp ObjectDetector.cpp  
  2.       g++ -o app.bin main.cpp ObjectDetector.cpp -I /home/*****/caffe/include/ -I /home/*****/caffe/.build_release/src/ -I /usr/local/cuda-8.0/include/ `pkg-config --libs --cflags opencv` -L /home/****/caffe/build/lib/ -lcaffe -lglog -lboost_system -lprotobuf   
具体路径参照自己的就好,生成app.bin可执行文件,运行,我们对一张图片进行测试,原图如下                               

                                                                        

检测后,如下:


                                                                 


这里为了方便,我直接输出的标签号以及对应的置信度了。可以看出 ,飞机的的label为1,船的label是4,我们从python版的demo.py中可以证实这点:

[cpp]  view plain  copy
  1. CLASSES = ('__background__',                             
  2.            'aeroplane''bicycle''bird''boat',  
  3.            'bottle''bus''car''cat''chair',  
  4.             'cow''diningtable''dog''horse',  
  5.              'motorbike''person''pottedplant',  
  6.             'sheep''sofa''train''tvmonitor')  


OK,大功告成啦~~~ 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值