目前部署服务的主流语言还是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> #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))
const int class_num=2;
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(){} };
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> #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))
const int class_num=2;
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(){} };
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
| 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-Y纯C++
版的Faster R-CNN代码,该代码将所有代码都改写为了C++版本,不像上一部分的代码中调用了很多python的库。
D-X-Y所封装的代码中对应原python版本中demo.py的接口在G:\gitProgram\caffe-faster-rcnn\src\api\FRCNN\frcnn_api.cpp
和G:\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]()