最近的研究中,想使用Python调用C++的编译后的dll。尝试了ctypes,但是发现ctypes对C语言编译的dll兼容性比较好,对C++封装的类就无能为力了。尝试了boost.python,发现它对C++的wrapper比较方便快捷而且不用修改C++已经做好的程序。正当准备使用boost.python大干一场,却发现了指针无法封装的问题。多次Google,证实由于Python没有指针,是没法将C++方法里面的指针形参wrapper成Python可调用的方法。有说可以用引用来实现指针功能的,没有尝试,以后有时间可能会试试。 考虑到我实际传入的是图像数据,在Python中间为ndarray格式,因此我打算将C++的指针形式参数直接改为array格式,然后函数给一个返回值即可。google了一些方法,大多使用boost.numeric来实现,不能直接读取numpy的ndarray格式,看起来比较繁琐就搁一边了。后来在github上找到了boost.numpy的支持,遂大喜,下载并CMake后编译成功,入坑。 编译完doc后,研究了下doc,在此记录下使用方法。
我是使用Python调用c++的一个类,因此将上面两句直接放在累的构造函数里即可。
用Python内建数据类型创建ndarray,需要使用dtypes获取内建Python数据类型,创建一个3x3的ndarray方法如下:
p::tuple shape = p::make_tuple(3, 3); np::dtype dtype = np::dtype::get_builtin<double>(); np::ndarray a = np::zeros(shape, dtype);使用python namespace的extract方法来打印输出。首先将其变量转换为string并打印出c++字符:
std::cout << "Original array:\n" << p::extract<char const *>(p::str(a)) << std::endl;也可以打印dtypes:
std::cout << "Datatype is:\n" << p::extract<char const *>(p::str(a.get_dtype())) << std::endl ;注意的问题:
此方法创建的ndarray数据保存区仍然为上面的数组,不能将该数组删除。shape和stride的shape必须一样,也就是说shape有几个维度就需要几个stride。我用的时候上面方法访问ndarray的方法不够方便,因此我查阅了其定义,发现可以使用 char * get_data() const;方法直接获取数据区域的指针,直接访问数据就方便多了。 另外boost.numpy定义如下:
namespace boost{ namespace numpy{ class ndarray : public python::object{ public: enum bitflag { NONE=0x0, C_CONTIGUOUS=0x1, F_CONTIGUOUS=0x2, V_CONTIGUOUS=0x1|0x2, ALIGNED=0x4, WRITEABLE=0x8, BEHAVED=0x4|0x8, CARRAY_RO=0x1|0x4, CARRAY=0x1|0x4|0x8, CARRAY_MIS=0x1|0x8, FARRAY_RO=0x2|0x4, FARRAY=0x2|0x4|0x8, FARRAY_MIS=0x2|0x8, UPDATE_ALL=0x1|0x2|0x4, VARRAY=0x1|0x2|0x8, ALL=0x1|0x2|0x4|0x8 }; ndarray view(dtype const & dt) const; ndarray astype(dtype const & dt) const; ndarray copy() const; int const shape(int n) const; int const strides(int n) const; char * get_data() const; dtype get_dtype() const; python::object get_base() const; void set_base(object const & base); Py_intptr_t const * get_shape() const; Py_intptr_t const * get_strides() const; int const get_nd() const; bitflag const get_flags() const; ndarray transpose() const; ndarray squeeze() const; ndarray reshape(python::tuple const & shape) const; python::object scalarize() const; }; ndarray zeros(python::tuple const & shape, dtype const & dt); ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt); ndarray empty(python::tuple const & shape, dtype const & dt); ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt); ndarray array(python::object const & obj); ndarray array(python::object const & obj, dtype const & dt); template <typename Container>ndarray from_data(void * data,dtype const & dt,Container shape,Container strides,python::object const & owner); template <typename Container>ndarray from_data(void const * data, dtype const & dt, Container shape, Container strides, python::object const & owner); ndarray from_object(python::object const & obj, dtype const & dt,int nd_min, int nd_max, ndarray::bitflag flags=ndarray::NONE); ndarray from_object(python::object const & obj, dtype const & dt,int nd, ndarray::bitflag flags=ndarray::NONE); ndarray from_object(python::object const & obj, dtype const & dt, ndarray::bitflag flags=ndarray::NONE); ndarray from_object(python::object const & obj, int nd_min, int nd_max,ndarray::bitflag flags=ndarray::NONE); ndarray from_object(python::object const & obj, int nd, ndarray::bitflag flags=ndarray::NONE); ndarray from_object(python::object const & obj, ndarray::bitflag flags=ndarray::NONE); ndarray::bitflag operator|(ndarray::bitflag a, ndarray::bitflag b); ndarray::bitflag operator&(ndarray::bitflag a, ndarray::bitflag b); }暂时不用,没有研究。