Noureddinesa commited on
Commit
901dbf6
·
verified ·
1 Parent(s): c47a001

Upload 5 files

Browse files
Files changed (5) hide show
  1. App.py +19 -0
  2. README.md +12 -0
  3. arial.ttf +0 -0
  4. requirements.txt +9 -0
  5. utilitis.py +161 -0
App.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from utilitis import Draw,Add_Results
3
+ from PIL import Image
4
+
5
+ st.title("Welcome to Textra WebApp")
6
+ st.markdown("### Drag and Drop Images Here:")
7
+ st.write("(PNG, JPG, JPEG)")
8
+ uploaded_file = st.file_uploader("Or select a file:", type=["png", "jpg", "jpeg"], accept_multiple_files=False)
9
+
10
+ if uploaded_file is not None:
11
+ image = Image.open(uploaded_file)
12
+ image = image.convert("RGB")
13
+ image,Results = Draw(image)
14
+ #st.write("Predicted Text:",type(image))
15
+ st.image(image, caption="Uploaded Image", use_column_width=True)
16
+ st.sidebar.title('Results')
17
+ Add_Results(Results)
18
+
19
+
README.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: LayoutLmv3 Space
3
+ emoji: 🏢
4
+ colorFrom: green
5
+ colorTo: red
6
+ sdk: streamlit
7
+ sdk_version: 1.33.0
8
+ app_file: App.py
9
+ pinned: false
10
+ ---
11
+
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
arial.ttf ADDED
Binary file (915 kB). View file
 
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ numpy==1.26.4
2
+ paddleocr==2.7.0.3
3
+ paddlepaddle==2.6.0
4
+ pillow==10.2.0
5
+ streamlit==1.33.0
6
+ torch==2.2.2
7
+ torchaudio==2.2.2
8
+ torchvision==0.17.2
9
+ transformers==4.39.2
utilitis.py ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from paddleocr import PaddleOCR
3
+ from PIL import ImageDraw, ImageFont
4
+ import torch
5
+ from transformers import AutoProcessor,LayoutLMv3ForTokenClassification
6
+ import numpy as np
7
+
8
+ model_Hugging_path = "Noureddinesa/Output_LayoutLMv3_v2"
9
+
10
+
11
+ #############################################################################
12
+ #############################################################################
13
+ def Labels():
14
+ labels = ['InvNum', 'InvDate', 'Fourni', 'TTC', 'TVA', 'TT', 'Autre']
15
+ id2label = {v: k for v, k in enumerate(labels)}
16
+ label2id = {k: v for v, k in enumerate(labels)}
17
+ return id2label, label2id
18
+
19
+ #############################################################################
20
+ #############################################################################
21
+ def Paddle():
22
+ ocr = PaddleOCR(use_angle_cls=False,lang='fr',rec=False)
23
+ return ocr
24
+
25
+ def processbbox(BBOX, width, height):
26
+ bbox = []
27
+ bbox.append(BBOX[0][0])
28
+ bbox.append(BBOX[0][1])
29
+ bbox.append(BBOX[2][0])
30
+ bbox.append(BBOX[2][1])
31
+ #Scaling
32
+ bbox[0]= 1000*bbox[0]/width # X1
33
+ bbox[1]= 1000*bbox[1]/height # Y1
34
+ bbox[2]= 1000*bbox[2]/width # X2
35
+ bbox[3]= 1000*bbox[3]/height # Y2
36
+ for i in range(4):
37
+ bbox[i] = int(bbox[i])
38
+ return bbox
39
+
40
+
41
+ def Preprocess(image):
42
+ image_array = np.array(image)
43
+ ocr = Paddle()
44
+ width, height = image.size
45
+ results = ocr.ocr(image_array, cls=True)
46
+ results = results[0]
47
+ test_dict = {'image': image ,'tokens':[], "bboxes":[]}
48
+ for item in results :
49
+ bbox = processbbox(item[0], width, height)
50
+ test_dict['tokens'].append(item[1][0])
51
+ test_dict['bboxes'].append(bbox)
52
+
53
+ print(test_dict['bboxes'])
54
+ print(test_dict['tokens'])
55
+ return test_dict
56
+
57
+ #############################################################################
58
+ #############################################################################
59
+ def Encode(image):
60
+ example = Preprocess(image)
61
+ image = example["image"]
62
+ words = example["tokens"]
63
+ boxes = example["bboxes"]
64
+ processor = AutoProcessor.from_pretrained(model_Hugging_path, apply_ocr=False)
65
+ encoding = processor(image, words, boxes=boxes,return_offsets_mapping=True,truncation=True, max_length=512, padding="max_length", return_tensors="pt")
66
+ offset_mapping = encoding.pop('offset_mapping')
67
+ return encoding, offset_mapping,words
68
+
69
+ def unnormalize_box(bbox, width, height):
70
+ return [
71
+ width * (bbox[0] / 1000),
72
+ height * (bbox[1] / 1000),
73
+ width * (bbox[2] / 1000),
74
+ height * (bbox[3] / 1000),
75
+ ]
76
+
77
+ def Run_model(image):
78
+ encoding,offset_mapping,words = Encode(image)
79
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
80
+ # load the fine-tuned model from the hub
81
+ model = LayoutLMv3ForTokenClassification.from_pretrained(model_Hugging_path)
82
+ model.to(device)
83
+ # forward pass
84
+ outputs = model(**encoding)
85
+
86
+ predictions = outputs.logits.argmax(-1).squeeze().tolist()
87
+ token_boxes = encoding.bbox.squeeze().tolist()
88
+
89
+ width, height = image.size
90
+
91
+ id2label, _ = Labels()
92
+ is_subword = np.array(offset_mapping.squeeze().tolist())[:,0] != 0
93
+ true_predictions = [id2label[pred] for idx, pred in enumerate(predictions) if not is_subword[idx]]
94
+ true_boxes = [unnormalize_box(box, width, height) for idx, box in enumerate(token_boxes) if not is_subword[idx]]
95
+ return true_predictions,true_boxes,words
96
+
97
+
98
+ def Get_Json(true_predictions,words):
99
+ Results = {}
100
+ i = 0
101
+ for prd in true_predictions:
102
+ if prd in ['InvNum','Fourni', 'InvDate','TT','TTC','TVA']:
103
+ #print(i,prd,words[i-1])
104
+ Results[prd] = words[i-1]
105
+ i+=1
106
+ return Results
107
+
108
+
109
+ def Draw(image):
110
+ true_predictions, true_boxes,words = Run_model(image)
111
+ draw = ImageDraw.Draw(image)
112
+
113
+ label2color = {
114
+ 'InvNum': 'blue',
115
+ 'InvDate': 'green',
116
+ 'Fourni': 'orange',
117
+ 'TTC':'purple',
118
+ 'TVA': 'magenta',
119
+ 'TT': 'red',
120
+ 'Autre': 'black'
121
+ }
122
+
123
+ # Adjust the thickness of the rectangle outline and label text position
124
+ rectangle_thickness = 4
125
+ label_x_offset = 20
126
+ label_y_offset = -40
127
+
128
+ # Custom font size
129
+ custom_font_size = 25
130
+
131
+ # Load a font with the custom size
132
+ font_path = "arial.ttf" # Specify the path to your font file
133
+ custom_font = ImageFont.truetype(font_path, custom_font_size)
134
+
135
+ for prediction, box in zip(true_predictions, true_boxes):
136
+ predicted_label = prediction
137
+ # Check if the predicted label exists in the label2color dictionary
138
+ if predicted_label in label2color:
139
+ color = label2color[predicted_label]
140
+ else:
141
+ color = 'black' # Default color if label is not found
142
+ if predicted_label != "Autre":
143
+ draw.rectangle(box, outline=color, width=rectangle_thickness)
144
+ # Draw text using the custom font and size
145
+
146
+ draw.rectangle((box[0], box[1]+ label_y_offset,box[2],box[3]+ label_y_offset), fill=color)
147
+ draw.text((box[0] + label_x_offset, box[1] + label_y_offset), text=predicted_label, fill='white', font=custom_font)
148
+
149
+ # Get the Results Json File
150
+ Results = Get_Json(true_predictions,words)
151
+
152
+ return image,Results
153
+
154
+
155
+ def Add_Results(data):
156
+ # Render the table
157
+ for key, value in data.items():
158
+ data[key] = st.sidebar.text_input(key, value)
159
+
160
+ #############################################################################
161
+ #############################################################################