2

I'm using cv2.HoughLinesP() and it's giving me lines it has detected. These lines are mostly accurate at finding the angle of the object. Then, I want to rotate the original image according to these lines.

My image:

enter image description here

My code:

import cv2 as cv
import numpy as np
img = cv.imread(img)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray,50,150,apertureSize = 3)
lines = cv.HoughLinesP(edges,1,np.pi/180,100,minLineLength=100,maxLineGap=10)
for line in lines:
    x1,y1,x2,y2 = line[0]
    cv.line(img,(x1,y1),(x2,y2),(0,255,0),5)
cv2.imshow('', img)
cv2.waitKey()

The result:

enter image description here

What I want:

enter image description here

nathancy
  • 42,661
  • 14
  • 115
  • 137
Nicolas Gervais
  • 33,817
  • 13
  • 115
  • 143
  • 1
    From the line end points, compute the angle of the lines and the length. Assuming you want landscape mode, find the longer two lines. Then average their angles. Then use the angle to rotate the line. See https://math.stackexchange.com/questions/707673/find-angle-in-degrees-from-one-point-to-another-in-2d-space – fmw42 Feb 24 '20 at 20:02
  • But why not just get the contour and then rotated bounding box which returns the angle. See cv2.findContours() and cv2.minAreaRect(). – fmw42 Feb 24 '20 at 20:32
  • See also https://inneka.com/ml/opencv/how-to-straighten-a-rotated-rectangle-area-of-an-image-using-opencv-in-python-2/ – fmw42 Feb 24 '20 at 20:41

1 Answers1

1

It seems you're trying to perform skew correction. Instead of using cv2.HoughLinesP to find the angle and rotate the object, you can use cv2.minAreaRect to find the angle then cv2.getRotationMatrix2D + cv2.warpAffine to deskew the image.

Input -> Output

Skew angle

-29.35775375366211

Code

import cv2
import numpy as np

# Load image, grayscale, Otsu's threshold 
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = 255 - gray
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Compute rotated bounding box
coords = np.column_stack(np.where(thresh > 0))
angle = cv2.minAreaRect(coords)[-1]

if angle < -45:
    angle = -(90 + angle)
else:
    angle = -angle
print(angle)

# Rotate image to deskew
(h, w) = image.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)

cv2.imshow('thresh', thresh)
cv2.imshow('rotated', rotated)
cv2.waitKey()

Note: For other skew correction techniques take a look at

  1. Python OpenCV skew correction

  2. How to de-skew an image

  3. Detect image orientation angle based on text direction

nathancy
  • 42,661
  • 14
  • 115
  • 137