c++调用python numpy编程_c++ numpy-程序员宅基地

技术标签: PyImport_Import  python学习  c++调用python类  c++调用python  PyObject_GetAttrString  多线程调用python  

背景

现在用c++重构了python工程,有一部分后处理不想再花时间重构了,所以直接拿过来调用。边搜资料边做的,做这个demo花了些时间,所以记下来以防忘记。

资料

找了很多的c++调用python的方法,首先可以肯定的有不止一种方式,直接使用python库、numpy arrayobject库来做;另外一种是使用boost/python boost/numpy的方式。后一种没有调通,是链接库的问题,也记录下来放在后面了。

1)常规的方式
  1. 调包的基本结构 C/C++调用Python(OpenCV与Numpy)作者收集了很多的信息,帮助蛮大的。
  2. 编译,收集自stackoverflow: how to build this project
    g++ -o cc cc.cpp `pkg-config --cflags --libs opencv` -I/usr/include/python3.5 -lpython3.5m
    值得说明一下的是,python3.5m是在路径/usr/lib/x86_64-linux-gnu/libpython3.5m.so下,可以自行搜素。另外,代码中有个warning,使用宏定义就可以去掉了,在代码中也有说明
  3. 代码块
  1. 补充
  • import_array()有奇怪的返回值,这篇博客也提到了解决方法 import_array()报错,返回值类型与函数类型不匹配。但是要删东西,还有不报错误的风险。这儿我忘记了在哪看到的代码了,也没能在历史记录里找到,先把代码贴过来。其实就是将这个函数加一个壳。然后用init替换import_array。
size_t init() {
    
    import_array();
}
  • 一个小插曲,c++主函数需要使用多线程,python放在子线程中执行。在子线程中异步调用时会有segment fault,而相同代码顺序执行的没有问题。我一度怀疑是多线程的锅,所以尝试了小半天的c++多线程调用python,顺便把筛选的资料附录在下面;也尝试了子线程加锁mutex。哦,忘记说了,多线程调用python时,也是给python解释器加锁。那下面就是C++多线程调用python的链接,按优先顺序排放。
    c++多线程调用python
    C++调用PythonAPI线程状态和全局解释器锁
    C++ 多线程调用Python脚本

  • c++调用python类
    通过c++去调用python类的资料我收集了一部分。比如1).c++访问python3-实例化类的方法、2).c++ 调用 python 实例 涉及 类 多参数 列表作为参数、3).c++调用python的代码、函数、类。这些在传递numpy的时候没有找到合适的示例,这儿没有说明文档始终调不通。所以最后还是通过按照上面调用python函数的方法,创建一个全局类对象来调用完成。

  • segmentation 错误 以及程序假死
    python异常时,c++调用python的报错信息不及时且信息少。所以,出现假死或段错误等奇怪的现象时,优先排查python代码

2) boost库的方式
  1. 调包的基本结构 C++调用python并传递数组
  2. debug出现的错误,主要是boost/numpy问题,安装之后还是出现找不到库的情况,stackoverflow上有个对话,是统一的问题,需要修改环境变量后解决了,先在这儿记下来吧
  3. boost库的安装

cc.cpp

// c++:  cc.cpp
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION //需要放在numpy/arrayobject.h之前

#include<opencv/cv.hpp>
#include <Python.h>
#include <iostream>
#include <numpy/arrayobject.h>


using namespace cv;
using namespace std;

int main(int argc, char *argv[]) {
    wchar_t *program = Py_DecodeLocale(argv[0], NULL);
    cout << argv[0] << endl;
    if (program == NULL) {
        fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
        exit(1);
    }
    Py_SetProgramName(program);  /* 不见得是必须的 */
    /* 非常重要,折腾的时间主要是因为这儿引起的【1】 */
    Py_Initialize();
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append(\"/home/user/project/run_retina/build\")");
    import_array();
    /* 非常重要 */

    /* 读图 */
    Mat sml_img = imread("lena.jpg");

    /* 导入模块和函数,貌似两种方式都可以,不需要加.py,后面回再提到 */
    // PyObject *pName = PyUnicode_DecodeFSDefault("simple_module");
    PyObject *pName = PyUnicode_FromString("simple_module");
    /*这些检查也非常有帮助*/
    if (pName == NULL) {
        PyErr_Print();
        throw std::invalid_argument("Error: PyUnicode_FromString");
    }
    PyObject *pModule = PyImport_Import(pName);
    if (pModule == NULL) {
        PyErr_Print();
        throw std::invalid_argument("fails to import the module");
    }
    PyObject *pFunc = PyObject_GetAttrString(pModule, "super_resolution");
    if (pFunc == NULL) {
        PyErr_Print();
        throw std::invalid_argument("fails to PyObject_GetAttrString");
    }
    /* 准备输入参数 */
    PyObject *pArgs = PyTuple_New(2);
    if (!sml_img.isContinuous()) { sml_img = sml_img.clone(); }
    npy_intp dims[] = {sml_img.rows, sml_img.cols, 3};

    PyObject *pValue = PyArray_SimpleNewFromData(3, dims, NPY_UINT8, sml_img.data);
    PyTuple_SetItem(pArgs, 0, pValue);  /* pValue的引用计数被偷偷减一,无需手动再减 */
    PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 2));    /* 图像放大2倍 */
    /* 调用函数 */
    PyObject *pRetValue = PyObject_CallObject(pFunc, pArgs);
    /* 解析返回结果 */
    PyArrayObject *ret_array;
    PyArray_OutputConverter(pRetValue, &ret_array);
    npy_intp *shape = PyArray_SHAPE(ret_array);
    Mat big_img(shape[0], shape[1], CV_8UC3, PyArray_DATA(ret_array));
    imwrite("aa.jpg", big_img);
    /* 释放所有 */
    //Py_DECREF(...);
    return 0;
}

simple_module.py

# simple_module.py
import cv2 as cv
def simple_func(a,b):return a+b
def super_resolution(img, scale=4):
    height, width = img.shape[:2]
    dsize = (width*scale, height*scale)
    big_img = cv.resize(img, dsize)
    print(img.shape, big_img.shape)
    cv.imwrite('aaa.jpg',big_img)
    return big_img

多个numpy返回值

/* 解析返回结果 */
    PyArrayObject *r1, *r2, *r3, *r4, *r5, *r6;
    PyArg_UnpackTuple(pRetValue, "ref", 6, 6, &r1, &r2, &r3, &r4, &r5, &r6);
    npy_intp *shape1 = PyArray_SHAPE(r1);
    npy_intp *shape2 = PyArray_SHAPE(r2);
    npy_intp *shape3 = PyArray_SHAPE(r3);
    npy_intp *shape4 = PyArray_SHAPE(r4);
    npy_intp *shape5 = PyArray_SHAPE(r5);
    npy_intp *shape6 = PyArray_SHAPE(r6);
    std::cout << "shape[1]:" << shape1[0] <<
              " shape2:" << shape2[0] << "," << shape2[1] <<
              " shape3:" << shape3[0] <<
              " shape4:" << shape4[0] << "," << shape4[1] <<
              " shape5:" << shape5[0] <<
              " shape6:" << shape6[0] << "," << shape6[1] <<
              std::endl;
# 返回值的打印结果
#-#-#-#-#-#-#-#-#-#-
list_id float32 (11,)
list_track float32 float32 (20, 2) (11,)
list_box float32 (11, 4)
entran;pass_by;ratio float32 (3,)
entrance_line;rec float32 (4, 2)
#-#-#-#-#-#-#-#-#-#-
shape[1]:11 shape2:20,2 shape3:11 shape4:11,4 shape5:3 shape6:4,2


  1. 代码c++ : cc.cpp

  2. 代码python :simple_module.py

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/daniaokuye/article/details/102477985

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签