使用numpy和pil将565(16位颜色)转换为888(24位颜色)

发布于 2024-10-25 06:37:59 字数 1630 浏览 6 评论 0原文

我必须以此为序,事实上我有一个使用 bitshift 和 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)

方案的区别在于,您需要将其打包为来自 putpixel 的 MSB(ALPHA,B,G,R)LSB 计数器直觉,但它可以工作,并且工作良好

I must preface this, with the fact that I have a working method using bitshift and putpixel, but it is incredibly slow, and I am looking to leverage numpy to speed up the process. I believe I am close, but not quite there. Having timed what I think should work, I'm seeing a 0.3 second improvement in time, hence my motivation.

The current working code:

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

The code I'm trying to get work looks like this:

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

so the final problem, is that the channels are not combining and I don't believe I should have to do that final bit shift (note that I get the red channel if I don't bit-shift by 8). Assistance on how to combine everything correctly would be much appreciated.

SOLUTION

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)

the difference is that you need to pack it as MSB(ALPHA,B,G,R)LSB counter intuitive from putpixel, but it works, and works well

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

酒解孤独 2024-11-01 06:37:59

警告:以下代码尚未经过检查,但我认为这将实现您想要的功能(如果我正确理解所有内容):

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 位是 alpha。移位数字可能看起来有点奇怪,因为我合并了 16 位格式的移位。另外,我使用 frombuffer 因为我们希望利用 Numpy 使用的缓冲区,而不是首先转换为字符串。

查看此页面可能会有所帮助。在我看来,这并不是很好,但根据我的经验,PIL 的情况就是这样。该文档确实不太人性化,事实上我经常觉得它令人困惑,但我不打算自愿重写它,因为我不怎么使用 PIL。

Warning: the following code hasn't been checked, but I think that this will do what you want (if I'm understanding everything correctly):

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)

I'm combining all of the channels together into 32-bits on the line that does all of the bit shifting. The leftmost 8-bits are the red, the next 8 are the green, the next 8 blue, and the last 8 alpha. The shifting numbers may seem a little strange because I incorporated the shifts from the 16-bit format. Also, I'm using frombuffer because then we want to take advantage of the buffer being used by Numpy rather than converting to a string first.

It might help to look at this page. It's not super great in my opinion, but that's how things go with PIL in my experience. The documentation is really not very user-friendly, in fact I often find it confusing, but I'm not about to volunteer to rewrite it because I don't use PIL much.

隔岸观火 2024-11-01 06:37:59

如果你想适当地进行缩放,这里有一个更接近 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))

If you want to do the scaling appropriately, here is a more PIL-ish to solve your problem.

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))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文