Mathematica Stack Exchange is a question and answer site for users of Mathematica. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have recorded images of a calibration target which I use to determine the resolution of a camera. For that I measure the distance of the parallel bright bars by measuring the brightness variation along the center of the bars perpendicular to their long side. The thickness of the bars is given.

Usually I am not able to align the target exactly in vertical direction.

An example image is given here:

enter image description here

To turn the image into the vertical direction I used a code developed by Markus van Almsick.

Do you know another alternative solution for doing such an alignment automatically?

VerticalAlignment[img_Image] :=
 Module[
  {contours = ImageAdjust@GradientFilter[img, 1], 
   dims = ImageDimensions[img], lines, intersections, phis},
  lines = 
   Map[(# - dims/2) &, ImageLines[contours, MaxFeatures -> 12], {-2}];
  intersections = Apply[
    Replace[
      RegionIntersection[InfiniteLine[#1], InfiniteLine[#2]], 
      {Point[vec : {_, _}] :> ToPolarCoordinates[vec],
       EmptyRegion[2] :> {\[Infinity], ArcTan @@ Subtract @@ #1}}
      ] &,
    Subsets[lines, {2}],
    {1}
    ];
  phis = Select[
    Cases[intersections, {_?(# > Norm[dims] &), phi_} :> 
      Mod[phi, Pi]], (Pi/3 < # < 2 Pi/3) &];
  If[
   phis == {},
   img,
   ImageRotate[img, Pi/2 - Median[phis], "MaxAreaCropping"]
   ]
  ]

VerticalAlignment[image] gives for the upper example:

enter image description here

Now I can do the following (mentioned in the beginning):

ListLinePlot[data[[All, 58, 1]], ImageSize -> Medium]

enter image description here

and determine the peak positions and their distances.

share|improve this question
1  
Strongly related if not a duplicate: "Best method to find variation in width along the image of a slit?" – Alexey Popkov Feb 29 at 13:47
up vote 13 down vote accepted

Using Radon instead of ImageLines@EdgeDetect@. No need for thinning the lines.

i     = ImageAdjust@Import@"http://i.stack.imgur.com/rRCH5.png";
cc    = ComponentMeasurements[MaxDetect[r = Radon@i, .1], "Centroid"];
angle = -cc[[All, 2, 1]] Pi/First@ImageDimensions@r// Mean;
ImageAdjust@ImageRotate[i, angle, Background -> Black] 

Mathematica graphics

The 0.1 in MaxDetect[r = Radon@i, .1] is empirical, but I found it working very well when using Radon[ ]. Otherwise you may find FindThreshold[ ] useful for estimating an ad hoc value.

Showing the alignment:

horline[i_Image, row_] := Graphics[{Orange, Thick, 
                              Line[{{0, row}, {Last@ImageDimensions@i, row}}]}]
With[{j = ImageAdjust@ImageRotate[i, angle, Background -> Black]}, 
                      Show[j, horline[j, #] & /@ cc[[All, 2, 2]]]]

Mathematica graphics

share|improve this answer
    
is there somewhere a good explanation about MaxDetect ?. I don't understand the documentation. – andre Feb 29 at 17:37
    
@andre Play with this Print[ListPlot[t = Table[Sin[3 x] + 1, {x, 0, 2 Pi, .01}]]]; Manipulate[ ListPlot[{t, MaxDetect[t, x]}, AxesOrigin -> {0, -1}], {x, 0, 2}] I believe it should be clear – Dr. belisarius Feb 29 at 17:55
    
@andre You may use cc = ComponentMeasurements[ MaxDetect[r = #, FindThreshold@#] &@Radon@i, "Centroid"]; if you don't like my heuristics – Dr. belisarius Feb 29 at 18:01
    
I vote for your solution since you answered everything what I asked and in addition measured the spacing ... thanks – mrz Feb 29 at 18:12
1  
@Dr. belisarius It's clear. Thanks ! – andre Feb 29 at 18:49

I don't know about the generality of this method, but you seem to already have a general method. This works on the image you provided, and is adapted from the code you posted,

img = Import["http://i.stack.imgur.com/rRCH5.png"];
ImageRotate[img, -ArcTan @@ 
   Flatten@(Differences /@ 
      Transpose[
       First@ImageLines[EdgeDetect@img, 
         MaxFeatures -> 1]]), "MaxAreaCropping"]

enter image description here

Essentially you just need to find one line using ImageLines and then find the angle it makes with the horizontal, then rotate it through the reverse of that angle.

share|improve this answer
    
Wau ... this is impressing ... thanks – mrz Feb 29 at 13:39

Another maybe interesting method strike on me with PrincipalComponents:

img = Import["http://i.stack.imgur.com/rRCH5.png"];
inipos = Position[
   ImageData@
    Image@First@Values@ComponentMeasurements[Binarize[img], "Mask"], 
   1., {2}];
mat = FindGeometricTransform[PrincipalComponents[N@inipos], 
    inipos][[2]];
ImageRotate@ImageTransformation[img, mat, PlotRange -> All]

enter image description here

share|improve this answer
    
@Dr. belisarius How about this? – yode Mar 4 at 20:37
1  
Nice :). Also ImageForwardTransformation[#, Last@FindGeometricTransform[PrincipalComponents[#], #, Transformation -> "Rigid"] &@ N@Position[ImageData@MaxDetect[#, .1], 1, {2}], PlotRange -> All] &@img – Dr. belisarius Mar 5 at 7:43
    
BTW you can't ping another user like this. S/he ought to be participating in the comments thread below the current answer/question. I saw it while browsing – Dr. belisarius Mar 5 at 7:45

Another method would be to minimize the height of the rotated and cropped image,

imgheight[a_?NumericQ] := 
 Last@ImageDimensions@ImageCrop@ImageRotate[Binarize@img, a]
NMinimize[{imgheight[a], -π <= a <= π}, a]
(* {92., {a -> -2.78909}} *)

The result,

ImageRotate[img, a /. %[[2]], "MaxAreaCropping"]

enter image description here

share|improve this answer
    
Also this method is very interesting ... – mrz Feb 29 at 18:08

So,I'm like the @Dr. belisarius's method with a mysterious Radon.But this solution will solve a more common case.When you original image is nearst vertical.straightimage will rotate it to vertical.If the origional image is nearst horizontal.It will do same thing.

img = ImageAdjust@Import@"http://i.stack.imgur.com/rRCH5.png";
imgrote = 
 ImageRotate[img, #, "SameRatioCropping"] & /@ Range[0, 3, 0.5]

enter image description here

straightimage[img_] := 
 Module[{lines = 
    ImageLines@
     DeleteSmallComponents[
      EdgeDetect[img, Method -> {"Canny", "StraightEdges" -> 0.4}]], 
   list},
  ImageRotate[img, 
   Mean@Select[
     list = Mod[-#, Pi/2, -Pi/4] & /@ ArcTan @@@ Subtract @@@ lines, 
     Chop[First@Commonest@Round[list, 1/1000] - #, 1/1000] === 0 &], 
   Background -> Transparent]]

Example:

straightimage /@ imgrote

enter image description here

share|improve this answer
    
Thank you .. this is very interesting – mrz Mar 4 at 9:18

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.