[Advanced Python] 12 - Transfer parameters

動態庫調用


1、Python調用 .so 

From: Python調用Linux下的動態庫(.so)html

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

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 .solinux

#!/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) 可能遇到的問題:c++

version `GLIBC_2.27' not found數組

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

 

 

2、傳參策略

Ref: python調用動態連接庫的基本過程【連接寫的不錯】app

  • 類型轉化表 

python傳參給C函數時,可能會由於python傳入實參與C函數形參類型不一致會出現問題( 通常int, string不會有問題,float要注意 )函數

 

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

提早把array傳入,而後在C函數中修改。ui

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.arrayspa

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) )

 

 

3、圖片的傳入傳出

  • 內外的格式不一樣

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)

 

  • 一個具體的例子

可見,即便參數解決,返回值依然是個問題。

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)

 

 

4、python調用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.

相關文章
相關標籤/搜索