使用PIL.Image和ctypes进行像素操作

3 投票
1 回答
2049 浏览
提问于 2025-04-16 19:40

我有一个C语言的函数,它可以对一个包含8位RGB值的二维数组进行像素处理。处理完后,我得到的结果是一个c_ubyte数组。我的代码大致是这样的:

from ctypes import cdll, CDLL, Structure, byref, c_utype, c_uint

# get a reference to the C shared library
cdll.loadLibrary(path_to_my_c_lib)
myclib = CDLL(path_to_my_c_lib)

# define the ctypes version of the C image that would look something like:
#     struct img {
#         unsigned char data[MAX_IMAGE_SIZE];
#         unsigned int width;
#         unsigned int height;
#     }
class Img(Structure): _fiels_ = [
    ('data', c_ubyte * MAX_IMAGE_SIZE),
    ('width', c_uint),
    ('height', c_uint),
]

# create a blank image, all pixels are black
img = Image()
img.width = WIDTH
img.height = HEIGHT

# call the C function which would look like this:
#     void my_pixel_manipulation_function(struct img *)
# and would now work its magic on the data
myclib.my_pixel_manipulation_function(byref(img))

现在,我想用PIL库把这个图像保存到文件里。目前我用以下代码把字节数据转换成图像数据:

from PIL import Image

s = ''.join([chr(c) for c in img.data[:(img.width*img.height*3)]])
im = Image.fromstring('RGB', (img.width, img.height), s)

# now I can...
im.save(filename)

这个方法可以用,但我觉得效率太低了。在一台2.2GHz的Core i7处理器上,处理一个592x336的图像需要125毫秒。逐个遍历整个数组并进行这种复杂的字符串拼接,感觉很傻,因为Image库可能可以直接从数组中获取数据。

我试着找方法把c_ubyte数组转换成字符串,或者用Image.frombuffer来代替Image.fromstring,但没能成功。

1 个回答

2

我不是PIL的用户,但通常来说,frombuffer方法是用来处理这种工作的:

你试过用Image.frombuffer吗?

http://effbot.org/imagingbook/image.htm

编辑:

显然,有时候解决方案就在我们眼前:

im = Image.frombuffer('RGB', (img.width, img.height), buff, 'raw', 'RGB', 0, 1)
im.save(filename)

顺便说一下,使用frombuffer的简写形式:

im = Image.frombuffer('RGB', (img.width, img.height), buff)

会生成一张倒过来的图片。真是让人费解……

撰写回答