ctypes python_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 : 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++的框架,非常适用于第三库的测试,运行.能够快速实现自动化测试,压力测试等,十分实用;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值