# How to align rotated images vertically

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: 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[
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 :> {\[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: Now I can do the following (mentioned in the beginning):

ListLinePlot[data[[All, 58, 1]], ImageSize -> Medium] and determine the peak positions and their distances.

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] 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]]]] • is there somewhere a good explanation about MaxDetect ?. I don't understand the documentation. – andre314 Feb 29 '16 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 '16 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 '16 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 '16 at 18:12
• @Dr. belisarius It's clear. Thanks ! – andre314 Feb 29 '16 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"] 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.

• Wau ... this is impressing ... thanks – mrz Feb 29 '16 at 13:39

Another maybe interesting method strike on me with PrincipalComponents:

img = Import["http://i.stack.imgur.com/rRCH5.png"];
inipos = Position[
ImageData@
1., {2}];
mat = FindGeometricTransform[PrincipalComponents[N@inipos],
inipos][];
ImageRotate@ImageTransformation[img, mat, PlotRange -> All] • @Dr. belisarius How about this? – yode Mar 4 '16 at 20:37
• Nice :). Also ImageForwardTransformation[#, Last@FindGeometricTransform[PrincipalComponents[#], #, Transformation -> "Rigid"] &@ N@Position[ImageData@MaxDetect[#, .1], 1, {2}], PlotRange -> All] &@img – Dr. belisarius Mar 5 '16 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 '16 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 /. %[], "MaxAreaCropping"] • Also this method is very interesting ... – mrz Feb 29 '16 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] 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 • Thank you .. this is very interesting – mrz Mar 4 '16 at 9:18