关于boost.numpy的使用

    xiaoxiao2021-03-25  10

    最近的研究中,想使用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,在此记录下使用方法。

    头文件和namespace

    #include <boost/numpy.hpp> #include <iostream> namespace p = boost::python; namespace np = boost::numpy;

    初始化Python runtime

    int main(int argc, char **argv){ Py_Initialize(); np::initialize(); }

    我是使用Python调用c++的一个类,因此将上面两句直接放在累的构造函数里即可。

    dtypes

    用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 ;

    创建ndarrys

    使用tuple创建

    p::object tu = p::make_tuple('a','b','c') ; np::ndarray example_tuple = np::array(tu) ;

    使用list创建

    p::list l ; l.append('a') ; np::ndarray example_list = np::array (l) ; // 也可指定一个dtype数据类型 np::dtype dt = np::dtype::get_builtin<int>(); np::ndarray example_list1 = np::array (l,dt);

    使用数组创建

    /**********一维***********/ int data[] = {1,2,3,4,5} ; // shape:(5,) p::tuple shape = p::make_tuple(5) ; // stride:创建ndarray时必须移动并得到下一个元素所需的字节数 // stride:(1,) p::tuple stride = p::make_tuple(sizeof(int)) ; // owner用来跟踪传入的数组 p::object own ; // 创建ndarray np::ndarray data_ex1 = np::from_data(data,dt, shape,stride,own); /**********二维***********/ uint8_t mul_data[][4] = {{1,2,3,4},{5,6,7,8},{1,3,5,7}}; shape = p::make_tuple(3,2) ; stride = p::make_tuple(sizeof(uint8_t)*2,sizeof(uint8_t)) ; np::dtype dt1 = np::dtype::get_builtin<uint8_t>(); np::ndarray mul_data_ex = np::from_data(mul_data,dt1, p::make_tuple(3,4),p::make_tuple(4,1),p::object());

    注意的问题:

    此方法创建的ndarray数据保存区仍然为上面的数组,不能将该数组删除。shape和stride的shape必须一样,也就是说shape有几个维度就需要几个stride。

    使用ndarrys

    int arr[] = {1,2,3,4,5} ; np::ndarray py_array = np::from_data(arr, np::dtype::get_builtin<int>() , p::make_tuple(5), p::make_tuple(sizeof(int)), p::object()); // print std::cout << "C++ array :" << std::endl ; for (int j=0;j<4;j++){ std::cout << arr[j] << ' ' ; } std::cout << std::endl << "Python ndarray :" << p::extract<char const *>(p::str(py_array)) << std::endl; // 访问并修改py_array,比较两者打印结果是否一致 py_array[1] = 5 ; std::cout << "Is the change reflected in the C++ array used to create the ndarray ? " << std::endl ; for (int j = 0; j < 5; j++){ std::cout << arr[j] << ' ' ; } // 修改原c++数组,比较两者打印结果是否一致 arr[2] = 8 ; std::cout << std::endl << "Is the change reflected in the Python ndarray ?" << std::endl << p::extract<char const *>(p::str(py_array)) << std::endl;

    boost.numpy定义

    我用的时候上面方法访问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); }

    ufunc

    暂时不用,没有研究。

    转载请注明原文地址: https://ju.6miu.com/read-200299.html

    最新回复(0)