python调用c++之pybind11

之前一直从事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.com/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.com/edmBernard/pybind11_opencv_numpy,不想把精力耽误在这个上面我直接选择了第一种做法。

3、c++返回值问题,如需返回的参数较多,可使用结构体的形式进行数据交互。如本例中的 outdata,目的就是为了返回结构到python中,比较适合返回的参数较多且类型不一致的情况。

最后祝大家天天进步!!学习Python最重要的就是心态。我们在学习过程中必然会遇到很多难题,可能自己想破脑袋都无法解决。这都是正常的,千万别急着否定自己,怀疑自己。如果大家在刚开始学习中遇到困难,想找一个python学习交流环境,可以加入我们,领取学习资料、一起讨论。


版权声明:本文为m0_64355682原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。