将SWIG代理对象作为输入传递给PIL.Image.frombuffer

1 投票
1 回答
758 浏览
提问于 2025-04-17 10:00

我正在使用SWIG中的array_class宏,这个宏在carrays.i文件里定义,用来创建一个无符号字符的缓冲区,这个缓冲区可以发送到我项目的C++部分,负责拍照。这一切都很顺利——在相机触发后,缓冲区里填充了数据,我可以通过Python中的[]来查看这个缓冲区里的内容。现在,我想用这个缓冲区创建一个PIL图像,使用Image.frombuffer

Image.frombuffer(mode, size, data) => image

(这是PIL 1.1.4中新增加的功能)。它可以从字符串或缓冲对象中的像素数据创建一个图像内存,使用标准的“原始”解码器。

但是我收到一个错误信息,告诉我我提供的SWIG对象不是一个Python缓冲区:

文件 "/usr/lib/python2.7/dist-packages/PIL/Image.py",第1853行,在frombuffer中
core.map_buffer(data, size, decoder_name, None, 0, args)
TypeError: 期望字符串或缓冲区

我该如何让这个SWIG对象的代理与Image.frombuffer所期望的缓冲区类型兼容呢?

1 个回答

0

如果你能处理好SWIG缓冲区的符号问题,你就可以直接创建一个PIL的ImagingMemoryInstance。在libImaging/Imaging.h这个文件里,你会看到这样的内容:

struct ImagingMemoryInstance {

    /* Format */
    char mode[4+1]; /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK") */
    int type;       /* Data type (IMAGING_TYPE_*) */
    int depth;      /* Depth (ignored in this version) */
    int bands;      /* Number of bands (1, 2, 3, or 4) */
    int xsize;      /* Image dimension. */
    int ysize;

    /* Colour palette (for "P" images only) */
    ImagingPalette palette;

    /* Data pointers */
    UINT8 **image8; /* Set for 8-bit images (pixelsize=1). */
    INT32 **image32;    /* Set for 32-bit images (pixelsize=4). */

    /* Internals */
    char **image;   /* Actual raster data. */
    char *block;    /* Set if data is allocated in a single block. */

    int pixelsize;  /* Size of a pixel, in bytes (1, 2 or 4) */
    int linesize;   /* Size of a line, in bytes (xsize * pixelsize) */

    /* Virtual methods */
    void (*destroy)(Imaging im);
};

... ImagingMemoryInstance*被定义为Imaging,这是一个基础结构体,你会在PIL的C扩展源代码中到处看到。别光听我说,自己去看看 -- 从API源代码来看,PIL的代码库相当清晰,结构也很合理。

正如@maxy提到的,你也可以很简单(甚至更简单)地创建一个NumPy数组结构体 -- 不过虽然NumPy的C API非常稳定,像是来自Guido的个人使用手册,我个人觉得在这种情况下,依赖一个库的源代码就足够了。

撰写回答