Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I have two images from motor scan, Image1 is shifted by MxN pixels from Image2. How can I find the shift between Image1 and Image2 ?

Image -1 1 Image -2 2

If we compare the shift between the images in terms of {X,Y} I will be able to tell how many steps of the motor scan corresponds to the pixel shift on the image array sensor.

share|improve this question
    
en.wikipedia.org/wiki/Phase_correlation - dont know if there is a buitin mathematica procedure though or if you need to roll your own. –  george2079 Nov 1 '13 at 18:27
    
All answers are equally good. It wouldn't be right if I choose one of them as the right answer. –  abhilash sukumari Nov 2 '13 at 7:04

4 Answers 4

Here you have the transformation function for the images:

{i1, i2} = Import@# & /@ {"http://i.stack.imgur.com/laZeT.png", 
                          "http://i.stack.imgur.com/LAHyF.png"};  
ch = ChanVeseBinarize /@ {i1, i2};
dsc = FillingTransform /@ (DeleteSmallComponents[#, 5000] & /@ ch);
pts = ImageCorrespondingPoints[dsc[[1]], dsc[[2]]];
f   = FindGeometricTransform[pts[[1]], pts[[2]], "Transformation" -> "Translation", Method->"RANSAC"]
GraphicsGrid@{{i1, ImagePerspectiveTransformation[i2, f[[2]], DataRange -> Full]}}

Mathematica graphics

The coefficients of the translation are:

{ {-146.587}, {-14.2423} }

Here you can see how the images overlap after the transformation (Thanks to Simon for the idea)

ColorCombine[{EdgeDetect[dsc[[1]]], 
              ImagePerspectiveTransformation[EdgeDetect[dsc[[2]]], f[[2]], 
              DataRange -> Full]}]

Mathematica graphics

share|improve this answer
    
Nicely done. You can use ColorCombine[{i1, ImagePerspectiveTransformation[i2, f[[2]], DataRange -> Full]}] to show how well they overlap. –  Simon Woods Nov 1 '13 at 18:57
    
@SimonWoods Thanks! I modified your idea slightly to get a (I think) less cluttered image –  belisarius Nov 1 '13 at 19:05
    
Why do you use ChanVeseBinarize ? Is it to adjusts the levels in image, rescaling them to cover the range 0 to 1 ? –  abhilash sukumari Nov 1 '13 at 19:15

There are many different image registration algorithms, all with different advantages and disadvantages. But I usually try the simplest choice first: I simply pass the two images to ImageCorrelate.

img1 = Import["http://i.stack.imgur.com/laZeT.png"];
img2 = Import["http://i.stack.imgur.com/LAHyF.png"];
corr = ImageAdjust[ImageCorrelate[img1, img2, EuclideanDistance]]

enter image description here

Intuitively, ImageCorrelate shifts img2 by every possible offset, calculates the difference with img1 with that offset, and stores the difference in the output image. So the pixel location with the lowest value in this image corresponds to the offset that minimizes the difference:

minOffset = PixelValuePositions[corr, Min[ImageData[corr]]][[1]] - 
   ImageDimensions[img1]/2;
FlipView[{ImageTransformation[img1, TranslationTransform[minOffset ], 
   PlotRange -> Full], img2}]

enter image description here

If you look at the result of ImageCorrelate, you can see that there's one global minimum. That's the offset where the "U" shapes in the two images are aligned. There's a second local minimum left of it; That's probably where the left "leg" of one U is aligned with the right leg of the other. The shape of the correlation function around the global minimum and the relative correlation values at the local minima give a qualitative impression of the accuracy and reliability of the alignment.

EuclideanDistance compares brightness values. So the different overall brightness in the two images can "move" the minimum. If you don't want that, you can apply a filter to the images that basically removes the low-frequency background lighting changes:

filter = LaplacianGaussianFilter[#, 25] &;
corr = ImageAdjust[
  ImageCorrelate[filter[img1], filter[img2], CosineDistance]]

enter image description here

(where 25 is roughly the width of the U-shape. Details smaller than that and low-frequency changes larger than that are removed by the LoG filter.)

share|improve this answer
    
+1 Thanks for the explanations - they're very useful for learning about image-processing. Your value is {-140, -12}, @s.s.o's is {149.983, 16.172} to {146.53, 15.249}, @belisarius' is {146.587, 14.2423}, - mine is a bit off at {150.42, 30.8978}. My two manual attempts (using Get Coordinates) were at the lower end of this range, agreeing with yours. –  cormullion Nov 2 '13 at 11:21

I think ImageCorrespondingPoints is a good use of what you need. You can improve the results by more preprocessing steps. You can also check ImageFeatureTrack and FindGeometricTransform.

img1 = Import["http://i.stack.imgur.com/laZeT.png"];
img2 = Import["http://i.stack.imgur.com/LAHyF.png"];
(*preprocess images*)
images = {DeleteSmallComponents@Binarize[img1, .2], 
  DeleteSmallComponents@Binarize[img2, .2]};
(*find matching points*)
matches = 
 ImageCorrespondingPoints[images[[1]], images[[2]], 
  "Transformation" -> "Translation"];
(*Show points on images*)
MapThread[
 Show[#1, Graphics[{Cyan, 
     MapIndexed[Inset[#2[[1]], #1] & , #2]}]] &, {images, matches}]

{{{351.461, 337.156}}, {{501.884, 358.838}}}

enter image description here

Edit 1

You can also use the option "Transformation" -> "Similarity" which adjusts translation, rotation, and scaling of the images.

images = {DeleteSmallComponents@Binarize[FillingTransform@img1, .2], 
   DeleteSmallComponents@Binarize[FillingTransform@img2, .2]};
matches = 
 ImageCorrespondingPoints[images[[1]], images[[2]], 
  "Transformation" -> "Similarity"]
Show[ImageAssemble[images], 
 Graphics[{Red, PointSize[.02], 
   MapThread[
    If[#2 === Missing[], {Cyan, Point[#1]}, 
      Arrow[{#1, #2 + {ImageDimensions[img1][[1]], 0}}]] &, 
    matches]}]]

{{{353.43, 359.493}, {377.258, 359.066}}, {{503.413, 375.665}, {523.788, 374.315}}}

enter image description here

share|improve this answer

Another alternative is to use component measurements. But I don't think this will give very accurate results, because the two images are not so similar in many ways, and the images are hard to 'prepare', having a lot of noise. Anyway, it's good to show approaches that don't work so well... :)

{i1, i2} = 
 Erosion[DeleteSmallComponents[
     ChanVeseBinarize[#, TargetColor -> Gray]], 10] & /@ {image1, image2}
c1 = 1 /. ComponentMeasurements[i1, "MinimalBoundingBox"];
c2 = 1 /. ComponentMeasurements[i2, "MinimalBoundingBox"];

To see some results:

Show[
ImageCompose[image1, {image2, .5}],
 Graphics[{Opacity[0.5], White, Polygon[c1], Polygon[c2], Green, 
 Text[#, #] & /@ c1, Text[#, #] & /@ c2}]]

composition

The best 'pair' of coordinates here are the rightmost corners, giving the translation from image1 to image2 as:

{150.42, 30.8978}

which sadly is only approximately close to Belisarius' result.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.