Search code examples
c++trigonometrysimdsseintrinsics

SSE intrinsics atan2


I need a very fast atan2 for getting the gradient out of the sobel values (I'm implementing canny edge algo.). Does anyone know a very fast implementation, preferable in intrinsics (SIMD) or a very fast approximation. (I think an approximation is enough, because the values are rounded to 0°, 45°, 90°, 135°)

ADD: I'm aware of Intel's IPP atan2 in SVML unfortunately I can't use it.


Solution

  • It seems that you want to round to an octant number, presumably from -22.5° to 337.5° in 45° increments.

    The octants are separated by four lines through the origin with equation

    Y = X tan(Θ),
    

    or

    a.Y - b.X = 0.
    

    with suitable scaling factors.

    By computing the signs of these expressions for the four desired angles, you will find the octant. By a clever combination, you can limit to three sign evaluations, as there are 8=2³ possibilities.

    It is likely that this can be evaluated with SIMD instructions by computing the discriminant expressions, their signs, and suitable combinations of their signs, but this isn't trivial.

    Probably a conversion to a multiple of 45° isn't necessary, not even a sequential numbering. It all depends on what you do with the octant information.


    Additional SIMD suggestion:

    With preloaded coefficients, you can compute all four line equations in a single go for an (X, Y) pair, using 16 bits integer arithmetic (possibly with multiply-and-add). Then get the signs and pack them to four bits with _mm_movemask_epi8. Use the four bit value as input to a small lookup table.