Matching masked images
Ok, here's the simple method illustrated in Python:



# Correlation is convolution with one input reversed
corr = fftconvolve(img1, img2[::-1, ::-1])

# Get coordinates of peak in x, y pixels
peak = unravel_index(corr.argmax(), corr.shape)
# peak = (199, 189)
# Calculate offset from center point
print array(peak) - 199 # Offset is [  0 -10]


So it finds the vertical offset (10 pixels), but not the horizontal, as you've shown (bottom left output below).  This is because the cross-correlation output is stronger in the center when more of the input images are overlapping (gets dark toward the edges even if the inputs are identical).  (The found peak is shown with the red cross.)

And here's the method I described in the comments.  I have no idea if there's a mathematically rigorous foundation for this or if it has a name, but it produces the right results.  It may or may not be the same thing as normalized cross-correlation (I haven't bothered to decipher what Wikipedia is saying):

weighting = fftconvolve(ones(shape(img1)), ones(shape(img2)))
corr = corr / weighting # Normalize
peak = unravel_index(corr.argmax(), corr.shape)[::-1]
# peak = (224, 189)
print array(peak)-199 # Offset of [ 25 -10]


So this method works.  It normalizes every element of the output array by the number of overlapping pixels that were used to calculate that element, so that when only the thin edges of the images are overlapped, it still produces a strong output.  Now the offset from the dim square is not swamped by the white bar (lower right of image).

Note that while this works perfectly with your example images, this method doesn't work as well for real images, since the edges of the output tend to vary wildly compared to the middle, and can produce spurious peaks, but if you know the offset is constrained to less than the image width, you can look for the peak only in realistic locations near the center, ignore the edges, and it works.



Wikipedia suggests a method using windowed images which I thought might improve on this, but unless I'm doing it wrong, it doesn't:

h = hamming(shape(img1)[0]) # 1D Hamming window
ham2d = outer(h, h) # 2D Hamming window

h1 = img1 * ham2d
h2 = img2 * ham2d

corr = fftconvolve(h1, h2[::-1,::-1])
peak = unravel_index(corr.argmax(), corr.shape)[::-1]
# peak = (216, 189)
print array(peak) - 199 # Offset is [ 17 -10]


The windowing does too much, and causes it to find an erroneous peak that's in between the previous two results.