File size: 3,036 Bytes
2089314
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import cv2
import re
import pytesseract
import numpy as np
import gradio as gr
import pandas as pd
from pytesseract import Output
from matplotlib import pyplot as plt


# get grayscale image
def get_grayscale(image):
    return cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# noise removal
def remove_noise(image):
    return cv2.medianBlur(image,5)

#thresholding
def thresholding(image, thresh_hold=0, which='ostu'):
    if which == 'ostu':
        return cv2.threshold(image, thresh_hold, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    elif which == 'simple':
        _, img = cv2.threshold(image,thresh_hold,255,cv2.THRESH_BINARY)
        return img
    elif which == 'adaptive':
        return cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)

#dilation
def dilate(image):
    kernel = np.ones((5,5),np.uint8)
    return cv2.dilate(image, kernel, iterations = 1)

#erosion
def erode(image):
    kernel = np.ones((5,5),np.uint8)
    return cv2.erode(image, kernel, iterations = 1)

#opening - erosion followed by dilation
def opening(image):
    kernel = np.ones((5,5),np.uint8)
    return cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)

#canny edge detection
def canny(image):
    return cv2.Canny(image, 100, 200)

#skew correction
def deskew(image):
    coords = np.column_stack(np.where(image > 0))
    angle = cv2.minAreaRect(coords)[-1]
    if angle < -45:
        angle = -(90 + angle)
    else:
        angle = -angle
    (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)
    return rotated

#template matching
def match_template(image, template):
    return cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)

def show_cvimg(img, figsize=(15, 15)):
    fig, ax = plt.subplots(dpi=80, figsize=figsize)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    ax.imshow(img)


def extract_purchased_items(txt):
    pat = '.*\s*(FB|FA|NB)'
    p = re.compile("(.*) (\d+[,\.\/\:\']*\d+) (FB|FA|NB)")

    txts = txt.split('\n')
    items = []
    not_parsed = []
    for t in txts:
        if re.match(pat, t):
            result = p.search(t)
            if result is not None:
                items.append({'item': result.group(1),
                              'price': re.sub('[,\.\/\:\']', '.', result.group(2)),
                              'type': result.group(3)
                             })
            else:
                not_parsed.append({'not parsed': t})
    return pd.DataFrame(items), pd.DataFrame(not_parsed)


def parse_receipt(img, **kwargs):
    # preprocessing
    gray = get_grayscale(img)
    thresh = thresholding(gray, **kwargs)

    # ocr
    custom_config = r'--oem 3 --psm 6'
    txt = pytesseract.image_to_string(thresh, config=custom_config)

    return extract_purchased_items(txt)


iface = gr.Interface(fn=parse_receipt, inputs="image", outputs=["dataframe", "dataframe"])
iface.launch()