Python封装C++ OpenCV接口如何通过输出参数直接返回Mat对象
实现可行性结论
这个需求完全可以实现,不需要依赖Py_BuildValue("O", obj)返回新对象的方案,核心思路是直接修改传入的output参数对应的numpy数组底层内存,具体实现注意以下几点:
核心实现要点
- 首先要确保Python层传入的
output_image已经提前分配好了和处理后输出尺寸、通道数、数据类型完全匹配的内存,不能是你当前示例里output_image = image这种浅拷贝、且尺寸和输出不匹配的情况,否则直接写入会触发内存越界。
正确的Python层调用前预处理示例:# 提前按超分逻辑计算输出尺寸,初始化对应大小的空numpy数组(也就是OpenCV的Mat对象) out_rows, out_cols = int(rows*scale), int(cols*scale) output_image = np.zeros((out_rows, out_cols, 3), dtype=np.uint8) - C层不需要新建
PyObject* obj返回,直接把处理后的输出矩阵绑定到传入output参数的底层内存即可,修改后的C封装代码示例:static PyObject* testProcess(PyObject* self, PyObject* args) { PyArrayObject *input, *output; if ( ! PyArg_ParseTuple(args, "OO", &input, &output) ) return NULL; // 解析输入矩阵的维度信息 int in_rows = PyArray_DIM(input, 0); int in_cols = PyArray_DIM(input, 1); cv::Mat in = cv::Mat(cv::Size(in_cols, in_rows), CV_8UC3, PyArray_DATA(input)); // 校验传入的output参数是否符合输出要求 int expected_out_rows = in_rows * 2; // 替换为实际的输出行计算逻辑 int expected_out_cols = in_cols * 2; // 替换为实际的输出列计算逻辑 if (PyArray_DIM(output, 0) != expected_out_rows || PyArray_DIM(output,1) != expected_out_cols || PyArray_TYPE(output) != NPY_UINT8 || PyArray_NDIM(output) !=3) { PyErr_SetString(PyExc_ValueError, "output参数尺寸/类型不匹配,请提前初始化对应大小的uint8三通道数组"); return NULL; } // 直接绑定output参数的底层内存构造cv::Mat,Process写入时会直接修改Python层的对象 cv::Mat out = cv::Mat(cv::Size(expected_out_cols, expected_out_rows), CV_8UC3, PyArray_DATA(output)); int ret = Process(in, out); if(ret < 0){ printf("Erreur Process : %x\n", ret); PyErr_SetString(PyExc_RuntimeError, "处理函数执行失败"); return NULL; } // 直接返回状态码即可,不需要返回新的图像对象 return Py_BuildValue("i", ret); } - 内存安全说明:上述实现中
cv::Mat out复用的是numpy数组预先申请的内存,cv::Mat销毁时不会释放外部传入的内存,不会和Python的垃圾回收机制冲突,无内存安全问题。
注意:你原始代码中存在两处笔误:Python层的
intput_image拼写错误、C++层的in ret应该为int ret,且未定义in_dims、out_dims变量,需要先修正这些基础错误再调整逻辑。
内容的提问来源于stack exchange,提问作者Pierre
相关产品推荐
相关产品推荐

