5

为了处理 8 位像素,在不丢失信息的情况下进行伽马校正等操作,我们通常对值进行上采样,以 16 位或其他方式工作,然后将它们下采样到 8 位。

现在,这对我来说是一个新领域,所以请原谅不正确的术语等。

出于我的需要,我选择在“非标准”Q15 中工作,我只使用范围的上半部分 (0.0-1.0),并且 0x8000 代表 1.0 而不是 -1.0。这使得在 C 中计算事物变得更加容易。

但是我遇到了SSSE3的问题。它具有将 Q15 数字相乘的 PMULHRSW 指令,但它使用 Q15 的“标准”范围是 [-1,1-2⁻¹⁵],因此将(我的)0x8000(1.0)乘以 0x4000(0.5)得到 0xC000(- 0.5),因为它认为 0x8000 是 -1。这很烦人。

我究竟做错了什么?我应该将像素值保持在 0000-7FFF 范围内吗?这不是违背了它作为定点格式的目的吗?有没有解决的办法?也许有什么技巧?

Q15 是否有某种明确的论文来讨论这一切?

4

2 回答 2

3

就个人而言,我会采用将最大值限制为 0x7FFF (~0.99something) 的解决方案。

  • 您不必费力地让处理器按照您想要的方式工作
  • 您不必花很长时间记录“怪异”代码的来龙去脉,因为在 0-0x7FFF 上操作将立即为您的代码读者所识别 - Q 格式被理解(根据我的经验)从-1.0+1.0-one lsb。否则算术不会很好,因为 1 lsb 的值在 0 的每一侧都不同!

除非你能想象自己成功地向一群争论不休的代码审查者争辩说,那额外的一点对算法的运行至关重要,而不仅仅是“最后 0.01% 的性能”,坚持每个人都能理解的代码,以及哪些映射到您可用的硬件。


或者,重新安排您之前的操作,以便所有像素都与您最初拥有的像素相反。或者下面的操作来接受你之前发送的否定。然后以Q15 格式使用从-1.0到的值。0.0

于 2012-09-02T16:25:12.103 回答
2

如果您确定不会使用任何“大于”的数字$8000,那么唯一的问题是至少有一个乘数是$8000(–1,尽管您希望它是 1)。

在这种情况下,解决方案相当简单:

pmulhrsw xmm0, xmm1
psignw xmm0, xmm0

或者,在我们的例子中绝对等价(谢谢,Peter Cordes!):

pmulhrsw xmm0, xmm1
pabsw xmm0, xmm0

这会将负值从乘以恢复为–1正值。

于 2017-09-16T21:04:09.563 回答