python调用c/c++动态链接库时需注意的问题

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

前言

目前由于工作原因需在windows环境下利用python调用c语言写的动态链接库。 c/c++代码由于其灵活性,在底层算法中得到广泛使用。许多函数都采用 c/c++语言进行编写,要在其它语言中进行调用需要进行转换。由于此次的函数调用涉及到指针的传入传出,涉及到许多知识点,费了较大工夫才顺利完成,特记录下来留作纪念,以便以后查阅。


一、 ctypes库

ctypes是python的一个外部函数库,提供了c的兼容数据类型,允许调用dll或者共享库的函数。通过ctypes库能以接近c语言的方式在python中完成动态链接库中的调用。

需要注意的是: ctypes只提供了 c的兼容,若要使用c++代码,则需要以c的方式进行编译,即在c++函数声明时加上前缀 "extern C"。

ctypes提供了 c的兼容数据类型,下表列举了两者之间基本数据类型的对应关系。

ctypes数据类型c数据类型
c_charchar
c_bytechar
c_ubyteunsigned char
c_shortshort
c_intint
c_uintunsigned int
c_longlong
c_ulongunsigned long
c_longlonglong long
c_ulonglongunsigend long long
c_floatfloat
c_doubledouble
c_char_pchar*
c_wchar_pwchar_t*
c_void_pvoid*

二、使用步骤

1. c接口函数介绍

动态链接库中的 c函数主要是用于图像处理,接收char*类型字符数组、 float参数、int*指针等参数类型,同时返回int*数组,其函数原型为:

 int* code_generate_based_array(const char* msg, int ecLevel, int picWidth, unsigned char* imgData, float coderatio, int* dstWidth)

 接口说明:

——入参int* dstWidth会在函数内部进行改变,得到最终图像的宽度

——返回值int*是个整型数组,存储处理完的图像颜色信息,图像的宽度为dstWidth的值,每个int值对应像素的rgb值,即一个int值为r,g,b三通道的结合值

 rgb=(int)(((int)r << 16) | (unsigned short)(((unsigned short)g << 8) | b));

2.引入库

在代码中需要处理图像,所以引入了PIL库进行图像处理,同时引入ctypes库进行动态链接库的函数转化及调用,代码如下:

from ctypes import *from PIL import Image

3.进行接口转换

利用ctypes库将c接口函数表示成python代码。

首先利用CDLL加载动态库:

dll=CDLL("动态链接库路径")

 利用ctypes库进行c语言函数的转换:

dll.code_generate_based_array.argtypes=[c_char_p,c_int,c_int,POINTER(c_ubyte),c_float,POINTER(c_int)]
dll.code_generate_based_array.restype=POINTER(c_int)

 其中,argtypes定义入参类型, restype定义返回类型。c语言中的指针可通过POINTER进行定义,转换关系为:

—— const char*转化为c_char_p

——int转化为c_int

——unsigned char*转化为POINTER(c_ubyte)

——float转化为c_float

—— int*转化为POINTER(c_int)

将原始图像读取转化为POINTER(c_ubyte)时需先定义一个数组,其代码如下:

def get_img_byte_array(img,width,height):
    img=img.convert('RGB')
    src_strlist=img.load()
    
    len=width*height*3

    result=(c_ubyte*len)()

    for i in range(0,height):
        for j in range(0,width):
            data=src_strlist[j,i]
            result[(i*width+j)*3]=data[0]
            result[(i*width+j)*3+1]=data[1]
            result[(i*width+j)*3+2]=data[2]
    return result

 这里有一个坑,就是定义数组时的方式,采用以下代码定义的是一维数组

    len=width*height*3

    result=(c_ubyte*len)()

此时数组长度为width*height*3,此时可采用下标result[i]的方式对数据进行操作;而采用以下代码则定义的是三维数组

result=(c_ubyte*width*height*3)()

需采用result[][][]的方式进行数据操作。 

 下面将给出接口实际调用的完整代码

from ctypes import *

from PIL import Image


def get_rgb(rgb):
    r=(rgb&0xFF0000)>>16;
    g=(rgb&0xFF00)>>8;
    b=0xFF&rgb;
    return (r,g,b)

def get_rgb_matrix(img,width):
    return [get_rgb(img[i*width+j]) for i in range(width) for j in range(width)]

'''
get byte array from PIL image
'''
def get_img_byte_array(img,width,height):
    img=img.convert('RGB')
    src_strlist=img.load()
    
    len=width*height*3

    result=(c_ubyte*len)()

    for i in range(0,height):
        for j in range(0,width):
            data=src_strlist[j,i]
            result[(i*width+j)*3]=data[0]
            result[(i*width+j)*3+1]=data[1]
            result[(i*width+j)*3+2]=data[2]
    return result


dll=CDLL("动态链接库路径")

img=Image.open(r'G:\pic\other\peo.jpeg')
width=img.size[0]
height=img.size[1]

dll.code_generate_based_array.argtypes=[c_char_p,c_int,c_int,POINTER(c_ubyte),c_float,POINTER(c_int)]
dll.code_generate_based_array.restype=POINTER(c_int)

dstWidth=c_int(0)  

result=dll.code_generate_based_array(b'https://www.vrcode.com',3,800,get_img_byte_array(img,width,height),0.5,dstWidth)

img_out=Image.new('RGB',(dstWidth.value,dstWidth.value))
    rgbArray=get_rgb_matrix(result, dstWidth.value)
    img_out.putdata(rgbArray)
    img_out.save('test_out_2.png')


经过测试,上述代码能够完成图像的转换并保存在指定路径,顺利完成接口的调用。 


总结

以上就是今天要总结的内容,本文介绍了python调用c语言动态链接库的过程,这个过程中涉及到类型的转换、图像的处理、指针的处理,并且过程中有几个坑,通过探索顺利把坑填平,实现了指定功能,在此分享给需要的朋友。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尘雨若烟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值