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