faster_rcnn c++版本的 caffe 封装,动态库(2)
摘要: 转载请注明出处,楼燚(yì)航的blog,http://www.cnblogs.com/louyihang-loves-baiyan/
github上的代码链接,求给星星:) https://github.com/YihangLou/FasterRCNN-Encapsulation-Cplusplus
在上一篇文章中,我们是将对caffe的调用隔离了出来,可以说相当于原来caffe源码下的tools中cpp文件使用相同,然后自己写了个CMakeLists.txt进行编译。这里是进一步将代码进行分离,封装成libfaster_rcnn.so文件进行使用。对于部分接口,我可能做了一些改动。
目录结构
├── CMakeLists.txt
├── lib
│ ├── CMakeLists.txt
│ ├── faster_rcnn.cpp
│ ├── faster_rcnn.hpp
├── main.cpp
├── pbs_cxx_faster_rcnn_demo.job
在这里main.cpp就是直接调用faster_rcnn.cpp的接口,他的内容也很简单,只是在之前的基础上,再加上libfaster_rcnn.so这个动态库文件
#include "faster_rcnn.hpp"
int main()
{
string model_file = "/home/lyh1/workspace/py-faster-rcnn/models/pascal_voc/VGG_CNN_M_1024/faster_rcnn_alt_opt/faster_rcnn_test.pt";
string weights_file = "/home/lyh1/workspace/py-faster-rcnn/output/default/yuanzhang_car/vgg_cnn_m_1024_fast_rcnn_stage2_iter_40000.caffemodel";
int GPUID=0;
Caffe::SetDevice(GPUID);
Caffe::set_mode(Caffe::GPU);
Detector det = Detector(model_file, weights_file);
det.Detect("/home/lyh1/workspace/py-faster-rcnn/data/demo/car.jpg");
return 0;
}
可以看到这里只是include了faster_rcnn.hpp头文件,其对应的CMakeLists.txt文件如下:
#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"
/share/apps/local/include
/usr/local/include
/opt/python/include/python2.7
/share/apps/opt/intel/mkl/include
/usr/local/cuda/include )
target_link_libraries(main /home/lyh1/workspace/py-faster-rcnn/faster_cxx_lib/lib/libfaster_rcnn.so
/home/lyh1/workspace/py-faster-rcnn/caffe-fast-rcnn/build/lib/libcaffe.so
/home/lyh1/workspace/py-faster-rcnn/lib/nms/gpu_nms.so
/share/apps/local/lib/libopencv_highgui.so
/share/apps/local/lib/libopencv_core.so
/share/apps/local/lib/libopencv_imgproc.so
/share/apps/local/lib/libopencv_imgcodecs.so
/share/apps/local/lib/libglog.so
/share/apps/local/lib/libboost_system.so
/share/apps/local/lib/libboost_python.so
/share/apps/local/lib/libglog.so
/opt/rh/python27/root/usr/lib64/libpython2.7.so
)
对于faster_rcnn.hpp
和faster_rcnn.cpp
,我们需要将他们编译成动态库,下面是他们对应的CMakeLists.txt,在文件中,可以看到跟上面这个区别是用了add_library语句,并且加入了SHARED关键字,SHARED代表动态库。其次,在编译动态库的过程中,是不需要链接的,但是我们知道这个库是依赖别的很多个库的,所以在最后形成可执行文件也就是上面这个CMakeLists.txt,我们需要添加这个动态库所依赖的那些动态库,至此就OK了。编译的话,非常傻瓜cmake .
然后在执行make
即可。
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"
/share/apps/local/include
/usr/local/include
/opt/python/include/python2.7
/share/apps/opt/intel/mkl/include
/usr/local/cuda/include )
add_library(faster_rcnn SHARED ${SRC_LIST})
首先将原来的cpp文件中的声明提取出来,比较简单,就是hpp文件对应cpp文件。如下:
#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
相应的cpp文件
#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>
#include "faster_rcnn.hpp"
using namespace caffe;
using namespace std;
/*
* === FUNCTION ======================================================================
* Name: Detector
* Description: Load the model file and weights file
* =====================================================================================
*/
//load modelfile and weights
Detector::Detector(const string& model_file, const string& weights_file)
{
net_ = shared_ptr<Net<float> >(new Net<float>(model_file, caffe::TEST));
net_->CopyTrainedLayersFrom(weights_file);
}
/*
* === FUNCTION ======================================================================
* Name: Detect
* Description: Perform detection operation
* Warning the max input size should less than 1000*600
* =====================================================================================
*/
//perform detection operation
//input image max size 1000*600
void Detector::Detect(const string& im_name)
{
float CONF_THRESH = 0.8;
float NMS_THRESH = 0.3;
const int max_input_side=1000;
const int min_input_side=600;
cv::Mat cv_img = cv::imread(im_name);
cv::Mat cv_new(cv_img.rows, cv_img.cols, CV_32FC3, cv::Scalar(0,0,0));
if(cv_img.empty())
{
std::cout<<"Can not get the image file !"<<endl;
return ;
}
int max_side = max(cv_img.rows, cv_img.cols);
int min_side = min(cv_img.rows, cv_img.cols);
float max_side_scale = float(max_side) / float(max_input_side);
float min_side_scale = float(min_side) /float( min_input_side);
float max_scale=max(max_side_scale, min_side_scale);
float img_scale = 1;
if(max_scale > 1)
{
img_scale = float(1) / max_scale;
}
int height = int(cv_img.rows * img_scale);
int width = int(cv_img.cols * img_scale);
int num_out;
cv::Mat cv_resized;
std::cout<<"imagename "<<im_name<<endl;
float im_info[3];
float data_buf[height*width*3];
float *boxes = NULL;
float *pred = NULL;
float *pred_per_class = NULL;
float *sorted_pred_cls = NULL;
int *keep = NULL;
const float* bbox_delt;
const float* rois;
const float* pred_cls;
int num;
for (int h = 0; h < cv_img.rows; ++h )
{
for (int w = 0; w < cv_img.cols; ++w)
{
cv_new.at<cv::Vec3f>(cv::Point(w, h))[0] = float(cv_img.at<cv::Vec3b>(cv::Point(w, h))[0])-float(102.9801);
cv_new.at<cv::Vec3f>(cv::Point(w, h))[1] = float(cv_img.at<cv::Vec3b>(cv::Point(w, h))[1])-float(115.9465);
cv_new.at<cv::Vec3f>(cv::Point(w, h))[2] = float(cv_img.at<cv::Vec3b>(cv::Point(w, h))[2])-float(122.7717);
}
}
cv::resize(cv_new, cv_resized, cv::Size(width, height));
im_info[0] = cv_resized.rows;
im_info[1] = cv_resized.cols;
im_info[2] = img_scale;
for (int h = 0; h < height; ++h )
{
for (int w = 0; w < width; ++w)
{
data_buf[(0*height+h)*width+w] = float(cv_resized.at<cv::Vec3f>(cv::Point(w, h))[0]);
data_buf[(1*height+h)*width+w] = float(cv_resized.at<cv::Vec3f>(cv::Point(w, h))[1]);
data_buf[(2*height+h)*width+w] = float(cv_resized.at<cv::Vec3f>(cv::Point(w, h))[2]);
}
}
net_->blob_by_name("data")->Reshape(1, 3, height, width);
net_->blob_by_name("data")->set_cpu_data(data_buf);
net_->blob_by_name("im_info")->set_cpu_data(im_info);
net_->ForwardFrom(0);
bbox_delt = net_->blob_by_name("bbox_pred")->cpu_data();
num = net_->blob_by_name("rois")->num();
rois = net_->blob_by_name("rois")->cpu_data();
pred_cls = net_->blob_by_name("cls_prob")->cpu_data();
boxes = new float[num*4];
pred = new float[num*5*class_num];
pred_per_class = new float[num*5];
sorted_pred_cls = new float[num*5];
keep = new int[num];
for (int n = 0; n < num; n++)
{
for (int c = 0; c < 4; c++)
{
boxes[n*4+c] = rois[n*5+c+1] / img_scale;
}
}
bbox_transform_inv(num, bbox_delt, pred_cls, boxes, pred, cv_img.rows, cv_img.cols);
for (int i = 1; i < class_num; i ++)
{
for (int j = 0; j< num; j++)
{
for (int k=0; k<5; k++)
pred_per_class[j*5+k] = pred[(i*num+j)*5+k];
}
boxes_sort(num, pred_per_class, sorted_pred_cls);
_nms(keep, &num_out, sorted_pred_cls, num, 5, NMS_THRESH, 0);
//for visualize only
vis_detections(cv_img, keep, num_out, sorted_pred_cls, CONF_THRESH);
}
cv::imwrite("vis.jpg",cv_img);
delete []boxes;
delete []pred;
delete []pred_per_class;
delete []keep;
delete []sorted_pred_cls;
}
/*
* === FUNCTION ======================================================================
* Name: vis_detections
* Description: Visuallize the detection result
* =====================================================================================
*/
void Detector::vis_detections(cv::Mat image, int* keep, int num_out, float* sorted_pred_cls, float CONF_THRESH)
{
int i=0;
while(sorted_pred_cls[keep[i]*5+4]>CONF_THRESH && i < num_out)
{
if(i>=num_out)
return;
cv::rectangle(image,cv::Point(sorted_pred_cls[keep[i]*5+0], sorted_pred_cls[keep[i]*5+1]),cv::Point(sorted_pred_cls[keep[i]*5+2], sorted_pred_cls[keep[i]*5+3]),cv::Scalar(255,0,0));
i++;
}
}
/*
* === FUNCTION ======================================================================
* Name: boxes_sort
* Description: Sort the bounding box according score
* =====================================================================================
*/
void Detector::boxes_sort(const int num, const float* pred, float* sorted_pred)
{
vector<Info> my;
Info tmp;
for (int i = 0; i< num; i++)
{
tmp.score = pred[i*5 + 4];
tmp.head = pred + i*5;
my.push_back(tmp);
}
std::sort(my.begin(), my.end(), compare);
for (int i=0; i<num; i++)
{
for (int j=0; j<5; j++)
sorted_pred[i*5+j] = my[i].head[j];
}
}
/*
* === FUNCTION ======================================================================
* Name: bbox_transform_inv
* Description: Compute bounding box regression value
* =====================================================================================
*/
void Detector::bbox_transform_inv(int num, const float* box_deltas, const float* pred_cls, float* boxes, float* pred, int img_height, int img_width)
{
float width, height, ctr_x, ctr_y, dx, dy, dw, dh, pred_ctr_x, pred_ctr_y, pred_w, pred_h;
for(int i=0; i< num; i++)
{
width = boxes[i*4+2] - boxes[i*4+0] + 1.0;
height = boxes[i*4+3] - boxes[i*4+1] + 1.0;
ctr_x = boxes[i*4+0] + 0.5 * width;
ctr_y = boxes[i*4+1] + 0.5 * height;
for (int j=0; j< class_num; j++)
{
dx = box_deltas[(i*class_num+j)*4+0];
dy = box_deltas[(i*class_num+j)*4+1];
dw = box_deltas[(i*class_num+j)*4+2];
dh = box_deltas[(i*class_num+j)*4+3];
pred_ctr_x = ctr_x + width*dx;
pred_ctr_y = ctr_y + height*dy;
pred_w = width * exp(dw);
pred_h = height * exp(dh);
pred[(j*num+i)*5+0] = max(min(pred_ctr_x - 0.5* pred_w, img_width -1), 0);
pred[(j*num+i)*5+1] = max(min(pred_ctr_y - 0.5* pred_h, img_height -1), 0);
pred[(j*num+i)*5+2] = max(min(pred_ctr_x + 0.5* pred_w, img_width -1), 0);
pred[(j*num+i)*5+3] = max(min(pred_ctr_y + 0.5* pred_h, img_height -1), 0);
pred[(j*num+i)*5+4] = pred_cls[i*class_num+j];
}
}
}
faster_rcnn c++版本的 caffe 封装,动态库(2)的更多相关文章
- faster_rcnn c++版本的 caffe 封装(1)
转载请注明出处,楼燚(yì)航的blog,http://www.cnblogs.com/louyihang-loves-baiyan/ 由于需要把FasterRCNN做的工程化,因此这里需要对Caff ...
- ffmpeg 2.8.1 最新版本 VS2013 可调式动态库
ffmpeg 2.8.1 最新版本 VS2013 可调式动态库 由于大多数初学者都在想尽各种版本寻求VC编译调试ffmpeg的版本,我也曾经移植过几个版本的ffmpeg到VC上编译.: 链接所需动态库 ...
- 【转】分析Linux和windows动态库
原文地址:http://www.cnblogs.com/chio/archive/2008/11/13/1333119.html 摘要:动态链接库技术实现和设计程序常用的技术,在Windows和Lin ...
- Linux和windows动态库
转载:http://www.cnblogs.com/chio/archive/2008/11/13/1333119.html 态链接库技术实现和设计程序常用的技术,在Windows和Linux系 统中 ...
- windows动态库与Linux动态库
Linux动态库和windows动态库的目的是基本一致的,但由于操作系统的不同,他们在许多方面还是不尽相同.但是尽管有差异Linux动态库的windows动态库还是可以移植的,有一些规则以及经验是必须 ...
- openssl动态库编译
通常Linux系统自带OpenSSL,但是其so文件由于没有debug信息,因此无法跟踪内部函数,对于学习 不太方便,需要通过源码重新安装. 我的Linux系统是CentOS7,自带的 ...
- C#调用C/C++动态库,封装各种复杂结构体
C#调用C/C++动态库,封装各种复杂结构体. 标签: c++结构内存typedefc# 2014-07-05 12:10 6571人阅读 评论(1) 收藏 举报 分类: C(8) C#(6) ...
- FFmpeg笔记:使用MSVC工具链编译Windows版本静态库、动态库
2019年3月开始,为了将音视频编解码功能集成到Cocos2d-x中,开始接触到FFmpeg: 当时开发环境还在Mac下,编译FFmpeg相比现在用Windows平台要方便的多: 最近,公司内部有个U ...
- C#调用C++动态库方法及动态库封装总结
我只是粗浅的学习过一些C++语法, 变量类型等基础内容, 如有不对的地方还望指出. 如果你跟我一样, 对指针操作不了解, 对封装C++动态库头疼的话, 下面内容还是有帮助的. 转载请注明出处: htt ...
随机推荐
- WPF DataGrid 鼠标双击选中的DataGridRow及Row数据
设置DataGrid的MouseDoubleClick事件 代码 //DataGrid鼠标双击事件 Private void dataGrid_MouseDoubleClick(object send ...
- 向 div 元素添加圆角边框:
div { border:2px solid; border-radius:25px; }
- Asp.net mvc自定义Filter简单使用
自定义Filter的基本思路是继承基类ActionFilterAttribute,并根据实际需要重写OnActionExecuting,OnActionExecuted,OnResultExecuti ...
- JSTL标签功能集锦
1.<fmt:parseNumber integerOnly="true" value="2/3" /> 结果为0 功能:fmt:parseNumb ...
- MongoDB固定集合(capped collection)
固定集合指的是事先创建而且大小固定的集合 . 固定集合特性:固定集合很像环形队列,如果空间不足,最早的文档就会被删除,为新的文档腾出空间.一般来说,固定集合适用于任何想要自动淘汰过期属性的场景,没有太 ...
- 一起谈谈MD5加密算法
MD5是一个安全的散列算法,输入两个不同的明文不会得到相同的输出值,根据输出值,不能得到原始的明文,即其过程不可逆:所以要解密MD5没有现成的算法,只能用穷举法,把可能出现的明文,用MD5算法散列之后 ...
- Managing database evolutions
When you use a relational database, you need a way to track and organize your database schema evolut ...
- html meta标签使用总结
meta标签作用 META标签是HTML标记HEAD区的一个关键标签,提供文档字符集.使用语言.作者等基本信息,以及对关键词和网页等级的设定等,最大的作用是能够做搜索引擎优化(SEO). PS:便于搜 ...
- js(jquery)解决input元素的blur事件和其他非表单元素的click事件冲突的方法
HTML结构:很简单,就一个input,一个div,能说明问题就OK了: <input type="text" value="默认值"><br ...
- SharePoint 自定义的列表页面中添加javascript的一个 For循环语句后,该页面就打不开了。
一个sharepoint 2013的普通的列表的自定义新建页面,我在其中新添加几行javascript代码后页面就打不开了.如图所示: 真是一言不合,友谊的页面说打不开就打不开啊.后来慢慢比对发现是因 ...