如何使用Python/C API将numpy.ndarray转换为cv::Mat?

1 投票
1 回答
2022 浏览
提问于 2025-04-18 00:00

我用Python来处理图像,但当我需要写一些自定义函数来操作矩阵时,发现numpy.ndarray在循环操作时速度太慢了。我想把这个数组转换成cv::Mat,这样我就能更方便地处理,因为我之前写C++代码时是基于cv::Mat结构进行图像处理的。

我的test.cpp文件:

#include <Python.h>
#include <iostream>

using namespace std;

static PyObject *func(PyObject *self, PyObject *args) {
    printf("What should I write here?\n");
    // How to parse the args to get an np.ndarray?
    // cv::Mat m = whateverFunction(theParsedArray);
    return Py_BuildValue("s", "Any help?");
}

static PyMethodDef My_methods[] = {
    { "func", (PyCFunction) func, METH_VARARGS, NULL },
   { NULL, NULL, 0, NULL }
};

PyMODINIT_FUNC initydw_cvpy(void) {
    PyObject *m=Py_InitModule("ydw_cvpy", My_methods);

    if (m == NULL)
        return;
}

main.py文件:

if __name__ == '__main__':
    print ydw_cvpy.func()

结果:

What should I write here?
Any help?

1 个回答

0

我很久没玩过原生的C语言和Python的绑定了(我通常使用 boost::python),不过关键在于 PyArray_FromAny。一些未经测试的示例代码可能看起来是这样的:

PyObject* source = /* somehow get this from the argument list */

PyArrayObject* contig = (PyArrayObject*)PyArray_FromAny(source,
        PyArray_DescrFromType(NPY_UINT8),
        2, 2, NPY_ARRAY_CARRAY, NULL);
if (contig == nullptr) {
  // Throw an exception
  return;
}

cv::Mat mat(PyArray_DIM(contig, 0), PyArray_DIM(contig, 1), CV_8UC1,
            PyArray_DATA(contig));

/* Use mat here */

PyDECREF(contig); // You can't use mat after this line

请注意,这段代码假设你有一个 CV_8UC1 的数组。如果你有一个 CV_8UC3 的数组,你需要请求一个三维数组。

PyArrayObject* contig = (PyArrayObject*)PyArray_FromAny(source,
    PyArray_DescrFromType(NPY_UINT8),
    3, 3, NPY_ARRAY_CARRAY, NULL);
assert(contig && PyArray_DIM(contig, 2) == 3);

如果你需要处理任何随机类型的数组,你可能还想看看 这个回答

撰写回答