The Cross-Correlation package is available on github: https://github.com/keflavich/image_registration.

The goal is to determine the offset between two images with primarily extended structure.

In [1]:
# import statement (with warnings silenced).   
with warnings.catch_warnings():
    warnings.filterwarnings("ignore")
    import image_registration
errmsgs = np.seterr(all='ignore') # silence warning messages about div-by-zero
Activating auto-logging. Current session state plus future input saved.
Filename       : /Users/adam/agpy/ipython_log_2012-09-03.py
Mode           : append
Output logging : True
Raw input log  : False
Timestamping   : False
State          : active
 Logging to /Users/adam/agpy/ipython_log_2012-09-03.py
In [8]:
# create a simulated image by randomly sampling from a power-law power spectrum with alpha=2
im1 = image_registration.tests.make_extended(100)
# create an offset version corrupted by noise
im2 = image_registration.tests.make_offset_extended(im1, 4.76666, -12.33333333333333333333333, noise=0.1)
subplot(121); img1=imshow(im1)
subplot(122); img2=imshow(im2)
In [3]:
# Run the registration methods 100 times each (and hide the output)
offsets_n1,eoffsets_n1 = image_registration.tests.compare_methods(im1,im2,noise=0.1)
Processed: 0 offsets in 0:00:00  0%                                            
Processed: 1 offsets in 0:00:00  1%                                            Processed: 2 offsets in 0:00:00  2%                                            
Processed: 3 offsets in 0:00:00  3%                                            Processed: 4 offsets in 0:00:00  4%                                            
Processed: 5 offsets in 0:00:00  5%                                            Processed: 6 offsets in 0:00:00  6%                                            
Processed: 7 offsets in 0:00:01  7%                                            Processed: 8 offsets in 0:00:01  8%                                            
Processed: 9 offsets in 0:00:01  9%                                            Processed: 10 offsets in 0:00:01 10%                                           
Processed: 11 offsets in 0:00:01 11%                                           Processed: 12 offsets in 0:00:01 12%                                           
Processed: 13 offsets in 0:00:02 13%                                           Processed: 14 offsets in 0:00:02 14%                                           
Processed: 15 offsets in 0:00:02 15%                                           Processed: 16 offsets in 0:00:02 16%                                           
Processed: 17 offsets in 0:00:02 17%                                           Processed: 18 offsets in 0:00:02 18%                                           
Processed: 19 offsets in 0:00:02 19%                                           Processed: 20 offsets in 0:00:03 20%                                           
Processed: 21 offsets in 0:00:03 21%                                           Processed: 22 offsets in 0:00:03 22%                                           
Processed: 23 offsets in 0:00:03 23%                                           Processed: 24 offsets in 0:00:03 24%                                           
Processed: 25 offsets in 0:00:03 25%                                           Processed: 26 offsets in 0:00:03 26%                                           
Processed: 27 offsets in 0:00:04 27%                                           Processed: 28 offsets in 0:00:04 28%                                           
Processed: 29 offsets in 0:00:04 29%                                           Processed: 30 offsets in 0:00:04 30%                                           
Processed: 31 offsets in 0:00:04 31%                                           Processed: 32 offsets in 0:00:04 32%                                           
Processed: 33 offsets in 0:00:04 33%                                           Processed: 34 offsets in 0:00:05 34%                                           
Processed: 35 offsets in 0:00:05 35%                                           Processed: 36 offsets in 0:00:05 36%                                           
Processed: 37 offsets in 0:00:05 37%                                           Processed: 38 offsets in 0:00:05 38%                                           
Processed: 39 offsets in 0:00:05 39%                                           Processed: 40 offsets in 0:00:06 40%                                           
Processed: 41 offsets in 0:00:06 41%                                           Processed: 42 offsets in 0:00:06 42%                                           
Processed: 43 offsets in 0:00:06 43%                                           Processed: 44 offsets in 0:00:06 44%                                           
Processed: 45 offsets in 0:00:06 45%                                           Processed: 46 offsets in 0:00:06 46%                                           
Processed: 47 offsets in 0:00:07 47%                                           Processed: 48 offsets in 0:00:07 48%                                           
Processed: 49 offsets in 0:00:07 49%                                           Processed: 50 offsets in 0:00:07 50%                                           
Processed: 51 offsets in 0:00:07 51%                                           Processed: 52 offsets in 0:00:07 52%                                           
Processed: 53 offsets in 0:00:07 53%                                           Processed: 54 offsets in 0:00:08 54%                                           
Processed: 55 offsets in 0:00:08 55%                                           Processed: 56 offsets in 0:00:08 56%                                           
Processed: 57 offsets in 0:00:08 57%                                           Processed: 58 offsets in 0:00:08 58%                                           
Processed: 59 offsets in 0:00:08 59%                                           Processed: 60 offsets in 0:00:09 60%                                           
Processed: 61 offsets in 0:00:09 61%                                           Processed: 62 offsets in 0:00:09 62%                                           
Processed: 63 offsets in 0:00:09 63%                                           Processed: 64 offsets in 0:00:09 64%                                           
Processed: 65 offsets in 0:00:09 65%                                           Processed: 66 offsets in 0:00:09 66%                                           
Processed: 67 offsets in 0:00:10 67%                                           Processed: 68 offsets in 0:00:10 68%                                           
Processed: 69 offsets in 0:00:10 69%                                           Processed: 70 offsets in 0:00:10 70%                                           
Processed: 71 offsets in 0:00:10 71%                                           Processed: 72 offsets in 0:00:10 72%                                           
Processed: 73 offsets in 0:00:10 73%                                           Processed: 74 offsets in 0:00:11 74%                                           
Processed: 75 offsets in 0:00:11 75%                                           Processed: 76 offsets in 0:00:11 76%                                           
Processed: 77 offsets in 0:00:11 77%                                           Processed: 78 offsets in 0:00:11 78%                                           
Processed: 79 offsets in 0:00:11 79%                                           Processed: 80 offsets in 0:00:11 80%                                           
Processed: 81 offsets in 0:00:12 81%                                           Processed: 82 offsets in 0:00:12 82%                                           
Processed: 83 offsets in 0:00:12 83%                                           Processed: 84 offsets in 0:00:12 84%                                           
Processed: 85 offsets in 0:00:12 85%                                           Processed: 86 offsets in 0:00:12 86%                                           
Processed: 87 offsets in 0:00:13 87%                                           Processed: 88 offsets in 0:00:13 88%                                           
Processed: 89 offsets in 0:00:13 89%                                           Processed: 90 offsets in 0:00:13 90%                                           
Processed: 91 offsets in 0:00:13 91%                                           Processed: 92 offsets in 0:00:13 92%                                           
Processed: 93 offsets in 0:00:13 93%                                           Processed: 94 offsets in 0:00:14 94%                                           
Processed: 95 offsets in 0:00:14 95%                                           Processed: 96 offsets in 0:00:14 96%                                           
Processed: 97 offsets in 0:00:14 97%                                           Processed: 98 offsets in 0:00:14 98%                                           
Processed: 99 offsets in 0:00:14 99%                                           Processed: 100 offsets in 0:00:14100%                                          
In [11]:
# plot the simulation data
# (note that the "gaussian" approach is hidden; it was problematic)
image_registration.tests.plot_compare_methods(offsets_n1,eoffsets_n1,dx=4.76666666,dy=-12.3333333333)
figure(2); ax=axis([4.7,4.85,-12.23,-12.43])
figure(1); ax=axis([4.7,4.85,-12.23,-12.43])
# the outputs below show the x,y standard deviations (i.e., the "simulated error"), 
# the means of the reported errors (i.e., the measured errors)
# and the ratio of the measured error to the simulated error - should be ~1 if correct
# the black X is the correct answer
Standard Deviations:  [ 0.00471562  0.00529775  0.00503669  0.00506778  0.          0.
  0.00464351  0.00482529]
Error Means:  [ 0.00497512  0.00497512  0.0727985   0.07114768  0.          0.
  0.00490234  0.00476562]
emeans/stds:  [  1.05503078   0.93910169  14.45364199  14.03922113          nan
          nan   1.05574073   0.98763573]
In [10]:
# plot the simulation data but zoomed in more (same as above otherwise)
# (note that the "gaussian" approach is hidden; it was problematic)
image_registration.tests.plot_compare_methods(offsets_n1,eoffsets_n1,dx=4.76666666,dy=-12.3333333333)
figure(2); ax=axis([4.74,4.79,-12.32,-12.35])
figure(1); ax=axis([4.74,4.79,-12.32,-12.35])
# the outputs below show the x,y standard deviations (i.e., the "simulated error"), 
# the means of the reported errors (i.e., the measured errors)
# and the ratio of the measured error to the simulated error - should be ~1 if correct
# the black X is the correct answer
Standard Deviations:  [ 0.00471562  0.00529775  0.00503669  0.00506778  0.          0.
  0.00464351  0.00482529]
Error Means:  [ 0.00497512  0.00497512  0.0727985   0.07114768  0.          0.
  0.00490234  0.00476562]
emeans/stds:  [  1.05503078   0.93910169  14.45364199  14.03922113          nan
          nan   1.05574073   0.98763573]

So how do these methods work? They all use the peak of the cross-correlation, which is most efficiently done via fourier transforms, to determine the offset.

The "cross_correlation_shift" function selects the cross-correlation peak, then finds the sub-pixel shift using a second order Taylor expansion.

The "register_images" function uses some linear algebra + fourier space tricks to upsample the image to determine sub-pixel shifts.

The "chi2_shift" function uses the same trick, but "automatically" determines the upsampling factor based on the $\Delta \chi^2$ values. The peak is identified, as is a region within $1\sigma$ (for 2 fitted parameters, $\Delta \chi^2<2.3$ , then the original image is magnified to include only the $1\sigma$ region.
The errors are determined by marginalizing over the other fitted parameter, BUT it is possible to return the full $\Delta \chi^2$ image if you are concerned with correlation.

In [ ]: