Skip to content

The ippsMagnitude_32f function says that almost zero-length vector is infinite #19506

@definability

Description

@definability
System information (version)
  • OpenCV => 4.5.1, 4.4.0
  • Intel IPP (ICV version, shipped with OpenCV as the third-party library) => 2020.0.0 [2020.0.0 Gold]
  • Operation System / Platform => Xubuntu 20.04 64 Bit, popOS 64 Bit, Windows 10 64 Bit
  • Compiler (for C++ version) => g++-9.3.0, clang++-10.0.0
  • Python (for Python version) => 3.7.8, 3.8.3, 3.8.5, 3.8.6, 3.9.0
Detailed description

When I use ippsMagnitude_32f (from the IPP shipped with OpenCV) to calculate the magnitude of a very small vector with single-precision floating-point coordinates (like 1E-20), I receive infinity instead of 1E-20 (or instead of at least zero).
Next, I describe how I've faced the issue.
You can skip straight to the "Steps to reproduce" sections.

I've discovered the issue when used cv2.calcOpticalFlowFarneback in the Python version of OpenCV.
There is at least one more user who faced this issue on StackOverflow.
The cv2.cartToPolar function has returned infinity (the flow magnitude cannot be so big), though the actual flow coordinates were like 1E-20.

Then I started digging deeper and became sure that the issue is really cv2.cartToPolar.
I've debugged it and found out that before the call of the hal::magnitude32f function the magnitude is zero, but after it, it's infinity

hal::magnitude32f( x, y, mag, len );

As far as there is no HAL implementation, it uses the ippsMagnitude_32f function
https://github.com/opencv/opencv/blob/fc1a15626226609babd128e043cf7c4e32f567ca/modules/core/src/mathfuncs_core.dispatch.cpp#L42..L52
Then, I wrote an example code that only calls this function and got the issue.

Steps to reproduce using C++
  • Download zip-archive with OpenCV 4.5.1 (using the official instruction)

  • Build it with cmake .. && make (make sure it contains IPP)

  • Write an example application

    #include <iostream>
    #include <ippicv.h>
    
    int main(int argc,const char* argv[])
    {
        float x = 0;
        float y = 1E-20;
        float mag = 0;
        ippsMagnitude_32f(&x, &y, &mag, 1);
        std::cout << "x " << x << std::endl;
        std::cout << "y " << y << std::endl;
        std::cout << "magnitude " << mag << std::endl;
        return 0;
    }
  • Compile the application, using the OpenCV version of the IPP library

    g++ main.cpp \
      opencv-master/build/3rdparty/ippicv/ippicv_lnx/icv/lib/intel64/libippicv.a \
      -I opencv-master/build/3rdparty/ippicv/ippicv_lnx/icv/include
  • Execute it and look at the resulting magnitude

    $ ./a.out
    x 0
    y 1e-20
    magnitude inf
Steps to reproduce using Python 3

As long as it's not possible to use ipp functions of OpenCV directly from Python, we can use cartToPolar, which uses ipp under the hood.

  • pip install opencv-python (installs version 4.5.1.48 for me now, date 2021-02-11)
  • Launch Python3 interpreter (I use default CPython interpreter) and write
    >>> import cv2, numpy
    >>> a = numpy.array([1E-20], dtype=numpy.float32)
    >>> cv2.cartToPolar(a, a)
    (array([[inf]], dtype=float32), array([[4.502441e-05]], dtype=float32))

The issue is reproduced on different machines with Python 3.8 and 3.9.

Issue submission checklist
  • I report the issue, it's not a question
  • I checked the problem with documentation, FAQ, open issues,
    forum.opencv.org, Stack Overflow, etc and have not found solution
  • I updated to latest OpenCV version and the issue is still there
  • There is reproducer code and related data files: videos, images, onnx, etc

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions