[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); 
  4. 上述调用中的"s"和"O"代表的是参数列表的类型, 我们可以在 Py_BuildValue 找到所有的类型, 本文最后也附了此表.

最后不要忘记销毁这些对象:  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 }

 类型参照:

s (string) [char *]
Convert a null-terminated C string to a Python object. If the C string pointer is NULLNone is used.
s# (string) [char *, int]
Convert a C string and its length to a Python object. If the C string pointer is NULL, the length is ignored and None is returned.
z (string or None) [char *]
Same as s.
z# (string or None) [char *, int]
Same as s#.
u (Unicode string) [Py_UNICODE *]
Convert a null-terminated buffer of Unicode (UCS-2 or UCS-4) data to a Python Unicode object. If the Unicode buffer pointer is NULLNoneis returned.
u# (Unicode string) [Py_UNICODE *, int]
Convert a Unicode (UCS-2 or UCS-4) data buffer and its length to a Python Unicode object. If the Unicode buffer pointer is NULL, the length is ignored and None is returned.
i (integer) [int]
Convert a plain C int to a Python integer object.
b (integer) [char]
Convert a plain C char to a Python integer object.
h (integer) [short int]
Convert a plain C short int to a Python integer object.
l (integer) [long int]
Convert a C long int to a Python integer object.
B (integer) [unsigned char]
Convert a C unsigned char to a Python integer object.
H (integer) [unsigned short int]
Convert a C unsigned short int to a Python integer object.
I (integer/long) [unsigned int]
Convert a C unsigned int to a Python integer object or a Python long integer object, if it is larger than sys.maxint.
k (integer/long) [unsigned long]
Convert a C unsigned long to a Python integer object or a Python long integer object, if it is larger than sys.maxint.
L (long) [PY_LONG_LONG]
Convert a C long long to a Python long integer object. Only available on platforms that support long long.
K (long) [unsigned PY_LONG_LONG]
Convert a C unsigned long long to a Python long integer object. Only available on platforms that support unsigned long long.
n (int) [Py_ssize_t]

Convert a C Py_ssize_t to a Python integer or long integer.

New in version 2.5.

c (string of length 1) [char]
Convert a C int representing a character to a Python string of length 1.
d (float) [double]
Convert a C double to a Python floating point number.
f (float) [float]
Same as d.
D (complex) [Py_complex *]
Convert a C Py_complex structure to a Python complex number.
O (object) [PyObject *]
Pass a Python object untouched (except for its reference count, which is incremented by one). If the object passed in is a NULL pointer, it is assumed that this was caused because the call producing the argument found an error and set an exception. Therefore, Py_BuildValue()will return NULL but won’t raise an exception. If no exception has been raised yet, SystemError is set.
S (object) [PyObject *]
Same as O.
N (object) [PyObject *]
Same as O, except it doesn’t increment the reference count on the object. Useful when the object is created by a call to an object constructor in the argument list.
O& (object) [converteranything]
Convert anything to a Python object through a converter function. The function is called with anything (which should be compatible withvoid *) as its argument and should return a “new” Python object, or NULL if an error occurred.
(items) (tuple) [matching-items]
Convert a sequence of C values to a Python tuple with the same number of items.
[items] (list) [matching-items]
Convert a sequence of C values to a Python list with the same number of items.
{items} (dictionary) [matching-items]
Convert a sequence of C values to a Python dictionary. Each pair of consecutive C values adds one item to the dictionary, serving as key and value, respectively.

If there is an error in the format string, the SystemError exception is set and NULL returned.

posted @ 2014-10-20 12:35  Lancelod_Liu  阅读(12616)  评论(1编辑  收藏  举报