首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用SWIG封送Python映像

使用SWIG封送Python映像
EN

Stack Overflow用户
提问于 2011-06-25 22:18:51
回答 3查看 1.1K关注 0票数 8

我有一个库,它采用了一个非常简单的C映像结构:

代码语言:javascript
复制
// Represents a one-channel 8-bit image
typedef struct simple_image_t {
    uint32 rows;
    uint32 cols;
    uint8 *imgdata;
} simple_image;

我没有创建这个库,也没有创建这个结构,所以我不能改变它。我负责使用SWIG为python包装这个库。Python包装器需要能够接收一个PIL并将其转换成这个结构。下面是我现在是如何做到的(使用%inline%):

代码语言:javascript
复制
// Allows python to easily create and initialize this structure
simple_image* py_make_simple_image(uint32 width, uint32 height)
{
    simple_image* img = new simple_image();
    img->rows = height;
    img->cols = width;
    img->imgdata = new uint8[height * width];

    return img;
}

// Allows python to set a particular pixel value
void py_set_simple_image(simple_image* img, uint32 pos, uint8 val)
{
    img->imgdata[pos] = val;
}

然后在python包装器端,下面是现在的情况:

代码语言:javascript
复制
# Make sure it's an 8-bit image
if pil_image.mode != "L":
    pil_image = pil_image.convert("L")

# Create the simple image structure
(width, height) = pil_image.size
img = swig_wrapper.py_make_simple_image(width, height)

try:
    # Copy the image data into the simple image structure
    pos = 0
    for pixel in pil_image.getdata():
        swig_wrapper.py_set_simple_image(img, pos, pixel)
        pos += 1

    # Call some library method that accepts a simple_image*
    return swig_wrapper.some_image_method(img)

finally:
    # Clean up the simple image structure
    swig_wrapper.py_destroy_simple_image(img)

然而,令人惊讶的是,正如您可能已经猜到的那样,在处理中等大小的图像时,非常慢。我知道用SWIG做事情的正确方法是使用类型地图,但是这意味着深入了解PIL的C API,而我现在没有时间这样做。

我在速度方面有什么选择?是否有更快的方法将像素数据从PIL图像编组到这个简单的图像结构?是不是有人已经这么做了,而我的谷歌技术就那么差了?我只是骨瘦如柴,很快就需要学习PIL的内部结构了吗?

谢谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-06-30 18:29:21

PIL的Image.tostring()返回imgdata所需的确切数据的字符串。我使用的类型地图相当简单,但并不完美,我将在下面加以说明。下面是我在Windows上创建的为我工作的示例代码:

sample.h

代码语言:javascript
复制
typedef unsigned int uint32;
typedef unsigned char uint8;

typedef struct simple_image_t {
    uint32 rows;
    uint32 cols;
    uint8 *imgdata;
} simple_image;

#ifdef SAMPLE_EXPORT
#   define SAMPLE_API __declspec(dllexport)
#else
#   define SAMPLE_API __declspec(dllimport)
#endif

SAMPLE_API void some_func(const simple_image* si);

sample.c

代码语言:javascript
复制
#include <stdio.h>

#define SAMPLE_EXPORT
#include "sample.h"

void some_func(const simple_image* si)
{
    uint32 i,j;

    printf(
        "rows = %d\n"
        "cols = %d\n",
        si->rows,si->cols);

    /* Dump a simple map of the image data */
    for(i = 0; i < si->rows; i++)
    {
        for(j = 0; j < si->cols; j++)
        {
            if(si->imgdata[i * si->rows + j] < 0x80)
                printf(" ");
            else
                printf("*");
        }
        printf("\n");
    }
}

sample.i

代码语言:javascript
复制
%module sample

%begin %{
#pragma warning(disable:4100 4127 4706)
%}

%{
#include "sample.h"
%}

%include <windows.i>

%typemap(in) uint8* (char* buffer, Py_ssize_t length) {
    PyString_AsStringAndSize($input,&buffer,&length);
    $1 = (uint8*)buffer;
}

%include "sample.h"

makefile

代码语言:javascript
复制
all: _sample.pyd

sample.dll: sample.c sample.h
    cl /nologo /W4 /LD /MD sample.c

sample_wrap.c: sample.i
    @echo sample.i
    swig -python sample.i

_sample.pyd: sample_wrap.c sample.dll
    cl /nologo /W4 /LD /MD /Fe_sample.pyd sample_wrap.c /Ic:\Python27\include -link /LIBPATH:c:\Python27\libs python27.lib sample.lib

example.py

代码语言:javascript
复制
from PIL import Image
import sample

im = Image.open('sample.gif')
im = im.convert('L')
si = sample.simple_image()
si.rows,si.cols = im.size
s = im.tostring() # Must keep a reference 
si.imgdata = s
sample.some_func(si)

通过这个快速示例,我还没有确定类型地图应该如何正确地增加string对象的引用计数。请注意,如果使用以下代码,上述代码可能会崩溃:

代码语言:javascript
复制
si.imgdata = im.tostring()

当前类型映射的PyString_AsStringAndSize返回指向PyString对象缓冲区的直接指针,但不增加对象的引用计数。它可以在some_func执行之前被垃圾收集(对于我来说,就是崩溃的Python)。分配给s将保持对字符串的引用,并防止出现问题。类型地图应该复制缓冲区,但你是在寻找速度,所以这个黑客可能就是你想要的。

票数 5
EN

Stack Overflow用户

发布于 2011-06-28 20:38:02

您可以使用array模块将图像转换为char数组,然后从swig将数据转换为C数组。

代码语言:javascript
复制
import array
imagar = array.array('B', pil_image.getdata())
(mem, length) = imagar.buffer_info()
swig_wrapper.py_copy(img, mem, length)

成为py_copy,类似于:

代码语言:javascript
复制
void py_copy(simple_image* img, uint32 mem, uint32 length) {
   memcpy((void*)img->imgdata ,(void*)mem, length );
}
票数 1
EN

Stack Overflow用户

发布于 2011-06-29 02:10:49

使用C型怎么样?它允许您直接访问c结构,因此不需要创建相当于结构的Python,您还应该能够执行memcpy (这比逐像素复制要快)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6480862

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档