• Pybind11实现python调取C++


    1、一些处理矩阵运算,图像处理算法,直接采用python实现可能速度稍微慢,效率不高,或者为了直接在python中调用其他C++第三方库。 图像,矩阵在python中通常表示为numpy.ndarray,因此如何在C++中解析numpy对象,numpy的数据如何传递到C++非常关键,解决了这些问题,就可以丝滑的在python numpy和C++中切换,互相调用。

    C++代码:

    #include<iostream>
    #include<pybind11/pybind11.h>
    #include<pybind11/numpy.h>
    
    namespace py = pybind11;
    
    /*
    1d矩阵相加
    */
    py::array_t<double> add_arrays_1d(py::array_t<double>& input1, py::array_t<double>& input2) {
    
        // 获取input1, input2的信息
        py::buffer_info buf1 = input1.request();
        py::buffer_info buf2 = input2.request();
    
        if (buf1.ndim !=1 || buf2.ndim !=1)
        {
            throw std::runtime_error("Number of dimensions must be one");
        }
    
        if (buf1.size !=buf2.size)
        {
            throw std::runtime_error("Input shape must match");
        }
    
        //申请空间
        auto result = py::array_t<double>(buf1.size);
        py::buffer_info buf3 = result.request();
    
        //获取numpy.ndarray 数据指针
        double* ptr1 = (double*)buf1.ptr;
        double* ptr2 = (double*)buf2.ptr;
        double* ptr3 = (double*)buf3.ptr;
    
        //指针访问numpy.ndarray
        for (int i = 0; i < buf1.shape[0]; i++)
        {
            ptr3[i] = ptr1[i] + ptr2[i];
        }
    
        return result;
    
    }
    
    /*
    2d矩阵相加
    */
    py::array_t<double> add_arrays_2d(py::array_t<double>& input1, py::array_t<double>& input2) {
    
        py::buffer_info buf1 = input1.request();
        py::buffer_info buf2 = input2.request();
    
        if (buf1.ndim != 2 || buf2.ndim != 2)
        {
            throw std::runtime_error("numpy.ndarray dims must be 2!");
        }
        if ((buf1.shape[0] != buf2.shape[0])|| (buf1.shape[1] != buf2.shape[1]))
        {
            throw std::runtime_error("two array shape must be match!");
        }
    
        //申请内存
        auto result = py::array_t<double>(buf1.size);
        //转换为2d矩阵
        result.resize({buf1.shape[0],buf1.shape[1]});
    
    
        py::buffer_info buf_result = result.request();
    
        //指针访问读写 numpy.ndarray
        double* ptr1 = (double*)buf1.ptr;
        double* ptr2 = (double*)buf2.ptr;
        double* ptr_result = (double*)buf_result.ptr;
    
        for (int i = 0; i < buf1.shape[0]; i++)
        {
            for (int j = 0; j < buf1.shape[1]; j++)
            {
                auto value1 = ptr1[i*buf1.shape[1] + j];
                auto value2 = ptr2[i*buf2.shape[1] + j];
    
                ptr_result[i*buf_result.shape[1] + j] = value1 + value2;
            }
        }
    
        return result;
    
    }
    
    //py::array_t<double> add_arrays_3d(py::array_t<double>& input1, py::array_t<double>& input2) {
    //  
    //  py::buffer_info buf1 = input1.request();
    //  py::buffer_info buf2 = input2.request();
    //
    //  if (buf1.ndim != 3 || buf2.ndim != 3)
    //      throw std::runtime_error("numpy array dim must is 3!");
    //
    //  for (int i = 0; i < buf1.ndim; i++)
    //  {
    //      if (buf1.shape[i]!=buf2.shape[i])
    //      {
    //          throw std::runtime_error("inputs shape must match!");
    //      }
    //  }
    //
    //  // 输出
    //  auto result = py::array_t<double>(buf1.size);
    //  result.resize({ buf1.shape[0], buf1.shape[1], buf1.shape[2] });
    //  py::buffer_info buf_result = result.request();
    //
    //  // 指针读写numpy数据
    //  double* ptr1 = (double*)buf1.ptr;
    //  double* ptr2 = (double*)buf2.ptr;
    //  double* ptr_result = (double*)buf_result.ptr;
    //
    //  for (int i = 0; i < buf1.size; i++)
    //  {
    //      std::cout << ptr1[i] << std::endl;
    //  }
    //
    //  /*for (int i = 0; i < buf1.shape[0]; i++)
    //  {
    //      for (int j = 0; j < buf1.shape[1]; j++)
    //      {
    //          for (int k = 0; k < buf1.shape[2]; k++)
    //          {
    //
    //              double value1 = ptr1[i*buf1.shape[1] * buf1.shape[2] + k];
    //              double value2 = ptr2[i*buf2.shape[1] * buf2.shape[2] + k];
    //
    //              double value1 = ptr1[i*buf1.shape[1] * buf1.shape[2] + k];
    //              double value2 = ptr2[i*buf2.shape[1] * buf2.shape[2] + k];
    //
    //              ptr_result[i*buf1.shape[1] * buf1.shape[2] + k] = value1 + value2;
    //
    //              std::cout << value1 << " ";
    //
    //          }
    //
    //          std::cout << std::endl;
    //
    //      }
    //  }*/
    //
    //  return result;
    //}
    
    /*
    numpy.ndarray 相加,  3d矩阵
    @return 3d numpy.ndarray
    */
    py::array_t<double> add_arrays_3d(py::array_t<double>& input1, py::array_t<double>& input2) {
    
        //unchecked<N> --------------can be non-writeable
        //mutable_unchecked<N>-------can be writeable
        auto r1 = input1.unchecked<3>();
        auto r2 = input2.unchecked<3>();
    
        py::array_t<double> out = py::array_t<double>(input1.size());
        out.resize({ input1.shape()[0], input1.shape()[1], input1.shape()[2] });
        auto r3 = out.mutable_unchecked<3>();
    
        for (int i = 0; i < input1.shape()[0]; i++)
        {
            for (int j = 0; j < input1.shape()[1]; j++)
            {
                for (int k = 0; k < input1.shape()[2]; k++)
                {
                    double value1 = r1(i, j, k);
                    double value2 = r2(i, j, k);
    
                    //下标索引访问 numpy.ndarray
                    r3(i, j, k) = value1 + value2;
                
                }
            }
        }
    
        return out;
    
    }
    
    PYBIND11_MODULE(numpy_demo2, m) {
    
        m.doc() = "Simple demo using numpy!";
    
        m.def("add_arrays_1d", &add_arrays_1d);
        m.def("add_arrays_2d", &add_arrays_2d);
        m.def("add_arrays_3d", &add_arrays_3d);
    }

    python测试代码:

    import demo9.numpy_demo2 as numpy_demo2
    import numpy as np
    
    
    var1 = numpy_demo2.add_arrays_1d(np.array([1, 3, 5, 7, 9]),
                                     np.array([2, 4, 6, 8, 10]))
    print('-'*50)
    print('var1', var1)
    
    var2 = numpy_demo2.add_arrays_2d(np.array(range(0,16)).reshape([4, 4]),
                                     np.array(range(20,36)).reshape([4, 4]))
    print('-'*50)
    print('var2', var2)
    
    input1 = np.array(range(0, 48)).reshape([4, 4, 3])
    input2 = np.array(range(50, 50+48)).reshape([4, 4, 3])
    var3 = numpy_demo2.add_arrays_3d(input1,
                                     input2)
    print('-'*50)
    print('var3', var3)

    结果如下:
    在这里插入图片描述
    2、python传递图像给C++

    需要注意的是:这里传入的图像都是8U的,0-255数值,如果不是此类的数值需要进行修改,见后续!

    #include <pybind11/numpy.h>
    
    /*
    Python->C++ Mat
    */
    cv::Mat numpy_uint8_1c_to_cv_mat(py::array_t<unsigned char>& input) {
    
        if (input.ndim() != 2)
            throw std::runtime_error("1-channel image must be 2 dims ");
    
        py::buffer_info buf = input.request();
    
        cv::Mat mat(buf.shape[0], buf.shape[1], CV_8UC1, (unsigned char*)buf.ptr);
        
        return mat;
    }
    
    cv::Mat numpy_uint8_3c_to_cv_mat(py::array_t<unsigned char>& input) {
    
        if (input.ndim() != 3)
            throw std::runtime_error("3-channel image must be 3 dims ");
    
        py::buffer_info buf = input.request();
    
        cv::Mat mat(buf.shape[0], buf.shape[1], CV_8UC3, (unsigned char*)buf.ptr);
    
        return mat;
    }
    
    
    /*
    C++ Mat ->numpy
    */
    py::array_t<unsigned char> cv_mat_uint8_1c_to_numpy(cv::Mat& input) {
    
        py::array_t<unsigned char> dst = py::array_t<unsigned char>({ input.rows,input.cols }, input.data);
        return dst;
    }
    
    py::array_t<unsigned char> cv_mat_uint8_3c_to_numpy(cv::Mat& input) {
    
        py::array_t<unsigned char> dst = py::array_t<unsigned char>({ input.rows,input.cols,3}, input.data);
        return dst;
    }
    
    
    
    //PYBIND11_MODULE(cv_mat_warper, m) {
    //
    //  m.doc() = "OpenCV Mat -> Numpy.ndarray warper";
    //
    //  m.def("numpy_uint8_1c_to_cv_mat", &numpy_uint8_1c_to_cv_mat);
    //  m.def("numpy_uint8_1c_to_cv_mat", &numpy_uint8_1c_to_cv_mat);
    //
    //
    //}
    
    
    ***如果数值不是0-255,需要进行原始数据的计算,如下:***
    
    py::array_t<unsigned char> remove_background(py::array_t<int>& input1, py::array_t<unsigned char>& color, int max_dist)
    {
        cv::Mat color_image = numpy_uint8_3c_to_cv_mat(color);
        py::buffer_info buf1 = input1.request();
        int* ptr1 = (int*)buf1.ptr;
        for (int i = 0; i < buf1.shape[0]; i++)
        {
            for (int j = 0; j < buf1.shape[1]; j++)
            {
                auto value1 = ptr1[i*buf1.shape[1] + j];
                if (value1 > max_dist)
                {
                    color_image.at<Vec3b>(i, j) = Vec3b(0, 0, 0);
                }
            }
        }
    }

    3、python传递list给C++

    例,python传递25个关节点的x,y,score给C++,C++返回x,y,score和空间的x,y,z给python

    在这里插入图片描述

     
  • 相关阅读:
    关于final shell
    vue axios 赋值后console可以查看到 html调用数据失败
    递归计数
    中国用户也能同步 Chrome 书签了
    Linux基础知识(CentOS7)
    问题关键词
    「工具推荐」golang 代码可视化工具 gocallvis
    php统一的gocheck方法
    激光原理与技术第七章
    小码哥汇编
  • 原文地址:https://www.cnblogs.com/lidabo/p/16621369.html
Copyright © 2020-2023  润新知