Python中的opencv与C++中的opencv图像数据转换_opencv的c++程序改写成python程序_是水啊!鲸鱼的博客-程序员宝宝

技术标签: c++  python  opencv  

1.c++调用python的步骤

  1. 初始化python
  2. 加载对应模块(使用dict和直接调用)
  3. 加载对应函数3.1使用类还要对类进行实例化
  4. 将参数封装为Python元组类型
  5. 传入参数到元组
  6. 获取并根据Python函数的定义解析返回值

2.直接上代码进行注释

#include <python2.7/Python.h>
//python与c++的接口在这个头文件里

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <numpy/ndarrayobject.h>
//使用PyArray需要包含此头文件,用于在python和c++之间进行涉及列表和数组之间的数据操作
#include <importance.h>
//这是一个重要第三方头文件用于python cv2和c++ mat之间的转换

void init_numpy(){
    import_array();//头文件包含了numpy的头文件,使用其来调用numpy库
}

int main(){
    cv::Mat img=cv::imread("/home/CLionProjects/untitled2/2.png");
    Py_Initialize();//用于初始化python,可以认为是调用python的解释器和import 一些库
    init_numpy();//初始化调用numpy

    PyRun_SimpleString("import sys");//该函数意味在python解释器下执行import sys引入
    PyRun_SimpleString("import string");//同上
    PyRun_SimpleString("sys.path.append('/home/CLionProjects/untitled2/src/python')");//指定即将调用的python文件的绝对地址,如果python文件和c++主程序文件在同一工程目录下,也可以替换为  ./

    PyRun_SimpleString("print sys.path");//调用python的解释器输出python解释器的路径和lib的路径等相关信息
    if(!Py_IsInitialized())//判断是否初始化,若初始化Py_IsInitialized()为true
    {
        std::cout<<"not initialize"<<std::endl;
    }

    PyObject * p_name= PyString_FromString("qwer");
    //将c++下的字符串转换为Python*对象,便于python调用,qwer为要使用的python的文件名,不带.py
    PyObject * p_module= PyImport_Import(p_name);
    //引入该模块即python文件
    if(!p_module)
    {
        std::cout<<"not p_module"<<std::endl;
    }
    PyObject * p_dict= PyModule_GetDict(p_module);
    //将Python文件内的python函数名,类名赋予字典属性,就是通过函数名类名名字找到指定函数或者类
    if(!p_dict)
    {
        std::cout<<"not dict"<<std::endl;
    }
    PyObject * p_class= PyDict_GetItemString(p_dict,"DQ");
    //通过python文件内的类名“DQ”找到对应的类DQ用PyObject*代替
    if(!p_class)
    {
        std::cout<<"not p_func"<<std::endl;
    }
    PyObject * p_instance= PyInstance_New(p_class,NULL,NULL);
    //将刚刚找到的DQ类进行初始化,类似c++对象的实例化
    //transform mat numpy to python
    //start,,,,这下面可以将c++ mat转换为python cv2,我并未使用,因为在转回来时回不来了,笑哭
    /*
    auto sz=img.size();
    获取图像的尺寸
    int wx=sz.width;int hy=sz.height;int cz=img.channels();//获取图像的宽和高及通道
数
    int ichannels=img.channels();int irows=img.rows;int icols=img.cols*ichannels;
    //因为传入的是三通道rgb图像需要将对遍历方法做准备,icols为三通道的所有的列数,这个和彩色图在内存上的存储方式有关,可以认为共用行数,;灰度图的每一列现在彩色图这边是三列,
    if(img.isContinuous())//判断图像是否连续有些时候,因为转换格式的不同,导致在内存上可能有缝隙
    {
        icols*=irows;
        irows=1;
    }
    uchar *p;//遍历图像的指针
    uchar * arrays=new uchar[wx*hy*cz];//存储图像所有像素点的数组
    for(int i=0;i<irows;i++)
    {
        p=img.ptr<uchar>(i);//mat智能指针用于指向图像的第i行的开头
        for(int j=0;j<icols;j++)
            arrays[++id]=p[j];//遍历图像++id起始为0,
    }
    npy_intp Dim[3]={hy,wx,cz};//设置数组维数
    PyObject * pyarray= PyArray_SimpleNewFromData(3,Dim,NPY_UBYTE,arrays);
    将c++数组转换为PyObject对象,3是三个维度,Dim[0]=Dim[1]=Dim[3]=hy*wx意为每一维度多少元素,数组类型和数组
    //end
    PyObject * arg= PyTuple_New(1);
    //声明一个PyTuple元组,在Python中元组作为容器,用来存放参数,返回值;就像一座雀桥(API,c++牛郎在这头,python织女在那头),喜鹊(Tuple)来运送 信息(参数,返回值),不论你的信息是什么,都要喜鹊转达告知对方,对不对
    PyTuple_SetItem(arg,0,pyarray);
    //刚刚创建的元组是空的,使用该函数对它赋值,在arg元组第0个位置(本身就一个元素)加入数组pyarray
    PyObject * d_result=PyObject_CallMethod(p_instance,"run","O",arg);
    //调用类内方法,p_instance是PyObject*类型的类的实例化对象,run为想要调用的方法名,“O”为传入参数格式,详情见文档,arg就是要传入参数了,返回值也是pb(PyObject)对象

    // python's cv2 transfrom to c++'s mat,这个对于我来说是行不通的,有知道的大佬可以分享一下,嘿嘿
    //start
    PyObject *redt;int *zero;//定义两个pb对象用于接收元组解析出来的元素值,就是喜鹊卸货了,你要有东西接着
    //if(PyTuple_Check(d_result)){
    //判断是否为元组,万一送信的不是喜鹊呢
    std::cout<<"is a tuple"<<std::endl;
    PyArg_UnpackTuple(dwt_result,"ref",2,2,&redt,&zero);
    //这个函数用于卸货,第一个2是该元组上最少有几个元素,第二个2是该元组上最多有几个元素,分别用redt,和zero的引用去装,本来返回的是图像,只有一个但是图像的格式是buffer不知道咋处理,又返回多一个值,0
    int py_aaray_dims= PyArray_NDIM(redt);//获取返回值的维度信息
    npy_intp *py_aaray_shape=PyArray_DIMS(redt);//每个维度的形状
    npy_intp array_row=py_aaray_shape[0];//row
    npy_intp array_col=py_aaray_shape[1];//col
    npy_intp array_high=py_aaray_shape[2];//channels
    std::cout<<py_aaray_dims<<","<<*py_aaray_shape<<","<<array_row<<"x"<<array_col<<"dims"<<array_high<<std::endl;
    cv::Mat dtimg(array_row,array_col,CV_8UC3, PyArray_DATA(redt));
    //构造图像,
    delete []arrays;//删除使用的指针
    //}
//!!!以上注释的代码没有用到。。。。
     */
    importance c;//构造一个对象,用于调用cv2 与mat的转换函数
    PyObject * pyarray=c.toNDArray(img);//将mat图像转换成pb对象用于传入python-cv2
    PyObject * arg=PyTuple_New(1);//同上面讲
    PyTuple_SetItem(arg,0,pyarray);//同上
    PyObject * d2_result=PyObject_CallMethod(p_instance,"run","O",arg);//同上
    cv::Mat detimg=c.toMat(d2_result).clone();//将pb的n维数组转换成mat,防止数据出错,使用clone()深拷贝
    detimg.cv::Mat::convertTo(detimg,CV_8UC3);//转换图像格式
    cv::imshow("1", detimg);
    cv::waitKey(0);
    //end
    /*
    //PyObject * tuple= PyTuple_New(2);
    //PyTuple_SetItem(tuple,0, Py_BuildValue("i",a));
    //同上,Py_BuildValue函数用来构造pb对象,这里可以看做对int型变量a,构造成一个pb类型
    //PyTuple_SetItem(tuple,1, Py_BuildValue("i",b));
    //PyObject * result=PyObject_Call(p_func,tuple,NULL);
    //调用一个函数(类外的),函数名为p_func,参数为tuple
    //int resul;
    //PyArg_Parse(result,"i",&resul);
    //单个元素元组解析
    //std::cout<<resul<<std::endl;
     */
   //下面用于释放指针,不然容易造成内存泄漏
    Py_DecRef(d_result);
    
    Py_DecRef(pyarray);
    Py_DecRef(arg);
    Py_DecRef(p_instance);
    Py_DecRef(p_class);
    Py_DecRef(p_dict);
    Py_DecRef(p_module);
    Py_DecRef(p_name);
    Py_Finalize();//释放掉python解释器
    return 0;
}

3.CmakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(dt
)

IF(NOT CMAKE_BUILD_TYPE)
    SET(CMAKE_BUILD_TYPE Release)
ENDIF()

MESSAGE("Build type: " ${CMAKE_BUILD_TYPE})

set(OpenCV_DIR "/usr/local/opencv3.4/share/OpenCV")

set(Python_ADDITIONAL_VERSIONS "2.7")
#This is to avoid detecting python 3
find_package(PythonLibs 2.7 EXACT REQUIRED)
if (NOT PythonLibs_FOUND)
    message(FATAL_ERROR "PYTHON LIBS not found.")
else()
    message("PYTHON LIBS were found!")
    message("PYTHON LIBS DIRECTORY: " ${PYTHON_LIBRARY} ${PYTHON_INCLUDE_DIRS})
endif()

find_package(OpenCV 3.4 QUIET)

find_package(PythonLibs REQUIRED)
if (NOT PythonLibs_FOUND)
    message(FATAL_ERROR "PYTHON LIBS not found.")
else()
    message("PYTHON LIBS were found!")
    message("PYTHON LIBS DIRECTORY: " ${PYTHON_LIBRARY})
endif()



include_directories(
        ${PROJECT_SOURCE_DIR}
        ${PROJECT_SOURCE_DIR}/include
        ${PYTHON_INCLUDE_DIRS}
        /usr/include/python2.7/
        /usr/lib/python2.7/dist-packages/numpy/core/include/numpy/    
)


add_library(${PROJECT_NAME} SHARED
        src/importance.cc
        )

target_link_libraries(${PROJECT_NAME}
        ${OpenCV_LIBS}
        /usr/lib/x86_64-linux-gnu/libpython2.7.so
        )




add_executable(main        test.cpp)
target_link_libraries(main ${PROJECT_NAME})

4.看到一些比较有用的链接也参考了一些

C调用Python(传递数字、字符串、list数组(一维、二维),结构体)

linux C++调用python脚本:C++opencv数据与python opencv数据交互

Python + C/C++ 嵌入式编程(1):多维数组Numpy.Array()在Python和C/C++文件间的传递问题

Python/C API 参考手册

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

智能推荐

Linux进阶之shell编程--if判断和for循环(四)_小毛驴马乔丽的博客-程序员宝宝

目录1.for循环2.if判断1.for循环for i in [取值列表] 可以取:数字 字符串 命令结果`` 序列do 要执行什么命令done案列:测试1-255有多少个IP地址在线(能ping通则在线)10.0.0.1-255ping -c2 -w1 10.0.0.2 &gt;/dev/null 2&gt;&amp;1echo $?案例:批量创建10个用户1)前缀为自己输入的字符 输入用户处加判断是否为空2)创建用户个数 判断是否是整...

Toobar样式_taoble 样式_wu_liao_de_ren_sheng的博客-程序员宝宝

使用Toolbar,要把原本的 ActionBar 隐藏起来。<style name="AppTheme" parent="AppTheme.Base"/><style name="AppTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="windowActionBar">false</item>

EasyExcel校验数据抛异常需要使用ExcelAnalysisException_easyexcel onexception_Mr1ght的博客-程序员宝宝

使用Excel导入数据的时候,避免不了校验数据这个过程,在使用EasyExcel进行数据校验的时候,在AnalysisEventListener中抛异常要使用ExcelAnalysisException而不是自己定义的运行时异常,EasyExcel会捕捉所有的非ExcelAnalysisException异常并封装成ExcelAnalysisException抛出,如下。 private void onException(AnalysisContext analysisContext, Except

keras-bert学习_是晨星啊的博客-程序员宝宝

TOKEN_PAD = '' # Token for padding 填充标记TOKEN_UNK = '&amp;lt;UNK&amp;gt;' # Token for unknown words 未登录词标记TOKEN_CLS = '&amp;lt;CLS&amp;gt;' # Token f...

JSP图书销售管理系统_图书销售系统前后台_夜未央5788的博客-程序员宝宝

该系统分为前后台,普通用户与管理员两种角色,前台普通用户登录,后台管理员登录;用户角色包含以下功能:提交订单,查看图书列表,查看图书详情,查看订单,查看购物车,用户登录等功能。管理员角色包含以下功能:一级分类管理,分类管理,发货,图书信息管理,添加图书,订单管理等功能。1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。2.IDE环境:IDEA,Eclipse,Myeclipse都可以。推荐IDEA;3.tomcat环境:Tomcat 7.x,8.x,9

随便推点

owl 相关属性_owl有以下属性推理_chenpe32cp的博客-程序员宝宝

转载自本文,以供个人查阅,感谢作者,查看原文请点击OWL属性1.属性概述 RDF/OWL里都是用二元关系来描述东西的,比如描述:比尔盖茨是一个人,在RDF/OWL里就是这样描述的:比尔盖茨 ——是——&gt; 人。其中,比尔盖茨 和 人 之间的那个关系“——是——&gt;”就是RDF/OWL里的属性。 属性:就是一个二元关系。OWL里包括两种属性: 1. 类型属性(...

vue前端向后端传递参数_vue向后端传多个字符串参数_疯狂的小强呀的博客-程序员宝宝

get方法传参get方法传参,我们只需要把要传递的参数拼接到要发送的路径地址后面。实例前端:export default { data () { return { name: "david", //要传递的值1 age: 20, //要传递的值2 } }, methods: { //在method里面定义一个向后端传递参数的方法,我这里使用的是async await方法向后端传递参数(注:async await是配套使用的),'http://l

OllyDBG 入门系列(七)-汇编功能_子曰小玖的博客-程序员宝宝

今天我们的目标程序是 MyUninstaller 1.34 版。这是一个非常小的程序卸载工具,VC6编写,大小只有61K。我拿到的这个是上次闪电狼兄弟给我的,附带在里面的简体中文语言文件是由六芒星制作的。这个程序有个毛病:就是在列出的可卸载程序上双击查看属性时,弹出的属性窗口的字体非常难看,应该就是系统字体(SYSTEM_FONT):我们今天的目标就是利用 OllyDBG 的汇编功能把上面显示的字体改成我们常见的9号(小五)宋体。首先我们用 OllyDBG 载入程序,按 CTR+N 组合键查找一下有哪些

Kafka配置--易错整理_RunningYuan的博客-程序员宝宝

1 rebalance带来的问题1.1 主题分区和消费者群组KafkaConsumer从Kafka订阅Topic,并从订阅的Topic拉取消息。Kafka的消费者属于消费者群组,一个群组的消费者订阅的是同一个主题,每个消费者接收主题一部分分区的消息。每个分区只能被消费者群组的一个消费者接收消息,如果一个消费者群组的消费者数多于一个主题的分区数,则多余的消费者会空闲。如果主题T1有4个分区,那么消费者群组1有1个、2个、4个和5个消费者的话,与分区的连接情况分别如下:.

好的代理IP对爬虫有多重要?_「已注销」的博客-程序员宝宝

现如今,随着科技的发展,我们已经进入了人工智能和大数据的时代。人工智能和大数据采集涉及到一个东西,那就是数据。但是,面对如此庞大的数据库,人类一点都收集不到,那么爬虫就会被利用。爬虫并不是万能的,在抓取数据的过程中很可能是反爬虫的,于是IP代理诞生了。代理IP本质是隐藏自己的IP地址,用新的IP代替访问操作。我们在获取代理IP的时候,先用电脑连接到代理IP(新IP),然后通过代理服务器上线,网页的内容通过代理服务器送回你自己的电脑。这样可以保证数据信息的安全性。网上有很多专业的代理IP服

推荐文章

热门文章

相关标签