Используя numpy и pil для преобразования 565 (16-битный цвет) в 888 (24-битный цвет) - PullRequest
1 голос
/ 24 марта 2011

Я должен предвосхитить это, учитывая тот факт, что у меня есть рабочий метод, использующий bithift и putpixel, но он невероятно медленный, и я стремлюсь использовать numpy для ускорения процесса. Я верю, что я близко, но не совсем там. После того, как я рассчитал, что должно работать, я вижу улучшение на 0,3 секунды, отсюда и моя мотивация.

Текущий рабочий код:

buff # a binary set of data
im = Image.new("RGBA",(xdim,ydim))
for y in xrange(ydim):
    for x in xrange(xdim):
        px = buff[x*y]
        # the 255 is for the alpha channel which I plan to use later
        im.putpixel((x,y),(px&0xF800) >> 8, (px&0x07E0) >> 3, (px&0x001F) <<3, 255))
return im

Код, который я пытаюсь получить, выглядит так:

im16 = numpy.fromstring(buff,dtype=numpy.uint16) #read data as shorts
im16 = numpy.array(im16,dtype=numpy.uint32) #now that it's in the correct order, convert to 32 bit so there is room to do shifting
r    = numpy.right_shift(8, im16.copy() & 0xF800)
g    = numpy.right_shift(3, im16.copy() & 0x07E0)
b    = numpy.left_shift( 3, im16 & 0x001F)
pA   = numpy.append(r,g)
pB   = numpy.append(b,numpy.ones((xdim,ydim),dtype=numpy.uint32) * 0xFF) #this is a black alpha channel
img  = numpy.left_shift(img,8) #gives me green channel
im24 = Image.fromstring("RGBA",(xdim,ydim),img)
return im24

итак, последняя проблема в том, что каналы не объединяются, и я не думаю, что мне нужно было бы делать это последнее смещение битов (обратите внимание, что я получаю красный канал, если я не смещу бит на 8). Помощь в том, как правильно все комбинировать, была бы очень признательна.

РЕШЕНИЕ

import numpy as np
arr = np.fromstring(buff,dtype=np.uint16).astype(np.uint32)
arr = 0xFF000000 + ((arr & 0xF800) >> 8) + ((arr & 0x07E0) << 5) + ((arr & 0x001F) << 19)
return Image.frombuffer('RGBA', (xdim,ydim), arr, 'raw', 'RGBA', 0, 1)

разница в том, что вам нужно упаковать его как счетчик LSB MSB (ALPHA, B, G, R), интуитивно понятный от putpixel, но он работает и работает хорошо

Ответы [ 2 ]

3 голосов
/ 24 марта 2011

Предупреждение: следующий код не был проверен, но я думаю, что это будет делать то, что вы хотите (если я все правильно понимаю):

import numpy as np
arr = np.fromstring(buff,dtype=np.uint16).astype(np.uint32)
arr = ((arr & 0xF800) << 16) + ((arr & 0x07E0) << 13) + ((arr & 0x001F) << 11) + 0xFF
return Image.frombuffer('RGBA', (xdim,ydim), arr, 'raw', 'RGBA', 0, 1)

Я объединяю всеканалы объединяются в 32-битные строки, которые выполняют все битовые смещения.Самые левые 8 битов - красный, следующие 8 - зеленый, следующие 8 синие и последние 8 букв.Смещающиеся числа могут показаться немного странными, потому что я включил сдвиги из 16-битного формата.Кроме того, я использую frombuffer, потому что тогда мы хотим использовать буфер, используемый Numpy, вместо того, чтобы сначала конвертировать в строку.

Это может помочь посмотреть на эту страницу .На мой взгляд, это не супер здорово, но в моем опыте дела обстоят с PIL.Документация на самом деле не очень удобна для пользователя, на самом деле меня часто смущает, но я не собираюсь добровольно переписывать ее, потому что я не пользуюсь PIL.

1 голос
/ 22 июня 2011

Если вы хотите выполнить масштабирование надлежащим образом, вот еще PIL-иш для решения вашей проблемы.

FROM_5 = ((np.arange(32, dtype=numpy.uint16) * 255 + 15) // 31).astype(numpy.ubyte)
FROM_6 = ((np.arange(64, dtype=numpy.uint16) * 255 + 31) // 63).astype(numpy.ubyte)

data = numpy.fromstring(buff, dtype=numpy.uint16)
r = Image.frombuffer('L', shape, FROM_5[data >> 11], 'raw', 'L', 0, 1)
g = Image.frombuffer('L', shape, FROM_6[(data >> 5) & 0x3F], 'raw', 'L', 0, 1)
b = Image.frombuffer('L', shape, FROM_5[data & 0x1F], 'raw', 'L', 0, 1)
return Image.merge('RGB', (r, g, b))
...