#include //应该是调用什么版本解使用什么版本的python
#include //使用的方式和cmakelist有些关系
Py_Initialize(); 初始化
PyRun_SimpleString("import sys"); //设置文件路径
PyRun_SimpleString("sys.path.append('./')");//./表示当前执行程序的路径
//中间在使用下面的一些具体的函数调用方式实现调用python
Py_Finalize();
PyRun_SimpleString(); //使用字符串实现直接写的python程序
PyObject *object;//创建python的object的指针,可以是model class fun arg return
Py_DECREF(object);//销毁object,感觉和c++的new和delete比较像
pModule = PyImport_ImportModule("test"); // 导入python的文件modle,不需要写后缀名.py
pDict = PyModule_GetDict(pModule); // 以字典形式存储model的信息,用于后续的调用
//创建python的数据类型的object
PyObject *Arg = Py_BuildValue("(s)", "dawd a");
PyObject *Arg = Py_BuildValue("(i, i)", 1, 2);
//创建好多参数
PyObject* cons_args = PyTuple_New(2);
PyObject* cons_arg1 = PyLong_FromLong(1);
PyObject* cons_arg2 = PyLong_FromLong(999);
PyTuple_SetItem(cons_args, 0, cons_arg1);
PyTuple_SetItem(cons_args, 1, cons_arg2)
PyObject *pFunc = PyObject_GetAttrString(pModule, "Hello"); //从字符串创建python函数object
PyObject *pFunc = PyDict_GetItemString(pDict, "Add"); //从字典创建python函数object
PyObject *result = PyEval_CallObject(pFunc, pArg); //实现python的函数object的调用并接受return
int c;
PyArg_Parse(result, "i", &c); // 数据类型转化python -> c++
构造函数
当成class的实例化对象
使用,后面在class的def __init__()
中加了个print()
发现没有输出才发现这个问题。python
代码中调用class
的func
貌似在c++
的调用中会有问题,我这里发现不能这么调用,所有解决方案就是把class
的声明、构造、实例化全部拆开到c++
中调用PyObject_CallMethod()
这个函数传递参数"s"
的时候不能使用string
需要转化为const char* image_name1 = querys[i].data();
才能正常传递参数PyObject *pClass = PyDict_GetItemString(pDict, "HFNet");//获取class
PyObject *pConstruct = PyInstanceMethod_New(pClass); //获取class构造函数
PyObject *cons_args = Py_BuildValue("(s)", "./Examples/python/model/hfnet");//设置实例化所需要的参数
PyObject *pInstance = PyObject_CallObject(pConstruct, cons_args); //实例化class
// PyObject_CallMethod(pInstance, methodname, "O", args)
// 参数0:[class的object]
// 参数1:[class的fun的名称]
// 参数2:[输入参数的类型] [O表示object][s表示char*,string的类型需要进行转化]
// ? 这里有个疑问,self参数需要输入吗?网上的example我看到过有的也有不传递的
// 参数...:[class内的fun的各个参数]
std::vector querys;
const char* image_name1 = querys[i].data();
result1 = PyObject_CallMethod(pInstance, "inference", "s", image_name1);
CMakeLists.txt
为准好事#set(PYTHON_INCLUDE_DIR /usr/include/python3.6)#这个好像并不影响
#python的虚拟环境,需要添加对应的.so,bash中 source /venv/bin/activate
set(PYTHON_LIBRARY /usr/lib/python3.6/config-3.6m-x86_64-linux-gnu/libpython3.6.so)
#看到有人添加
#include_directories( /usr/include/python3.6)
#的这里我没弄感觉也能编译
add_executable(usepython
Examples/python/usepython.cc)
target_link_libraries(usepython -lpython3.6m)
##写法2还是用下面这种吧,这样头文件包含就可以直接#include 不用指定python版本
#下面这种写法写可以
find_package(PythonLibs REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})
add_executable(usepython
Examples/python/usepython.cc)
target_link_libraries(usepython ${PYTHON_LIBRARIES})
简单的调用例子如下
c++
#include
#include
//#include
int main()
{
// - 基础的调用
// 初始化Python
//在使用Python系统前,必须使用Py_Initialize对其
//进行初始化。它会载入Python的内建模块并添加系统路
//径到模块搜索路径中。这个函数没有返回值,检查系统
//是否初始化成功需要使用Py_IsInitialized。
Py_Initialize();
// 检查初始化是否成功
if (!Py_IsInitialized())
{
return -1;
}
// - 添加当前路径
// PyRun_SimpleString(FILE *fp, char *filename);
//直接运行python的代码
PyRun_SimpleString("import sys");
// PyRun_SimpleString("print '---import sys---'");
//下面这个./表示当前运行程序的路径,如果使用../则为上级路径,根据此来设置
PyRun_SimpleString("sys.path.append('./Examples/python/')");
PyRun_SimpleString("print(sys.path)");
// - 引入模块
PyObject *pModule, *pDict, *preturn; // python的对象的指针
//要调用的python文件名
pModule = PyImport_ImportModule("testpy"); //加载模型不用加后缀名.py
if (!pModule)
{
printf("can't find your_file.py");
getchar();
return -1;
}
//获取模块字典属性
pDict = PyModule_GetDict(pModule);
if (!pDict)
{
return -1;
}
std::cout << "加载模型成功" << std::endl;
PyObject *pFunc;
// - 直接调用函数
//直接获取模块中的函数
PyRun_SimpleString("print('使用string获取模块中的函数')");
pFunc = PyObject_GetAttrString(pModule, "Hello"); //从字符串创建python函数对象
//参数类型转换,传递一个字符串
//将c/c++类型的字符串转换为python类型,元组中的python类型查看python文档
PyRun_SimpleString("print('生成python的数据类型')");
PyObject *pArg = Py_BuildValue("(s)", "Hello");
PyRun_SimpleString("print('实现py函数调用')");
//调用直接获得的函数,并传递参数
PyEval_CallObject(pFunc, pArg);
// - 从字典属性中获取函数
PyRun_SimpleString("print('使用字典获取模块中的函数')");
pFunc = PyDict_GetItemString(pDict, "Add"); //从字典创建python函数对象
//参数类型转换,传递两个整型参数
pArg = Py_BuildValue("(i, i)", 1, 2); //创建python的数据类型
//调用函数,并得到python类型的返回值
PyObject *result = PyEval_CallObject(pFunc, pArg); //实现python的函数调用
// c用来保存c/c++类型的返回值
int c;
//将python类型的返回值转换为c/c++类型
PyArg_Parse(result, "i", &c); // 数据类型转化python -> c++
//输出返回值
std::cout << "a + b = c =" << c << std::endl;
// - 通过字典属性获取模块中的类
PyRun_SimpleString("print('---------通过字典属性获取模块中的class-----------')");
PyObject *pClass = PyDict_GetItemString(pDict, "Test");
//实例化获取的类
PyRun_SimpleString("print('实例化获取的class')");
PyObject *pInstance = PyInstanceMethod_New(pClass);
//调用类的方法
PyRun_SimpleString("print('调用class中Method')");
result = PyObject_CallMethod(pInstance, "SayHello", "(Oss)", pInstance, "zyh", "12");
//输出返回值
char *name = NULL;
PyRun_SimpleString("print('输出返回结果')");
PyArg_Parse(result, "s", &name);
printf("%s\n", name);
// - 使用文件路径传递图像参数
PyRun_SimpleString("print('---------使用文件路径传递图像参数-----------')");
pFunc = PyDict_GetItemString(pDict, "show_image"); //从字典创建python函数对象
pArg = Py_BuildValue("(s)", "Data/db1.jpg");
preturn = PyEval_CallObject(pFunc, pArg);
name = NULL;
PyArg_Parse(preturn, "s", &name);
printf("%s\n", name);
Py_DECREF(pModule);
Py_DECREF(pDict);
Py_DECREF(pFunc);
Py_DECREF(pArg);
Py_DECREF(result);
Py_DECREF(pClass);
Py_DECREF(pInstance);
Py_DECREF(preturn);
//释放python
Py_Finalize();
// getchar();
return 0;
}
python
import sys
import cv2
def Hello(s):
print("Hello World")
print(s)
def Add(a, b):
print('a=', a)
print('b=', b)
return a + b
class Test:
def __init__(self):
print("Init")
def SayHello(self, name, old):
print("Hello,", name, old)
return name
def show_image(name):
print(name)
image = cv2.imread(name)
cv2.imshow("image", image)
cv2.waitKey(0)
return name
PyObject *cvmat2py(cv::Mat &image)
{
import_array();
int row, col;
col = image.cols; //列宽
row = image.rows; //行高
int channel = image.channels();
int irow = row, icol = col * channel;
npy_intp Dims[3] = {row, col, channel}; //图像维度信息
PyObject *pyArray = PyArray_SimpleNewFromData(channel, Dims, NPY_UBYTE, image.data);
PyObject *ArgArray = PyTuple_New(1);
PyTuple_SetItem(ArgArray, 0, pyArray);
return ArgArray;
}
numpy.ndarray
中的numpy.float32、numpy.int32
转化为c++
格式的数据*(float *)PyArray_GETPTR1(Py_global_desc, i);
*(int *)PyArray_GETPTR1(Py_global_desc, i, j);
-具体的例子可以参考函数useNet.cc中void GetFeature()
import cv2
放在python
文件中,没有缩进就会直接报错,放在函数内部就不会出现错误,后来有没有这个问题了,可能是c++
写example的时候使用{}
分别引入两次python导致的??{}
不是会自己提供作用阈吗?,还是这个接口是全局的?c++
多线程开cv::imshow()
程序会崩溃,没想到用c++
自己用一个cv::imshow()
,然后python也开一个cv.imshow()
也会崩溃。啊这当时还以为cv::Mat
转为PyObject
的格式出了问题呢,结果不是的。