10
$\begingroup$

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.

$\endgroup$
14
$\begingroup$

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

$\endgroup$
  • $\begingroup$ is there somewhere a good explanation about MaxDetect ?. I don't understand the documentation. $\endgroup$ – andre314 Feb 29 '16 at 17:37
  • $\begingroup$ @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 $\endgroup$ – Dr. belisarius Feb 29 '16 at 17:55
  • $\begingroup$ @andre You may use cc = ComponentMeasurements[ MaxDetect[r = #, FindThreshold@#] &@Radon@i, "Centroid"]; if you don't like my heuristics $\endgroup$ – Dr. belisarius Feb 29 '16 at 18:01
  • $\begingroup$ I vote for your solution since you answered everything what I asked and in addition measured the spacing ... thanks $\endgroup$ – mrz Feb 29 '16 at 18:12
  • 1
    $\begingroup$ @Dr. belisarius It's clear. Thanks ! $\endgroup$ – andre314 Feb 29 '16 at 18:49
6
$\begingroup$

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.

$\endgroup$
  • $\begingroup$ Wau ... this is impressing ... thanks $\endgroup$ – mrz Feb 29 '16 at 13:39
4
$\begingroup$

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

$\endgroup$
  • $\begingroup$ @Dr. belisarius How about this? $\endgroup$ – yode Mar 4 '16 at 20:37
  • 1
    $\begingroup$ Nice :). Also ImageForwardTransformation[#, Last@FindGeometricTransform[PrincipalComponents[#], #, Transformation -> "Rigid"] &@ N@Position[ImageData@MaxDetect[#, .1], 1, {2}], PlotRange -> All] &@img $\endgroup$ – Dr. belisarius Mar 5 '16 at 7:43
  • $\begingroup$ 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 $\endgroup$ – Dr. belisarius Mar 5 '16 at 7:45
3
$\begingroup$

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

$\endgroup$
  • $\begingroup$ Also this method is very interesting ... $\endgroup$ – mrz Feb 29 '16 at 18:08
2
$\begingroup$

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

$\endgroup$
  • $\begingroup$ Thank you .. this is very interesting $\endgroup$ – mrz Mar 4 '16 at 9:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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