Advertisement
dan-masek

pybind11 - cv::Mat <-> np.array

Mar 31st, 2020
557
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.16 KB | None | 0 0
  1. #include <pybind11/pybind11.h>
  2. #include <pybind11/embed.h>
  3. #include <pybind11/numpy.h>
  4.  
  5. #include <opencv2/opencv.hpp>
  6.  
  7. #include <iostream>
  8.  
  9. namespace py = pybind11;
  10.  
  11. // Restrict to only C-Style memory layout
  12. void process_array(py::array_t<uint8_t, py::array::c_style>& arr)
  13. {
  14.     if (arr.ndim() != 3) {
  15.         throw std::runtime_error("Incorrect array shape.");
  16.     }
  17.  
  18.     // Note: Shares buffer with the Python array -- limit to current function
  19.     // or make a deep copy (otherwise assure the source array lifetime is longer)
  20.     cv::Mat img(arr.shape(0), arr.shape(1)
  21.         , CV_8UC3
  22.         , static_cast<uchar*>(arr.mutable_data()));
  23.  
  24.     std::cout << "Rows = " << img.rows << "\n";
  25.     std::cout << "Columns = " << img.cols << "\n";
  26.     std::cout << "Channels = " << img.channels() << "\n";
  27.     std::cout << img << "\n";
  28. }
  29.  
  30. PYBIND11_EMBEDDED_MODULE(test_module, m)
  31. {
  32.     m.doc() = "Test module";
  33.  
  34.     m.def("process_array", &process_array, "Test function");
  35. }
  36.  
  37. int main()
  38. {
  39.     // Start the interpreter and keep it alive
  40.     py::scoped_interpreter guard{};
  41.  
  42.     try {
  43.         auto locals = py::dict{};
  44.  
  45.         py::exec(R"(
  46.            import numpy as np
  47.            import test_module
  48.  
  49.            def test_py_to_cpp():
  50.                a = np.arange(4*5*3, dtype=np.uint8).reshape(4,5,3)
  51.                test_module.process_array(a)
  52.  
  53.            def test_cpp_to_py(arr):
  54.                arr += 1
  55.        )");
  56.  
  57.         //auto test_py_to_cpp = py::globals()["test_py_to_cpp"];
  58.         //test_py_to_cpp();
  59.  
  60.         auto test_cpp_to_py = py::globals()["test_cpp_to_py"];
  61.  
  62.         cv::Mat img(cv::Mat::zeros(4, 5, CV_8UC3) + cv::Scalar(1,1,1));
  63.  
  64.         // Create a numpy array that shares the buffer with the Mat
  65.         /*
  66.         py::array_t<uint8_t, py::array::c_style> arr(
  67.             py::buffer_info(
  68.                 img.data // Buffer
  69.                 , sizeof(uint8_t) // Item size
  70.                 , py::format_descriptor<uint8_t>::format()
  71.                 , 3 // Dimension count
  72.                 , std::vector<size_t> { static_cast<size_t>(img.rows)
  73.                     , static_cast<size_t>(img.cols)
  74.                     , static_cast<size_t>(img.channels()) } // Dimensions
  75.                 , std::vector<size_t> { sizeof(uint8_t) * img.channels() * img.cols
  76.                     , sizeof(uint8_t) * img.channels()
  77.                     , sizeof(uint8_t) } // Strides
  78.             ));
  79.         */
  80.  
  81.         py::array_t<uint8_t, py::array::c_style> arr(
  82.             // Dimensions of the array
  83.             {   static_cast<size_t>(img.rows)
  84.                 , static_cast<size_t>(img.cols)
  85.                 , static_cast<size_t>(img.channels())
  86.             }
  87.             // Data buffer
  88.             , img.data
  89.             // Holds an extra reference to the Mat owning the shared buffer
  90.             , py::capsule(new cv::Mat(img), [](void *m) { delete reinterpret_cast<cv::Mat*>(m); })
  91.         );
  92.  
  93.         std::cout << "Before\n" << img << "\n";
  94.         test_cpp_to_py(arr);
  95.         std::cout << "After\n" << img << "\n";
  96.     } catch (py::error_already_set& e) {
  97.         std::cerr << e.what() << "\n";
  98.     }
  99.    
  100.     return 0;
  101. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement