Phase Correlation - Poor Performance on Noisy/Blurred Images? I have successfully tested 1D phase correlation algorithm to determine vertical shift between two synthetic images.

When I moved to real images, however, it is not able to detect translation at all (the peak is located at 0, which is wrong result).

I have the following images:

  

And resulting phase correlation (Magnitude, Real, Imaginary):







The first scanline of the image is completely white, but the shift is obviously larger (20 pixels).

The expected result is white line on 20th row which happens only on synthetic images or light noise.

My algorithm is very simple - for each image column:


Compute 1D FT of source and target image columns (a=FT(A), b=FT(B))
Compute cross-power spectrum (cross_power = a *. conj(b) / |a *. conj(b)|) - *. denotes pointwise mutliplication, conj(x) denotes complex conjugate
Compute phase correlation (phase = IFT(cross_power))
Find maximum magnitude in every column of phase.
Find consensus peak location (e.g. median of detected peak locations)


Can you please advise me how to improve baseline phase correlation algorithm to deal with real-world (noisy) images?

Should I rather use NCC (Normalized Cross Correlation) instead of FFT-based phase correlation?



UPDATE

I was experimenting with zero padding to rule out errors introduced by circular shifting (only simple linear shifting of images is desirable) and tested this on original images from Wikipedia:

  

The single peak is clearly there as it should be:



However - if I perform slight smoothing (Gaussian blur) to reduce noise and actually improve the result, the phase correlation comes out totally mangled:

  



Here is the enhanced version - the original peak is weaker (why??) and there appeared new peaks around zero shifts (why??):
One-dimensional version

The one-dimensional version that you list won't work. When there is a large enough shift in images (more than one or two pixels in real-world images), there will be nothing relating the column pixels.

For an example of this, try:

I5 = rand(100,100)*255;
I6 = zeros(100,100);
I6(11:100,22:100) = I5(1:90,1:79);


So that we have I5:



and I6:



Then the one-dimensional phase correlation is just:



whereas the two-dimensional phase correlation is:



It's a bit hard to see, but there is a very high peak in the bottom-righthand corner of the image. No clear peak exists in the one dimensional version.

Why doesn't smoothing help? #1

What correlation is trying to do is to find "similar" variations in each image.  If the underlying signals are sufficiently random, then this will work well: the correlation of white noise with itself gives a really nice peak at the origin, and close-to-zero elsewhere.

Smoothing a "random" image with a Gaussian will have the effect of smoothing out the correlation your expecting --- spreading the energy in any peaks over a wider area.

Smoothing has the opposite effect of "pre-whitening" the image. Pre-whitening (as the name suggests) tries to make the image more like white noise --- which has the best form if we are doing correlation-based detection (in that the peak is well-localized).

What you are better off doing is using the matlab diff operation for a simplistic, but surprisingly effective, way of pre-whitening images.

See this example.

Why doesn't smoothing help? #2

Why does smoothing cause the extra peaks?

If you smooth each image with a kernel $k(x,y)$ then we get:
$$
h_a = g_a \star k\\
h_b = g_b \star k
$$
where $\star$ is convolution.

Now,
$$
H_a = K G_a\\
H_b = K G_b\\
R = \frac{H_a H_b^*}{|H_a H_b^*|} = \frac{|K|^2G_a G_b^*}{|K|^2|G_a G_b^*|}\\ 
=  \frac{G_a G_b^*}{|G_a G_b^*|}
$$

What I suspect is happening (though I am not sure) is that perhaps your kernel has near-zero values in the frequency domain, causing numerical problems?

If I apply a kernel:

K = one(5,5);


to my random images, then I get:



for the two-dimensional correlation, which makes the peak more spread out, but does not exhibit the problems you are seeing.