# 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@"https://i.stack.imgur.com/rRCH5.png";
cc    = ComponentMeasurements[MaxDetect[r = Radon@i, .1], "Centroid"];
angle = -cc[[All, 2, 1]] Pi/First@ImageDimensions@r// Mean; 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. Feb 29, 2016 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 Feb 29, 2016 at 17:55
• @andre You may use cc = ComponentMeasurements[ MaxDetect[r = #, FindThreshold@#] &@Radon@i, "Centroid"]; if you don't like my heuristics Feb 29, 2016 at 18:01
– mrz
Feb 29, 2016 at 18:12
• @Dr. belisarius It's clear. Thanks ! Feb 29, 2016 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["https://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, 2016 at 13:39

Another maybe interesting method strike on me with PrincipalComponents:

img = Import["https://i.stack.imgur.com/rRCH5.png"];
inipos = Position[
ImageData@
1., {2}];
mat = FindGeometricTransform[PrincipalComponents[N@inipos],
inipos][];
ImageRotate@ImageTransformation[img, mat, PlotRange -> All] – yode
Mar 4, 2016 at 20:37
• Nice :). Also ImageForwardTransformation[#, Last@FindGeometricTransform[PrincipalComponents[#], #, Transformation -> "Rigid"] &@ N@Position[ImageData@MaxDetect[#, .1], 1, {2}], PlotRange -> All] &@img Mar 5, 2016 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 Mar 5, 2016 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, 2016 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@"https://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, 2016 at 9:18