C++ 调用 Python 脚本,并把 cv::Mat 类型传参到 Python 端

发布时间 2023-08-22 16:36:34作者: DoubleLi

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)