0

I'm trying to write a C# console application that takes an image with text in it and rotate it so the text is as close to horizontal as possible so that OCR is more accurate.

Using AWS Rekognition I can get a bounding box with corner points which provide a guide as to the rotation needed however I don't have the maths ability to work out what sort of algorithm would work best.

As an example, AWS will provide these relative coordinates:

"X": 0.6669167280197144, "Y": 0.6940382719039917

"X": 0.759939968585968, "Y": 0.681664764881134

"X": 0.7622751593589783, "Y": 0.7211361527442932

"X": 0.6692519187927246, "Y": 0.7335096001625061

So far, I've tried using either the top or bottom "Y" coordinates to create a ratio and then multiplying that by either 6 or -6.

This is the code I've tried.

var rotationAngle = (int)Math.Round(coordRatio * 6 * rotationDirection);

OR

var rotationAngle = Math.Sin(Math.Cos(coordRatio * Math.PI)) * 10 * rotationDirection;
ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
  • Where are you coming up with your multiplier -6, 6, or 10? You can calculate the necessary rotation angle by picking any edge and using basic trig. Draw a sample rotated rectangle out on paper, draw the correctly rotated angle, and consider what Sin and Cos mean. – Eric J. Sep 10 '19 at 02:11
  • Compute approximate width and height of the line. A simple formula, `w = length(p1+p3-p2-p4)/2`, `h = length(p1+p2-p3-p4)/2`, I might have missed the order, the idea is compute length of segments connecting opposite mid.points of the quad. Construct affine transform matrix that maps the quad you have on input into axis aligned rectangle of that size. Transform the image with that matrix. Unlike just rotation, this should also compensate for skew or perspective distortions, both happen in practice when people using smartphones instead of scanners. – Soonts Sep 10 '19 at 02:36
  • Thanks @EricJ. Drawing it up on paper helped a lot. TAN(Opp/Adj) gives me the angle of the top of the bounding box however since the image is rotated around the midpoint of the image rather than where the angle is calculated the value is not correct. – user3011051 Sep 10 '19 at 04:05
  • Thanks @Soonts. Your solution sounds like it is exactly what I need however I don't really understand your answer. Are you able to provide more details for a maths noob like me? – user3011051 Sep 10 '19 at 04:07
  • [See here](https://stackoverflow.com/questions/29622850/getting-values-from-mouse-hover-on-a-class-object-c-sharp/29644962#29644962) – TaW Sep 10 '19 at 04:33

1 Answers1

2

This seems like it should be reasonably simple trig.

Given the x and y coordinates of a point we can get the angle of that point in radians clockwise from the 'up' vector ({x:0, y:1}) using the Math.Atan2 method:

double x = 1;
double y = 1;
double radians = Math.Atan2(x, y);

radians is set to 0.7853981... (or 45 degrees).

We can use this to find the angle between two points by finding the different between the points and calculate the angle as above:

Point p1 = new Point(0.6669167280197144d, 0.6940382719039917d);
Point p2 = new Point(0.759939968585968d, 0.681664764881134);
Point difference = p2 - p1;
double radians = Math.Atan2(difference.X, difference.Y);

(Using a very simple Point class I just threw together.)

This results in 1.70303529... radians (97.5767... degrees). Walking the list of points gives us... some strange results:

          Radians     Degrees
-------------------------------
p1 - p0   1.7030353   97.576734
p2 - p1   0.0590928   3.3857640
p3 - p2  -1.4385580  -82.423302
p0 - p3  -3.0824998  -176.61423

Sadly it doesn't look like this is a simple problem after all. We can figure out the angles between any two points, but it doesn't look like we've got a proper rectangle defined here. It looks like it might be a parallelogram. We have two pairs of roughly parallel lines, but those pairs are not at right angles. Internal angles are approximately 94.2 and 85.8 degrees.

In order to fix this image you'll probably want to start by rotating it so that the longest sides ([p0,p1] and [p3,p0]) are horizontal. This would be a rotation of (90 - 97.576734 = -7.576734 degrees, or 1.5707963 - 1.7030353 = -0.1322383 radians), preferably around the center of the points ({X: 0.7145959, Y: 0.7075872}). Then you can work out the skew value and fix the parallelogram back into a rectangle.

Corey
  • 15,524
  • 2
  • 35
  • 68
  • Thanks @corey. I'm not sure that I fully understand your answer but it's definitely pointed me in the right direction. – user3011051 Sep 11 '19 at 01:25
  • If you need more explanation on any of the bits let me know. It was fun to play with. If you get nothing else from it, `Math.Atan2` is a useful thing to know about. – Corey Sep 11 '19 at 01:48