之前一直从事c++相关算法及代码的相关工作,因公司内部代码管理需要,需将算法封装待python平台使用,根据此需求,对python调用c++代码的方式进行了学习,最终综合考虑封装难度及多代码管理使用pybind11进行了相关功能的实现。
pybind11是一个用于c++与python之间相互调用和数据交互的库
以我自己的算法为例介绍一下pybind11的基本使用,我的调用算法中还包含了其他的c++库,例如opencv,此处还出现了一个我没想到的bug后续会介绍。
Windows系统
Requires
win10,64bit
Visual Studio2015
python3.6(Anaconda)
pybind11安装
下载pybind11源码,获取其头文件,下载地址:https://github/pybind/pybind11
因其为Head-only形式的,不需要编译动态库,直接使用include即可。
demo应用测试
1、创建Vistual Studio工程,将需要调用的c++代码放入其中
设置项目类型及输出文件类型,分别为.pyd及dll
2、添加pybind11和python相关头文件路径及库文件和其路径,编译成库
头文件设置如下:
库文件目录及附件库设置如下:
需使用pybind11的格式,对函数和结构体进行封装,c++封装的头文件及源文件格式如下:
Passenger_pyd.h
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
struct outdata
{
int in;
int out;
};
int test( Mat frame);
outdata* video_test(char* file_path, int channel, int inNum, int outNum);
Passenger_pyd.cpp
#include<pybind11/pybind11.h>
namespace py = pybind11;
PYBIND11_MODULE(Passenger_pyd, m) {
m.doc() = "pybind11 example module";
py::class_<outdata>(m, "outdata")
.def_readonly("in_num", &outdata::in)
.def_readonly("out_num", &outdata::out);
// Add bindings here
m.def("Testframe", &test, "Test frame");
m.def("DetectionTrack", &video_test, "Detection and Track");
编译生成.pyd和lib
3、python端(pycharm)调用格式如下:
import Passenger_pyd
if __name__ == '__main__':
innum=0
outnum=0
ichn=0
jpeg_file="e:\\1.jpeg"
frame=cv2.imread(jpeg_file)
outdata=Passenger_pyd.DetectionTrack(jpeg_file,ichn,innum,outnum)
print(outdata.in_num,outdata.out_num)
#Passenger_pyd.Testframe(frame)
测试过程中存在的部分问题
1、需注意PYBIND11_MODULE的name需和库文件名保持一致,否则会出现如下错误:
import Passenger_pyd
ImportError: dynamic module does not define module export function (PyInit_Passenger_pyd)
2、此demo中曾尝试将opencv的Mat作为参数传入到c++代码中,即被注释掉的下列一行
#Passenger_pyd.Testframe(frame)
因pybind11不支持opencv 的Mat类会报如下错误:
Passenger_pyd.Testframe(frame)
TypeError: Testframe(): incompatible function arguments. The following argument types are supported:
1. (arg0: cv::Mat) -> int
Invoked with: array [[ ...,
[ 36, 39, 37],
[ 19, 22, 20],
[ 0, 1, 0]]], dtype=uint8)
此情况有两种解决办法,一种是将文件路径传入c++中使用imread得到Mat,另一种则可在c++端侧对array格式进行转化,相关转化可参考链接:https://github/edmBernard/pybind11_opencv_numpy,不想把精力耽误在这个上面我直接选择了第一种做法。
3、c++返回值问题,如需返回的参数较多,可使用结构体的形式进行数据交互。如本例中的 outdata,目的就是为了返回结构到python中,比较适合返回的参数较多且类型不一致的情况。
最后祝大家天天进步!!学习Python最重要的就是心态。我们在学习过程中必然会遇到很多难题,可能自己想破脑袋都无法解决。这都是正常的,千万别急着否定自己,怀疑自己。如果大家在刚开始学习中遇到困难,想找一个python学习交流环境,可以加入我们,领取学习资料、一起讨论。
更多推荐
python调用c++之pybind11
发布评论