Thursday 20 June 2013

Moment-Based De-skewing

I needed to discover the orientation of an object in a binary image then de-skew the image. Hough transform would not work for me cause I needed speed so I opted for the use of image moments. Using second order central moments, it is possible to calculate the angle that the major axis of the object forms with the horizontal axis. The algorithm used can determine this angle to within ±90 degrees. So let get started.

Code

import cv2
from math import atan, pi, ceil

img  =  cv2.imread('mask3.jpg', 0)
h,w = img.shape[:2]
cv2.imshow('original', img)
m = cv2.moments(img)

# You can read about Image Moments 
# Chapter 18 Shape analysis - Page 633 
# Digital Image Processing 4th Edition By William K. Pratt
# OR http://en.wikipedia.org/wiki/Image_moment

x = m['m10']/m['m00']
y = m['m01']/m['m00']
mu02 = m['mu02']
mu20 = m['mu20']
mu11 = m['mu11']

lambda1 = 0.5*( mu20 + mu02 ) + 0.5*( mu20**2 + mu02**2 - 2*mu20*mu02 + 4*mu11**2 )**0.5
lambda2 = 0.5*( mu20 + mu02 ) - 0.5*( mu20**2 + mu02**2 - 2*mu20*mu02 + 4*mu11**2 )**0.5 
lambda_m = max(lambda1, lambda2)

# Convert from radians to degrees
angle = atan((lambda_m - mu20)/mu11)*180/pi

print angle

# Create a rotation matrix and use it to de-skew the image.
center = tuple(map(int, (x, y)))
rotmat = cv2.getRotationMatrix2D(center, angle , 1)
rotatedImg = cv2.warpAffine(img, rotmat, (w, h), flags = cv2.INTER_CUBIC)       
   
cv2.imshow('final', rotatedImg)
cv2.waitKey()

Results

I would not be explaining the maths behind Image moments, if you care to know more check the reference in the code. Nothing explains code better than some tests! Here are a few test images and the de-skewed resulting images.

Original Image De-skewed Image Orientation (degree)
-89.99
-0.0
-39.03
46.95
3.57

Conclusion

As you can see the algorithm works pretty well, an anticlockwise skew returns a negative angle and a clockwise skew returns a positive angle. Be aware the results you get will vary based on the quality of the segmented mask. Low quality (see last test image) segmentation would change the centre of the mask and this would after the calculated angle. So depending on your case you might need some pre-processing before de-skewing. Please feel free to post questions in the comments. Happy Coding!

4 comments:

  1. angle = calculation from radians to degrees, does not give correct angle on image with text lines, I made some correction instead 18000 I set 1800, I checked for skews about 2%-3% it gave correct angle, have I made correctly ?

    ReplyDelete
    Replies
    1. I have made some corrections to the code, please have a look at it

      Delete
    2. yes, now it correct,
      I took examples for theta calculate also from houghLines with Atan2
      thanks for correction.
      your code for deskew, I found is the only one works accuratly with openCV.
      for diversified images

      Delete
  2. images, on invoices with frames (vertical and horizontals) it gives not accurate angles the (the angle is about 30% skew) , on "smooth" images, like your rectangles examles, the angle is correct,
    can you advice something about ?

    ReplyDelete