时间:2019-02-12 标签:c++sseintrinsicsatan2

c++ SSE intrinsics atan2

我需要一个非常快的 atan2 来从 sobel 值中获取梯度(我正在实施 canny edge 算法。)。有谁知道一个非常快速的实现,最好是内在函数(SIMD)或一个非常快速的近似。 (我认为一个近似值就足够了,因为这些值四舍五入为 0°、45°、90°、135°)

提前致谢

ADD:我知道英特尔在 SVML 中的 IPP atan2,不幸的是我不能使用它。

您似乎想四舍五入到一个八分圆数,大概是从 -22.5°337.5°,增量为 45°

八分圆通过方程

通过原点的四条线分隔
Y = X tan(Θ),

a.Y - b.X = 0.

具有 suitable 个比例因子。

通过计算四个所需角度的这些表达式的符号,您将找到八分圆。通过巧妙的组合,您可以将符号评估限制为三个,因为有 8=2³ 种可能性。

很可能可以使用 SIMD 指令通过计算判别表达式、它们的符号和它们符号的 suitable 组合来对此进行评估,但这并非微不足道。

可能不需要转换为 45° 的倍数,甚至不需要顺序编号。这完全取决于您如何处理八分圆信息。


其他 SIMD 建议:

使用预加载系数,您可以使用 16 位整数运算(可能使用乘加法)一次性计算出 (X, Y) 对的所有四个直线方程。然后得到标志并用_mm_movemask_epi8将它们打包成四位。使用四位值作为小型查找的输入 table.

如 GCC 内联汇编中所述 here atan2() is already a single FPU instruction: x87 FPU opcode FPATAN. Just look at the disassembly your compiler generates when you call std::atan2(). If it is not that single FPU instruction, then you can try this

inline double my_atan2 (double y, double x) { 
  double result; 
  asm (
     "fpatan\n\t" 
     : "=t" (result)       // outputs; t = top of fpu stack
     : "0" (x),            // inputs; 0 = same as result
       "u" (y)             //         u = 2nd floating point register
     );   
  return result; 
}