在 Python (NumPy) 中存储未与字节对齐且没有填充的数据

问题描述 投票:0回答:1

我有用 10 或 12 位整数表示的图像数据,我想将此数据保存到磁盘,而无需在使用 16 位整数表示它们时写入不必要的 6 或 4 个零填充。所有这些都最好用 Python 实现。

更具体地说 - 如果我有 2 个 12 位整数存储为 16 位整数,它们将占用 32 位空间,但数据本身仅覆盖 24 位。如果我能够将它们存储为 3 个 8 位整数,那么填充就不会浪费空间。唯一需要做的就是记住原始输入数组的形状(图像分辨率)和位深度,以便能够恢复原始数据。

数据源使用

NumPy nd-arrays
np.int16
dtype,最高有效位设置为零作为填充。数据的目标是 HDF5 文件,使用
h5py
模块进行操作,该模块也使用
NumPy nd-arrays
作为基础数据类型。因此,如果操作可以使用 NumPy 本身完成,而无需转换为不同数据类型的任何额外开销,我会发现最好。但欢迎任何建议的解决方案。

我无法找到任何至少相当有效的解决方案。使用简单的位掩码操作以某种方式划分和组合数字可能是不可行的,因为它会花费比节省磁盘写入时间更多的 CPU 时间。这个假设来自这样的预期:该操作需要按元素完成,而无需任何向量化/其他优化。

因此,一些优化的功能可能是必要的,但我还没有找到。我正在处理每秒数百兆字节的数据(视频),因此这种优化确实会让我的 SSD 更容易管理存储数据。

python numpy numpy-ndarray bit
1个回答
0
投票

我不知道这是否非常有效,或者您正在寻找什么。但是您可以简单地展平阵列,然后进行一些基本的移位/掩模(或

*16
+
)。创建一个
np.uint8
数组,您可以使用您知道的任何存储数组的方法来存储该数组。 或者重新创建“代表 12 位数组的 16 位”

这肯定不是很有效率。但至少它是矢量化的(不是“逐元素”,至少,如果你的意思是“在纯Python迭代中为每个元素执行纯Python操作”。我的意思是,它仍然是逐元素的,但是在numpy迭代中.无论如何,我不明白它怎么可能不是逐元素的:你必须至少读取所有元素一次才能执行任何操作)

像这样

def storable8from12(arr):
   tmp32=arr.reshape(-1,2).astype(np.uint32)
   return ((tmp32[:,0]<<12)+tmp32[:,1]).view(np.uint8).reshape(-1,4)[:,:3].reshape(len(arr),-1)

一些临时数组甚至比您想要减少的数组还要大。但没有for循环。我认为这是为了存储,而不是直接在内存中,您想要减小大小。

那么,反过来

def unpack12bitsFrom8(st):
   tmp32=np.pad(st.reshape(-1,3), ((0,0),(0,1))).view(np.uint32)
   odd=(tmp32&0xfff000)>>12
   even=tmp32&0xfff
   return np.hstack([odd,even]).reshape(len(st),-1).astype(np.uint16)

所以,再次不确定这是否是您所期望的。因为你显然已经想到了按位操作(

<<
&
之类的东西)。但我不明白你为什么说它不是“向量化”(从我们通常在
numpy
中赋予这个词的意义上来说:
for
循环是在numpy内部完成的)

© www.soinside.com 2019 - 2024. All rights reserved.