Faster R-CNN代码的caffe封装


目前部署服务的主流语言还是C++,因此项目上线前,在需要部署调试的时候需要对Faster R-CNN工程化为C++代码。这篇博文总结的部分主要将python版本的demo.py代码及其相关的部分改写成C++版本。

封装1

封装听起来很复杂,其实就是隐藏代码的实现细节,只暴露出对应的接口。Faster R-CNN具有很广泛的流行度了,相关的资料在可以说在目标检测模型里是最多的。
为了方便理解,首先给出C++工程demo的目录结构。

1
2
3
4
5
6
7
.
└── lib
│ │── faster_rcnn.cpp
│ │── faster_rcnn.hpp
│ │── CMakeLists.txt
│—— CMakeLists.txt
│—— main.cpp

其中faster_rcnn.cpp与faster_rcnn.hpp是对应的demo接口,main.cpp可以直接调用。
faster_rcnn.cpp文件如下:

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
#ifndef FASTER_RCNN_HPP
#define FASTER_RCNN_HPP
#include <stdio.h> // for snprintf
#include <string>
#include <vector>
#include <math.h>
#include <fstream>
#include <boost/python.hpp>
#include "caffe/caffe.hpp"
#include "gpu_nms.hpp"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace caffe;
using namespace std;

#define max(a, b) (((a)>(b)) ? (a) :(b))
#define min(a, b) (((a)<(b)) ? (a) :(b))

//background and car
const int class_num=2;

/*
* === Class ======================================================================
* Name: Detector
* Description: FasterRCNN CXX Detector
* =====================================================================================
*/
class Detector {
public:
Detector(const string& model_file, const string& weights_file);
void Detect(const string& im_name);
void bbox_transform_inv(const int num, const float* box_deltas, const float* pred_cls, float* boxes, float* pred, int img_height, int img_width);
void vis_detections(cv::Mat image, int* keep, int num_out, float* sorted_pred_cls, float CONF_THRESH);
void boxes_sort(int num, const float* pred, float* sorted_pred);

private:
shared_ptr<Net<float> > net_;
Detector(){}
};

//Using for box sort
struct Info
{
float score;
const float* head;
};
bool compare(const Info& Info1, const Info& Info2)
{
return Info1.score > Info2.score;
}
#endif

其对应的faster_rcnn.hpp文件为

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
#ifndef FASTER_RCNN_HPP
#define FASTER_RCNN_HPP
#include <stdio.h> // for snprintf
#include <string>
#include <vector>
#include <math.h>
#include <fstream>
#include <boost/python.hpp>
#include "caffe/caffe.hpp"
#include "gpu_nms.hpp"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace caffe;
using namespace std;

#define max(a, b) (((a)>(b)) ? (a) :(b))
#define min(a, b) (((a)<(b)) ? (a) :(b))

//background and car
const int class_num=2;

/*
* === Class ======================================================================
* Name: Detector
* Description: FasterRCNN CXX Detector
* =====================================================================================
*/
class Detector {
public:
Detector(const string& model_file, const string& weights_file);
void Detect(const string& im_name);
void bbox_transform_inv(const int num, const float* box_deltas, const float* pred_cls, float* boxes, float* pred, int img_height, int img_width);
void vis_detections(cv::Mat image, int* keep, int num_out, float* sorted_pred_cls, float CONF_THRESH);
void boxes_sort(int num, const float* pred, float* sorted_pred);

private:
shared_ptr<Net<float> > net_;
Detector(){}
};

//Using for box sort
struct Info
{
float score;
const float* head;
};
bool compare(const Info& Info1, const Info& Info2)
{
return Info1.score > Info2.score;
}
#endif

初次在linux上运行C++代码时,真是各种蒙圈,看着Makefile文件也搞不明白其中关键字代表的意义,使用cmake后,感觉容易了很多。如下是lib文件夹底下,即faster_rcnn.cpp对应的CMakeLists.txt文件。

1
2
3
4
5
6
7
8
9
cmake_minimum_required (VERSION 2.8)

SET (SRC_LIST faster_rcnn.cpp)
include_directories ( "${PROJECT_SOURCE_DIR}/../../caffe-fast-rcnn/include"
"${PROJECT_SOURCE_DIR}/../../lib/nms"
/usr/local/include
/usr/include/python2.7
/usr/local/cuda/include )
add_library(faster_rcnn SHARED ${SRC_LIST})

然后依次执行cmake.make就完成编译了。接下来是调用faster_rcnn.cpp接口的main.cpp文件。

1
2
3
4
5
6
7
8
9
10
11
12
#include "faster_rcnn.hpp"
int main()
{
string model_file = "/home/ouyang/Program/py-faster-rcnn/models/pascal_voc/VGG16/faster_rcnn_alt_opt/faster_rcnn_test.pt";
string weights_file = "/home/ouyang/Program/py-faster-rcnn/output/faster_rcnn_end2end/voc_2007_trainval/vgg16_faster_rcnn_iter_170000.caffemodel";
int GPUID=2;
Caffe::SetDevice(GPUID);
Caffe::set_mode(Caffe::CPU);
Detector det = Detector(model_file, weights_file);
det.Detect("/home/ouyang/Program/py-faster-rcnn/data/demo/90.jpg");
return 0;
}

里面的pt文件和model文件的路径替换成对应的就好。然后是main.cpp对应的CMakeLists.txt文件。

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
#This part is used for compile faster_rcnn_demo.cpp
cmake_minimum_required (VERSION 2.8)

project (main_demo)

add_executable(main main.cpp)

include_directories ( "${PROJECT_SOURCE_DIR}/../caffe-fast-rcnn/include"
"${PROJECT_SOURCE_DIR}/../lib/nms"
"${PROJECT_SOURCE_DIR}/lib"
/usr/local/include
/usr/include/python2.7
/usr/local/cuda/include)

target_link_libraries(main /home/ouyang/Program/py-faster-rcnn/Cplusplus2/lib/libfaster_rcnn.so
/home/ouyang/Program/py-faster-rcnn/caffe-fast-rcnn/build/lib/libcaffe.so
/home/ouyang/Program/py-faster-rcnn/lib/nms/libgpu_nms.so
/usr/local/lib/libopencv_highgui.so
/usr/local/lib/libopencv_core.so
/usr/local/lib/libopencv_imgproc.so
/usr/local/lib/libopencv_imgcodecs.so
/usr/lib/x86_64-linux-gnu/libglog.so
/usr/lib/x86_64-linux-gnu/libboost_system.so
/usr/lib/x86_64-linux-gnu/libboost_python.so
/usr/lib/x86_64-linux-gnu/libglog.so
/usr/lib/x86_64-linux-gnu/libpython2.7.so
)

相同的执行cmake.make完成该部分的编译。

封装2

上面C++封装的Faster R-CNN结构简单,代码量也少,部署起来很方便。但在项目中也有着致命的弱点,检测速度大概比python版的Faster R-CNN慢了一个数量级。因此很有必要寻求另外的封装方式,这里参考D-X-YC++版的Faster R-CNN代码,该代码将所有代码都改写为了C++版本,不像上一部分的代码中调用了很多python的库。
D-X-Y所封装的代码中对应原python版本中demo.py的接口在G:\gitProgram\caffe-faster-rcnn\src\api\FRCNN\frcnn_api.cppG:\gitProgram\caffe-faster-rcnn\include\api\FRCNN\frcnn_api.hpp。这里我将所需要的文件整合到一起,目录结构为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.
└── lib
│ │── frcnn_api.cpp
│ │── frcnn_api.hpp
│ │── CMakeLists.txt
│—— CMakeLists.txt
│—— main.cpp
└── include
│ │── api
│ │ api.hpp
│ │ └── FRCNN
│ │ │ │── frcnn_api.hpp
│ │ │ │── rpn_api.hpp
│ │── caffe
│ │ │──proto
│—— libcaffe.so.1.0.0
│—— libcaffe.so
│—— test.prototxt

上述代码结构中的include来自D-X-Y代码中的include,/include/caffe/proto来自D-X-Y代码中编译后产生,对应的路径为./caffe-faster-rcnn/.build_release/src/caffe/proto
第二种方式就不贴对应的代码了,在这里我也将两种方式对应的代码放在github上,供大家参考代码

欢迎关注我的公众号

enter description here

-------------本文结束感谢您的阅读-------------