前言:python的开发效率高,但是运行效率低是大家都知道,特别在对列表进行读写操作时,有时候就无法忍受。除了使用numpy进行操作外,还有一些方法可以提高运行效率。
写一个C文件
#include
#include
void helloWorld(){
printf("Hello world\n");
}
int plus(int x){
return x+1;
}
然后使用gcc编译成动态链接库
gcc hello.c -shared -fpic -o hello.so -lm
python代码如下
import ctypes
libc=ctypes.cdll.LoadLibrary(\"./CFile/hello.so\")
libc.helloWorld()
print(libc.plus(3))
这样,就能够简单地传个整数计算或者执行一些底层操作。
有一点注意的是,使用g++编译成动态链接库的时候,C++代码的方法名称和链接库里面的名称不尽相同,可以通过
nm hello.so
查看连接库对应方法的名称
但是这个方法有个bug,不能够传浮点数或者返回浮点数,也不能传列表等对象
还有一个方法。
使用ctypes混编是无法传一个opencv mat对象进去的,于是我看到一份代码
https://github.com/yushulx/opencv-python-webcam-barcode-reade
于是我就参考着,简化了一下代码,粗略估计,在手提上测试这一份暴力代码,速度提升了500倍,
首先构造一个python c库的基本结构要有
//method to be registered
static PyMethodDef Methods[] ={
{\"printBinImgBits\", printBinImgBits, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
//initilize function
PyMODINIT_FUNC
initPrintBinImgBits(void){
printf(\"PrintBinImgBits Init\\n\");
(void) Py_InitModule(\"PrintBinImgBits\", Methods);
}
python import这个库的时候会执行initPrintBinImgBits初始化。然后在初始化的时候应该注册可以被python调用的方法(我猜是这样的)。然后就写方法
#include
#include
#include
static PyObject * printBinImgBits(PyObject *self, PyObject *args) {
PyObject *o;
if (!PyArg_ParseTuple(args, \"O\", &o))
return NULL;
PyObject *ao = PyObject_GetAttrString(o, \"__array_struct__\");
PyArrayInterface *pai = (PyArrayInterface*)PyCObject_AsVoidPtr(ao);
char *buffer = (char*)pai->data; // The address of image data
int width = pai->shape[1]; // image width
int height = pai->shape[0]; // image height
int size = pai->strides[0] * pai->shape[0]; // image size = stride * height
int stride = pai->strides[0];
for(int j=0;j
然后还有写一个python setup文件,编译安装这个库
from distutils.core import setup, Extension
mModule = Extension(\'PrintBinImgBits\',
sources= [\'PrintBinImgBits.c\'],
include_dirs=[\"/usr/lib/python2.7/dist-packages/numpy/core/include/numpy\"],
library_dirs=[],
libraries=[])
setup (name = \'PrintBinImgBits\',
version=\'1.0\',
description=\'Python PrintBinImgBits extension\',
ext_modules= [mModule])
执行
sudo python setup.py build install
即可安装这个库到 /usr/local/lib/python2.7/dist-packages/ 下
然后调用就简单了
import PrintBinImgBits
import cv2
import numpy as np
img=cv2.imread(\"test.jpg\")
grayImg=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
binImg=cv2.inRange(grayImg,np.array([128]),np.array([255]))
PrintBinImgBits.printBinImgBits(binImg)
执行代码,就会输出图像的二值化像素点,(RGB彩图我没试过,应该大致一样)
如何从C代码里面返回一个列表或者其他对象
PyObject* retval = Py_BuildValue("i", 666)
返回列表为例,改成
PyObject *retval=PyList_New(count);
写入列表即
PyList_SetItem(retval, j, Py_BuildValue("i",x));
调用模块,即可返回一个列表
代码地址:
https://github.com/HeroChan0330/Python-hybrid-compile-with-c
这篇加上后面三篇博客都是从我的wordpress上面搬过来了(因为服务器到期了,卑微),可能会有点细节问题)