Python與C/C++呼叫之ctypes
標籤(空格分隔): C/C++ python python呼叫C 人工智慧 AI
-
python訪問C/C++
- python的底層大部分都是C/C++實現,python和C和C++具有天然的互相呼叫優勢;
- 很多核心的演算法庫都是C/C++寫的,在python開發過程中,經常訪問別人的動態庫;
- 知名人工智慧(深度學習)框架訓練系統都是python寫的,而執行時一般都是以動態庫的形式提供;
-
python訪問C/C++的方式
- ctypes;
- pybind11;
- cffi
- swig
-
ctypes的優勢
- 不要修改動態庫的原始碼;
- 只需要動態庫和標頭檔案;
- 使用比較簡單,而且目前大部分庫都是相容C/C++;
本文以一個典型的深度學習(人工智慧AI)的影象檢測的python自動化測試,介紹ctypes的使用;
-
ctypes的使用
結構體標頭檔案:
//
// Created by yinlib on 18-12-4.
//
#ifndef CVIMAGETEST_CV_COMMON_H
#define CVIMAGETEST_CV_COMMON_H
#ifdef __MSC_VER
# define CV_IMAGE_API_ __declspec(dllexport)
#else
# define CV_IMAGE_API_ __attribute__((visibility("default")))
#endif
#ifdef __cplusplus
# define CV_IMAGE_API extern "C" CV_IMAGE_API_
#else
# define CV_IMAGE_API CV_IMAGE_API_
#endif
#define RC_OK 0
#define RC_E_HANDLE -1
#define RC_E_INVALIDARG -2
#define RC_E_OUTOFMEMORY -3
#define RC_E_INVALID_FORMAT -4
#define RC_E_FAIL -5
typedef void *mt_handle_t;
typedef int mt_result_t;
typedef struct rect_t{
int left;
int top;
int right;
int bottom;
} rect_t;
typedef struct point3f_t{
float x;
float y;
float z;
}point_t;
typedef struct extra_info_t{
float mvp_mat[3][3];
point_t *points_ori;
int point_count;
}extra_info_t;
typedef struct detection_result_t{
rect_t rect;
float score;
int label;
int orientation;
extra_info_t extra_info;
} detection_result_t;
#endif //CVIMAGETEST_CV_COMMON_H
介面標頭檔案:
#pragma once
#include "mt_image_common.h"
CV_IMAGE_API
mt_result_t
mt_image_detect_init_config(const char* congif);
CV_IMAGE_API
mt_result_t
mt_image_detect_create(const char* model_path, mt_handle_t* handle);
CV_IMAGE_API
void
mt_image_detect_destroy(mt_handle_t handle);
CV_IMAGE_API
void
mt_image_release_detect_result(detection_result_t* detection_result, int count);
CV_IMAGE_API
mt_result_t
mt_image_detect_compact(mt_handle_t handle, const unsigned char* img, int format, int image_width,
int image_height, int image_stride, detection_result_t** detect_info, int* count);
CV_IMAGE_API
mt_result_t
mt_image_detect_reset(mt_handle_t handle);
結構體的對映:
from ctypes import *
import os
import shutil
class rect_t(Structure):
pass
rect_t._fields_ = [
('left', c_int),
('top', c_int),
('right', c_int),
('bottom', c_int),
]
class point3f_t(Structure):
pass
point3f_t._fields_ = [
('x', c_float),
('y', c_float),
('z', c_float),
]
class extra_info(Structure):
pass
extra_info._fields_ = [
('mvp_mat', c_float*3*3),
('point_t', POINTER(point3f_t)),
('point_count', c_int),
]
class detection_result(Structure):
pass
detection_result._fields_ = [
('rect', rect_t),
('score', c_float),
('label', c_int),
('orientation', c_int),
('extra_info', extra_info),
]
def movefile(srcpath, dstpath):
if not os.path.isfile(srcpath):
print(srcpath + ' is not exist!')
else:
fpath, fname = os.path.split(dstpath)
if not os.path.exists(fpath):
os.makedirs(fpath)
shutil.copy(srcpath, dstpath)
print('copy ' + srcpath + '->' + dstpath)
介面對映:
import ctypes
import os
class MtLibrary:
def __init__(self, path):
self.path = path
self.lib = None
self.hasInit = False
def load_library(self):
dl = ctypes.cdll.LoadLibrary
print('load_library lib is Exist : ' + str(os.path.exists(self.path)))
print(os.getcwd())
lib = dl(self.path)
self.lib = lib
self.hasInit = True
def init_license(self, licence):
if not self.hasInit:
print('lib has not init!!')
return False
licence_context = bytes(licence, "utf8")
return self.lib.mt_image_detect_init_config(licence_context)
def create_handle(self, path, handle):
if not self.hasInit:
print('lib has not init!!')
return None
return self.lib.mt_image_detect_create(path, handle)
def reset_handle(self, handle):
return self.lib.mt_image_detect_reset(handle)
def detect_image(self, handle, image, format, width, height, stride, detect_info, count):
if not self.hasInit:
print('lib has not init!!')
return None
return self.lib.mt_image_detect_compact(handle, image, format, width, height, stride, detect_info, count)
def release_result(self, detect_result, count):
if not self.hasInit:
print("lib has not init!!")
return None
return self.lib.mt_image_release_detect_result(detect_result, count)
def destroy_handle(self, handle):
if not self.hasInit:
print("lib has not init!!")
return None
return self.lib.mt_image_detect_destroy(handle)
重點問題:
- 結構體和複雜結構提的對映
C中的結構體
typedef struct extra_info_t{
float mvp_mat[3][3];
point_t *points_ori;
int point_count;
}extra_info_t;
typedef struct detection_result_t{
rect_t rect;
float score;
int label;
int orientation;
extra_info_t extra_info;
} detection_result_t;
Python中的類
class extra_info(Structure):
pass
extra_info._fields_ = [
('mvp_mat', c_float*3*3),
('point_t', POINTER(point3f_t)),
('point_count', c_int),
]
class detection_result(Structure):
pass
detection_result._fields_ = [
('rect', rect_t),
('score', c_float),
('label', c_int),
('orientation', c_int),
('extra_info', extra_info),
]
多維陣列
float mvp_mat[3][3] --> c_float33
陣列指標
point_t *points_ori --> POINTER(point3f_t)
- 呼叫時指標(二級指標)的對映
CV_IMAGE_API
mt_result_t
mt_image_detect_compact(mt_handle_t handle, const unsigned char* img, int format, int image_width,
int image_height, int image_stride, detection_result_t** detect_info, int* count);
python呼叫:
TARGETPOINTER_t = POINTER(detection_result)
result_handle = TARGETPOINTER_t()
print('result_handle: ' + str(result_handle))
count = c_int(0)
status = mt_image_detect.detect_image(handle, byref(image_data), 0, width, height, width * 3, byref(result_handle), pointer(count))
print('detect_image status: ' + str(status) + " count : " + str(count.value))
detect_content = result_handle.contents
針對於二級指標,必須POINTER(detection_result)生成T*,然後建立result_handle = TARGETPOINTER_t(),然後通過byref(result_handle)得到二級指標
- byref(n)返回的相當於C的指標右值&n,本身沒有被分配空間;
- pointer返回的相當於指標左值T* p=&n,可以改變,可以取地址; POINTER得到是類;
呼叫結果
/home/sensetime/miniconda3/envs/pythonPIL/bin/python /home/sensetime/jayzwang/workspace/clion_workspace/PyImageTest/image_test.py
copy ../CvImageTest/build/libmtimage.so->./extents/libs/libmtimage.so
copy ../CvImageTest/mt_image_common.h->./extents/include/mt_image_common.h
copy ../CvImageTest/mt_image_detect.h->./extents/include/mt_image_detect.h
test license
load_library lib is Exist : True
/home/sensetime/jayzwang/workspace/clion_workspace/PyImageTest
mt_image_detect_init_config.14: in
init_license : 0
mt_image_detect_create.24: in
create_handle : 0 handle : c_long(94128605088976)
pil image : 768 height : 576
width : 768 height : 576 format : None
image pointer : <cparam 'P' (0x559c061f1960)> image_date [-1] : 255
result_handle: <__main__.LP_detection_result object at 0x7fd92de1d1e0>
mt_image_detect_compact.62: in
mt_image_detect_compact.75: mt_image_detect_compact : 0x559c060ce080
detect_image status: 0 count : 1
detect result left : 20
detect result label: 1
detect result points: 1
mt_image_detect_reset.82: in
reset_handle status: 0
mt_image_release_detect_result.46: in
mt_image_detect_destroy.34: in
destroy_handle status: 0 handle : c_long(94128605088976)
其他:
- 檔案移動
def movefile(srcpath, dstpath):
if not os.path.isfile(srcpath):
print(srcpath + ' is not exist!')
else:
fpath, fname = os.path.split(dstpath)
if not os.path.exists(fpath):
os.makedirs(fpath)
shutil.copy(srcpath, dstpath)
print('copy ' + srcpath + '->' + dstpath)
- 圖片讀取和轉碼,使用pil讀取,並轉換成BGR(AI/深度學習的大部分輸入都是BGR)
hand_image = Image.open('./extents/test_image/timg.jpeg')
hand_image = hand_image.convert('RGB')
width, height = hand_image.size
image_format = hand_image.format
image_data = (c_ubyte * (width * height * 3))()
print('pil image : ' + str(width) + " height : " + str(height))
# hand_image.show()
for x in range(height):
for y in range(width):
r, g, b = hand_image.getpixel((y, x))
#bgr = b, g, r
image_data[(x * width + y)*3] = b
image_data[(x * width + y)*3 + 1] = g
image_data[(x * width + y)*3 + 2] = r
- 寫檔案
out_file = open('image_in', 'wb')
out_file.write(image_data)
out_file.close()
結語:
ctypes是非常輕量級的python呼叫C/C++的框架,非常適用於第三庫的測試,執行.能夠快速實現自動化測試,壓力測試等,十分實用;
相關文章
- Python呼叫C/C++方式PythonC++
- c與c++的相互呼叫C++
- java呼叫c++動態庫之jni呼叫JavaC++
- Python呼叫C++編寫的方法PythonC++
- Windows上Python使用swig呼叫C++WindowsPythonC++
- linux下qt用c++呼叫pythonLinuxQTC++Python
- python和c++的相互呼叫教程PythonC++
- C++呼叫C介面C++
- C++呼叫LuaC++
- python使用ctypes呼叫擴充套件模組的例項方法Python套件
- SWIG 打包C++陣列供python呼叫 tcyC++陣列Python
- 技術積累——C++ 呼叫 python 專案C++Python
- Linux C/C++呼叫mongDBLinuxC++
- Python與C++引用分析PythonC++
- C#呼叫 C++的DLLC#C++
- linux下使用boost.python呼叫c++動態庫LinuxPythonC++
- Qt中用C++呼叫Python檔案的三種方法QTC++Python
- C++呼叫 c#生成的dllC++C#
- 組合語言-019(彙編程式與c\c++相互呼叫)組合語言C++
- C++庫封裝JNI介面——實現java呼叫c++C++封裝Java
- java動態呼叫c++庫JavaC++
- flutter中呼叫C++的庫FlutterC++
- C 與 C++C++
- 使用ctypes來擴充套件Python套件Python
- C#呼叫PythonC#Python
- 【C++】C++之Lambda表示式C++
- C#呼叫C++動態連結庫C#C++
- C++呼叫C#的動態庫dllC++C#
- ctypes與numpy.ctypeslib的使用
- 【C++】C++之型別轉換C++型別
- 交叉編譯c++給android呼叫編譯C++Android
- C++中函式呼叫的用法C++函式
- C++如何解析函式呼叫C++函式
- Android JNI實現Java與C/C++互相呼叫,以及so庫的生成和呼叫(JNI方式呼叫美圖秀秀so)AndroidJavaC++
- C++之templateC++
- Luogu1196 銀河英雄傳說 + Python函式的定義與呼叫(C++/Python 雙語言實現)Python函式C++
- 【大型軟體開發】開發日誌(五).net框架與C++的融合:CLR——C++呼叫C#的DLL框架C++C#
- 效能分析之CPU分析-從CPU呼叫高到具體程式碼行(C/C++)C++