openradar / TINT

TINT Is Not TITAN. Python code for tracking objects. Specifically storm cells.
BSD 2-Clause "Simplified" License
80 stars 43 forks source link

Flow Vector Bug Fix #36

Closed eshort0401 closed 5 years ago

eshort0401 commented 5 years ago

I've noticed that the fft_flowvectors function can produce some erratic behaviour due to both inconsistent rounding between fft_flowvectors and fft_shift, and "Bankers Rounding" in numpy/python. Note fft_flowvectors uses np.round(dims/2, 0) (line 54 of phase_correlation.py) to get the "center" of the matrix, which is subject to Bankers Rounding, whereas fft_shift uses np.int(fft_mat.shape[0]/2) (lines 75 and 76 of phase_correlation.py) which always rounds down. These inconsistencies can produce errors of up to 2 pixels - consider the following examples.

import numpy as np
import tint
from tint.phase_correlation import fft_flowvectors

# 1 Pixel Error - odd and center rounds up
im1 = np.zeros((99,99))
im2 = np.zeros((99,99))

r  = np.random.rand(5,5) * 100
im1[55:60,55:60] = r
im2[60:65,60:65] = r

s = fft_flowvectors(im1,im2)
print(s)

# 1 Pixel Error - even
im1 = np.zeros((100,100))
im2 = np.zeros((100,100))

r  = np.random.rand(5,5) * 100
im1[55:60,55:60] = r
im2[60:65,60:65] = r

s = fft_flowvectors(im1,im2)
print(s)

# 2 Pixel Error - even and center rounds down
im1 = np.zeros((101,101))
im2 = np.zeros((101,101))

r  = np.random.rand(5,5) * 100
im1[55:60,55:60] = r
im2[60:65,60:65] = r

s = fft_flowvectors(im1,im2)
print(s)

With the current version of TINT the above code would produce an output of

[6. 6.]
[6. 6.]
[7. 7.]

With the proposed pull the output would become

[5 5]
[5 5]
[5 5]

I considered many other similar examples with analogous results! Note the flow vectors are now integer arrays, but this doesn't appear to affect TINT downstream in any way.

I discovered this strange behaviour when I tried using the flow vectors to estimate object (in my case mesoscale convective system) velocities, calculated from a 2.5 km resolution radar dataset, with scans every 10 minutes. In this case, a 2 pixel error in each dimension corresponds to a velocity magnitude error of 11.8 m/s, and given that a typical system moves ~10 m/s my velocities also often pointed in the completely wrong direction! Note errors of 2 pixels will probably minimally affect TINT's object matching functions - especially in my case as my objects are generally large. However, because other users may also consider using the flow vectors as velocity estimates I think it's still worth considering this a bug.

The changes I've made to phase_correlation.py are very simple. I've just replaced the rounding functions in fft_flowvectors and fft_shift with np.ceil, and changed the final expression for pshift in fft_flowvectors to better reflect the way fft_shift actually determines the new ``center" point of the matrix.

zssherman commented 5 years ago

Thanks @eshort0401 ! Looks good to me, and passing so merging.