Mattral commited on
Commit
28cc9b7
Β·
verified Β·
1 Parent(s): a6259d7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +226 -7
app.py CHANGED
@@ -1,12 +1,231 @@
1
  import os
 
 
 
 
 
 
 
 
 
2
  import sys
3
 
4
- # Add the 'app' directory to sys.path
5
- app_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'app')
6
- if app_dir not in sys.path:
7
- sys.path.append(app_dir)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
- # Import and run FinalApp.py
10
- import FinalApp
11
 
12
- FinalApp.main() # Call the main function directly if defined
 
 
1
  import os
2
+ import cv2
3
+ import numpy as np
4
+ from PIL import Image
5
+ from path import Path
6
+ import streamlit as st
7
+ from typing import Tuple
8
+ import easyocr # Import EasyOCR
9
+
10
+ from pathlib import Path
11
  import sys
12
 
13
+ # Add the 'app' directory to the sys.path
14
+ # Assuming 'app' is in the current working directory
15
+ sys.path.append(str(Path(__file__).parent / 'app'))
16
+ from app.dataloader_iam import Batch
17
+ from app.model import Model, DecoderType
18
+ from app.preprocessor import Preprocessor
19
+ from streamlit_drawable_canvas import st_canvas
20
+
21
+
22
+ # Set page config at the very beginning (only executed once)
23
+ st.set_page_config(
24
+ page_title="HTR App",
25
+ page_icon=":pencil:",
26
+ layout="centered",
27
+ initial_sidebar_state="auto",
28
+ )
29
+
30
+ ms = st.session_state
31
+ if "themes" not in ms:
32
+ ms.themes = {"current_theme": "light",
33
+ "refreshed": True,
34
+
35
+ "light": {"theme.base": "dark",
36
+ "theme.backgroundColor": "black",
37
+ "theme.primaryColor": "#c98bdb",
38
+ "theme.secondaryBackgroundColor": "#5591f5",
39
+ "theme.textColor": "white",
40
+ "theme.textColor": "white",
41
+ "button_face": "🌜"},
42
+
43
+ "dark": {"theme.base": "light",
44
+ "theme.backgroundColor": "white",
45
+ "theme.primaryColor": "#5591f5",
46
+ "theme.secondaryBackgroundColor": "#82E1D7",
47
+ "theme.textColor": "#0a1464",
48
+ "button_face": "🌞"},
49
+ }
50
+
51
+
52
+ def ChangeTheme():
53
+ previous_theme = ms.themes["current_theme"]
54
+ tdict = ms.themes["light"] if ms.themes["current_theme"] == "light" else ms.themes["dark"]
55
+ for vkey, vval in tdict.items():
56
+ if vkey.startswith("theme"): st._config.set_option(vkey, vval)
57
+
58
+ ms.themes["refreshed"] = False
59
+ if previous_theme == "dark": ms.themes["current_theme"] = "light"
60
+ elif previous_theme == "light": ms.themes["current_theme"] = "dark"
61
+
62
+
63
+ btn_face = ms.themes["light"]["button_face"] if ms.themes["current_theme"] == "light" else ms.themes["dark"]["button_face"]
64
+ st.button(btn_face, on_click=ChangeTheme)
65
+
66
+ if ms.themes["refreshed"] == False:
67
+ ms.themes["refreshed"] = True
68
+ st.rerun()
69
+
70
+
71
+ def get_img_size(line_mode: bool = False) -> Tuple[int, int]:
72
+ """
73
+ Auxiliary method that sets the height and width
74
+ Height is fixed while width is set according to the Model used.
75
+ """
76
+ if line_mode:
77
+ return 256, get_img_height()
78
+ return 128, get_img_height()
79
+
80
+ def get_img_height() -> int:
81
+ """
82
+ Auxiliary method that sets the height, which is fixed for the Neural Network.
83
+ """
84
+ return 32
85
+
86
+ def infer(line_mode: bool, model: Model, fn_img: Path) -> None:
87
+ """
88
+ Auxiliary method that does inference using the pretrained models:
89
+ Recognizes text in an image given its path.
90
+ """
91
+ img = cv2.imread(fn_img, cv2.IMREAD_GRAYSCALE)
92
+ assert img is not None
93
+
94
+ preprocessor = Preprocessor(get_img_size(line_mode), dynamic_width=True, padding=16)
95
+ img = preprocessor.process_img(img)
96
+
97
+ batch = Batch([img], None, 1)
98
+ recognized, probability = model.infer_batch(batch, True)
99
+ return [recognized, probability]
100
+
101
+ def infer_super_model(image_path) -> None:
102
+ reader = easyocr.Reader(['en']) # Initialize EasyOCR reader
103
+ result = reader.readtext(image_path)
104
+ recognized_texts = [text[1] for text in result] # Extract recognized texts
105
+ probabilities = [text[2] for text in result] # Extract probabilities
106
+ return recognized_texts, probabilities
107
+
108
+
109
+
110
+ def main():
111
+
112
+ st.title('Extract text from Image Demo')
113
+
114
+ st.markdown("""
115
+ Streamlit Web Interface for Handwritten Text Recognition (HTR), Optical Character Recognition (OCR)
116
+ implemented with TensorFlow and trained on the IAM off-line HTR dataset.
117
+ The model takes images of single words or text lines (multiple words) as input and outputs the recognized text.
118
+ """, unsafe_allow_html=True)
119
+
120
+ st.markdown("""
121
+ Predictions can be made using one of two models:
122
+ - Single_Model (Trained on Single Word Images)
123
+ - Line_Model (Trained on Text Line Images)
124
+ - Super_Model ( Most Robust Option for English )
125
+ - Burmese (Link)
126
+ """, unsafe_allow_html=True)
127
+
128
+ st.subheader('Select a Model, Choose the Arguments and Draw in the box below or Upload an Image to obtain a prediction.')
129
+
130
+ #Selectors for the model and decoder
131
+ modelSelect = st.selectbox("Select a Model", ['Single_Model', 'Line_Model', 'Super_Model'])
132
+
133
+
134
+ if modelSelect != 'Super_Model':
135
+ decoderSelect = st.selectbox("Select a Decoder", ['Bestpath', 'Beamsearch', 'Wordbeamsearch'])
136
+
137
+
138
+ #Mappings (dictionaries) for the model and decoder. Asigns the directory or the DecoderType of the selected option.
139
+ modelMapping = {
140
+ "Single_Model": '../model/word-model',
141
+ "Line_Model": '../model/line-model'
142
+ }
143
+
144
+ decoderMapping = {
145
+ 'Bestpath': DecoderType.BestPath,
146
+ 'Beamsearch': DecoderType.BeamSearch,
147
+ 'Wordbeamsearch': DecoderType.WordBeamSearch
148
+ }
149
+
150
+ #Slider for pencil width
151
+ strokeWidth = st.slider("Stroke Width: ", 1, 25, 6)
152
+
153
+ #Canvas/Text Box for user input. BackGround Color must be white (#FFFFFF) or else text will not be properly recognised.
154
+ inputDrawn = st_canvas(
155
+ fill_color="rgba(255, 165, 0, 0.3)",
156
+ stroke_width=strokeWidth,
157
+ update_streamlit=True,
158
+ background_image=None,
159
+ height = 200,
160
+ width = 400,
161
+ drawing_mode='freedraw',
162
+ key="canvas",
163
+ background_color = '#FFFFFF'
164
+ )
165
+
166
+ #Buffer for user input (images uploaded from the user's device)
167
+ inputBuffer = st.file_uploader("Upload an Image", type=["png"])
168
+
169
+ #Inference Button
170
+ inferBool = st.button("Recognize Text")
171
+
172
+ # After clicking the "Recognize Text" button, check if the model selected is Super_Model
173
+ if inferBool:
174
+ if modelSelect == 'Super_Model':
175
+ inputArray = None # Initialize inputArray to None
176
+
177
+ # Handling uploaded file
178
+ if inputBuffer is not None:
179
+ with Image.open(inputBuffer).convert('RGB') as img:
180
+ inputArray = np.array(img)
181
+
182
+ # Handling canvas data
183
+ elif inputDrawn.image_data is not None:
184
+ # Convert RGBA to RGB
185
+ inputArray = cv2.cvtColor(np.array(inputDrawn.image_data, dtype=np.uint8), cv2.COLOR_RGBA2RGB)
186
+
187
+ # Now check if inputArray has been set
188
+ if inputArray is not None:
189
+ # Initialize EasyOCR Reader
190
+ reader = easyocr.Reader(['en']) # Assuming English language; adjust as necessary
191
+ # Perform OCR
192
+ results = reader.readtext(inputArray)
193
+
194
+ # Display results
195
+ all_text = ''
196
+ for (bbox, text, prob) in results:
197
+ all_text += f'{text} (confidence: {prob:.2f})\n'
198
+
199
+ st.write("**Recognized Texts and their Confidence Scores:**")
200
+ st.text(all_text)
201
+ else:
202
+ st.write("No image data found. Please upload an image or draw on the canvas.")
203
+
204
+
205
+ else:
206
+ # Handle other model selections as before
207
+ if ((inputDrawn.image_data is not None or inputBuffer is not None) and inferBool == True):
208
+ #We turn the input into a numpy array
209
+ if inputDrawn.image_data is not None:
210
+ inputArray = np.array(inputDrawn.image_data)
211
+
212
+ if inputBuffer is not None:
213
+ inputBufferImage = Image.open(inputBuffer)
214
+ inputArray = np.array(inputBufferImage)
215
+
216
+ #We turn this array into a .png format and save it.
217
+ inputImage = Image.fromarray(inputArray.astype('uint8'), 'RGBA')
218
+ inputImage.save('userInput.png')
219
+ #We obtain the model directory and the decoder type from their mapping
220
+ modelDir = modelMapping[modelSelect]
221
+ decoderType = decoderMapping[decoderSelect]
222
+
223
+ #Finally, we call the model with this image as attribute and display the Best Candidate and its probability on the Interface
224
+ model = Model(list(open(modelDir + "/charList.txt").read()), modelDir, decoderType, must_restore=True)
225
+ inferedText = infer(modelDir == '../model/line-model', model, 'userInput.png')
226
 
227
+ st.write("**Best Candidate: **", inferedText[0][0])
228
+ st.write("**Probability: **", str(inferedText[1][0]*100) + "%")
229
 
230
+ if __name__ == "__main__":
231
+ main()