gpt4 book ai didi

python - 使用 ctypes 数组时 PIL 的 Image.frombuffer 预期数据长度

转载 作者:太空狗 更新时间:2023-10-30 02:34:38 24 4
gpt4 key购买 nike

我正在使用 Python、PIL 和 ctypes 进行图像处理。当我一起破解东西时,我使用 PIL 的 fromstring 函数将像素缓冲区从 ctypes 获取到 PIL 对象中。我只是遍历数组,构建 python 字符串。

这行得通

tx = foo.tx
tx.restype = POINTER(c_ubyte)
result = tx(...args...)

#TODO there must also be a better way to do this
pystr = ""
for i in xrange(w*h*4):
pystr += result[i]
i = Image.fromstring("RGBA", (w, h), pystr)
i.save("out.png")

它不是很漂亮,但是很管用。用 TODO 评论并继续。在初始管道就位后,分析显示此代码块存在严重的性能问题。我想这并不奇怪。

这不起作用

类似于这个问题:Pixel manipulation with PIL.Image and ctypes ,我正在尝试使用 frombuffer() 将像素数据更有效地获取到 PIL 对象中:

tx = foo.tx
tx.restype = POINTER(c_ubyte)
result = tx(...args...)
i = Image.frombuffer('RGBA', (w, h), result, 'raw', 'RGBA', 0, 1)
i.save("out.png")

尽管 fromstring 有效,但使用 frombuffer 会导致以下异常:

Traceback (most recent call last):
File "test.py", line 53, in <module>
i = Image.frombuffer('RGBA', (w, h), res, 'raw', 'RGBA', 0, 1)
File "/Library/Python/2.7/site-packages/PIL/Image.py", line 1853, in frombuffer
core.map_buffer(data, size, decoder_name, None, 0, args)
ValueError: buffer is not large enough

环境

缓冲区在 C 中被 malloc 为:

unsigned char *pixels_color = (unsigned char*)malloc((WIDTH*HEIGHT*4)*sizeof(unsigned char*));
  • 对于每个波段 RGBA,缓冲区每个像素有 4 个字节。
  • Mac OS X 10.7、python2.7.1、PIL 1.1.7

编辑

基于 eryksun在下面的评论和回答中,我将缓冲区分配从 C 库中的 malloc 移到了 Python 中,并将指针传递给了 C:

tx = foo.tx
tx.restype = POINTER(c_ubyte)

pix_clr = (c_ubyte*(w*h*4))()

tx(...args..., pix_clr)
i = Image.frombuffer('RGBA', (w, h), pix_clr, 'raw', 'RGBA', 0, 1)
i.save("out.png")

这按预期工作。它仍然没有解释 为什么 PIL 对 C 分配的缓冲区不满意,但无论如何这是更好的内存管理结构。感谢 ErykSun 和 HYRY!

最佳答案

当您设置 tx.restype = POINTER(c_ubyte) 时,生成的 ctypes 指针对象是一个 4 或 8 字节的缓冲区,用于图像缓冲区的地址 .您需要从该地址创建一个 ctypes 数组。

如果你提前知道大小,你可以设置SIZE = WIDTH * HEIGHT * 4; tx.restype = POINTER(c_ubyte * SIZE)。否则设置 tx.restype = POINTER(c_ubyte),并转换为动态大小,即 size = w * h * 4; pbuf = cast(result, POINTER(c_ubyte * size)).无论哪种方式,您都需要取消引用指针以获取数组。使用 buf = pbuf[0]buf = pbuf.contents。然后你可以将 buf 传递给 Image.frombuffer

也就是说,使用 ctypes 分配内存通常更简单。这为您提供了引用计数内存管理,而不必手动释放内存。以下是一个玩具示例。

假设是动态大小,调用者需要获取图像尺寸以便分配数组,所以我添加了一个结构,它具有图像的宽度、高度和深度,由 C 填充函数 get_image_info。函数 get_image 接收指向图像数组的指针以复制数据。

import ctypes

lib = ctypes.CDLL('imgtest.dll')

class ImageInfo(ctypes.Structure):
_fields_ = (
('width', ctypes.c_int),
('height', ctypes.c_int),
('depth', ctypes.c_int),
)

pImageInfo = ctypes.POINTER(ImageInfo)
pImage = ctypes.POINTER(ctypes.c_ubyte)

lib.get_image_info.argtypes = [pImageInfo]
lib.get_image_info.restype = ctypes.c_int

lib.get_image.argtypes = [pImage]
lib.get_image.restype = ctypes.c_int

imgnfo = ImageInfo()
lib.get_image_info(ctypes.byref(imgnfo))
w, h, d = imgnfo.width, imgnfo.height, imgnfo.depth

imgdata = (w * h * d * ctypes.c_ubyte)()
lib.get_image(imgdata)

from PIL import Image
img = Image.frombuffer('RGBA', (w, h), imgdata, 'raw', 'RGBA', 0, 1)

C 声明:

typedef struct _ImageInfo {
int width;
int height;
int depth;
} ImageInfo, *pImageInfo;

typedef unsigned char *pImage;

int get_image_info(pImageInfo imgnfo);
int get_image(pImage img);

关于python - 使用 ctypes 数组时 PIL 的 Image.frombuffer 预期数据长度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7142169/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com