Marshaling PILON PIL Image с использованием SWIG

У меня есть библиотека, которая занимает очень простую структуру изображения C:

// Represents a one-channel 8-bit image typedef struct simple_image_t { uint32 rows; uint32 cols; uint8 *imgdata; } simple_image; 

Я не создал эту библиотеку и эту структуру, поэтому я не могу ее изменить. Я отвечаю за упаковку этой библиотеки для python с помощью SWIG. Оболочка Python должна иметь возможность отображать изображение PIL и преобразовывать его в эту структуру. Вот как я делаю это прямо сейчас (используя SWIG %inline% ):

 // 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 вот как выглядят вещи прямо сейчас:

 # 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 подходящий способ сделать это – использовать типографию, но это означало бы копаться в C API PIL, и у меня просто не было времени сделать это на данный момент.

Каковы мои возможности в плане скорости? Существуют ли более быстрые способы маршалирования данных пикселей из изображения PIL в эту простую структуру изображения? Кто-то уже сделал это, и мои навыки Google просто так плохи? Я просто костяк, и вскоре мне нужно будет изучить внутренности PIL?

Благодарю.

3 Solutions collect form web for “Marshaling PILON PIL Image с использованием SWIG”

PIL Image.tostring() возвращает строку точных данных, которые вам нужны для imgdata . Типичная карта, которую я использовал, довольно проста, но не идеальна, о чем я расскажу ниже. Вот пример кода, который я создал для Windows, который работал для меня:

sample.h

 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

 #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

 %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

 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

 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) 

В этом кратком примере я не определил, как должна отображаться типовая карта, чтобы увеличить счетчик ссылок на строковый объект. Обратите внимание, что приведенный выше код может быть поврежден, если был использован следующий код:

 si.imgdata = im.tostring() 

Текущая папка PyString_AsStringAndSize в PyString_AsStringAndSize возвращает прямой указатель на буфер объекта PyString, но не увеличивает счетчик ссылок для объекта. Это может быть сбор мусора перед выполнением some_func (и был для меня, сбой Python). Присвоение s сохраняет ссылку на строку и предотвращает проблемы. Карта typemap должна скопировать буфер, но вы искали скорость, чтобы этот хак мог быть тем, что вы хотите.

Может быть, вы можете преобразовать изображение в массив символов с помощью модуля array , а затем, с помощью swig, memcpy данных в ваш массив C.

 import array imagar = array.array('B', pil_image.getdata()) (mem, length) = imagar.buffer_info() swig_wrapper.py_copy(img, mem, length) 

будучи py_copy что-то вроде:

 void py_copy(simple_image* img, uint32 mem, uint32 length) { memcpy((void*)img->imgdata ,(void*)mem, length ); } 

Как насчет использования ctypes ? Это позволяет вам иметь прямой доступ к c-структурам, поэтому нет необходимости создавать эквивалент Python для структуры, и вы также должны иметь возможность делать memcpy (что будет быстрее, чем копирование по пикселям).

Python - лучший язык программирования в мире.