Search code examples
pythonpython-3.xopencvopticalflow

CV2 optical flow function is not deterministic


I'm trying to get the amount of motion by calculating the optical flow magnitude between two images (in Python 3.7 and cv2 v4.0). But passing the same images, I see the final value is not deterministic. Sometimes it prints inf and sometimes it prints 7.372749678324908e-05.

What is the problem? Why it's not deterministic?!

def getOpticalMag(prev_image, curr_image):

    prev_image_gray = cv2.cvtColor(prev_image, cv2.COLOR_BGR2GRAY)
    curr_image_gray = cv2.cvtColor(curr_image, cv2.COLOR_BGR2GRAY)

    flow = cv2.calcOpticalFlowFarneback(prev_image_gray, curr_image_gray, flow=None,
                                        pyr_scale=0.5, levels=1, winsize=15,
                                        iterations=2,
                                        poly_n=5, poly_sigma=1.1, flags=0)

    mag, ang = cv2.cartToPolar(flow[...,0], flow[...,1])

    return np.mean(mag)

Solution

  • I've found out that it's a bug in the underlying IPP (IPPICV) part of OpenCV, which is shipped with the Python version in order to make it work faster, so posted it and it's already milestoned https://github.com/opencv/opencv/issues/19506.

    You can write your own converter from cartesian to polar coordinates using numpy like in this feature request https://github.com/numpy/numpy/issues/5228#issue-46746558 (if you use Python version of OpenCV, you have NumPy already)

    def cartToPol(x, y):
        ang = numpy.arctan2(y, x)
        mag = numpy.hypot(x, y)
        return mag, ang
    

    Another solution is to compile OpenCV without IPP or use the C++ version of OpenCV: in my Ubuntu 20.04, this bug doesn't exist for the C++ version because I didn't install IPP.