Extract individual field from table image to excel with OCR

前端 未结 3 923
醉酒成梦
醉酒成梦 2020-12-09 23:25

I have scanned images which have tables as shown in this image:

I am trying to extract each box separately and perform OCR but when I try to detect horizont

3条回答
  •  一整个雨季
    2020-12-10 00:00

    You're on the right track. Here's a continuation of your approach with slight modifications. The idea is:

    1. Obtain binary image. Load image, convert to grayscale, and Otsu's threshold.

    2. Remove all character text contours. We create a rectangular kernel and perform opening to only keep the horizontal/vertical lines. This will effectively make the text into tiny noise so we find contours and filter using contour area to remove them.

    3. Repair horizontal/vertical lines and extract each ROI. We morph close to fix and broken lines and smooth the table. From here we sort the box field contours using imutils.sort_contours() with the top-to-bottom parameter. Next we find contours and filter using contour area then extract each ROI.


    Here's a visualization of each box field and the extracted ROI

    Code

    import cv2
    import numpy as np
    from imutils import contours
    
    # Load image, grayscale, Otsu's threshold
    image = cv2.imread('1.jpg')
    original = image.copy()
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
    
    # Remove text characters with morph open and contour filtering
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
    opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=1)
    cnts = cv2.findContours(opening, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    for c in cnts:
        area = cv2.contourArea(c)
        if area < 500:
            cv2.drawContours(opening, [c], -1, (0,0,0), -1)
    
    # Repair table lines, sort contours, and extract ROI
    close = 255 - cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel, iterations=1)
    cnts = cv2.findContours(close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    (cnts, _) = contours.sort_contours(cnts, method="top-to-bottom")
    for c in cnts:
        area = cv2.contourArea(c)
        if area < 25000:
            x,y,w,h = cv2.boundingRect(c)
            cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), -1)
            ROI = original[y:y+h, x:x+w]
    
            # Visualization
            cv2.imshow('image', image)
            cv2.imshow('ROI', ROI)
            cv2.waitKey(20)
    
    cv2.imshow('opening', opening)
    cv2.imshow('close', close)
    cv2.imshow('image', image)
    cv2.waitKey()
    

提交回复
热议问题