【问题标题】:Numpy unpack uint16 to 1-5-5-5 bit chunksNumpy 将 uint16 解包为 1-5-5-5 位块
【发布时间】:2020-07-24 14:46:04
【问题描述】:

我正在尝试使用 numpy 将二进制字符串转换为 Python 中的图像,但我很难找到一种通过非常规位分布(据我所知)来处理它的好方法。

这些是转换方式和转换内容的细节。 16 位纹理图块 (256*256)。每个 bitu16 代表一个像素,其颜色的格式为 ARGB,MSB 到 LSB: 1 位透明度
5位红色通道 5位绿色通道 5位蓝色通道

Numpy 并不真正支持任何 1 位或 5 位。我尝试使用不同的 argb 通道设置 np.dtype 但没有任何运气。 unpackbits 似乎不适用于 uint16,所以在这种情况下,我可能不得不将其拆分为 2 个 uint8


dt = np.dtype([('a', np.bool_), ('r', np.half), ('g', np.half), ('b', np.half)])

data = data.read(131072)

dataFromBuffer = np.frombuffer(data, dtype=dt)
img  = dataFromBuffer.reshape(256, 256)


【问题讨论】:

    标签: python numpy python-imaging-library bin


    【解决方案1】:

    关于在这种情况下缺少位 numpy 位级别支持,您是对的。处理位的高级(但功能性)方法可以如下完成:

    image_16_bit = 123 # A 16bit integer.
    
    bits = '{:016b}'.format(image_16_bit) 
    
    transparency = int(bits[0], 2)
    red_channel = int(bits[1:6], 2)
    green_channel = int(bits[6:11], 2)
    blue_channel = int(bits[11:], 2)
    
    print(transparency, red_channel, green_channel, blue_channel) # 0 0 3 27
    

    您可以在所有整数上运行它,然后收集各个通道值。最后,您可以将其转换为一个 numpy 数组,以将您的图像作为一个 numpy 数组。

    【讨论】:

      【解决方案2】:

      以下是如何让你的方法奏效:

      # make small example
      x = np.random.randint(0,1<<16,size=(5,5),dtype=np.uint16)
      
      # set up dtype
      dt = np.dtype([*zip('argb',(bool,*3*(np.uint8,)))])
      
      # bit of bit twiddling
      
      def unpack_argb(x):
          out = np.empty(x.shape,dt)
          for i,ch in enumerate(reversed('argb')):
              out[ch] = (x>>(5*i))&31
          return out
      
      def pack_argb(x):
          out = x['a'].astype(np.uint16)
          for ch in 'rgb':
              out <<= 5
              out += x[ch]&31
          return out
      
      # check round trip
      np.all(x == pack_argb(unpack_argb(x)))
      # True
      

      更新:

      def argb16_to_rgba32(x):
          out = np.empty(x.shape+(4,),np.uint8)
          out[...,3] = (x>>8)&0x80
          out[...,0] = (x>>7)&0xf8
          out[...,1] = (x>>2)&0xf8
          out[...,2] = (x<<3)&0xf8
          return out
      
      def rgba32_to_argb16(x):
          x16 = x.astype(np.uint16)&0xf8
          out = (x16[...,3]&0x80)<<8
          out += x16[...,0]<<7
          out += x16[...,1]<<2
          out += x16[...,2]>>3
          return out
      

      【讨论】:

      • 这个脚本非常快,所以我试图找出一种方法来修改它以让枕头接受并且 alpha 为 255 或 0,两者都给出了自定义 dtype 和 i 元组的问题,是否有可能以相同的方法执行 unpack_argb 以将 argb 转换为 (256*256*4) 数组中的 rgba? (有点像 daveldito,但速度和你一样)
      • @Blikpils 这当然是可能的。现在我没有时间,但我会在未来几天尝试更新答案。
      • @Blikpils 完成。让我知道它是否适合你。我检查了往返看起来不错,但我不是 100% 我正确映射了通道。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-27
      • 1970-01-01
      • 1970-01-01
      • 2023-01-20
      • 2011-06-13
      • 1970-01-01
      • 2019-01-27
      相关资源
      最近更新 更多