【问题标题】:Precisly convert float 32 to unsigned short or unsigned char将 float 32 精确转换为 unsigned short 或 unsigned char
【发布时间】:2012-12-22 05:19:54
【问题描述】:

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

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

here 我可以得到以下函数(没有钳位):

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

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

但后来我想到了有序抖动,尤其是拜耳抖动。要转换为 uint8_t,我想我可以使用一个 4x4 矩阵和一个 8x8 矩阵来表示 unsigned short。

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

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

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

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

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

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

【问题讨论】:

  • 我假设这是一道 C 题。
  • 是的,我忘了准确地说,它是 C/C++

标签: c casting char unsigned short


【解决方案1】:

首先,需要注意的是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 位值的表太大而无法放入缓存中,实际上可能会大大降低您的性能。上面的sn-p只需要2条浮点指令,或者FMA只需要1条。 SIMD 将进一步提高性能 4-32 倍(或更多),因此 LUT 方法的性能很容易被超越,因为并行化表查找要困难得多

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

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

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

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

      【讨论】:

      • 感谢 unwind 您的意见。现在假设我还想同时进行基本的色彩空间转换,即在转换为 U8/U16 之前,进行色彩空间转换(以浮点形式),然后将其缩小为 U8/U16。在那种情况下使用 lut 不是更有效吗?是的,我仍然有索引 lut 的问题......
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-11
      相关资源
      最近更新 更多