如何通过共享内存向python发送cv::Mat? 我有一个C++应用程序,它通过共享内存将数据发送到Python函数。 这在Python中使用ctypes非常有效,例如double和float。现在,我需要向函数添加一个cv::Mat
我目前的代码是: //h //主Python函数如何通过共享内存向python发送cv::Mat? 我有一个C++应用程序,它通过共享内存将数据发送到Python函数。 这在Python中使用ctypes非常有效,例如double和float。现在,我需要向函数添加一个cv::Mat,python,c++,opencv,shared-memory,Python,C++,Opencv,Shared Memory,我目前的代码是: //h //主Python函数 import TransferData import sys import mmap import ctypes def datathrough(): shmem = mmap.mmap(-1, ctypes.sizeof(TransferData.TransferData), "TransferDataSHMEM") data = TransferData.TransferData.from_buffer(shmem)
import TransferData
import sys
import mmap
import ctypes
def datathrough():
shmem = mmap.mmap(-1, ctypes.sizeof(TransferData.TransferData), "TransferDataSHMEM")
data = TransferData.TransferData.from_buffer(shmem)
print('Python Program - Getting Data')
print('Python Program - Filling Data')
TransferData.fill(data)
如何将cv::Mat
帧数据添加到Python端?我将它作为一个代码> uChar */COD>从C++发送,我理解,我需要它是一个<代码> NoMPy < /CuffelSub,以获得Python中的<代码> CV2.Mat < /C>。从“宽度、高度、通道、帧数据”到opencv pythoncv2.Mat
的正确方法是什么
我之所以使用共享内存,是因为速度是一个因素,我已经使用Python API方法进行了测试,它对于我的需要来说太慢了。总体思路(在OpenCV Python绑定中使用)是创建一个numpyndarray
,它与Mat
对象共享数据缓冲区,并将其传递给Python函数
注意:在这一点上,我将仅限于连续矩阵的例子
我们可以利用这个班
- 我们需要为numpy数组确定合适的
。这是一个简单的1对1映射,我们可以使用dtype
开关来实现:
py::dtype determine_np_dtype(int depth) { switch (depth) { case CV_8U: return py::dtype::of<uint8_t>(); case CV_8S: return py::dtype::of<int8_t>(); case CV_16U: return py::dtype::of<uint16_t>(); case CV_16S: return py::dtype::of<int16_t>(); case CV_32S: return py::dtype::of<int32_t>(); case CV_32F: return py::dtype::of<float>(); case CV_64F: return py::dtype::of<double>(); default: throw std::invalid_argument("Unsupported data type."); } }
- 提供将共享缓冲区的生存期延长到numpy阵列的生存期的方法。我们可以围绕源代码的浅拷贝
,创建一个Mat
——由于对象的实现方式,这有效地增加了所需时间的引用计数pybind11::capsule
假设我们有一个Python函数,比如py::capsule make_capsule(cv::Mat& m) { return py::capsule(new cv::Mat(m) , [](void *v) { delete reinterpret_cast<cv::Mat*>(v); } ); }
在pybind对象中捕获def foo(arr): print(arr.shape)
。那么,从C++中调用这个函数,使用<代码>垫>代码>作为源,我们会做这样的事情:fun
cv::Mat img; // Initialize this somehow auto result = fun(mat_to_nparray(img));
示例程序#include <pybind11/pybind11.h> #include <pybind11/embed.h> #include <pybind11/numpy.h> #include <pybind11/stl.h> #include <opencv2/opencv.hpp> #include <iostream> namespace py = pybind11; // The 4 functions from above go here... int main() { // Start the interpreter and keep it alive py::scoped_interpreter guard{}; try { auto locals = py::dict{}; py::exec(R"( import numpy as np def test_cpp_to_py(arr): return (arr[0,0,0], 2.0, 30) )"); auto test_cpp_to_py = py::globals()["test_cpp_to_py"]; for (int i = 0; i < 10; i++) { int64 t0 = cv::getTickCount(); cv::Mat img(cv::Mat::zeros(1024, 1024, CV_8UC3) + cv::Scalar(1, 1, 1)); int64 t1 = cv::getTickCount(); auto result = test_cpp_to_py(mat_to_nparray(img)); int64 t2 = cv::getTickCount(); double delta0 = (t1 - t0) / cv::getTickFrequency() * 1000; double delta1 = (t2 - t1) / cv::getTickFrequency() * 1000; std::cout << "* " << delta0 << " ms | " << delta1 << " ms" << std::endl; } } catch (py::error_already_set& e) { std::cerr << e.what() << "\n"; } return 0; }
考虑到这一切都在一个进程中,共享内存似乎是多余的。OpenCV Python绑定使用Python API来映射CV::MAT在C++侧和Python端的NUMPY数组——主要是簿记,底层缓冲区被共享。我很好奇您的Python API方法是什么样子的——很可能是实现问题导致了它的性能低下。谢谢您的回复。在C++和Python之间高速传递CV::MAT数据是可能的吗?我在任何地方都找不到一个示例。请给我一些时间,找出一个基于pybind11的实现甚至还有一些github回购协议与转换器。OpenCV的实现也有代码,只是有点难以理解。谢谢!这将是一个很好的概念证明:|在我写一个答案之前,还需要更多的研究、清理和概括。非常好的答案@谢谢。仍然应该包括非连续的
s(ROI)。我得到以下错误,错误:'array'不是'py'@Fisa的成员。你需要发布一个关于这个的新问题。非常好的解决方案!很有魅力!!Mat
py::capsule make_capsule(cv::Mat& m) { return py::capsule(new cv::Mat(m) , [](void *v) { delete reinterpret_cast<cv::Mat*>(v); } ); }
py::array mat_to_nparray(cv::Mat& m) { if (!m.isContinuous()) { throw std::invalid_argument("Only continuous Mats supported."); } return py::array(determine_np_dtype(m.depth()) , determine_shape(m) , m.data , make_capsule(m)); }
def foo(arr): print(arr.shape)
cv::Mat img; // Initialize this somehow auto result = fun(mat_to_nparray(img));
#include <pybind11/pybind11.h> #include <pybind11/embed.h> #include <pybind11/numpy.h> #include <pybind11/stl.h> #include <opencv2/opencv.hpp> #include <iostream> namespace py = pybind11; // The 4 functions from above go here... int main() { // Start the interpreter and keep it alive py::scoped_interpreter guard{}; try { auto locals = py::dict{}; py::exec(R"( import numpy as np def test_cpp_to_py(arr): return (arr[0,0,0], 2.0, 30) )"); auto test_cpp_to_py = py::globals()["test_cpp_to_py"]; for (int i = 0; i < 10; i++) { int64 t0 = cv::getTickCount(); cv::Mat img(cv::Mat::zeros(1024, 1024, CV_8UC3) + cv::Scalar(1, 1, 1)); int64 t1 = cv::getTickCount(); auto result = test_cpp_to_py(mat_to_nparray(img)); int64 t2 = cv::getTickCount(); double delta0 = (t1 - t0) / cv::getTickFrequency() * 1000; double delta1 = (t2 - t1) / cv::getTickFrequency() * 1000; std::cout << "* " << delta0 << " ms | " << delta1 << " ms" << std::endl; } } catch (py::error_already_set& e) { std::cerr << e.what() << "\n"; } return 0; }
* 4.56413 ms | 0.225657 ms * 3.95923 ms | 0.0736127 ms * 3.80335 ms | 0.0438603 ms * 3.99262 ms | 0.0577587 ms * 3.82262 ms | 0.0572 ms * 3.72373 ms | 0.0394603 ms * 3.74014 ms | 0.0405079 ms * 3.80621 ms | 0.054546 ms * 3.72177 ms | 0.0386222 ms * 3.70683 ms | 0.0373651 ms