[C++/Python] 如何在C++中使用一个Python类? (Use Python-defined class in C++)

最近在做基于OpenCV的车牌识别, 其中需要用到深度学习的一些代码(Python), 所以一开始的时候开发语言选择了Python(祸患之源).

固然现在Python的速度不算太慢, 但你一定要用Python来操作图像, 实现某些算法的时候, 效率就变得非常重要. 可惜的是, Python在大多数算法实现中, 由于其循环操作实在是太慢, 导致实现的算法效率非常之低.

所以现在我要把深度学习中的一个类(分类器)转换到C++中, 在这个过程之前, 需要做一些test projects, 我主要参照的文章是: C++调用Python(3).

开发环境为 VS2012, WIN7 64.

所有代码都在最后放出, 这里先逐步讲解.

首先我们需要导入合适的头文件: Python.h, 它位于你的Python安装目录的include目录下. (2.6, 2.7版本实测通过)

使用VS的话, 可以按如下方法设置一下项目属性:

  1. 调试 -> xxx属性(最后一栏) -> VC++目录 -> 右侧库目录
  2. 增加C:\Python27\libs, 具体路径个人可能不同.

这样就完成了最基本的配置, 下面我们开始导入.py文件并使用它.

我们使用的.py文件非常简单, 代码如下:

 1 #!/usr/bin/python
 2 # Filename: testpy.py
 3 class Person:
 4     def sayHi(self):
 5         print ‘hi‘
 6 class Second:
 7     def invoke(self,obj):
 8          obj.sayHi()
 9 def sayhi(name):
10     print ‘hi‘,name;

注: 下述所有导入方法在导入失败时不会报错, 只会返回空指针.

第一步是导入.py文件:

  1. 使用PyObject* pModule来存储导入的.py文件模块, 调用的方法是PyImport_ImportModule(path):  PyObject* pModule = PyImport_ImportModule("testpy");
  2. 使用PyObject* pDict来存储导入模块中的方法字典, 调用的方法是PyModule_GetDict(module):  PyObject* pDict = PyModule_GetDict(pModule);

这样就完成了.py文件的导入.

第二步是导入已导入模块中的方法或类:

  1. 获取方法, 调用的方法是PyDict_GetItemString(dict, methodName): PyObject* pFunHi = PyDict_GetItemString(pDict, "sayhi");
  2. 获取类, 调用的方法同上, 注意红体部分的字符串对应于.py文件中的类/方法名:  PyObject* pClassSecond = PyDict_GetItemString(pDict, "Second");

第三步是使用导入的方法或类:

  1. 使用方法, 调用PyObject_CallFunction(pFunc, "s", args)即可:  PyObject_CallFunction(pFunHi, "s", "lhb");
  2. 使用类构造对象, 调用PyInstance_New(pClass, NULL, NULL)即可:  PyObject* pInstanceSecond = PyInstance_New(pClassSecond, NULL, NULL); , 注意其中的pClassSecond为第二步.2中获取的类指针
  3. 使用类对象的方法, 调用PyObject_CallMethod(pInstance, methodname, "O", args)即可:  PyObject_CallMethod(pInstanceSecond, "invoke", "O", pInstancePerson);

最后不要忘记销毁这些对象:  Py_DECREF(pointer);

下面是C++的实现代码, 代码来自于我参考的博客, 略有修改.

 1 /*
 2  * test.cpp
 3  *  Created on: 2010-8-12
 4  *      Author: lihaibo
 5  */
 6 #include <C:/Python27/include/Python.h>
 7 #include <iostream>
 8 #include <string>
 9
10 int main(void) {
11     Py_Initialize(); // 启动虚拟机
12     if (!Py_IsInitialized())
13         return -1;
14     // 导入模块
15     PyObject* pModule = PyImport_ImportModule("testpy");
16     if (!pModule) {
17         printf("Cant open python file!/n");
18         return -1;
19     }
20     // 模块的字典列表
21     PyObject* pDict = PyModule_GetDict(pModule);
22     if (!pDict) {
23         printf("Cant find dictionary./n");
24         return -1;
25     }
26     // 演示函数调用
27     PyObject* pFunHi = PyDict_GetItemString(pDict, "sayhi");
28     PyObject_CallFunction(pFunHi, "s", "lhb");
29     Py_DECREF(pFunHi);
30     // 演示构造一个Python对象,并调用Class的方法
31     // 获取Second类
32     PyObject* pClassSecond = PyDict_GetItemString(pDict, "Second");
33     if (!pClassSecond) {
34         printf("Cant find second class./n");
35         return -1;
36     }
37     //获取Person类
38     PyObject* pClassPerson = PyDict_GetItemString(pDict, "Person");
39     if (!pClassPerson) {
40         printf("Cant find person class./n");
41         return -1;
42     }
43     //构造Second的实例
44     PyObject* pInstanceSecond = PyInstance_New(pClassSecond, NULL, NULL);
45     if (!pInstanceSecond) {
46         printf("Cant create second instance./n");
47         return -1;
48     }
49     //构造Person的实例
50     PyObject* pInstancePerson = PyInstance_New(pClassPerson, NULL, NULL);
51     if (!pInstancePerson) {
52         printf("Cant find person instance./n");
53         return -1;
54     }
55     //把person实例传入second的invoke方法
56     PyObject_CallMethod(pInstanceSecond, "invoke", "O", pInstancePerson);
57     //释放
58     Py_DECREF(pInstanceSecond);
59     Py_DECREF(pInstancePerson);
60     Py_DECREF(pClassSecond);
61     Py_DECREF(pClassPerson);
62     Py_DECREF(pModule);
63     Py_Finalize(); // 关闭虚拟机
64     return 0;
65 }
时间: 2024-08-02 00:01:05

[C++/Python] 如何在C++中使用一个Python类? (Use Python-defined class in C++)的相关文章

如何在html中把一个图片或者表格覆盖在一张已有图片上的任意位置

如何在html中把一个图片或者表格覆盖在一张已有图片上的任意位置 <div style="position:relative;"> <img src="" width="500" height="500" /> <div style="position:absolute; left:80px; top:50px; border:#000 solid 1px;"><i

如何在JAVA中实现一个固定最大size的hashMap

如何在JAVA中实现一个固定最大size的hashMap 利用LinkedHashMap的removeEldestEntry方法,重载此方法使得这个map可以增长到最大size,之后每插入一条新的记录就会删除一条最老的记录. import java.util.LinkedHashMap; import java.util.Map; public class MaxSizeHashMap<K, V> extends LinkedHashMap<K, V> { private fina

CAD技巧-如何在CAD中绘制一个圆环?

CAD技巧,如何在CAD中绘制一个圆环?在日常的工作中,在编辑CAD图纸的时候,我们需要借助CAD编辑器中的许多图形来编辑一张完整的CAD图纸文件,以此来设计出我们满意的图纸,我们会使用到许多的图形比如说多边形.直线.正方,长方形等一些图形,但是我们如何在CAD中绘制一个圆环了?具体要怎么来操作?下面我们就来一起看看吧! 步骤一:首先还是需要打开电脑,然后在电脑桌面上任意的打开一个浏览器,在浏览器的搜索框中搜索迅捷CAD编辑器,鼠标点击进入官网,点击下载安装最新版本的CAD编辑器,下载完成之后,

CAD技巧,如何在CAD中添加一个多行文本?

CAD技巧,如何在CAD中添加一个多行文本?在编辑CAD图纸的过程能够为了更加方便快捷建筑设计师们都会借助CAD编辑器来绘制图形,但是一张CAD图纸中的内容太多,在有的地方需要给CAD图纸进行一些标注,以便更好的查看,但是如何在CAD中添加一个多行文本?小伙伴们知道要怎么来操作吗?下面小编就利用迅捷CAD编辑器标准版来教教大家如何在CAD中添加一个多行文本?想要了解的朋友就一起来看看吧! 使用第一步:在电脑桌面中没有下载安装迅捷CAD编辑器的小伙伴们,在电脑中任意的打开一个浏览器,在浏览器的搜索

在存放源程序的文件夹中建立一个子文件夹 myPackage。例如,在“D:\java”文件夹之中创建一个与包同名的子文件夹 myPackage(D:\java\myPackage)。在 myPackage 包中创建一个YMD类,该类具有计算今年的年份、可以输出一个带有年月日的字符串的功能。设计程序SY31.java,给定某人姓名和出生日期,计算该人年龄,并输出该人姓名、年龄、出生日期。程序使用YM

题目补充: 在存放源程序的文件夹中建立一个子文件夹 myPackage.例如,在"D:\java"文件夹之中创建一个与包同名的子文件夹 myPackage(D:\java\myPackage).在 myPackage 包中创建一个YMD类,该类具有计算今年的年份.可以输出一个带有年月日的字符串的功能.设计程序SY31.java,给定某人姓名和出生日期,计算该人年龄,并输出该人姓名.年龄.出生日期.程序使用YMD的方法来计算年龄. 主要考包的运用 用到java.util.Calendar

如何在linux中执行一个脚本

---恢复内容开始--- 如何在LINUX中在系统启动时自动执行一个执行脚本 如果是开机马上执行的脚本,可以将脚本写到rc.local中: 如果是用户登录后自动执行脚本,可以将脚本写到相应的用户目录下"-/.bash_profile",若脚本"-/.bash_profile"不存在,可以直接拷贝"/etc/profile"命名为"-/.bash_profile": 如果是要任一用户登录后自动执行脚本,可以将脚本写到"

如何在solr中添加一个core

在上一篇博文中已经介绍了如何在tomcat中部署solr,部署完之后solr默认是有一个core的,也就是collection1,如下图: 如果想自定义一个core,该如何做呢? 本文将承接上一篇博文(http://simplelife.blog.51cto.com/9954761/1864071)继续展开! 1.在solrhome文件夹下复制一份collection1,并改名为simple,与collection1放在同一个文件夹中 2.进入simple文件夹中修改core.propertie

python:一秒中启动一个下载服务器

一.背景 在实际工作中,时不时会有这样的一个需求:将文件传给其他同事.将文件传给同事本身并不是一个很繁琐的工作,现在的聊天工具一般都支持文件传输.但是,如果需要传送的文件较多,那么,操作起来就会比较麻烦.此外,如果文件在远程的服务器上,你要将文件传给同事,则需要先将远程服务器的文件下载到本地,然后再通过聊天工具传给同事.再或者,你并不是特别清楚要传哪几个文件给同事,所以,你们需要进行来回的交流.交流的时间成本是比较高的,会降低办事效率.此时,你们需要更加高效的方法. 二.实现 这个时候,如果你知

多文档中建立一个对话框类,通过这个方法来在其他类中得到对话框对象指针,访问对话框成员

{ // 添加内容 m_pDrawTool = new CDrawToolDlg; m_pDrawTool->Create(IDD_DRAWTOOLS, this); m_pDrawTool->ShowWindow(SW_SHOW); // 让窗口出现在屏幕右下方 CRect dlgRect; CRect mainRect; m_pDrawTool->GetClientRect(&dlgRect); GetWindowRect(mainRect); // 计算显示的坐标 int