系统:Windows10
IDE:VS2019
本文讲解如何从C++调用python函数,且包含opencv。
比如我有一个python函数show_img,我想在C++调用它。py文件名为showimg.py。
import cv2
def show_img(img):
cv2.namedWindow('img',0)
cv2.imshow('img',img)
cv2.waitKey(0)
#...some process
print(img.shape)
print(img[:,:,0])
return str(img.shape)
一、环境配置
配置release,因为没有debug版。
属性->通用属性->VC++目录->包含目录 添加:
D:\opencv\build\include\
C:\Users\TOMATO\AppData\Local\Programs\Python\Python38\include
C:\Users\TOMATO\AppData\Local\Programs\Python\Python38\Lib\site-packages\numpy\core\include
属性->通用属性->VC++目录->库目录 添加:
D:\opencv\build\x64\vc15\lib
C:\Users\TOMATO\AppData\Local\Programs\Python\Python38\libs
C:\Users\TOMATO\AppData\Local\Programs\Python\Python38\Lib\site-packages\numpy\core\lib
属性->通用属性->链接器->输入->附加依赖项 添加:
opencv_world420.lib
python38.lib
python3.lib
_tkinter.lib
npymath.lib
如果未使用opencv和python的默认安装路径,请换成自己的。
注意opencv版本。比如我之前报错qt.qpa.plugin: Could not find the Qt platform plugin "windows" in "":
但这并不是真的缺少qt插件。而是因为C++中的opencv和python中的版本不一样!将版本换成一致的即可。
二、主程序
#include <opencv2/opencv.hpp>
#include<iostream>
#include<string>
#include <Python.h>
#include <numpy/arrayobject.h>
using namespace std;
int main() {
Py_SetPythonHome(L"C:/Users/TOMATO/AppData/Local/Programs/Python/Python38");
Py_Initialize();
import_array();//千万不要忘
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('C:/Users/TOMATO/AppData/Local/Programs/Python/Python38/Lib/site-packages')");
PyRun_SimpleString("sys.path.append('./')");
PyRun_SimpleString("import numpy as np");
PyRun_SimpleString("import cv2");
cv::Mat img = cv::imread("D:/projects/test_images/coins.jpg", -1);
PyObject* pModule(0);
pModule = PyImport_ImportModule("showimg");//myModel:Python文件名
PyObject* pDict = PyModule_GetDict(pModule);
int m, n, c;
m = img.rows;
n = img.cols;
c = img.channels();
std::cout << m << std::endl << n << std::endl << c << std::endl;
npy_intp Dims[3] = { m, n, c };//图像维度信息
PyObject* pyArray = PyArray_SimpleNewFromData(3, Dims, NPY_UBYTE, img.data);
PyObject* ArgArray = PyTuple_New(1);
PyTuple_SetItem(ArgArray,0,pyArray);
PyObject* pFunc = PyDict_GetItemString(pDict, "show_img");//函数名show_img
PyObject* pValue=PyObject_CallObject(pFunc, ArgArray);
char* re_val;
PyArg_Parse(pValue, "s", &re_val);
std::cout << "re_val=" << re_val << std::endl;
Py_Finalize();
cv::destroyAllWindows();
return 0;
}
如码所示,所有py对象都是PyObject,非常省心。cv::Mat其实就是通过函数PyArray_SimpleNewFromData包装成了PyObject* pyArray。值得一提的是返回类型的转换,本文是字符转为C++的char*。若是int值,可用如下方式转换。
int re_val;
re_val = PyInt_AsLong(pValue)
若使用Anaconda,会出现错误:"Importing the numpy c-extensions failed."。使用pip重新安装包即可解决。
pip install --upgrade --force-reinstall numpy
opencv也不行,同理
pip install --upgrade --force-reinstall opencv-python
三、运行结果
把showimg.py文件放在工作目录下,运行程序。结果如下
可见我们从C++读入一张图片赋值到cv::Mat img,然后把img转换成PyObject* pyArray,传入python函数,实现了图像的显示,并取得了函数返回值,转成char* 打印出来。