我正在寻找有关有损数据压缩方法的建议。我需要将
uint16
压缩为 uint8
,以便分辨率损失随着 uint16
值的增加而增加。我目前正在使用以下内容:
def log2_compress(x: np.uint16) -> np.uint8:
# Add l to avoid log2(0)
y = math.log2(x + 1)
# log2(1) = 0.
# log2(65536) = 16.
# Scale from [0,16] to [0,255].
return np.uint8((y / 16) * 255)
这很简单,但有一个缺点,那就是在
uint8
方面很浪费,即
log2_compress(0) = 0
log2_compress(1) = 15
log2_compress(2) = 25
所以不使用
[1,14]
、[16,24]
等。有人可以建议一种类似于 log2_compress
但使用更多(全部?) uint8
位的方法吗?我也不太关心性能。
取决于你的意思
分辨率损失随着
的增加而增加 价值观uint16
您可能想尝试不同的压缩功能。如果没有有关上下文的任何进一步信息,我们将假设您正在寻找递增的凹函数来将 [0~65535] 映射到 [0~255]。
您可以先尝试一下该功能
sqrt
:
def sqrt_compress(x: np.uint16) -> np.uint8:
return np.uint8(math.sqrt(x))
如果这个函数的平滑度不完全符合您的需要,您可以尝试其他幂而不是平方根的 1/2。您可以添加功率作为参数
p
,这将影响压缩函数的平滑度:
def power_compress_p(x: np.uint16, p: float = 2) -> np.uint8:
"""Compression function. Higher value of p use less bits."""
return np.uint8(2 ** (8 - 16 / p) * x ** (1 / p))
对于您的用例,请使用
p > 1
。
幂函数显然不是唯一存在的压缩,如果您想更好地控制粒度,您可以使用字典来定义映射函数。