Как передать битовую карту байтов в функцию Cython? Я получаю значения мусора
Я делаю поиск субизображения в python, и он явно слишком медленный. Итак, в процессе конвертации в Cython я обнаружил, что это не так просто. Питонская сторона вещей показывает байты как правильные (при выполнении debugPrint), и поиск субизображения был протестирован и работает отлично. Однако, выполнив свое первое преобразование py в Cy, я столкнулся с камнем преткновения. Единственное, что я делаю, чтобы преобразовать некоторые байты Python (я думаю, что они являются байтами....: o) в указатель на char * - это присваивание. Я как-то теряю право собственности на блок данных?
Вот соответствующий код:
cdef struct PixelsBMP:
char* data
int width, height, bands
# Here's how I create the bytes:
cpdef grabPixelsBMP(img=None):
if img is None:
img = ImageGrab.grab()
elif isinstance(img, str):
img = Image.open(img)
with io.BytesIO() as bytes_io:
img.save(bytes_io, 'BMP')
data = bytes_io.getvalue()
offset = int.from_bytes(data[10:14], byteorder='little', signed=False)
data = data[offset:] # pixels start here
cdef PixelsBMP px;
px.data = data
px.width = img.width
px.height = img.height
px.bands = 3 if img.mode == 'RGB' else 4
return px
# Here's how I access the bytes:
cpdef debugPrintPixels(PixelsBMP px):
import sys
cdef char* d = px.data
print('width:', px.width)
print('height:', px.height)
print('bands (alpha=>4):', px.bands)
cdef:
int pad_sum = 0
int pad = nextMult4Pad(px.width * px.bands)
int x, y, offs
for y in range(0, px.height):
for x in range(0, px.width):
offs = px.width * px.bands * y + px.bands * x + pad_sum
sys.stdout.write('(' + str(hex(d[offs])) + ',' + str(hex(d[offs + 1])) + ',' + \
str(hex(d[offs + 2])) + ((',' + str(hex(d[offs + 3]))) if px.bands == 4 else '') + ')')
print()
pad_sum += pad
Что это печатает:
('width:', 7)
('height:', 3)
('bands (alpha=>4):', 4)
(0x0,0x0,0x0,0x0)(0x0,0x0,0x0,0x0)(0x1,0x0,0x0,0x0)(0x30,-0x3f,0x4a,0x5c)(0x2,0x0,0x0,0x0)(-0x1,-0x1,-0x1,-0x1)(0x0,0x7,0x0,0x0)()
(0x0,0x0,0x0,0x0)(0x1,0x0,0x0,0x0)(0x30,-0x3f,0x4a,0x5c)(0x2,0x0,0x0,0x0)(-0x1,-0x1,-0x1,-0x1)(0x0,0x4,0x0,0x0)(0x0,0x0,0x0,0x0)()
(0x1,0x0,0x0,0x0)(0x30,-0x3f,0x4a,0x5c)(0x4,0x0,0x0,0x0)(-0x1,-0x1,-0x1,-0x1)(0x64,0x1,0x0,0x53)(0x0,0x0,0x0,0x0)(0x1,0x0,0x0,0x0)()
Где должно быть изображение черных пикселей с альфа-каналом = 255.
Правильно ли я получаю доступ к байту с помощью Cython?
1 ответ
Это проблема владения памятью. Ваш bytes_io
владеет данными, которые px_data
указывает на. Вам нужно выделить немного памяти и скопировать данные:
# at the top of your file
from libc.stdlib cimport malloc
from libc.string cimport memcpy
#replacing px.data = data
cdef char* data_str = data
px.data = <char*>malloc(sizeof(char)*len(data))
memcpy(px.data,data_str, len(data))
Когда вы закончите со структурой, вам нужно освободить данные. Обратите внимание, что если вы передаете структуру в Python (например, путем вызова cpdef grabPixelsBMP
из Python) он генерирует его словарную копию. Вы должны освободить данные, хранящиеся в структуре, а не в словаре. Управление памятью в С может быть сложным...