python腳本調用c/c++庫,以opencv的python接口爲例

第一部分轉自 http://blog.csdn.net/yjfkpyu/article/details/3941878
Python開發效率高,運行效率低。而c/c++恰恰相反。因此在python腳本中調用c/c++的庫,對python進行擴展,是很有必要的。使用python api,http://www.python.org/doc/,需要安裝python-dev。
test.c文件如下
#include <Python.h>//包含python的頭文件
// 1 c/cpp中的函數
int my_c_function(const char *arg)
{
  int n = system(arg);
  return n;
}
// 2 python 包裝
static PyObject * wrap_my_c_fun(PyObject *self, PyObject *args)
{
  const char * command;
  int n;
  if (!PyArg_ParseTuple(args, "s", &command))//這句是把python的變量args轉換成c的變量command
    return NULL;
  n = my_c_function(command);//調用c的函數
  return Py_BuildValue("i", n);//把c的返回值n轉換成python的對象
}
// 3 方法列表
static PyMethodDef MyCppMethods[] = {
  //MyCppFun1是python中註冊的函數名,wrap_my_c_fun是函數指針
  {"MyCppFun1", wrap_my_c_fun, METH_VARARGS, "Execute a shell command."},
  {NULL, NULL, 0, NULL} 
};
// 4 模塊初始化方法
PyMODINIT_FUNC initMyCppModule(void)
{
  //初始模塊,把MyCppMethods初始到MyCppModule中
  PyObject *m = Py_InitModule("MyCppModule", MyCppMethods);
  if (m == NULL) return;
}

test.py文件如下
import MyCppModule//導入python的模塊(也就是c的模塊,注意so文件名是MyCppModule)
r = MyCppModule.MyCppFun1("ls -l")//調用
print r
print "OK"

從這裏開始是我個人的分析

原來如此!
首先我們得現有一個c/c++函數,這個c函數被一個它的wrapper調用,wrapper又稱爲導出函數,這裏是wrap_my_c_fun。這一步實際上就是把python類型的輸入轉成c類型的輸入並傳入c函數,並把c函數中返回的c類型的輸出轉換成python類型的輸出返回。而再上一層,是一個方法列表,裏面保存的全部是函數指針,其中METH_VARARGS是參數傳遞的標準形式,它通過Python的元組在Python解釋器和C函數之間傳遞參數,我們把wrap_my_c_fun放在這個列表當中。最後,我們在初始化函數中初始化一個MyCppModule的模塊。這樣,import的時候我們就已經有了my_c_function的python模塊。MyCppModule了。


現在再看opencv是如何做的
首先,在/home/intel/Documents/Install-OpenCV-master/Ubuntu/2.4/OpenCV/opencv-2.4.9/modules/python/src2/cv2.cpp的最後有一個函數
void initcv2() 這個就相當於上面的initMyCppModule。裏面調用了PyObject* m = Py_InitModule(MODULESTR, methods); 相當於Py_InitModule("MyCppModule", MyCppMethods);其中MODULESTR=cv2,也就是我們將來要import的庫的名字。而methods則是函數列表的名字。
函數列表也在該文件中
static PyMethodDef methods[] = {
#include "pyopencv_generated_func_tab.h"
  {"createTrackbar", pycvCreateTrackbar, METH_VARARGS, "createTrackbar(trackbarName, windowName, value, count, onChange) -> None"},
  {"setMouseCallback", (PyCFunction)pycvSetMouseCallback, METH_KEYWORDS, "setMouseCallback(windowName, onMouse [, param]) -> None"},
  {NULL, NULL},
};	相當於static PyMethodDef MyCppMethods[]

再往裏就是pycvCreateTrackbar和pycvSetMouseCallback,這裏沒有繼續往裏找,原因是這裏並不是我們真正執行opencv的函數的時候走的路徑。
實際上我們的函數走的是PyObject* m = Py_InitModule(MODULESTR, methods);後面的一句話PyObject* cv_m = init_cv();
因爲opencv中有cv和cv2,這裏實際上是cv2的模塊初始化函數調用了cv的模塊初始化函數,主要內容都在這兒呢。


init_cv的定義在/home/intel/Documents/Install-OpenCV-master/Ubuntu/2.4/OpenCV/opencv-2.4.9/modules/python/src2/cv2.cv.hpp下
init_cv函數中有這樣一句話,這句話是cv2.cv這個module的初始化 m = Py_InitModule(OLD_MODULESTR, old_methods);


我們看函數列表old_methods
static PyMethodDef old_methods[] = {
#if PYTHON_USE_NUMPY
    {"fromarray", (PyCFunction)pycvfromarray, METH_KEYWORDS, "fromarray(array [, allowND]) -> CvMat"},
#endif
  {"FindDataMatrix", pyfinddatamatrix, METH_VARARGS},
  {"temp_test", temp_test, METH_VARARGS},
#include "generated1.i"
  {NULL, NULL},
};
目前我就追蹤到這裏,貌似opencv的python接口也不像這裏。但是也沒有想到會在哪裏,如果哪位大神知道麻煩告訴我,我將來知道了也會在這裏更新。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章