1

首先很抱歉,如果这是重复的,我找不到任何主题来回答我的问题。

我正在编写一个小程序,用于将 32 位浮点值转换为 short int(16 位)和 unsigned char(8 位)值。这是用于 HDR 图像的目的。

这里我可以获得以下功能(没有钳位):

static inline uint8_t u8fromfloat(float x)
{
    return (int)(x * 255.0f);
}

我想以同样的方式我们可以通过乘以得到short int(pow( 2,16 ) -1)

但后来我最终想到了有序抖动,尤其是拜耳抖动。要转换为 uint8_t 我想我可以使用 4x4 矩阵和 8x8 矩阵来表示无符号短。

我还想到了一个查找表来加速这个过程,这样:

uint16_t LUT[0x10000] // 2¹⁶ values contained

并存储对应于浮点数的 2^16 个无符号短值。由于 unsigned short ↔ unsigned int 之间的隐式转换,同一个表也可以用于 uint8_t

但是这样的查找表在内存中不是很大吗?还有一个人怎么会填满这样的桌子?!

现在我很困惑,你认为什么是最好的?

在 uwind 回答后编辑:现在假设我还想同时进行基本的色彩空间转换,即在转换为 U8/U16 之前,进行色彩空间转换(浮点数),然后将其缩小为 U8/U16 . 在那种情况下使用LUT不是更有效吗?是的,我仍然有索引 LUT 的问题。

4

3 回答 3

1

在我看来,查找表无济于事,因为要对其进行索引,您需要将浮点数转换为某种整数类型。捕获 22。

该表需要 0x10000 * sizeof (uint16_t) 字节,即 128 KB。以现代标准衡量并不多,但另一方面缓存是宝贵的。但是,正如我所说,该表并没有为解决方案添加太多内容,因为您需要将浮点数转换为整数才能进行索引。

您可以创建一个由浮点数的原始位索引的表,重新解释为整数,但这必须是 32 位,这会变得非常大(8 GB 左右)。

进行您概述的直接运行时转换。

于 2013-01-08T11:12:38.737 回答
0

只需坚持乘法 - 它会正常工作。

几乎所有现代 CPU 都具有适用于这些东西的矢量指令(SSE、AVX、...),因此您可能会考虑为此进行编程。或者,如果可能的话,使用自动矢量化代码的编译器(英特尔 C 和 GCC)。即使在查找表是一种可能的解决方案的情况下,这通常也会更快,因为您不会受到内存延迟的影响。

于 2013-01-08T11:16:53.483 回答
0

首先,需要注意的是,float有24位的精度,不可能适应16位int甚至8位。其次,float的范围要大得多,不能存储在任何intlong long int

所以你的问题标题实际上是不正确的,无法将任何浮点数精确转换为短或字符。您希望将0 到 1 之间的浮点值映射到 8 位或 16 位 int范围。


对于您上面使用的代码,它可以正常工作。然而,值 255 极不可能被返回,因为它需要恰好 1.0 作为输入,否则诸如 254.99999 之类的值最终将被截断为 254。您应该将值四舍五入

return (int)(x * 255.0f + .5f);

或者更好,使用链接中提供的代码以获得更平衡的分布

static inline uint8_t u8fromfloat_trick(float x)
{
    union { float f; uint32_t i; } u;
    u.f = 32768.0f + x * (255.0f / 256.0f);
    return (uint8_t)u.i;
}

使用 LUT 不会更快,因为16 位值的表太大而无法放入缓存中,实际上可能会大大降低您的性能。上面的代码片段只需要 2 条浮点指令,或者只需要 1 条FMA指令。SIMD 将进一步提高性能 4-32 倍(或更多),因此 LUT 方法的性能很容易被超越,因为并行化表查找要困难得多

于 2013-10-09T01:08:02.347 回答