1. 程式人生 > >windows下實現c++版faster-rcnn

windows下實現c++版faster-rcnn

本文主要參考:http://blog.csdn.net/oYangZi12/article/details/53290426?locationNum=5&fps=1 
1.下載微軟提供的caffe(https://github.com/Microsoft/caffe)並編譯,Pre-Build Steps 
Copy .\windows\CommonSettings.props.example to .\windows\CommonSettings.props 選擇cpu或者gpu模式。 
2.在caffe-master中libcaffe的相應位置加入roi-pooling層對應的cpp,hpp,cu檔案重新編譯caffe)。因roi-pooling層已經在微軟版本的caffe中存在,只需要找到並新增到libcaffe模組下。caffe-master\include\caffe\layers\roi_pooling_layer.hpp,caffe-master\include\caffe\layers\smooth_l1_loss_layer.hpp新增至caffe-master\include\caffe\layers路徑下,將caffe-master\src\caffe\layers\roi_pooling_layer.cpp,caffe-master\src\caffe\layers\smooth_l1_loss_layer新增至caffe-master\src\caffe\layers路徑下。 
3.重新build(生成各模組),並對整個caffe工程進行build.build成功則roi_pooling_layer層新增成功。 
4.caffe-master工程下新增Faster_rcnn模組,這裡直接將Classification模組中classification.cpp替換掉,Classification重新命名成Detect,新增Faster_rcnn.h,Faster_rcnn.cpp和Detect.cpp,新增路徑為..\caffe-master\examples\cpp_classification\ 
5.Faster_rcnn.h程式碼如下:

#pragma once
#include <gflags\gflags.h>
#include <glog\logging.h>
#include <cstring>
#include <map>
#include <string>
#include <vector>
#include "boost\algorithm\string.hpp"
#include "caffe\caffe.hpp"
#include "caffe\util\signal_handler.h"
#include <opencv2\opencv.hpp>
using namespace cv; using caffe::Blob; using caffe::Caffe; using caffe::Net; using caffe::Layer; using caffe::Solver; using caffe::shared_ptr; using caffe::string; using caffe::Timer; using caffe::vector; using std::ostringstream; struct config{ int maxsize; int target_size; int feat_stride; int
anchor[9][4]; int test_min_box_size; int per_nms_topN; int after_nms_topN; float overlap; config(){ maxsize = 1000; target_size = 600; feat_stride = 16; int tmp[9][4] = { {-83,-39,100,56}, {-175,-87,192,104}, {-359,-183,376,200}, {-55,-55,72,72}, {-119,-119,136,136}, {-247,-247,264,264}, {-35,-79,52,96}, {-79,-167,96,184}, {-167,-343,184,360} }; memcpy(anchor, tmp, 9 * 4 * sizeof(int)); test_min_box_size = 16; per_nms_topN = 6000; after_nms_topN = 300; overlap = 0.7; } }; struct abox { float x1; float y1; float x2; float y2; float score; }; class Faster_rcnn { public: Faster_rcnn(Mat); ~Faster_rcnn(); bool init(); Mat gettarget(Mat); public: config conf; private: Mat im, m_src; Size input_geometry_; shared_ptr<Net<float> > rpn_net, faster_rcnn_net; double im_scale; Size feature_map_size; private: bool loadnet(); bool imgtoblob(); vector<abox> forward(); bool rpn_converttoboxs(); void prep_im_size(); Mat proposal_local_anchor(); Mat bbox_tranform_inv(Mat, Mat, string); Mat get_rpn_score(Blob<float>*, int w, int h); void m_sort(Mat&, Mat&); void boxes_filter(vector<abox>&, int, vector<abox>, vector<int>); void filter_boxs(Mat&, Mat&, vector<abox>&); void nms(vector<abox>, double overlap, vector<int>& vPick, int &nPick); void testdetection(vector<abox>&); };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95

Faster_rcnn.cpp程式碼如下:

#include "Faster_rcnn.h"
#include <opencv2\opencv.hpp>

#include <algorithm>
#include "caffe\common.hpp"
#include "caffe\layers\input_layer.hpp"
#include "caffe\layers\inner_product_layer.hpp"
#include "caffe\layers\dropout_layer.hpp"
#include "caffe\layers\conv_layer.hpp"
#include "caffe\layers\relu_layer.hpp"
#include "caffe\layers\reshape_layer.hpp"
#include "caffe\layers\pooling_layer.hpp"
#include "caffe\layers\lrn_layer.hpp"
#include "caffe\layers\softmax_layer.hpp"
#include "caffe\layers\roi_pooling_layer.hpp"
//
//namespace caffe
//{
//  extern INSTANTIATE_CLASS(InputLayer);
//  extern INSTANTIATE_CLASS(InnerProductLayer);
//  extern INSTANTIATE_CLASS(DropoutLayer);
//  extern INSTANTIATE_CLASS(ConvolutionLayer);
//  extern INSTANTIATE_CLASS(ROIPoolingLayer);
//  REGISTER_LAYER_CLASS(Convolution);
//  extern INSTANTIATE_CLASS(ReLULayer);
//  REGISTER_LAYER_CLASS(ReLU);
//  extern INSTANTIATE_CLASS(PoolingLayer);
//  REGISTER_LAYER_CLASS(Pooling);
//  extern INSTANTIATE_CLASS(LRNLayer);
//  REGISTER_LAYER_CLASS(LRN);
//  extern INSTANTIATE_CLASS(SoftmaxLayer);
//  REGISTER_LAYER_CLASS(Softmax);
//  extern INSTANTIATE_CLASS(ReshapeLayer);
//
//}





cv::Scalar colortable[20] = { cv::Scalar(0, 0, 0), cv::Scalar(0, 0, 125),
cv::Scalar(0, 125, 125), cv::Scalar(125, 125, 125), cv::Scalar(125, 0, 0), cv::Scalar(125, 125, 0), cv::Scalar(0, 125, 0), cv::Scalar(125, 0, 125),
cv::Scalar(0, 0, 255), cv::Scalar(0, 255, 255), cv::Scalar(255, 255, 255), cv::Scalar(255, 0, 0), cv::Scalar(255, 255, 0), cv::Scalar(0, 255, 0),
cv::Scalar(255, 0, 255), cv::Scalar(0, 255, 100), cv::Scalar(0, 0, 100),
cv::Scalar(255, 0, 100), cv::Scalar(255, 255, 100), cv::Scalar(100, 100, 100) };
string classname[20] = { "aeroplane", "bike", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog",
"horse", "motobike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor" };
Faster_rcnn::Faster_rcnn(Mat src)
{
    m_src = src;
}
Faster_rcnn::~Faster_rcnn()
{
    //if (boxs != NULL) delete boxs;
}
bool Faster_rcnn::init()
{
    //init
    Caffe::set_mode(Caffe::CPU);
    loadnet();
    return true;
}
bool Faster_rcnn::loadnet()
{
    //load net
    rpn_net.reset(new Net<float>("F:\\fast rcnn\\fasterrcnn_vs2013_beta\\fasterrcnn_vs2013\\faster_rcnn_VOC0712_ZF\\proposal_test.prototxt", caffe::TEST));
    rpn_net->CopyTrainedLayersFrom("F:\\fast rcnn\\fasterrcnn_vs2013_beta\\fasterrcnn_vs2013\\faster_rcnn_VOC0712_ZF\\proposal_final");
    faster_rcnn_net.reset(new Net<float>("F:\\fast rcnn\\fasterrcnn_vs2013_beta\\fasterrcnn_vs2013\\faster_rcnn_VOC0712_ZF\\detection_test.prototxt", caffe::TEST));
    faster_rcnn_net->CopyTrainedLayersFrom("F:\\fast rcnn\\fasterrcnn_vs2013_beta\\fasterrcnn_vs2013\\faster_rcnn_VOC0712_ZF\\detection_final");
    /*rpn_net.reset(new Net<float>("faster_rcnn_VOC0712_ZF\\proposal_test.prototxt", caffe::TEST));
    rpn_net->CopyTrainedLayersFrom("faster_rcnn_VOC0712_ZF\\proposal_final");
    faster_rcnn_net.reset(new Net<float>("faster_rcnn_VOC0712_ZF\\detection_test.prototxt", caffe::TEST));
    faster_rcnn_net->CopyTrainedLayersFrom("faster_rcnn_VOC0712_ZF\\detection_final");*/
    return true;
}
bool Faster_rcnn::imgtoblob()
{
    Mat sample_float;
    m_src.convertTo(sample_float, CV_32FC3);
    cv::Scalar channel_mean = cv::mean(sample_float);
    Mat mean = cv::Mat(m_src.rows, m_src.cols, sample_float.type(), channel_mean);

    Mat sample_normalized;
    subtract(sample_float, mean, sample_normalized);
    prep_im_size();
    resize(sample_normalized, sample_normalized, input_geometry_);
    Blob<float>* input_layer = rpn_net->input_blobs()[0];
    input_layer->Reshape(1, sample_normalized.channels(), sample_normalized.rows, sample_normalized.cols);
    rpn_net->Reshape();
    float* input_data = input_layer->mutable_cpu_data();
    vector<cv::Mat> input_channels;
    for (int i = 0; i < input_layer->channels(); ++i)
    {
        cv::Mat channel(sample_normalized.rows, sample_normalized.cols, CV_32FC1, input_data);
        input_channels.push_back(channel);
        input_data += sample_normalized.rows * sample_normalized.cols;
    }
    cv::split(sample_normalized, input_channels);
    CHECK(reinterpret_cast<float*>(input_channels.at(0).data) == rpn_net->input_blobs()[0]->cpu_data()) << "Input channels are not wrapping the input layer of the network.";

    return true;
}
bool aboxcomp(abox& b1, abox& b2)
{
    return b1.score > b2.score;
}
vector<abox> Faster_rcnn::forward()
{
    //forward
    const vector<Blob<float>*>& result = rpn_net->Forward();
    Blob<float>* resule0 = result[0];
    Blob<float>* resule1 = result[1];
    Mat boxs_delta(resule0->num()*resule0->channels()*resule0->width()*resule0->height() / 4, 4, CV_32FC1);
    float* p = resule0->mutable_cpu_data();
    int num = 0;
    for (int i = 0; i < resule0->num()*resule0->channels()*resule0->width()*resule0->height() / 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            boxs_delta.at<float>(i, j) = resule0->data_at(0, num%resule0->channels(),
                (num - num / resule0->channels() / resule0->height() * resule0->channels() * resule0->height()) / resule0->height(),
                num / resule0->channels() / resule0->height());
            num++;
            //int order = j + i * 4;
            //boxs_delta.at<float>(i, j) = resule0->data_at(0, (order % (resule0->height()*resule0->channels())) % resule0->channels(), (order % (resule0->height()*resule0->channels())) / resule0->channels(), order / (resule0->height()*resule0->channels()));
        }
    }
    //create anchors
    feature_map_size = Size(resule0->width(), resule0->height());
    //prep_im_size();
    Mat anchors = proposal_local_anchor();
    Mat pre_box = bbox_tranform_inv(anchors, boxs_delta, "rpn");
    //Mat score(resule0->width(), resule0->height(), CV_32FC1);
    Mat score = get_rpn_score(resule1, resule0->width(), resule0->height());
    vector<abox> aboxes;
    filter_boxs(pre_box, score, aboxes);
    std::sort(aboxes.begin(), aboxes.end(), aboxcomp);
    //m_sort(pre_box,score);
    vector<int> vPick(aboxes.size());
    int nPick;
    /////////////有cuda版,待加入,此處為cpu版///////
    nms(aboxes, conf.overlap, vPick, nPick);
    vector<abox> aboxes_;
    boxes_filter(aboxes_, nPick, aboxes, vPick);
    return aboxes_;
}
void Faster_rcnn::nms(vector<abox> input_boxes, double overlap, vector<int> &vPick, int &nPick)
{
    int nSample = min(int(input_boxes.size()), conf.per_nms_topN);

    vector<double> vArea(nSample);
    for (int i = 0; i < nSample; ++i)
    {
        vArea[i] = double(input_boxes.at(i).x2 - input_boxes.at(i).x1 + 1)
            * (input_boxes.at(i).y2 - input_boxes.at(i).y1 + 1);
    }

    std::multimap<double, int> scores;
    for (int i = 0; i < nSample; ++i)
        scores.insert(std::pair<double, int>(input_boxes.at(i).score, i));

    nPick = 0;

    do
    {
        int last = scores.rbegin()->second;
        vPick[nPick] = last;
        nPick += 1;

        for (std::multimap<double, int>::iterator it = scores.begin(); it != scores.end();)
        {
            int it_idx = it->second;
            double xx1 = max(input_boxes.at(last).x1, input_boxes.at(it_idx).x1);
            double yy1 = max(input_boxes.at(last).y1, input_boxes.at(it_idx).y1);
            double xx2 = min(input_boxes.at(last).x2, input_boxes.at(it_idx).x2);
            double yy2 = min(input_boxes.at(last).y2, input_boxes.at(it_idx).y2);

            double w = max(double(0.0), xx2 - xx1 + 1), h = max(double(0.0), yy2 - yy1 + 1);

            double ov = w*h / (vArea[last] + vArea[it_idx] - w*h);

            if (ov > overlap)
            {
                it = scores.erase(it);
            }
            else
            {
                it++;
            }
        }

    } while (scores.size() != 0);
}
void Faster_rcnn::boxes_filter(vector<abox>& aboxes, int nPick, vector<abox> row, vector<int> vPick)
{
    int n = min(nPick, conf.after_nms_topN);
    for (int i = 0; i < n; i++)
    {
        aboxes.push_back(row[vPick[i]]);
    }
}
void Faster_rcnn::filter_boxs(Mat& pre_box, Mat& score, vector<abox>& aboxes)
{
    aboxes.clear();
    for (int i = 0; i < pre_box.rows; i++)
    {
        int widths = pre_box.at<float>(i, 2) - pre_box.at<float>(i, 0) + 1;
        int heights = pre_box.at<float>(i, 3) - pre_box.at<float>(i, 1) + 1;
        if (widths < conf.test_min_box_size || heights < conf.test_min_box_size)
        {
            pre_box.at<float>(i, 0) = 0;
            pre_box.at<float>(i, 1) = 0