• C/C++调用Python


    还是给自己的一个收藏贴啊 谁要是感觉伤害了谁 那忍着吧

    其实直接用c++更好 但写视频处理之前都是py写的numpy也好用 改不动了才有此下策 其实也不喜欢这样写 ,之前还有py调用c++ ++返回的mat不知道怎么对应py也很烦 还不想用第三方的包

    基本使用方法

    Python 提供了一套 CAPI库,使得开发者能很方便地从C/ C++ 程序中调用 Python 模块,C++ 用户应该注意,尽管 API 是完全使用 C 来定义的,但头文件已将入口点声明为 extern "C",因此 API 在 C++ 中使用此 API 不必再做任何特殊处理。

    具体的文档参考官方指南:https://docs.python.org/3.9/extending/embedding.html

    如果需要使用这个套API,我们需要引入一个头文件和一个库文件,以Cmake构建为例,我们需要在 CMakeLists.txt 中加入:

    • ​​​​​​​
    find_package (Python COMPONENTS Interpreter Development REQUIRED)target_include_directories(${PROJECT_NAME} PRIVATE ${Python_INCLUDE_DIRS})target_link_libraries(${PROJECT_NAME} PRIVATE ${Python_LIBRARIES})

    Windows环境下应该是需要保证如下两个环境变量的存在(暂未测试)。

    然后我们就可以在 main.cpp 中引入相应的头文件了:

    #include 

    之后,主程序要做的一件事就是是初始化 Python 解释器:

    Py_Initialize();

    当然,既然需要初始化解释器,作为可以在 C 语言中编写的代码,我们一般还需要对它进行释放(在不需要的时候):

    Py_Finalize();

    现在我们变可以将需要运行的 Python 语句以字符串的形式传递给 Python 解释器:

    PyRun_SimpleString("print("Hello world!")");

    举个简单的栗子

    此方法没办法进行数值的传递(暂不考虑转换为字符串传递,毕竟麻烦的同时接收数据也是一个大问题):

    1. 初始化Python解释器;

    2. 以字符串的形式传递代码;

    3. 释放python解释器。

    代码如下:

    #define PY_SSIZE_T_CLEAN#include 
    int main(int, char **){    Py_Initialize();                                       // 初始化python解释器    PyRun_SimpleString("import matplotlib.pyplot as plt"); // 运行python代码    PyRun_SimpleString("plt.plot([1,2,3,4], [12,3,23,231])");    PyRun_SimpleString("plt.show()");    Py_Finalize(); // 释放python解释器};
    

    结果如下:

    显然,我们成功的在 C++ 程序中调用 Python 并绘制图像并显示了出来。

    常用数据类型

    在python中有一句话叫做“一切皆对象”,这句话可以结合源码更好的进行理解。

    在python里,一切变量、函数、类等,在解释器中执行时,都会在在堆中新建一个对象,并将名字绑定在对象上。

    在 C/C++ 中,所有的 Python 类型都被声明为 PyObject ,为了能够操作 Python 的数据,Python提供了各种数据类型和 C 语言数据类型的转换操作:

    PyObject *object;  // 创建python的object的指针Py_DECREF(object); // 销毁object

    1.数字与字符串处理

    在 Python/C API 中提供了 Py_BuildValue() 函数对数字和字符串进行转换处理,使之变成Python中相应的数据类型。

    PyObject* Arg = Py_BuildValue("(i, i)"12);  //i表示创建int型变量

    2.列表操作

    在 Python/C API 中提供了 PyList_New() 函数用以创建一个新的 Python 列表。PyList_New() 函数的返回值为所创建的列表。

    3.元组操作

    在 Python/C API 中提供了 PyTuple_New() 函数,用以创建一个新的 Python 元组。PyTuple_New() 函数返回所创建的元组。

    4.字典操作

    在 Python/C API 中提供了 PyDict_New() 函数用以创建一个新的字典。PyDict_New() 函数返回所创建的字典。

    5. cv::Mat 操作

    cv::Mat应该是我们会经常使用的格式了,参考代码如下:

    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;}

    更多操作请参考:https://docs.python.org/zh-cn/3/c-api/arg.html#building-values

    举个稍复杂一点的栗子

    此方法可以进行进行数值的传递:

    1. 初始化Python解释器;           

    2. 从C++到Python转换数据;

    3. 用转换后的数据做参数调用Python函数;

    4. 把函数返回值转换为C++数据结构;

    5. 释放python解释器。

    whaosoft aiot http://143ai.com

    C++代码如下:

    #define PY_SSIZE_T_CLEAN#include #include 
    int main(int, char **){    // 初始化python解释器    Py_Initialize();    if (!Py_IsInitialized())    {        return -1;    }
        // 添加编译后文件的所在路径    PyRun_SimpleString("import sys");    PyRun_SimpleString("sys.path.append('./')");
        // 要调用的python文件名    auto pModule = PyImport_ImportModule("common"); // 记得复制到编译后文件的路径下,同时不用加后缀名“.py“    if (!pModule)    {        std::cout << "Can't find your xx.py file.";        getchar();        return -1;    }
        //获取模块中的函数    auto pFunc = PyObject_GetAttrString(pModule, "add"); //从字符串创建python函数对象
        // 参数类型转换    PyObject *pArg = Py_BuildValue("ii", 1, 2);
        //调用直接获得的函数,并传递参数    auto *py_result = PyEval_CallObject(pFunc, pArg);
        int c_result;    // 将python类型的返回值转换为C类型    PyArg_Parse(py_result, "i", &c_result);    std::cout << "return: " << c_result << std::endl;};

    Python代码如下(命名为 common.py):

    def add(a, b):    print('a: ', a)    print('b: ', b)    return a + b

    结果如下(代码中设置的 python 文件搜索路径为编译后的文件路径):

    这样比较简单的两个实现就完成了,更多操作请参考:https://docs.python.org/3.9/c-api/index.html#c-api-index

  • 相关阅读:
    uni-app进行表单效验
    2023王道计算机网络总结
    Textpad 缺少Java编译和运行功能
    create® 3入门教程-传感器检测
    VSCode 工具常用插件
    Kafka实现保证一批消息顺序生产消费的方案
    【Linux】gcc/g++
    ES使用ik分词器查看分词结果及自定义词汇
    【机器学习合集】激活函数合集 ->(个人学习记录笔记)
    三菱PLC网络MC3E通信—读取或写入——字符串或数字
  • 原文地址:https://blog.csdn.net/qq_29788741/article/details/126184243