高效地将字符串(或元组)转换为ctypes数组

5
我有一段代码,它将PIL图像转换为ctypes数组,以便传递给C函数:
w_px, h_px = img.size
pixels = struct.unpack('%dI'%(w_px*h_px), img.convert('RGBA').tostring())
pixels_array = (ctypes.c_int * len(pixels))(*pixels)

但我正在处理大型图片,将这么多项解包为函数参数似乎明显很慢。我能做的最简单的事情是什么,以获得合理的加速?

我只是将其转换为元组作为中间步骤,因此如果不必要,那就更好了。


还有(ctypes.c_int * n).from_buffer,你可以用它来处理字符串。我仍在尝试找到如何在不立即将PIL Image转换为字符串的情况下使用它。 - Kos
1个回答

7
您可以首先构建一个未初始化的数组:
pixarray = (ctypes.c_int * (w_px * h_px))()

然后将图片的内容复制到其中:

# dylib in MacOSX, cdll.wincrt in Win, libc.so.? in Unix, ...
clib = ctypes.CDLL('libc.dylib')

_ = clib.memcpy(pixarray, im.tostring(), w_px * h_px * 4)

memcpy的返回值是一个你不关心的地址,所以我通过将其赋值给名称“单下划线”(按照惯例表示“我不关心这个”;-)来“吞掉”它。

编辑: 正如@Mu Mind在评论中指出的那样,后面的片段可以简化为使用ctypes.memmove,而无需去平台相关地查找clib:只需执行以下操作即可

_ = ctypes.memmove(pixarray, im.tostring(), w_px * h_px * 4)

3
看起来 ctypes.memmove 可以以跨平台的方式完成相同的操作:ctypes.memmove(pixarray, im.tostring(), w_pxh_px4) - Mu Mind
@Mu,非常棒,加一并感谢!让我相应地编辑答案。 - Alex Martelli
哎呀,看起来输出存在字节序问题。有什么建议吗? - Mu Mind
很不幸,我认为 ctypes 没有交换字节的方式 -- array 模块可以这样做,你可以使用它来代替,使用数组的隐式缓冲区接口或 array.buffer_info(尽管后者仅用于向后兼容)。 - Alex Martelli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接