C++ 调用 Python 脚本,并把 cv::Mat 类型传参到 Python 端
前言
查看了很多参考,最后找到一个完整的示例并且跑通,在开始这个任务之前,首先应该确保你的环境是没有问题的,比如:
- C++ 和 Python 之间可以传递简单类型的参数
- C++ 端独立通过 opencv 加载图像是没有问题的
- Python 端 import cv2 独立加载图像是没有问题的
具备上面这些条件后,可以参考下面的代码,将 cv::Mat 类型的参数传递到 Python 端。
代码
这部分主要参考 sending Mat。
C++ 端需要借助 numpy,所以也需要配置好 numpy 的头文件位置。
C++ code
#include "Python.h"
#include "numpy/arrayobject.h"
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
// for the references to all the functions
PyObject *m_PyDict, *m_PyFooBar;
// for the reference to the Pyhton module
PyObject* m_PyModule;
int main() {
Py_Initialize();
// PySys_SetArgv(argc, (wchar_t**)argv);
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
PyRun_SimpleString("sys.path.append('/home/tt/test')");
PyObject *sys_path = PySys_GetObject("path");
PyList_Append(sys_path, PyUnicode_FromString("."));
// this macro is defined be NumPy and must be included
import_array1(-1);
m_PyModule = PyImport_ImportModule("cal");
if (m_PyModule != NULL)
{
// get dictionary of available items in the module
m_PyDict = PyModule_GetDict(m_PyModule);
// grab the functions we are interested in
m_PyFooBar = PyDict_GetItemString(m_PyDict, "foo_bar");
// execute the function
if (m_PyFooBar != NULL)
{
// take a cv::Mat object from somewhere (we'll just create one)
// cv::Mat img = cv::Mat::zeros(480, 640, CV_8UC3);
cv::Mat img = cv::imread("/home/tt/test/1.png");
int r = img.rows;
int c = img.cols;
int chnl = img.channels();
// total number of elements (here it's an RGB image of size 640x480)
int nElem = r * c * chnl;
// create an array of apropriate datatype
uchar* m = new uchar[nElem];
// copy the data from the cv::Mat object into the array
std::memcpy(m, img.data, nElem * sizeof(uchar));
// the dimensions of the matrix
npy_intp mdim[] = { r, c, chnl};
// convert the cv::Mat to numpy.array
PyObject* mat = PyArray_SimpleNewFromData(chnl, mdim, NPY_UINT8, (void*) m);
// create a Python-tuple of arguments for the function call
// "()" means "tuple". "O" means "object"
PyObject* args = Py_BuildValue("(O)", mat);
// execute the function
PyObject* result = PyEval_CallObject(m_PyFooBar, args);
// process the result
// ...
// decrement the object references
Py_XDECREF(mat);
Py_XDECREF(result);
Py_XDECREF(args);
delete[] m;
}
}
else
{
std::cerr << "Failed to load the Python module!" << std::endl;
PyErr_Print();
}
return 0;
}
Python code
def foo_bar(img=None):
if img is not None:
cv2.imshow("image in python", img)
cv2.imwrite("/home/tt/test/111.png", img)
cv2.waitKey(0)