您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

如何通过共享内存将cv :: Mat发送至python?

如何通过共享内存将cv :: Mat发送至python?

总体思路(在OpenCV Python绑定中使用)是创建一个ndarrayMat对象共享其数据缓冲区的numpy ,并将其传递给Python函数

注意:在这一点上,我将示例限制为仅连续矩阵。

我们可以利用pybind11::array该类。

我们需要确定适合dtypenumpy数组使用的数组。这是一个简单的一对一映射,我们可以使用switch

py::dtype determine_np_dtype(int depth)

{ switch (depth) { case CV_8U: return py::dtype::of (); case CV_8S: return py::dtype::of (); case CV_16U: return py::dtype::of (); case CV_16S: return py::dtype::of (); case CV_32S: return py::dtype::of (); case CV_32F: return py::dtype::of (); case CV_64F: return py::dtype::of (); default: throw std::invalid_argument(“Unsupported data type.”); } }

确定numpy数组的形状。为了使它的行为类似于OpenCV,让我们将1-channel映射Mat到2D numpy数组,将multi-channel映射Mat到3D numpy数组。

std::vector<std::size_t> determine_shape(cv::Mat& m)

{ if (m.channels() == 1) { return { static_cast (m.rows) , static_cast (m.cols) }; }

return {
    static_cast<size_t>(m.rows)
    , static_cast<size_t>(m.cols)
    , static_cast<size_t>(m.channels())
};

}

提供将共享缓冲区的生存期延长到numpy数组的生存期的方法。我们可以pybind11::capsule围绕源创建一个浅表副本Mat-由于对象的实现方式,这可以在所需的时间内有效地增加其引用计数。

py::capsule make_capsule(cv::Mat& m)

{ return py::capsule(new cv::Mat(m) , { delete reinterpret_cast<: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));
}

假设我们有一个Python函数,例如

def foo(arr):
    print(arr.shape)

捕获在pybind对象中fun。然后使用aMat作为源从C ++调用函数,我们将执行以下操作:

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
python 2022/1/1 18:45:22 有380人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶