[Advanced Python] Call C++ libraries

导入 C++,若干话题:

Python调用 .so 

传参类型转化表 

图片的传入传出

python调用C++中的类

 

 

 

Call C++


调用动态库 .so

From: Python调用Linux下的动态库(.so)

(1) 生成.so:.c to .so

lolo@-id:workme$ gcc -Wall -g -fPIC -c linuxany.c -o linuxany.o
lolo@
-id:workme$ ls linux linuxany.c linuxany.o lolo@-id:workme$ gcc -shared linuxany.o -o linuxany.so
lolo@
-id:workme$ ls libmax.so linux linuxany.c linuxany.o linuxany.so

 

(2) 调用.so:Python call .so

#!/usr/bin/python
 
from ctypes import *
import os 
//参数为生成的.so文件所在的绝对路径 libtest = cdll.LoadLibrary(os.getcwd() + '/linuxany.so')
//直接用方法名进行调用   print libtest.display('Hello,I am linuxany.com') print libtest.add(2,2010)

 

(3) 可能遇到的问题:

version `GLIBC_2.27' not found

Download updated version from: https://mirror.freedif.org/GNU/libc/ 

 

 

传参转化表

Ref: python调用动态链接库的基本过程【链接写的不错】

  • 类型转化表 

python传参给C函数时,可能会因为python传入实参与C函数形参类型不一致会出现问题( 一般int, string不会有问题,float要注意 )

 

  • Python [list] --> C [array]

提前把array传入,然后在C函数中修改。

import ctypes
pyarray
= [1, 2, 3, 4, 5] carrary = (ctypes.c_int * len(pyarray)) (*pyarray) print so.sum_array(carray, len(pyarray))

返回值,其实一样道理,只是:返回时再把 c array 转换为 np.array

pyarray = [1,2,3,4,5,6,7,8]
carray = (ctypes.c_int*len(pyarray))(*pyarray)
so.modify_array(carray, len(pyarray))
print np.array(carray)  // <----

 

  • 形参方式

"传参" 前定义函数接口。

Ref: Python OpenCV pass mat ptr to c++ code

import ctypes
import numpy as np
from numpy.ctypeslib import ndpointer

pyarray
= np.array([1,2,3,4,5,6,7,8], dtype="int32")  # numpy中的数据类型指定很重要,即dtype的设定
so = ctypes.CDLL('./sum.so')

fun
= so.modify_array
/* 告知对方,将要传递怎么样的参数 */ fun.argtypes
= [ndpointer(ctypes.c_int), ctypes.c_int] fun.restype = None
fun(pyarray, len(pyarray))
print( np.array(pyarray) )

 

 

图片的传入传出

  • 内外的格式不同

Python numpy image 转换为 C pointer 的方法。

所以,一定要确保numpy image是numpy array数据类型

image = cv2.imread("xxx.jpg");

  

  • 强制转化保证格式安全

(1) Crop之后的格式data有点问题,例如:

image = whl_img[y1:y2, x1:x2]

crop之后的numpy image的type虽然也为numpy array,但实际传入的image data却不正确

 

(2) 统一解决方案:

image = numpy.array(image)

 

  • 一个具体的例子

可见,即使参数解决,返回值依然是个问题。返回值也通过 uint8_t* 处理,注意代表的内存段最好不会被自动回收,例如:static。

static thread_local Mat tag;
ImageWrapper ScanBuff(uint8_t* data, size_t Width, size_t Height) {   Mat OldFrame= Mat(Height, Width, CV_8UC3, data);
  ... ...
}

一些有参考价值的代码。

#!/usr/bin/python

#import os
import cv2
import numpy as np
import numpy.ctypeslib as npct
from   ctypes import *

import ctypes
import numpy as np
from numpy.ctypeslib import ndpointer


objectPath = './lolo.bmp'
img = cv2.imread(objectPath)
img_row = img_height = img.shape[0]
img_col = img_width  = img.shape[1]

print('img_row: %d, img_col: %d' % (img_row, img_col) )

##################################################################################

# https://stackoverflow.com/questions/37073399/python-opencv-pass-mat-ptr-to-c-code
# https://www.cnblogs.com/fariver/p/6573112.html

# (1) 定义这是一个怎样的指针 ucharPtr
= npct.ndpointer(dtype=np.uint8, ndim=1, flags='CONTIGUOUS')

# (2) 加载动态库和函数 CONST_LIB_PATH
= '../lib/linux/libtagdetect.so' so = cdll.LoadLibrary( CONST_LIB_PATH ) #fun = so.ScanBuffer fun = so['ScanBuffer']
# (3) 定义参数的类型 fun.argtypes = [ucharPtr, ctypes.c_int, ctypes.c_int] fun.restype = None # (4) 自定义一个符合条件的fake image in_image = np.zeros( (img_row, img_col), np.uint8, order='C' ).ravel() print(in_image.shape)

# (5) 执行动态库内的函数 fun(in_image, img_width, img_height)

 

 

调用C++中的类

因为python不能直接调用C++中的类,所以必须把C++中的类转换为C的接口

转换原则

      • 所有的C++关键字及其特有的使用方式均不能出现在.h文件里,.h中仅有C函数的包装函数声明
      • 在class.cpp中实现对类的成员函数接口转换的函数,包括对类内成员的读写函数get() and set()
      • 如果要在包装函数中要实例化对象,尽量用new constructor()的将对象的内存实例化在堆中,否则对象会被析构
      • 记得在所有包含函数声明的文件中加入以下关键字,声明该函数为C函数,否则该函数的符号不会记录在二进制文件中
#ifdef __cplusplus
extern "C" {
#endif
  xxxxxx function declaration xxxxx
#ifdef __cplusplus
}
#endif

 

 End.

posted @ 2018-06-19 18:07  郝壹贰叁  阅读(221)  评论(0编辑  收藏  举报