2

In this image I am trying to detect horizontal lines. The code works well when image is not skewed. However, it is not working on such skewed images. I have tried this method to detect the right angle by histogram but many times is actually making it more skewed - python-opencv-skew-correction-for-ocr

Skewed image

Below is code to detect horizontal lines:

    gray=cv2.cvtColor(img_final_bin,cv2.COLOR_BGR2GRAY)
    horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (100,1))
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
    detected_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
    cnts, hierarchy = cv2.findContours(detected_lines, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)


    boundingBoxes = [list(cv2.boundingRect(c)) for c in cnts]

Below is the code for skew correction, which is giving wrong results to me:

def correct_skew(image, delta=0.001, limit=3):
    def determine_score(arr, angle):
        data = inter.rotate(arr, angle, reshape=False, order=0)
        histogram = np.sum(data, axis=1)
        score = np.sum((histogram[1:] - histogram[:-1]) ** 2)
        return histogram, score

    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] 

    print("thresh", thresh.shape)
    thresh1 = thresh[0:500, 0:500]
    print("thresh1", thresh1.shape)

    scores = []
    angles = np.arange(-limit, limit + delta, delta)
    for i, angle in enumerate(angles):
        histogram, score = determine_score(thresh1, angle)
        scores.append(score)
        # if i%100 == 0:   
        #     print(score, angle, len(angles), i)

    best_angle = angles[scores.index(max(scores))]

    (h, w) = image.shape[:2]
    center = (w // 2, h // 2)
    M = cv2.getRotationMatrix2D(center, best_angle, 1.0)
    rotated = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_CUBIC, \
              borderMode=cv2.BORDER_REPLICATE)

    return best_angle, rotated
Community
  • 1
  • 1
Sandeep Bhutani
  • 589
  • 7
  • 23
  • How about taking an image of some perfectly horizontal text and lines, rotating it through a few known angles and seeing what result you get from the algorithm and how the corrected version compares to the original? – Mark Setchell Apr 26 '20 at 16:51
  • Thanks for looking into this.. i have tried this on many variations.. few times it has given good results but most of times it fails.... I am looking for some better skew correction algo , or if this is correct the what is mistake in this... If someone has experience on such issues, then they can try the image I have attached – Sandeep Bhutani Apr 26 '20 at 16:55
  • Maybe if the skew angle is 17, you need to rotate by -17 as the correction? I'm guessing, obviously, but I am sure some testing will help. – Mark Setchell Apr 26 '20 at 16:57
  • the skew angle returned by above code is incorrect.. for example the image i have shown above is actually the output of this algo,, origionally it was little skewed now it is more skewed – Sandeep Bhutani Apr 26 '20 at 17:14

1 Answers1

5

Python Wand, which is based upon ImageMagick has a deskew function.

Input:

enter image description here


from wand.image import Image
from wand.display import display

with Image(filename='table.png') as img:
    img.deskew(0.4*img.quantum_range)
    img.save(filename='table_deskew.png')
    display(img)


Result:

enter image description here

fmw42
  • 46,825
  • 10
  • 62
  • 80
  • Thanks.. it seem to work on this image... but would it work on other images too or the threshold 0.4*img.quantum_range is customized for this image only? – Sandeep Bhutani Apr 26 '20 at 18:36
  • The threshold of 0.4*img.quantum_range is typical value use for almost all images, especially of black text on white background. However, if there is too few lines of text, it may not work too well. The more rows of text the better. – fmw42 Apr 26 '20 at 18:39
  • Do you know the actual *"units"* of what the threshold represents please, Fred? 40% of what? – Mark Setchell Apr 27 '20 at 13:24
  • Mark, no I do not. It is some internal threshold value in a radon transformation. You would have to look at the code to see how it is being used. – fmw42 Apr 27 '20 at 17:12