35

Detect angle and rotate image in python

I want to detect an angle (i.e, A) on the left hand side of figure (a) and rotate it in a correct one (i.e. figure b). This image is an answer sheet paper.

How can I do this in Python?

Martin Evans
  • 45,791
  • 17
  • 81
  • 97
Welcome789
  • 525
  • 2
  • 6
  • 11

1 Answers1

69

You could use OpenCV with HoughLines to detect lines in the image. The angle of each of the lines can be found from this:

import numpy as np
import cv2
import math
from scipy import ndimage

img_before = cv2.imread('rotate_me.png')

cv2.imshow("Before", img_before)    
key = cv2.waitKey(0)

img_gray = cv2.cvtColor(img_before, cv2.COLOR_BGR2GRAY)
img_edges = cv2.Canny(img_gray, 100, 100, apertureSize=3)
lines = cv2.HoughLinesP(img_edges, 1, math.pi / 180.0, 100, minLineLength=100, maxLineGap=5)

angles = []

for [[x1, y1, x2, y2]] in lines:
    cv2.line(img_before, (x1, y1), (x2, y2), (255, 0, 0), 3)
    angle = math.degrees(math.atan2(y2 - y1, x2 - x1))
    angles.append(angle)

cv2.imshow("Detected lines", img_before)    
key = cv2.waitKey(0)

median_angle = np.median(angles)
img_rotated = ndimage.rotate(img_before, median_angle)

print(f"Angle is {median_angle:.04f}")
cv2.imwrite('rotated.jpg', img_rotated)  

This would give you an output as:

rotated image

It shows the lines that were detected to rotate. The angle calculated is:

Angle is 3.9793

statistics.median() could also be used instead of the numpy version if you are using Python 3.4 or later.

Note: angles holds the list of angles found which could be both vertical or horizontal. Depending on the image, you might find it better to use a different method to decide on which angle to use to rotate the image with. For example you could filter only angles which fall within a certain range before using the median function on them.

Martin Evans
  • 45,791
  • 17
  • 81
  • 97
  • 2
    Thank you so much Martin Evans, it helps me a lot. I want to find the angle, and that is a good answer. – Welcome789 Oct 13 '17 at 15:13
  • is there a way we can change the background black colour with the same white colour after rotation ? thank you – DataDoctor Jan 06 '20 at 18:57
  • 5
    You could try and investigate the `cval` parameter for the [`rotate`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.rotate.html#scipy-ndimage-rotate) function. – Martin Evans Jan 06 '20 at 19:36
  • 1
    Shouldn't the for loop be `for [[x1, y1, x2, y2]] in lines:`? And btw, if you write `print(...)` it's python3 compatible ;) – myrdd Aug 29 '20 at 08:25
  • @MartinEvans Sorry to bother you Martin, I'm trying to solve the exact same problem using your code. But when it comes to OpenCV and image processing I'm completely off. If it possible for you can you please explain what might cause the angle to be calculated as zero? Thank you. – Ravexina Dec 10 '20 at 22:22
  • I suggest you first try with the image shown above to test it gives a similar result with your setup. Your image might have a much higher resolution and so would probably need different settings for `Canny()` and `HoughLinesP()`. A possible workaround would be to first resize your image. – Martin Evans Dec 11 '20 at 08:53
  • Thanks @MartinEvans. I've already tried poking around the values and resizing the image. I've posted my question [here](https://stackoverflow.com/questions/65256508/automatically-rotate-transform-picture-using-opencv). If it's possible for you, I would be thankful if you could check it out and give your opinion on it. Thanks. – Ravexina Dec 11 '20 at 18:17
  • For the image in your example the code is actually working but most of the lines are actually straight. My example uses a `median()` of all values which is why you are getting `0`. Do a `print(angles)` and it will show you all the angles found. You could then use different logic to pick the angle you need. – Martin Evans Dec 14 '20 at 21:28
  • @MartinEvans I am trying to solve a use-case similar to [link](https://stackoverflow.com/questions/74015306/correct-the-object-orientation-in-the-image-calculate-the-correct-angle-of-rota). Can you please look this once? – Ekanshu Nov 09 '22 at 11:40
  • When I used this code with a medical form, the page is oriented landscape. The detected angle is -90 so is rotated 90 clockwise and its flipped down. I'm not understanding why this is happening. – eduardosufan Jul 27 '23 at 13:58
  • I suggest you print `angles` to see the angles that are being detected. For your case, it might be better to first discard entries that do not fall within a certain range before applying the median function. – Martin Evans Jul 27 '23 at 18:56