python3 ctypes 调用so_C++调用Python3接口

通过在C++程序调用Python3所提供的C接口可以实现调用Python程序所实现的功能。在C++调用深度学习训练好的模型时,如果不使用一些部署手段,这种C++调用Python接口的方式虽然大大牺牲了效率,但是可以说是也是一种取巧的方法。这里记录一下C++如何去调用Python3的接口,作为一个总结。

操作系统:Ubuntu16.04

构建工具:CMake

要想在 C++ 中调用 Python3 ,必须在 Cmake 中添加一些 Python3 的动态链接库:

可以在 include_directories中加入:

/usr/include/python3.5

在 target_link_libraries 中加入:

 /usr/lib/x86_64-linux-gnu/libboost_python-py35.so
 /usr/lib/x86_64-linux-gnu/libstdc++.so.6
 /usr/lib/x86_64-linux-gnu/libpython3.5m.so

1. 调用Python3中的函数

int 

代码中值得注意的是有很多固定写法:

Py_Initialize(): Python的初始化
PyRun_SimpleString:执行简单的Python语句
Py_DecRef`: 释放资源
Py_Finalize: 结束Python

其中`../scripts`是存放Python代码的路径,路径是相对于c++ bin文件的路径而言。

`PyImport_ImportModule("testFunction");`调用了名为 `testFunction` 的 py 程序。

PyObject *pFunction = PyObject_GetAttrString(pModule, "func2");

得到python程序中的 函数`func`的PyObjet指针 。

PyObject *args = PyTuple_New(1);
PyObject *args1 = PyUnicode_FromString("../air.jpg");

PyTuple_SetItem(args, 0, args1);

这里,是封装函数参数,放到一个Py元组中。

PyObject *pRet = PyObject_CallObject(pFunction, args);

这里是调用了刚才 `func`函数,并传递了参数,同时得到一个返回对象。程序利用了` PyArg_Parse(pRet,"i", &res);`进行对 pRet 的 Py 对象进行解析,解析成 int 类型。由此得到正确的返回值。

可以看一下testFunction.py程序:

import 

Python程序对传递进来的字符串(也就是图像名)进行图像读取并显示大小,同时调用了 `TensorFlow` 完成类一个简单运算,最后打印结果,返回整型 1。

通过 C++ 调用,就能够完成该Python函数的运行,同时得到返回值。当然这是最简单的一个 C++ 调用 Python3 的例子。

2. 调用Python3中的类

一般面向对象,皆使用类,因此 C++ 调用 Python3 也需要对类的调用进行支持。

int 

有了上面调用函数的例子,调用类就变得简单了。该程序主要是调用testClass.py 中的 TestDemo 类。 和调用函数不同的这两句代码:

PyObject *pInstance = PyObject_Call(pClass,args1, nullptr); //创建实例
PyObject *pRet = PyObject_CallMethod(pInstance,"evaluate", "O", args2);

其中`PyObject_Call` 是创建一个类的实例,同时可以传递 Python类中`__init__ `的参数,得到实例对象,通过 `PyObject_CallMethod` 调用类的成员方法 `evaluate`, 同样的可以传递参数。

其中`testClass.py`代码为:

from 

实现的功能和之前的测试调用函数是一样的功能,只不过封装到类中。

3. 特殊返回对象处理(Map)

对于Python特殊的数据结构的返回, Python3 API也有相应的处理,使用最多的就是之前封装传参的PyTuple对象。另外还会有对列表进行处理的 PyList对象。而这里记录处理比较复杂的Map类型。

int 

值得注意的是这句:

PyObject 

这是对返回对象进行了字典键值的提取,真正得到键内容还得继续处理。 而代码中 `PyDict_Size(pDict)` 得到字典的键值对数量。

PyObject 

`pKeys` 相当于得到所有的键,存成List类型,`PyList_GetItem` 从List中取出第 i 个元素,然后再解析这个对象,就拿到了第 i 个键。解析采用了 `PyUnicode_AsUTF8` 解析的是字符串。

PyObject 

这句代码相当于从字典中 根据键拿到所谓的值,而值可以是列表形式,因此解析 `pValue`时 具体情况具体分析了。上述代码演示了值为列表的解析过程。

Python代码非常简单,返回类一个字典,键为字符串,值为列表类型:

def 

4. OpenCV的Mat图像的传递

想要利用C++调用深度学习网络推断模型进行目标检测或者进行图像语义分割,若通过C++调用Python3的接口这种方式,那麽必定需要传递OpenCV的Mat图像,通过Python 的 numpy 去承接图像。

int 

代码中进行了依次Mat转换成PyObject的过程,然后在传递这个PyObject到类的成员方法。如下代码所示:

cv

Python代码如下所示:

class 

这里能够成功传递图像,但没有利用网络来对图像处理。

tips: 具体的相关代码能够在这里找到。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值