File size: 4,454 Bytes
15f17fb
043bbad
7369767
043bbad
 
 
 
 
7369767
 
043bbad
 
 
 
 
15f17fb
 
043bbad
15f17fb
 
043bbad
15f17fb
 
 
043bbad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7369767
043bbad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15f17fb
043bbad
 
 
 
 
 
 
 
 
 
 
15f17fb
043bbad
 
 
 
 
 
15f17fb
043bbad
 
 
15f17fb
 
 
043bbad
15f17fb
043bbad
15f17fb
043bbad
15f17fb
043bbad
 
 
 
15f17fb
043bbad
7369767
 
 
 
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import hashlib
from types import SimpleNamespace
import gradio as gr
from PIL import Image
from ultralytics import YOLO
from ultralytics.utils.plotting import save_one_box
import easyocr
import zxingcpp
import numpy as np

from utils import custom_plot


model = YOLO("YOLOV8s_Barcode_Detection.pt")
reader = easyocr.Reader(['en'])
key_hash = "6734e0268423441620ada6c66bf76c255500139962741833ab33185274b8a010"
hash = lambda x: hashlib.sha256(x.encode()).hexdigest()


def process_image(input_img, activation_key, progress=gr.Progress()):
    if input_img is None:
        return None, "請上傳圖片後再進行辨識。"
    if hash(activation_key) != key_hash:
        return None, "金鑰錯誤,請確認後再試一次。"

    # Perform object detection on an image
    result = model(input_img, imgsz=(1280))[0]

    crops = []
    for d in result.boxes:
        crops.append(save_one_box(
            d.xyxy,
            result.orig_img.copy(),
            save=False,
        ))

    texts = []

    for pr, crop in enumerate(crops):
        progress((pr+1) / len(crops), desc="辨識中")
        img = Image.fromarray(crop)
        res = zxingcpp.read_barcodes(img)

        if not res:
            # rotate and retry
            for i in range(1, 8):
                res = zxingcpp.read_barcodes(img.rotate(i, resample=2))
                if res:
                    break
                res = zxingcpp.read_barcodes(img.rotate(-i, resample=2))
                if res:
                    break
            
        if not res:
            # resort to ocr the bottom-left no.
            full_res = reader.readtext(crop, allowlist='-0123456789')
            res = sorted(
                [r for r in full_res if (
                    r[0][3][0] < (img.width/4) and r[0][3][1] > (img.height/3) and
                    r[0][0][0] < (img.width/4) and r[0][0][1] > (img.height/2)
                )],
                key=lambda x: x[2], reverse=True,
            )
            if res:
                pred_text = res[0][1]
                # sanity check if the no. is not divided into multiple box
                cur_box = res[0]
                # if len(cur_box[1]) < 13:
                other_boxes = [r for r in full_res if r[1] != cur_box[1]]
                thrs = np.linalg.norm(img.size) / 25
                while other_boxes:
                    upper = np.linalg.norm(cur_box[0][1] - np.array([b[0][0] for b in other_boxes]), axis=1)
                    lower = np.linalg.norm(cur_box[0][2] - np.array([b[0][3] for b in other_boxes]), axis=1)
                    is_same = (upper < thrs) & (lower < thrs)
                    rank = sorted(
                        [(i, dist, s) for (i, dist), s in zip(enumerate(lower + upper), is_same) if s],
                        key=lambda x: x[1]
                    )
                    if rank:
                        cur_box = other_boxes[rank[0][0]]
                        other_boxes = [r for r in other_boxes if r[1] != cur_box[1]]
                        pred_text += cur_box[1]
                    else:
                        break
                # HACK
                if len(pred_text) != 15:
                    res = []
            res = [SimpleNamespace(text=pred_text)] if res else []
        
        texts.append(res[0].text if res else None)

    output_text = '\n'.join([t for t in texts if isinstance(t, str)])
    results_img = custom_plot(
        result, font_size=40, pil=True,
        barcode_texts=texts,
    )
    return results_img, output_text



# Defining the Gradio Interface
with gr.Blocks() as demo:
    gr.Markdown("# Barcode")
    gr.Markdown("請用下方 example 圖片測試條碼辨識功能,或上傳您自己的圖片。")
    
    with gr.Row():
        with gr.Column():
            input_view = gr.Image(type="pil", label="輸入圖片")
            activation_key = gr.Textbox(label="金鑰")
            btn = gr.Button("辨識", variant="primary")

            gr.Examples(examples=[["example1.jpeg", ""], ["example2.jpeg", ""]], inputs=input_view)
        with gr.Column():
            output_view = gr.Image(type="pil", label="辨識結果")
        with gr.Column():
            text_output = gr.Textbox(label="條碼內容")

    # Wire up the button
    btn.click(
        fn=process_image, 
        inputs=[input_view, activation_key],
        outputs=[output_view, text_output]
    )

if __name__ == "__main__":
    demo.launch()