Spaces:
Sleeping
Sleeping
Use streamlit_option_menu
Browse files- Home.py +13 -15
- __pycache__/multipage.cpython-37.pyc +0 -0
- app_pages/__pycache__/about.cpython-37.pyc +0 -0
- app_pages/__pycache__/home.cpython-37.pyc +0 -0
- app_pages/__pycache__/ocr_comparator.cpython-37.pyc +0 -0
- app_pages/about.py +37 -0
- app_pages/home.py +19 -0
- app_pages/img_demo_1.jpg +0 -0
- app_pages/img_demo_2.jpg +0 -0
- app_pages/ocr.png +0 -0
- pages/App.py β app_pages/ocr_comparator.py +457 -466
- multipage.py +68 -0
- pages/About.py +0 -37
- requirements.txt +2 -1
Home.py
CHANGED
@@ -1,19 +1,17 @@
|
|
1 |
import streamlit as st
|
|
|
|
|
2 |
|
3 |
-
|
4 |
-
st.
|
|
|
|
|
|
|
5 |
|
6 |
-
|
|
|
|
|
|
|
7 |
|
8 |
-
|
9 |
-
|
10 |
-
st.write("")
|
11 |
-
st.write("")
|
12 |
-
|
13 |
-
st.markdown("##### This app allows you to compare, from a given image, the results of different solutions:")
|
14 |
-
st.markdown("##### *EasyOcr, PaddleOCR, MMOCR, Tesseract*")
|
15 |
-
st.write("")
|
16 |
-
st.write("")
|
17 |
-
st.markdown("π Select the **About** page from the sidebar for information on how the app works")
|
18 |
-
|
19 |
-
st.markdown("π or directly select the **App** page")
|
|
|
1 |
import streamlit as st
|
2 |
+
from multipage import MultiPage
|
3 |
+
from app_pages import home, about, ocr_comparator
|
4 |
|
5 |
+
app = MultiPage()
|
6 |
+
st.set_page_config(
|
7 |
+
page_title='OCR Comparator', layout ="wide",
|
8 |
+
initial_sidebar_state="expanded",
|
9 |
+
)
|
10 |
|
11 |
+
# Add all your application here
|
12 |
+
app.add_page("Home", "house", home.app)
|
13 |
+
app.add_page("About", "info-circle", about.app)
|
14 |
+
app.add_page("App", "cast", ocr_comparator.app)
|
15 |
|
16 |
+
# The main app
|
17 |
+
app.run()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__pycache__/multipage.cpython-37.pyc
ADDED
Binary file (2.65 kB). View file
|
|
app_pages/__pycache__/about.cpython-37.pyc
ADDED
Binary file (2.02 kB). View file
|
|
app_pages/__pycache__/home.cpython-37.pyc
ADDED
Binary file (889 Bytes). View file
|
|
app_pages/__pycache__/ocr_comparator.cpython-37.pyc
ADDED
Binary file (46.5 kB). View file
|
|
app_pages/about.py
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
|
3 |
+
def app():
|
4 |
+
st.title("OCR solutions comparator")
|
5 |
+
|
6 |
+
st.write("")
|
7 |
+
st.write("")
|
8 |
+
st.write("")
|
9 |
+
|
10 |
+
st.markdown("##### This app allows you to compare, from a given picture, the results of different solutions:")
|
11 |
+
st.markdown("##### *EasyOcr, PaddleOCR, MMOCR, Tesseract*")
|
12 |
+
st.write("")
|
13 |
+
st.write("")
|
14 |
+
|
15 |
+
st.markdown(''' The 1st step is to choose the language for the text recognition (not all solutions \
|
16 |
+
support the same languages), and then choose the picture to consider. It is possible to upload a file, \
|
17 |
+
to take a picture, or to use a demo file. \
|
18 |
+
It is then possible to change the default values for the text area detection process, \
|
19 |
+
before launching the detection task for each solution.''')
|
20 |
+
st.write("")
|
21 |
+
|
22 |
+
st.markdown(''' The different results are then presented. The 2nd step is to choose one of these \
|
23 |
+
detection results, in order to carry out the text recognition process there. It is also possible to change \
|
24 |
+
the default settings for each solution.''')
|
25 |
+
st.write("")
|
26 |
+
|
27 |
+
st.markdown("###### The recognition results appear in 2 formats:")
|
28 |
+
st.markdown(''' - a visual format resumes the initial image, replacing the detected areas with \
|
29 |
+
the recognized text. The background is + or - strongly colored in green according to the \
|
30 |
+
confidence level of the recognition.
|
31 |
+
A slider allows you to change the font size, another \
|
32 |
+
allows you to modify the confidence threshold above which the text color changes: if it is at \
|
33 |
+
70% for example, then all the texts with a confidence threshold higher or equal to 70 will appear \
|
34 |
+
in white, in black otherwise.''')
|
35 |
+
|
36 |
+
st.markdown(" - a detailed format presents the results in a table, for each text box detected. \
|
37 |
+
It is possible to download this results in a local csv file.")
|
app_pages/home.py
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
|
3 |
+
def app():
|
4 |
+
st.image('ocr.png')
|
5 |
+
|
6 |
+
st.write("")
|
7 |
+
|
8 |
+
st.markdown('''#### OCR, or Optical Character Recognition, is a computer vision task, \
|
9 |
+
which includes the detection of text areas, and the recognition of characters.''')
|
10 |
+
st.write("")
|
11 |
+
st.write("")
|
12 |
+
|
13 |
+
st.markdown("##### This app allows you to compare, from a given image, the results of different solutions:")
|
14 |
+
st.markdown("##### *EasyOcr, PaddleOCR, MMOCR, Tesseract*")
|
15 |
+
st.write("")
|
16 |
+
st.write("")
|
17 |
+
st.markdown("π Select the **About** page from the sidebar for information on how the app works")
|
18 |
+
|
19 |
+
st.markdown("π or directly select the **App** page")
|
app_pages/img_demo_1.jpg
ADDED
app_pages/img_demo_2.jpg
ADDED
app_pages/ocr.png
ADDED
pages/App.py β app_pages/ocr_comparator.py
RENAMED
@@ -929,491 +929,482 @@ def raz():
|
|
929 |
###################################################################################################
|
930 |
## MAIN
|
931 |
###################################################################################################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
932 |
|
933 |
-
##-----------
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
<style>
|
938 |
-
section[data-testid="stSidebar"] {
|
939 |
-
width: 5rem;
|
940 |
-
}
|
941 |
-
</style>
|
942 |
-
""",unsafe_allow_html=True)
|
943 |
-
|
944 |
-
|
945 |
-
st.title("OCR solutions comparator")
|
946 |
-
st.markdown("##### *EasyOCR, PPOCR, MMOCR, Tesseract*")
|
947 |
-
#st.markdown("#### PID : " + str(os.getpid()))
|
948 |
-
|
949 |
-
# Initializations
|
950 |
-
with st.spinner("Initializations in progress ..."):
|
951 |
-
reader_type_list, reader_type_dict, list_dict_lang, \
|
952 |
-
cols_size, dict_back_colors, fig_colorscale = initializations()
|
953 |
-
img_demo_1, img_demo_2 = get_demo()
|
954 |
-
|
955 |
-
##----------- Choose language & image -------------------------------------------------------------
|
956 |
-
st.markdown("#### Choose languages for the text recognition:")
|
957 |
-
lang_col = st.columns(4)
|
958 |
-
easyocr_key_lang = lang_col[0].selectbox(reader_type_list[0]+" :", list_dict_lang[0].keys(), 26)
|
959 |
-
easyocr_lang = list_dict_lang[0][easyocr_key_lang]
|
960 |
-
ppocr_key_lang = lang_col[1].selectbox(reader_type_list[1]+" :", list_dict_lang[1].keys(), 22)
|
961 |
-
ppocr_lang = list_dict_lang[1][ppocr_key_lang]
|
962 |
-
mmocr_key_lang = lang_col[2].selectbox(reader_type_list[2]+" :", list_dict_lang[2].keys(), 0)
|
963 |
-
mmocr_lang = list_dict_lang[2][mmocr_key_lang]
|
964 |
-
tesserocr_key_lang = lang_col[3].selectbox(reader_type_list[3]+" :", list_dict_lang[3].keys(), 35)
|
965 |
-
tesserocr_lang = list_dict_lang[3][tesserocr_key_lang]
|
966 |
-
|
967 |
-
st.markdown("#### Choose picture:")
|
968 |
-
cols_pict = st.columns([1, 2])
|
969 |
-
img_typ = cols_pict[0].radio("", ['Upload file', 'Take a picture', 'Use a demo file'], \
|
970 |
-
index=0, on_change=raz)
|
971 |
-
|
972 |
-
if img_typ == 'Upload file':
|
973 |
-
image_file = cols_pict[1].file_uploader("Upload a file:", type=["jpg","jpeg"], on_change=raz)
|
974 |
-
if img_typ == 'Take a picture':
|
975 |
-
image_file = cols_pict[1].camera_input("Take a picture:", on_change=raz)
|
976 |
-
if img_typ == 'Use a demo file':
|
977 |
-
with st.expander('Choose a demo file:', expanded=True):
|
978 |
-
demo_used = st.radio('', ['File 1', 'File 2'], index=0, \
|
979 |
-
horizontal=True, on_change=raz)
|
980 |
-
cols_demo = st.columns([1, 2])
|
981 |
-
cols_demo[0].markdown('###### File 1')
|
982 |
-
cols_demo[0].image(img_demo_1, width=150)
|
983 |
-
cols_demo[1].markdown('###### File 2')
|
984 |
-
cols_demo[1].image(img_demo_2, width=300)
|
985 |
-
if demo_used == 'File 1':
|
986 |
-
image_file = 'img_demo_1.jpg'
|
987 |
-
else:
|
988 |
-
image_file = 'img_demo_2.jpg'
|
989 |
-
|
990 |
-
##----------- Process input image -----------------------------------------------------------------
|
991 |
-
if image_file is not None:
|
992 |
-
image_path, image_orig, image_cv2 = load_image(image_file)
|
993 |
-
list_images = [image_orig, image_cv2]
|
994 |
-
|
995 |
-
##----------- Form with original image & hyperparameters for detectors ----------------------------
|
996 |
-
with st.form("form1"):
|
997 |
-
col1, col2 = st.columns(2, ) #gap="medium")
|
998 |
-
col1.markdown("##### Original image")
|
999 |
-
col1.image(list_images[0], width=500, use_column_width=True)
|
1000 |
-
col2.markdown("##### Hyperparameters values for detection")
|
1001 |
-
|
1002 |
-
with col2.expander("Choose detection hyperparameters for " + reader_type_list[0], \
|
1003 |
-
expanded=False):
|
1004 |
-
t0_min_size = st.slider("min_size", 1, 20, 10, step=1, \
|
1005 |
-
help="min_size (int, default = 10) - Filter text box smaller than \
|
1006 |
-
minimum value in pixel")
|
1007 |
-
t0_text_threshold = st.slider("text_threshold", 0.1, 1., 0.7, step=0.1, \
|
1008 |
-
help="text_threshold (float, default = 0.7) - Text confidence threshold")
|
1009 |
-
t0_low_text = st.slider("low_text", 0.1, 1., 0.4, step=0.1, \
|
1010 |
-
help="low_text (float, default = 0.4) - Text low-bound score")
|
1011 |
-
t0_link_threshold = st.slider("link_threshold", 0.1, 1., 0.4, step=0.1, \
|
1012 |
-
help="link_threshold (float, default = 0.4) - Link confidence threshold")
|
1013 |
-
t0_canvas_size = st.slider("canvas_size", 2000, 5000, 2560, step=10, \
|
1014 |
-
help='''canvas_size (int, default = 2560) \n
|
1015 |
-
Maximum e size. Image bigger than this value will be resized down''')
|
1016 |
-
t0_mag_ratio = st.slider("mag_ratio", 0.1, 5., 1., step=0.1, \
|
1017 |
-
help="mag_ratio (float, default = 1) - Image magnification ratio")
|
1018 |
-
t0_slope_ths = st.slider("slope_ths", 0.01, 1., 0.1, step=0.01, \
|
1019 |
-
help='''slope_ths (float, default = 0.1) - Maximum slope \
|
1020 |
-
(delta y/delta x) to considered merging. \n
|
1021 |
-
Low valuans tiled boxes will not be merged.''')
|
1022 |
-
t0_ycenter_ths = st.slider("ycenter_ths", 0.1, 1., 0.5, step=0.1, \
|
1023 |
-
help='''ycenter_ths (float, default = 0.5) - Maximum shift in y direction. \n
|
1024 |
-
Boxes wiifferent level should not be merged.''')
|
1025 |
-
t0_height_ths = st.slider("height_ths", 0.1, 1., 0.5, step=0.1, \
|
1026 |
-
help='''height_ths (float, default = 0.5) - Maximum different in box height. \n
|
1027 |
-
Boxes wiery different text size should not be merged.''')
|
1028 |
-
t0_width_ths = st.slider("width_ths", 0.1, 1., 0.5, step=0.1, \
|
1029 |
-
help="width_ths (float, default = 0.5) - Maximum horizontal \
|
1030 |
-
distance to merge boxes.")
|
1031 |
-
t0_add_margin = st.slider("add_margin", 0.1, 1., 0.1, step=0.1, \
|
1032 |
-
help='''add_margin (float, default = 0.1) - \
|
1033 |
-
Extend bounding boxes in all direction by certain value. \n
|
1034 |
-
This is rtant for language with complex script (E.g. Thai).''')
|
1035 |
-
t0_optimal_num_chars = st.slider("optimal_num_chars", None, 100, None, step=10, \
|
1036 |
-
help="optimal_num_chars (int, default = None) - If specified, bounding boxes \
|
1037 |
-
with estimated number of characters near this value are returned first.")
|
1038 |
-
|
1039 |
-
with col2.expander("Choose detection hyperparameters for " + reader_type_list[1], \
|
1040 |
-
expanded=False):
|
1041 |
-
t1_det_algorithm = st.selectbox('det_algorithm', ['DB'], \
|
1042 |
-
help='Type of detection algorithm selected. (default = DB)')
|
1043 |
-
t1_det_max_side_len = st.slider('det_max_side_len', 500, 2000, 960, step=10, \
|
1044 |
-
help='''The maximum size of the long side of the image. (default = 960)\n
|
1045 |
-
Limit thximum image height and width.\n
|
1046 |
-
When theg side exceeds this value, the long side will be resized to this size, and the short side \
|
1047 |
-
will be ed proportionally.''')
|
1048 |
-
t1_det_db_thresh = st.slider('det_db_thresh', 0.1, 1., 0.3, step=0.1, \
|
1049 |
-
help='''Binarization threshold value of DB output map. (default = 0.3) \n
|
1050 |
-
Used to er the binarized image of DB prediction, setting 0.-0.3 has no obvious effect on the result.''')
|
1051 |
-
t1_det_db_box_thresh = st.slider('det_db_box_thresh', 0.1, 1., 0.6, step=0.1, \
|
1052 |
-
help='''The threshold value of the DB output box. (default = 0.6) \n
|
1053 |
-
DB post-essing filter box threshold, if there is a missing box detected, it can be reduced as appropriate. \n
|
1054 |
-
Boxes sclower than this value will be discard.''')
|
1055 |
-
t1_det_db_unclip_ratio = st.slider('det_db_unclip_ratio', 1., 3.0, 1.6, step=0.1, \
|
1056 |
-
help='''The expanded ratio of DB output box. (default = 1.6) \n
|
1057 |
-
Indicatee compactness of the text box, the smaller the value, the closer the text box to the text.''')
|
1058 |
-
t1_det_east_score_thresh = st.slider('det_east_cover_thresh', 0.1, 1., 0.8, step=0.1, \
|
1059 |
-
help="Binarization threshold value of EAST output map. (default = 0.8)")
|
1060 |
-
t1_det_east_cover_thresh = st.slider('det_east_cover_thresh', 0.1, 1., 0.1, step=0.1, \
|
1061 |
-
help='''The threshold value of the EAST output box. (default = 0.1) \n
|
1062 |
-
Boxes sclower than this value will be discarded.''')
|
1063 |
-
t1_det_east_nms_thresh = st.slider('det_east_nms_thresh', 0.1, 1., 0.2, step=0.1, \
|
1064 |
-
help="The NMS threshold value of EAST model output box. (default = 0.2)")
|
1065 |
-
t1_det_db_score_mode = st.selectbox('det_db_score_mode', ['fast', 'slow'], \
|
1066 |
-
help='''slow: use polygon box to calculate bbox score, fast: use rectangle box \
|
1067 |
-
to calculate. (default = fast) \n
|
1068 |
-
Use rectlar box to calculate faster, and polygonal box more accurate for curved text area.''')
|
1069 |
-
|
1070 |
-
with col2.expander("Choose detection hyperparameters for " + reader_type_list[2], \
|
1071 |
-
expanded=False):
|
1072 |
-
t2_det = st.selectbox('det', ['DB_r18','DB_r50','DBPP_r50','DRRG','FCE_IC15', \
|
1073 |
-
'FCE_CTW_DCNv2','MaskRCNN_CTW','MaskRCNN_IC15', \
|
1074 |
-
'MaskRCNN_IC17', 'PANet_CTW','PANet_IC15','PS_CTW',\
|
1075 |
-
'PS_IC15','Tesseract','TextSnake'], 10, \
|
1076 |
-
help='Text detection algorithm. (default = PANet_IC15)')
|
1077 |
-
st.write("###### *More about text detection models* π \
|
1078 |
-
[here](https://mmocr.readthedocs.io/en/latest/textdet_models.html)")
|
1079 |
-
t2_merge_xdist = st.slider('merge_xdist', 1, 50, 20, step=1, \
|
1080 |
-
help='The maximum x-axis distance to merge boxes. (defaut=20)')
|
1081 |
-
|
1082 |
-
with col2.expander("Choose detection hyperparameters for " + reader_type_list[3], \
|
1083 |
-
expanded=False):
|
1084 |
-
t3_psm = st.selectbox('Page segmentation mode (psm)', \
|
1085 |
-
[' - Default', \
|
1086 |
-
' 4 Assume a single column of text of variable sizes', \
|
1087 |
-
' 5 Assume a single uniform block of vertically aligned text', \
|
1088 |
-
' 6 Assume a single uniform block of text', \
|
1089 |
-
' 7 Treat the image as a single text line', \
|
1090 |
-
' 8 Treat the image as a single word', \
|
1091 |
-
' 9 Treat the image as a single word in a circle', \
|
1092 |
-
'10 Treat the image as a single character', \
|
1093 |
-
'11 Sparse text. Find as much text as possible in no \
|
1094 |
-
particular order', \
|
1095 |
-
'13 Raw line. Treat the image as a single text line, \
|
1096 |
-
bypassing hacks that are Tesseract-specific'])
|
1097 |
-
t3_oem = st.selectbox('OCR engine mode', ['0 Legacy engine only', \
|
1098 |
-
'1 Neural nets LSTM engine only', \
|
1099 |
-
'2 Legacy + LSTM engines', \
|
1100 |
-
'3 Default, based on what is available'], 3)
|
1101 |
-
t3_whitelist = st.text_input('Limit tesseract to recognize only this characters :', \
|
1102 |
-
placeholder='Limit tesseract to recognize only this characters', \
|
1103 |
-
help='Example for numbers only : 0123456789')
|
1104 |
-
|
1105 |
-
color_hex = col2.color_picker('Set a color for box outlines:', '#004C99')
|
1106 |
-
color_part = color_hex.lstrip('#')
|
1107 |
-
color = tuple(int(color_part[i:i+2], 16) for i in (0, 2, 4))
|
1108 |
-
|
1109 |
-
submit_detect = st.form_submit_button("Launch detection")
|
1110 |
-
|
1111 |
-
##----------- Process text detection --------------------------------------------------------------
|
1112 |
-
if submit_detect:
|
1113 |
-
# Process text detection
|
1114 |
-
|
1115 |
-
if t0_optimal_num_chars == 0:
|
1116 |
-
t0_optimal_num_chars = None
|
1117 |
-
|
1118 |
-
# Construct the config Tesseract parameter
|
1119 |
-
t3_config = ''
|
1120 |
-
psm = t3_psm[:2]
|
1121 |
-
if psm != ' -':
|
1122 |
-
t3_config += '--psm ' + psm.strip()
|
1123 |
-
oem = t3_oem[:1]
|
1124 |
-
if oem != '3':
|
1125 |
-
t3_config += ' --oem ' + oem
|
1126 |
-
if t3_whitelist != '':
|
1127 |
-
t3_config += ' -c tessedit_char_whitelist=' + t3_whitelist
|
1128 |
-
|
1129 |
-
list_params_det = \
|
1130 |
-
[[easyocr_lang, \
|
1131 |
-
{'min_size': t0_min_size, 'text_threshold': t0_text_threshold, \
|
1132 |
-
'low_text': t0_low_text, 'link_threshold': t0_link_threshold, \
|
1133 |
-
'canvas_size': t0_canvas_size, 'mag_ratio': t0_mag_ratio, \
|
1134 |
-
'slope_ths': t0_slope_ths, 'ycenter_ths': t0_ycenter_ths, \
|
1135 |
-
'height_ths': t0_height_ths, 'width_ths': t0_width_ths, \
|
1136 |
-
'add_margin': t0_add_margin, 'optimal_num_chars': t0_optimal_num_chars \
|
1137 |
-
}], \
|
1138 |
-
[ppocr_lang, \
|
1139 |
-
{'det_algorithm': t1_det_algorithm, 'det_max_side_len': t1_det_max_side_len, \
|
1140 |
-
'det_db_thresh': t1_det_db_thresh, 'det_db_box_thresh': t1_det_db_box_thresh, \
|
1141 |
-
'det_db_unclip_ratio': t1_det_db_unclip_ratio, \
|
1142 |
-
'det_east_score_thresh': t1_det_east_score_thresh, \
|
1143 |
-
'det_east_cover_thresh': t1_det_east_cover_thresh, \
|
1144 |
-
'det_east_nms_thresh': t1_det_east_nms_thresh, \
|
1145 |
-
'det_db_score_mode': t1_det_db_score_mode}],
|
1146 |
-
[mmocr_lang, {'det': t2_det, 'merge_xdist': t2_merge_xdist}],
|
1147 |
-
[tesserocr_lang, {'lang': tesserocr_lang, 'config': t3_config}]
|
1148 |
-
]
|
1149 |
-
|
1150 |
-
show_info1 = st.empty()
|
1151 |
-
show_info1.info("Readers initializations in progress (it may take a while) ...")
|
1152 |
-
list_readers = init_readers(list_params_det)
|
1153 |
-
|
1154 |
-
show_info1.info("Text detection in progress ...")
|
1155 |
-
list_images, list_coordinates = process_detect(image_path, list_images, list_readers, \
|
1156 |
-
list_params_det, color)
|
1157 |
-
show_info1.empty()
|
1158 |
-
|
1159 |
-
# Clear previous recognition results
|
1160 |
-
st.session_state.df_results = pd.DataFrame([])
|
1161 |
-
|
1162 |
-
st.session_state.list_readers = list_readers
|
1163 |
-
st.session_state.list_coordinates = list_coordinates
|
1164 |
-
st.session_state.list_images = list_images
|
1165 |
-
st.session_state.list_params_det = list_params_det
|
1166 |
-
|
1167 |
-
if 'columns_size' not in st.session_state:
|
1168 |
-
st.session_state.columns_size = [2] + [1 for x in reader_type_list[1:]]
|
1169 |
-
if 'column_width' not in st.session_state:
|
1170 |
-
st.session_state.column_width = [500] + [400 for x in reader_type_list[1:]]
|
1171 |
-
if 'columns_color' not in st.session_state:
|
1172 |
-
st.session_state.columns_color = ["rgb(228,26,28)"] + \
|
1173 |
-
["rgb(0,0,0)" for x in reader_type_list[1:]]
|
1174 |
-
|
1175 |
-
if st.session_state.list_coordinates:
|
1176 |
-
list_coordinates = st.session_state.list_coordinates
|
1177 |
-
list_images = st.session_state.list_images
|
1178 |
-
list_readers = st.session_state.list_readers
|
1179 |
-
list_params_det = st.session_state.list_params_det
|
1180 |
-
|
1181 |
-
##----------- Text detection results --------------------------------------------------------------
|
1182 |
-
st.subheader("Text detection")
|
1183 |
-
show_detect = st.empty()
|
1184 |
-
list_ok_detect = []
|
1185 |
-
with show_detect.container():
|
1186 |
-
columns = st.columns(st.session_state.columns_size, ) #gap='medium')
|
1187 |
-
for no_col, col in enumerate(columns):
|
1188 |
-
column_title = '<p style="font-size: 20px;color:' + \
|
1189 |
-
st.session_state.columns_color[no_col] + \
|
1190 |
-
';">Detection with ' + reader_type_list[no_col]+ '</p>'
|
1191 |
-
col.markdown(column_title, unsafe_allow_html=True)
|
1192 |
-
if isinstance(list_images[no_col+2], PIL.Image.Image):
|
1193 |
-
col.image(list_images[no_col+2], width=st.session_state.column_width[no_col], \
|
1194 |
-
use_column_width=True)
|
1195 |
-
list_ok_detect.append(reader_type_list[no_col])
|
1196 |
-
else:
|
1197 |
-
col.write(list_images[no_col+2], use_column_width=True)
|
1198 |
-
|
1199 |
-
st.subheader("Text recognition")
|
1200 |
|
1201 |
-
|
1202 |
-
st.
|
1203 |
-
|
|
|
|
|
|
|
1204 |
|
1205 |
-
|
1206 |
-
st.markdown("##### Hyperparameters values for recognition:")
|
1207 |
-
with st.form("form2"):
|
1208 |
-
with st.expander("Choose recognition hyperparameters for " + reader_type_list[0], \
|
1209 |
expanded=False):
|
1210 |
-
|
1211 |
-
|
1212 |
-
|
1213 |
-
|
1214 |
-
|
1215 |
-
|
1216 |
-
|
1217 |
-
|
1218 |
-
|
1219 |
-
|
1220 |
-
|
1221 |
-
|
1222 |
-
|
1223 |
-
|
1224 |
-
|
1225 |
-
|
1226 |
-
|
1227 |
-
|
1228 |
-
|
1229 |
-
|
1230 |
-
|
1231 |
-
|
1232 |
-
|
1233 |
-
|
1234 |
-
|
1235 |
-
|
1236 |
-
|
1237 |
-
|
1238 |
-
|
1239 |
-
|
1240 |
-
|
1241 |
-
|
1242 |
-
|
|
|
|
|
|
|
1243 |
expanded=False):
|
1244 |
-
|
1245 |
-
|
1246 |
-
|
1247 |
-
|
1248 |
-
|
1249 |
-
|
1250 |
-
|
1251 |
-
|
1252 |
-
|
1253 |
-
|
1254 |
-
|
1255 |
-
|
1256 |
-
|
1257 |
-
|
1258 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1259 |
expanded=False):
|
1260 |
-
|
1261 |
-
|
1262 |
-
|
1263 |
-
|
1264 |
-
|
1265 |
-
|
1266 |
-
|
1267 |
-
|
|
|
|
|
|
|
1268 |
expanded=False):
|
1269 |
-
|
1270 |
-
|
1271 |
-
|
1272 |
-
|
1273 |
-
|
1274 |
-
|
1275 |
-
|
1276 |
-
|
1277 |
-
|
1278 |
-
|
1279 |
-
'11 Sparse text. Find as much text as possible in no \
|
1280 |
particular order', \
|
1281 |
-
|
1282 |
bypassing hacks that are Tesseract-specific'])
|
1283 |
-
|
1284 |
-
|
1285 |
-
|
1286 |
-
|
1287 |
-
|
1288 |
-
|
1289 |
-
|
1290 |
-
|
1291 |
-
|
1292 |
-
|
1293 |
-
|
1294 |
-
|
1295 |
-
|
1296 |
-
|
1297 |
-
|
1298 |
-
|
|
|
|
|
|
|
|
|
1299 |
|
1300 |
# Construct the config Tesseract parameter
|
1301 |
-
|
1302 |
-
psm =
|
1303 |
if psm != ' -':
|
1304 |
-
|
1305 |
-
oem =
|
1306 |
if oem != '3':
|
1307 |
-
|
1308 |
-
if
|
1309 |
-
|
1310 |
-
|
1311 |
-
|
1312 |
-
[
|
1313 |
-
|
1314 |
-
|
1315 |
-
|
1316 |
-
|
1317 |
-
|
1318 |
-
|
1319 |
-
|
1320 |
-
|
1321 |
-
|
1322 |
-
|
1323 |
-
|
1324 |
-
|
|
|
|
|
|
|
|
|
|
|
1325 |
]
|
1326 |
|
1327 |
-
|
1328 |
-
|
1329 |
-
|
1330 |
-
|
1331 |
-
|
1332 |
-
|
1333 |
-
|
1334 |
-
|
1335 |
-
|
1336 |
-
|
1337 |
-
st.session_state.
|
1338 |
-
|
1339 |
-
|
1340 |
-
|
1341 |
-
|
1342 |
-
|
1343 |
-
|
1344 |
-
|
1345 |
-
|
1346 |
-
|
1347 |
-
|
1348 |
-
|
1349 |
-
|
1350 |
-
|
1351 |
-
|
1352 |
-
|
1353 |
-
|
1354 |
-
|
1355 |
-
|
1356 |
-
|
1357 |
-
|
1358 |
-
|
1359 |
-
|
1360 |
-
|
1361 |
-
|
1362 |
-
|
1363 |
-
|
1364 |
-
|
1365 |
-
|
1366 |
-
|
1367 |
-
|
1368 |
-
|
1369 |
-
|
1370 |
-
|
1371 |
-
|
1372 |
-
|
1373 |
-
|
1374 |
-
|
1375 |
-
|
1376 |
-
|
1377 |
-
|
1378 |
-
|
1379 |
-
|
1380 |
-
|
1381 |
-
|
1382 |
-
|
1383 |
-
|
1384 |
-
|
1385 |
-
|
1386 |
-
|
1387 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1388 |
cols = st.columns(cols_size)
|
1389 |
-
cols[0].image(row.cropped_image, width=150)
|
1390 |
-
for ind_col in range(1, len(cols), 2):
|
1391 |
-
cols[ind_col].write(getattr(row, results_cols[ind_col]))
|
1392 |
-
cols[ind_col+1].write("("+str( \
|
1393 |
-
getattr(row, results_cols[ind_col+1]))+"%)")
|
1394 |
-
|
1395 |
-
st.download_button(
|
1396 |
-
label="Download results as CSV file",
|
1397 |
-
data=convert_df(st.session_state.df_results),
|
1398 |
-
file_name='OCR_comparator_results.csv',
|
1399 |
-
mime='text/csv',
|
1400 |
-
)
|
1401 |
-
|
1402 |
-
if not st.session_state.df_results_tesseract.empty:
|
1403 |
-
with st.expander("Detailed areas for Tesseract", expanded=False):
|
1404 |
-
cols = st.columns([2,2,1])
|
1405 |
cols[0].markdown('#### Detected area')
|
1406 |
-
|
1407 |
-
|
1408 |
-
|
1409 |
-
|
1410 |
-
cols
|
1411 |
-
cols
|
1412 |
-
cols[
|
|
|
|
|
|
|
|
|
1413 |
|
1414 |
st.download_button(
|
1415 |
-
label="Download
|
1416 |
data=convert_df(st.session_state.df_results),
|
1417 |
-
file_name='
|
1418 |
mime='text/csv',
|
1419 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
929 |
###################################################################################################
|
930 |
## MAIN
|
931 |
###################################################################################################
|
932 |
+
def app():
|
933 |
+
##----------- Initializations ---------------------------------------------------------------------
|
934 |
+
#print("PID : ", os.getpid())
|
935 |
+
|
936 |
+
st.title("OCR solutions comparator")
|
937 |
+
st.markdown("##### *EasyOCR, PPOCR, MMOCR, Tesseract*")
|
938 |
+
#st.markdown("#### PID : " + str(os.getpid()))
|
939 |
+
|
940 |
+
# Initializations
|
941 |
+
with st.spinner("Initializations in progress ..."):
|
942 |
+
reader_type_list, reader_type_dict, list_dict_lang, \
|
943 |
+
cols_size, dict_back_colors, fig_colorscale = initializations()
|
944 |
+
img_demo_1, img_demo_2 = get_demo()
|
945 |
+
|
946 |
+
##----------- Choose language & image -------------------------------------------------------------
|
947 |
+
st.markdown("#### Choose languages for the text recognition:")
|
948 |
+
lang_col = st.columns(4)
|
949 |
+
easyocr_key_lang = lang_col[0].selectbox(reader_type_list[0]+" :", list_dict_lang[0].keys(), 26)
|
950 |
+
easyocr_lang = list_dict_lang[0][easyocr_key_lang]
|
951 |
+
ppocr_key_lang = lang_col[1].selectbox(reader_type_list[1]+" :", list_dict_lang[1].keys(), 22)
|
952 |
+
ppocr_lang = list_dict_lang[1][ppocr_key_lang]
|
953 |
+
mmocr_key_lang = lang_col[2].selectbox(reader_type_list[2]+" :", list_dict_lang[2].keys(), 0)
|
954 |
+
mmocr_lang = list_dict_lang[2][mmocr_key_lang]
|
955 |
+
tesserocr_key_lang = lang_col[3].selectbox(reader_type_list[3]+" :", list_dict_lang[3].keys(), 35)
|
956 |
+
tesserocr_lang = list_dict_lang[3][tesserocr_key_lang]
|
957 |
+
|
958 |
+
st.markdown("#### Choose picture:")
|
959 |
+
cols_pict = st.columns([1, 2])
|
960 |
+
img_typ = cols_pict[0].radio("", ['Upload file', 'Take a picture', 'Use a demo file'], \
|
961 |
+
index=0, on_change=raz)
|
962 |
+
|
963 |
+
if img_typ == 'Upload file':
|
964 |
+
image_file = cols_pict[1].file_uploader("Upload a file:", type=["jpg","jpeg"], on_change=raz)
|
965 |
+
if img_typ == 'Take a picture':
|
966 |
+
image_file = cols_pict[1].camera_input("Take a picture:", on_change=raz)
|
967 |
+
if img_typ == 'Use a demo file':
|
968 |
+
with st.expander('Choose a demo file:', expanded=True):
|
969 |
+
demo_used = st.radio('', ['File 1', 'File 2'], index=0, \
|
970 |
+
horizontal=True, on_change=raz)
|
971 |
+
cols_demo = st.columns([1, 2])
|
972 |
+
cols_demo[0].markdown('###### File 1')
|
973 |
+
cols_demo[0].image(img_demo_1, width=150)
|
974 |
+
cols_demo[1].markdown('###### File 2')
|
975 |
+
cols_demo[1].image(img_demo_2, width=300)
|
976 |
+
if demo_used == 'File 1':
|
977 |
+
image_file = 'img_demo_1.jpg'
|
978 |
+
else:
|
979 |
+
image_file = 'img_demo_2.jpg'
|
980 |
|
981 |
+
##----------- Process input image -----------------------------------------------------------------
|
982 |
+
if image_file is not None:
|
983 |
+
image_path, image_orig, image_cv2 = load_image(image_file)
|
984 |
+
list_images = [image_orig, image_cv2]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
985 |
|
986 |
+
##----------- Form with original image & hyperparameters for detectors ----------------------------
|
987 |
+
with st.form("form1"):
|
988 |
+
col1, col2 = st.columns(2, ) #gap="medium")
|
989 |
+
col1.markdown("##### Original image")
|
990 |
+
col1.image(list_images[0], width=500, use_column_width=True)
|
991 |
+
col2.markdown("##### Hyperparameters values for detection")
|
992 |
|
993 |
+
with col2.expander("Choose detection hyperparameters for " + reader_type_list[0], \
|
|
|
|
|
|
|
994 |
expanded=False):
|
995 |
+
t0_min_size = st.slider("min_size", 1, 20, 10, step=1, \
|
996 |
+
help="min_size (int, default = 10) - Filter text box smaller than \
|
997 |
+
minimum value in pixel")
|
998 |
+
t0_text_threshold = st.slider("text_threshold", 0.1, 1., 0.7, step=0.1, \
|
999 |
+
help="text_threshold (float, default = 0.7) - Text confidence threshold")
|
1000 |
+
t0_low_text = st.slider("low_text", 0.1, 1., 0.4, step=0.1, \
|
1001 |
+
help="low_text (float, default = 0.4) - Text low-bound score")
|
1002 |
+
t0_link_threshold = st.slider("link_threshold", 0.1, 1., 0.4, step=0.1, \
|
1003 |
+
help="link_threshold (float, default = 0.4) - Link confidence threshold")
|
1004 |
+
t0_canvas_size = st.slider("canvas_size", 2000, 5000, 2560, step=10, \
|
1005 |
+
help='''canvas_size (int, default = 2560) \n
|
1006 |
+
Maximum e size. Image bigger than this value will be resized down''')
|
1007 |
+
t0_mag_ratio = st.slider("mag_ratio", 0.1, 5., 1., step=0.1, \
|
1008 |
+
help="mag_ratio (float, default = 1) - Image magnification ratio")
|
1009 |
+
t0_slope_ths = st.slider("slope_ths", 0.01, 1., 0.1, step=0.01, \
|
1010 |
+
help='''slope_ths (float, default = 0.1) - Maximum slope \
|
1011 |
+
(delta y/delta x) to considered merging. \n
|
1012 |
+
Low valuans tiled boxes will not be merged.''')
|
1013 |
+
t0_ycenter_ths = st.slider("ycenter_ths", 0.1, 1., 0.5, step=0.1, \
|
1014 |
+
help='''ycenter_ths (float, default = 0.5) - Maximum shift in y direction. \n
|
1015 |
+
Boxes wiifferent level should not be merged.''')
|
1016 |
+
t0_height_ths = st.slider("height_ths", 0.1, 1., 0.5, step=0.1, \
|
1017 |
+
help='''height_ths (float, default = 0.5) - Maximum different in box height. \n
|
1018 |
+
Boxes wiery different text size should not be merged.''')
|
1019 |
+
t0_width_ths = st.slider("width_ths", 0.1, 1., 0.5, step=0.1, \
|
1020 |
+
help="width_ths (float, default = 0.5) - Maximum horizontal \
|
1021 |
+
distance to merge boxes.")
|
1022 |
+
t0_add_margin = st.slider("add_margin", 0.1, 1., 0.1, step=0.1, \
|
1023 |
+
help='''add_margin (float, default = 0.1) - \
|
1024 |
+
Extend bounding boxes in all direction by certain value. \n
|
1025 |
+
This is rtant for language with complex script (E.g. Thai).''')
|
1026 |
+
t0_optimal_num_chars = st.slider("optimal_num_chars", None, 100, None, step=10, \
|
1027 |
+
help="optimal_num_chars (int, default = None) - If specified, bounding boxes \
|
1028 |
+
with estimated number of characters near this value are returned first.")
|
1029 |
+
|
1030 |
+
with col2.expander("Choose detection hyperparameters for " + reader_type_list[1], \
|
1031 |
expanded=False):
|
1032 |
+
t1_det_algorithm = st.selectbox('det_algorithm', ['DB'], \
|
1033 |
+
help='Type of detection algorithm selected. (default = DB)')
|
1034 |
+
t1_det_max_side_len = st.slider('det_max_side_len', 500, 2000, 960, step=10, \
|
1035 |
+
help='''The maximum size of the long side of the image. (default = 960)\n
|
1036 |
+
Limit thximum image height and width.\n
|
1037 |
+
When theg side exceeds this value, the long side will be resized to this size, and the short side \
|
1038 |
+
will be ed proportionally.''')
|
1039 |
+
t1_det_db_thresh = st.slider('det_db_thresh', 0.1, 1., 0.3, step=0.1, \
|
1040 |
+
help='''Binarization threshold value of DB output map. (default = 0.3) \n
|
1041 |
+
Used to er the binarized image of DB prediction, setting 0.-0.3 has no obvious effect on the result.''')
|
1042 |
+
t1_det_db_box_thresh = st.slider('det_db_box_thresh', 0.1, 1., 0.6, step=0.1, \
|
1043 |
+
help='''The threshold value of the DB output box. (default = 0.6) \n
|
1044 |
+
DB post-essing filter box threshold, if there is a missing box detected, it can be reduced as appropriate. \n
|
1045 |
+
Boxes sclower than this value will be discard.''')
|
1046 |
+
t1_det_db_unclip_ratio = st.slider('det_db_unclip_ratio', 1., 3.0, 1.6, step=0.1, \
|
1047 |
+
help='''The expanded ratio of DB output box. (default = 1.6) \n
|
1048 |
+
Indicatee compactness of the text box, the smaller the value, the closer the text box to the text.''')
|
1049 |
+
t1_det_east_score_thresh = st.slider('det_east_cover_thresh', 0.1, 1., 0.8, step=0.1, \
|
1050 |
+
help="Binarization threshold value of EAST output map. (default = 0.8)")
|
1051 |
+
t1_det_east_cover_thresh = st.slider('det_east_cover_thresh', 0.1, 1., 0.1, step=0.1, \
|
1052 |
+
help='''The threshold value of the EAST output box. (default = 0.1) \n
|
1053 |
+
Boxes sclower than this value will be discarded.''')
|
1054 |
+
t1_det_east_nms_thresh = st.slider('det_east_nms_thresh', 0.1, 1., 0.2, step=0.1, \
|
1055 |
+
help="The NMS threshold value of EAST model output box. (default = 0.2)")
|
1056 |
+
t1_det_db_score_mode = st.selectbox('det_db_score_mode', ['fast', 'slow'], \
|
1057 |
+
help='''slow: use polygon box to calculate bbox score, fast: use rectangle box \
|
1058 |
+
to calculate. (default = fast) \n
|
1059 |
+
Use rectlar box to calculate faster, and polygonal box more accurate for curved text area.''')
|
1060 |
+
|
1061 |
+
with col2.expander("Choose detection hyperparameters for " + reader_type_list[2], \
|
1062 |
expanded=False):
|
1063 |
+
t2_det = st.selectbox('det', ['DB_r18','DB_r50','DBPP_r50','DRRG','FCE_IC15', \
|
1064 |
+
'FCE_CTW_DCNv2','MaskRCNN_CTW','MaskRCNN_IC15', \
|
1065 |
+
'MaskRCNN_IC17', 'PANet_CTW','PANet_IC15','PS_CTW',\
|
1066 |
+
'PS_IC15','Tesseract','TextSnake'], 10, \
|
1067 |
+
help='Text detection algorithm. (default = PANet_IC15)')
|
1068 |
+
st.write("###### *More about text detection models* π \
|
1069 |
+
[here](https://mmocr.readthedocs.io/en/latest/textdet_models.html)")
|
1070 |
+
t2_merge_xdist = st.slider('merge_xdist', 1, 50, 20, step=1, \
|
1071 |
+
help='The maximum x-axis distance to merge boxes. (defaut=20)')
|
1072 |
+
|
1073 |
+
with col2.expander("Choose detection hyperparameters for " + reader_type_list[3], \
|
1074 |
expanded=False):
|
1075 |
+
t3_psm = st.selectbox('Page segmentation mode (psm)', \
|
1076 |
+
[' - Default', \
|
1077 |
+
' 4 Assume a single column of text of variable sizes', \
|
1078 |
+
' 5 Assume a single uniform block of vertically aligned text', \
|
1079 |
+
' 6 Assume a single uniform block of text', \
|
1080 |
+
' 7 Treat the image as a single text line', \
|
1081 |
+
' 8 Treat the image as a single word', \
|
1082 |
+
' 9 Treat the image as a single word in a circle', \
|
1083 |
+
'10 Treat the image as a single character', \
|
1084 |
+
'11 Sparse text. Find as much text as possible in no \
|
|
|
1085 |
particular order', \
|
1086 |
+
'13 Raw line. Treat the image as a single text line, \
|
1087 |
bypassing hacks that are Tesseract-specific'])
|
1088 |
+
t3_oem = st.selectbox('OCR engine mode', ['0 Legacy engine only', \
|
1089 |
+
'1 Neural nets LSTM engine only', \
|
1090 |
+
'2 Legacy + LSTM engines', \
|
1091 |
+
'3 Default, based on what is available'], 3)
|
1092 |
+
t3_whitelist = st.text_input('Limit tesseract to recognize only this characters :', \
|
1093 |
+
placeholder='Limit tesseract to recognize only this characters', \
|
1094 |
+
help='Example for numbers only : 0123456789')
|
1095 |
+
|
1096 |
+
color_hex = col2.color_picker('Set a color for box outlines:', '#004C99')
|
1097 |
+
color_part = color_hex.lstrip('#')
|
1098 |
+
color = tuple(int(color_part[i:i+2], 16) for i in (0, 2, 4))
|
1099 |
+
|
1100 |
+
submit_detect = st.form_submit_button("Launch detection")
|
1101 |
+
|
1102 |
+
##----------- Process text detection --------------------------------------------------------------
|
1103 |
+
if submit_detect:
|
1104 |
+
# Process text detection
|
1105 |
+
|
1106 |
+
if t0_optimal_num_chars == 0:
|
1107 |
+
t0_optimal_num_chars = None
|
1108 |
|
1109 |
# Construct the config Tesseract parameter
|
1110 |
+
t3_config = ''
|
1111 |
+
psm = t3_psm[:2]
|
1112 |
if psm != ' -':
|
1113 |
+
t3_config += '--psm ' + psm.strip()
|
1114 |
+
oem = t3_oem[:1]
|
1115 |
if oem != '3':
|
1116 |
+
t3_config += ' --oem ' + oem
|
1117 |
+
if t3_whitelist != '':
|
1118 |
+
t3_config += ' -c tessedit_char_whitelist=' + t3_whitelist
|
1119 |
+
|
1120 |
+
list_params_det = \
|
1121 |
+
[[easyocr_lang, \
|
1122 |
+
{'min_size': t0_min_size, 'text_threshold': t0_text_threshold, \
|
1123 |
+
'low_text': t0_low_text, 'link_threshold': t0_link_threshold, \
|
1124 |
+
'canvas_size': t0_canvas_size, 'mag_ratio': t0_mag_ratio, \
|
1125 |
+
'slope_ths': t0_slope_ths, 'ycenter_ths': t0_ycenter_ths, \
|
1126 |
+
'height_ths': t0_height_ths, 'width_ths': t0_width_ths, \
|
1127 |
+
'add_margin': t0_add_margin, 'optimal_num_chars': t0_optimal_num_chars \
|
1128 |
+
}], \
|
1129 |
+
[ppocr_lang, \
|
1130 |
+
{'det_algorithm': t1_det_algorithm, 'det_max_side_len': t1_det_max_side_len, \
|
1131 |
+
'det_db_thresh': t1_det_db_thresh, 'det_db_box_thresh': t1_det_db_box_thresh, \
|
1132 |
+
'det_db_unclip_ratio': t1_det_db_unclip_ratio, \
|
1133 |
+
'det_east_score_thresh': t1_det_east_score_thresh, \
|
1134 |
+
'det_east_cover_thresh': t1_det_east_cover_thresh, \
|
1135 |
+
'det_east_nms_thresh': t1_det_east_nms_thresh, \
|
1136 |
+
'det_db_score_mode': t1_det_db_score_mode}],
|
1137 |
+
[mmocr_lang, {'det': t2_det, 'merge_xdist': t2_merge_xdist}],
|
1138 |
+
[tesserocr_lang, {'lang': tesserocr_lang, 'config': t3_config}]
|
1139 |
]
|
1140 |
|
1141 |
+
show_info1 = st.empty()
|
1142 |
+
show_info1.info("Readers initializations in progress (it may take a while) ...")
|
1143 |
+
list_readers = init_readers(list_params_det)
|
1144 |
+
|
1145 |
+
show_info1.info("Text detection in progress ...")
|
1146 |
+
list_images, list_coordinates = process_detect(image_path, list_images, list_readers, \
|
1147 |
+
list_params_det, color)
|
1148 |
+
show_info1.empty()
|
1149 |
+
|
1150 |
+
# Clear previous recognition results
|
1151 |
+
st.session_state.df_results = pd.DataFrame([])
|
1152 |
+
|
1153 |
+
st.session_state.list_readers = list_readers
|
1154 |
+
st.session_state.list_coordinates = list_coordinates
|
1155 |
+
st.session_state.list_images = list_images
|
1156 |
+
st.session_state.list_params_det = list_params_det
|
1157 |
+
|
1158 |
+
if 'columns_size' not in st.session_state:
|
1159 |
+
st.session_state.columns_size = [2] + [1 for x in reader_type_list[1:]]
|
1160 |
+
if 'column_width' not in st.session_state:
|
1161 |
+
st.session_state.column_width = [500] + [400 for x in reader_type_list[1:]]
|
1162 |
+
if 'columns_color' not in st.session_state:
|
1163 |
+
st.session_state.columns_color = ["rgb(228,26,28)"] + \
|
1164 |
+
["rgb(0,0,0)" for x in reader_type_list[1:]]
|
1165 |
+
|
1166 |
+
if st.session_state.list_coordinates:
|
1167 |
+
list_coordinates = st.session_state.list_coordinates
|
1168 |
+
list_images = st.session_state.list_images
|
1169 |
+
list_readers = st.session_state.list_readers
|
1170 |
+
list_params_det = st.session_state.list_params_det
|
1171 |
+
|
1172 |
+
##----------- Text detection results --------------------------------------------------------------
|
1173 |
+
st.subheader("Text detection")
|
1174 |
+
show_detect = st.empty()
|
1175 |
+
list_ok_detect = []
|
1176 |
+
with show_detect.container():
|
1177 |
+
columns = st.columns(st.session_state.columns_size, ) #gap='medium')
|
1178 |
+
for no_col, col in enumerate(columns):
|
1179 |
+
column_title = '<p style="font-size: 20px;color:' + \
|
1180 |
+
st.session_state.columns_color[no_col] + \
|
1181 |
+
';">Detection with ' + reader_type_list[no_col]+ '</p>'
|
1182 |
+
col.markdown(column_title, unsafe_allow_html=True)
|
1183 |
+
if isinstance(list_images[no_col+2], PIL.Image.Image):
|
1184 |
+
col.image(list_images[no_col+2], width=st.session_state.column_width[no_col], \
|
1185 |
+
use_column_width=True)
|
1186 |
+
list_ok_detect.append(reader_type_list[no_col])
|
1187 |
+
else:
|
1188 |
+
col.write(list_images[no_col+2], use_column_width=True)
|
1189 |
+
|
1190 |
+
st.subheader("Text recognition")
|
1191 |
+
|
1192 |
+
st.markdown("##### Using detection performed above by:")
|
1193 |
+
st.radio('Choose the detecter:', list_ok_detect, key='detect_reader', \
|
1194 |
+
horizontal=True, on_change=highlight)
|
1195 |
+
|
1196 |
+
##----------- Form with hyperparameters for recognition -----------------------
|
1197 |
+
st.markdown("##### Hyperparameters values for recognition:")
|
1198 |
+
with st.form("form2"):
|
1199 |
+
with st.expander("Choose recognition hyperparameters for " + reader_type_list[0], \
|
1200 |
+
expanded=False):
|
1201 |
+
t0_decoder = st.selectbox('decoder', ['greedy', 'beamsearch', 'wordbeamsearch'], \
|
1202 |
+
help="decoder (string, default = 'greedy') - options are 'greedy', \
|
1203 |
+
'beamsearch' and 'wordbeamsearch.")
|
1204 |
+
t0_beamWidth = st.slider('beamWidth', 2, 20, 5, step=1, \
|
1205 |
+
help="beamWidth (int, default = 5) - How many beam to keep when decoder = \
|
1206 |
+
'beamsearch' or 'wordbeamsearch'.")
|
1207 |
+
t0_batch_size = st.slider('batch_size', 1, 10, 1, step=1, \
|
1208 |
+
help="batch_size (int, default = 1) - batch_size>1 will make EasyOCR faster \
|
1209 |
+
but use more memory.")
|
1210 |
+
t0_workers = st.slider('workers', 0, 10, 0, step=1, \
|
1211 |
+
help="workers (int, default = 0) - Number thread used in of dataloader.")
|
1212 |
+
t0_allowlist = st.text_input('allowlist', value="", max_chars=None, \
|
1213 |
+
placeholder='Force EasyOCR to recognize only this subset of characters', \
|
1214 |
+
help='''allowlist (string) - Force EasyOCR to recognize only subset of characters.\n
|
1215 |
+
Usefor specific problem (E.g. license plate, etc.)''')
|
1216 |
+
t0_blocklist = st.text_input('blocklist', value="", max_chars=None, \
|
1217 |
+
placeholder='Block subset of character (will be ignored if allowlist is given)', \
|
1218 |
+
help='''blocklist (string) - Block subset of character. This argument will be \
|
1219 |
+
ignored if allowlist is given.''')
|
1220 |
+
t0_detail = st.radio('detail', [0, 1], 1, horizontal=True, \
|
1221 |
+
help="detail (int, default = 1) - Set this to 0 for simple output")
|
1222 |
+
t0_paragraph = st.radio('paragraph', [True, False], 1, horizontal=True, \
|
1223 |
+
help='paragraph (bool, default = False) - Combine result into paragraph')
|
1224 |
+
t0_contrast_ths = st.slider('contrast_ths', 0.05, 1., 0.1, step=0.01, \
|
1225 |
+
help='''contrast_ths (float, default = 0.1) - Text box with contrast lower than \
|
1226 |
+
this value will be passed into model 2 times.\n
|
1227 |
+
Firs with original image and second with contrast adjusted to 'adjust_contrast' value.\n
|
1228 |
+
The with more confident level will be returned as a result.''')
|
1229 |
+
t0_adjust_contrast = st.slider('adjust_contrast', 0.1, 1., 0.5, step=0.1, \
|
1230 |
+
help = 'adjust_contrast (float, default = 0.5) - target contrast level for low \
|
1231 |
+
contrast text box')
|
1232 |
+
|
1233 |
+
with st.expander("Choose recognition hyperparameters for " + reader_type_list[1], \
|
1234 |
+
expanded=False):
|
1235 |
+
t1_rec_algorithm = st.selectbox('rec_algorithm', ['CRNN', 'SVTR_LCNet'], 0, \
|
1236 |
+
help="Type of recognition algorithm selected. (default=CRNN)")
|
1237 |
+
t1_rec_batch_num = st.slider('rec_batch_num', 1, 50, step=1, \
|
1238 |
+
help="When performing recognition, the batchsize of forward images. \
|
1239 |
+
(default=30)")
|
1240 |
+
t1_max_text_length = st.slider('max_text_length', 3, 250, 25, step=1, \
|
1241 |
+
help="The maximum text length that the recognition algorithm can recognize. \
|
1242 |
+
(default=25)")
|
1243 |
+
t1_use_space_char = st.radio('use_space_char', [True, False], 0, horizontal=True, \
|
1244 |
+
help="Whether to recognize spaces. (default=TRUE)")
|
1245 |
+
t1_drop_score = st.slider('drop_score', 0., 1., 0.25, step=.05, \
|
1246 |
+
help="Filter the output by score (from the recognition model), and those \
|
1247 |
+
below this score will not be returned. (default=0.5)")
|
1248 |
+
|
1249 |
+
with st.expander("Choose recognition hyperparameters for " + reader_type_list[2], \
|
1250 |
+
expanded=False):
|
1251 |
+
t2_recog = st.selectbox('recog', ['ABINet','CRNN','CRNN_TPS','MASTER', \
|
1252 |
+
'NRTR_1/16-1/8','NRTR_1/8-1/4','RobustScanner','SAR','SAR_CN', \
|
1253 |
+
'SATRN','SATRN_sm','SEG','Tesseract'], 7, \
|
1254 |
+
help='Text recognition algorithm. (default = SAR)')
|
1255 |
+
st.write("###### *More about text recognition models* π \
|
1256 |
+
[here](https://mmocr.readthedocs.io/en/latest/textrecog_models.html)")
|
1257 |
+
|
1258 |
+
with st.expander("Choose recognition hyperparameters for " + reader_type_list[3], \
|
1259 |
+
expanded=False):
|
1260 |
+
t3r_psm = st.selectbox('Page segmentation mode (psm)', \
|
1261 |
+
[' - Default', \
|
1262 |
+
' 4 Assume a single column of text of variable sizes', \
|
1263 |
+
' 5 Assume a single uniform block of vertically aligned \
|
1264 |
+
text', \
|
1265 |
+
' 6 Assume a single uniform block of text', \
|
1266 |
+
' 7 Treat the image as a single text line', \
|
1267 |
+
' 8 Treat the image as a single word', \
|
1268 |
+
' 9 Treat the image as a single word in a circle', \
|
1269 |
+
'10 Treat the image as a single character', \
|
1270 |
+
'11 Sparse text. Find as much text as possible in no \
|
1271 |
+
particular order', \
|
1272 |
+
'13 Raw line. Treat the image as a single text line, \
|
1273 |
+
bypassing hacks that are Tesseract-specific'])
|
1274 |
+
t3r_oem = st.selectbox('OCR engine mode', ['0 Legacy engine only', \
|
1275 |
+
'1 Neural nets LSTM engine only', \
|
1276 |
+
'2 Legacy + LSTM engines', \
|
1277 |
+
'3 Default, based on what is available'], 3)
|
1278 |
+
t3r_whitelist = st.text_input('Limit tesseract to recognize only this \
|
1279 |
+
characters :', \
|
1280 |
+
placeholder='Limit tesseract to recognize only this characters', \
|
1281 |
+
help='Example for numbers only : 0123456789')
|
1282 |
+
|
1283 |
+
submit_reco = st.form_submit_button("Launch recognition")
|
1284 |
+
|
1285 |
+
if submit_reco:
|
1286 |
+
process_detect.clear()
|
1287 |
+
##----------- Process recognition ------------------------------------------
|
1288 |
+
reader_ind = reader_type_dict[st.session_state.detect_reader]
|
1289 |
+
list_boxes = list_coordinates[reader_ind]
|
1290 |
+
|
1291 |
+
# Construct the config Tesseract parameter
|
1292 |
+
t3r_config = ''
|
1293 |
+
psm = t3r_psm[:2]
|
1294 |
+
if psm != ' -':
|
1295 |
+
t3r_config += '--psm ' + psm.strip()
|
1296 |
+
oem = t3r_oem[:1]
|
1297 |
+
if oem != '3':
|
1298 |
+
t3r_config += ' --oem ' + oem
|
1299 |
+
if t3r_whitelist != '':
|
1300 |
+
t3r_config += ' -c tessedit_char_whitelist=' + t3r_whitelist
|
1301 |
+
|
1302 |
+
list_params_rec = \
|
1303 |
+
[{'decoder': t0_decoder, 'beamWidth': t0_beamWidth, \
|
1304 |
+
'batch_size': t0_batch_size, 'workers': t0_workers, \
|
1305 |
+
'allowlist': t0_allowlist, 'blocklist': t0_blocklist, \
|
1306 |
+
'detail': t0_detail, 'paragraph': t0_paragraph, \
|
1307 |
+
'contrast_ths': t0_contrast_ths, 'adjust_contrast': t0_adjust_contrast
|
1308 |
+
},
|
1309 |
+
{ **list_params_det[1][1], **{'rec_algorithm': t1_rec_algorithm, \
|
1310 |
+
'rec_batch_num': t1_rec_batch_num, 'max_text_length': t1_max_text_length, \
|
1311 |
+
'use_space_char': t1_use_space_char, 'drop_score': t1_drop_score}, \
|
1312 |
+
**{'lang': list_params_det[1][0]}
|
1313 |
+
},
|
1314 |
+
{'recog': t2_recog},
|
1315 |
+
{'lang': tesserocr_lang, 'config': t3r_config}
|
1316 |
+
]
|
1317 |
+
|
1318 |
+
show_info2 = st.empty()
|
1319 |
+
|
1320 |
+
with show_info2.container():
|
1321 |
+
st.info("Text recognition in progress ...")
|
1322 |
+
df_results, df_results_tesseract, list_reco_status = \
|
1323 |
+
process_recog(list_readers, list_images[1], list_boxes, list_params_rec)
|
1324 |
+
show_info2.empty()
|
1325 |
+
|
1326 |
+
st.session_state.df_results = df_results
|
1327 |
+
st.session_state.list_boxes = list_boxes
|
1328 |
+
st.session_state.df_results_tesseract = df_results_tesseract
|
1329 |
+
st.session_state.list_reco_status = list_reco_status
|
1330 |
+
|
1331 |
+
if 'df_results' in st.session_state:
|
1332 |
+
if not st.session_state.df_results.empty:
|
1333 |
+
##----------- Show recognition results ------------------------------------------------------------
|
1334 |
+
results_cols = st.session_state.df_results.columns
|
1335 |
+
list_col_text = np.arange(1, len(cols_size), 2)
|
1336 |
+
list_col_confid = np.arange(2, len(cols_size), 2)
|
1337 |
+
|
1338 |
+
dict_draw_reco = {'in_image': st.session_state.list_images[1], \
|
1339 |
+
'in_boxes_coordinates': st.session_state.list_boxes, \
|
1340 |
+
'in_list_texts': [st.session_state.df_results[x].to_list() \
|
1341 |
+
for x in results_cols[list_col_text]], \
|
1342 |
+
'in_list_confid': [st.session_state.df_results[x].to_list() \
|
1343 |
+
for x in results_cols[list_col_confid]], \
|
1344 |
+
'in_dict_back_colors': dict_back_colors, \
|
1345 |
+
'in_df_results_tesseract' : st.session_state.df_results_tesseract, \
|
1346 |
+
'in_reader_type_list': reader_type_list
|
1347 |
+
}
|
1348 |
+
show_reco = st.empty()
|
1349 |
+
|
1350 |
+
with st.form("form3"):
|
1351 |
+
st.plotly_chart(fig_colorscale, use_container_width=True)
|
1352 |
+
|
1353 |
+
col_font, col_threshold = st.columns(2)
|
1354 |
+
|
1355 |
+
col_font.slider('Font scale', 1, 7, 1, step=1, key="font_scale_sld")
|
1356 |
+
col_threshold.slider('% confidence threshold for text color change', 40, 100, 64, \
|
1357 |
+
step=1, key="conf_threshold_sld")
|
1358 |
+
col_threshold.write("(text color is black below this % confidence threshold, \
|
1359 |
+
and white above)")
|
1360 |
+
|
1361 |
+
draw_reco_images(**dict_draw_reco)
|
1362 |
+
|
1363 |
+
submit_resize = st.form_submit_button("Refresh")
|
1364 |
+
|
1365 |
+
if submit_resize:
|
1366 |
+
draw_reco_images(**dict_draw_reco, \
|
1367 |
+
in_font_scale=st.session_state.font_scale_sld, \
|
1368 |
+
in_conf_threshold=st.session_state.conf_threshold_sld)
|
1369 |
+
|
1370 |
+
st.subheader("Recognition details")
|
1371 |
+
with st.expander("Detailed areas for EasyOCR, PPOCR, MMOCR", expanded=True):
|
1372 |
cols = st.columns(cols_size)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1373 |
cols[0].markdown('#### Detected area')
|
1374 |
+
for i in range(1, (len(reader_type_list)-1)*2, 2):
|
1375 |
+
cols[i].markdown('#### with ' + reader_type_list[i//2])
|
1376 |
+
|
1377 |
+
for row in st.session_state.df_results.itertuples():
|
1378 |
+
#cols = st.columns(1 + len(reader_type_list)*2)
|
1379 |
+
cols = st.columns(cols_size)
|
1380 |
+
cols[0].image(row.cropped_image, width=150)
|
1381 |
+
for ind_col in range(1, len(cols), 2):
|
1382 |
+
cols[ind_col].write(getattr(row, results_cols[ind_col]))
|
1383 |
+
cols[ind_col+1].write("("+str( \
|
1384 |
+
getattr(row, results_cols[ind_col+1]))+"%)")
|
1385 |
|
1386 |
st.download_button(
|
1387 |
+
label="Download results as CSV file",
|
1388 |
data=convert_df(st.session_state.df_results),
|
1389 |
+
file_name='OCR_comparator_results.csv',
|
1390 |
mime='text/csv',
|
1391 |
)
|
1392 |
+
|
1393 |
+
if not st.session_state.df_results_tesseract.empty:
|
1394 |
+
with st.expander("Detailed areas for Tesseract", expanded=False):
|
1395 |
+
cols = st.columns([2,2,1])
|
1396 |
+
cols[0].markdown('#### Detected area')
|
1397 |
+
cols[1].markdown('#### with Tesseract')
|
1398 |
+
|
1399 |
+
for row in st.session_state.df_results_tesseract.itertuples():
|
1400 |
+
cols = st.columns([2,2,1])
|
1401 |
+
cols[0].image(row.cropped, width=150)
|
1402 |
+
cols[1].write(getattr(row, 'text'))
|
1403 |
+
cols[2].write("("+str(getattr(row, 'conf'))+"%)")
|
1404 |
+
|
1405 |
+
st.download_button(
|
1406 |
+
label="Download Tesseract results as CSV file",
|
1407 |
+
data=convert_df(st.session_state.df_results),
|
1408 |
+
file_name='OCR_comparator_Tesseract_results.csv',
|
1409 |
+
mime='text/csv',
|
1410 |
+
)
|
multipage.py
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
This file is the framework for generating multiple Streamlit applications
|
3 |
+
through an object oriented framework.
|
4 |
+
|
5 |
+
Source: https://huggingface.co/spaces/deepset/wikipedia-assistant/tree/main
|
6 |
+
"""
|
7 |
+
|
8 |
+
# Import necessary libraries
|
9 |
+
import streamlit as st
|
10 |
+
from streamlit_option_menu import option_menu
|
11 |
+
|
12 |
+
|
13 |
+
# Define the multipage class to manage the multiple apps in our program
|
14 |
+
class MultiPage:
|
15 |
+
"""Framework for combining multiple streamlit applications."""
|
16 |
+
|
17 |
+
def __init__(self) -> None:
|
18 |
+
"""Constructor class to generate a list which will store all our applications as an instance variable."""
|
19 |
+
self.pages = []
|
20 |
+
|
21 |
+
def add_page(self, title, icon, func) -> None:
|
22 |
+
"""Class Method to Add pages to the project
|
23 |
+
|
24 |
+
Args:
|
25 |
+
title ([str]): The title of page which we are adding to the list of apps
|
26 |
+
|
27 |
+
func: Python function to render this page in Streamlit
|
28 |
+
"""
|
29 |
+
|
30 |
+
self.pages.append(
|
31 |
+
{
|
32 |
+
"title": title,
|
33 |
+
"icon": icon,
|
34 |
+
"function": func
|
35 |
+
}
|
36 |
+
)
|
37 |
+
|
38 |
+
def run(self):
|
39 |
+
# Drodown to select the page to run
|
40 |
+
st.markdown("""
|
41 |
+
<style>
|
42 |
+
section[data-testid="stSidebar"] > div:first-of-type {
|
43 |
+
background-color: var(--secondary-background-color);
|
44 |
+
background: var(--secondary-background-color);
|
45 |
+
width: 250px;
|
46 |
+
padding: 4rem 0;
|
47 |
+
box-shadow: -2rem 0px 2rem 2rem rgba(0,0,0,0.16);
|
48 |
+
}
|
49 |
+
section[aria-expanded="true"] > div:nth-of-type(2) {
|
50 |
+
display: none;
|
51 |
+
}
|
52 |
+
.main > div:first-of-type {
|
53 |
+
padding: 1rem 0;
|
54 |
+
}
|
55 |
+
</style>
|
56 |
+
""", unsafe_allow_html=True)
|
57 |
+
|
58 |
+
with st.sidebar:
|
59 |
+
selected = option_menu("OCR Comparator",
|
60 |
+
[page["title"] for page in self.pages],
|
61 |
+
icons=[page["icon"] for page in self.pages],
|
62 |
+
menu_icon="app-indicator", default_index=0)
|
63 |
+
|
64 |
+
# Run the selected page
|
65 |
+
for index, item in enumerate(self.pages):
|
66 |
+
if item["title"] == selected:
|
67 |
+
self.pages[index]["function"]()
|
68 |
+
break
|
pages/About.py
DELETED
@@ -1,37 +0,0 @@
|
|
1 |
-
import streamlit as st
|
2 |
-
|
3 |
-
st.set_page_config(page_title='OCR Comparator', layout ="wide")
|
4 |
-
st.title("OCR solutions comparator")
|
5 |
-
|
6 |
-
st.write("")
|
7 |
-
st.write("")
|
8 |
-
st.write("")
|
9 |
-
|
10 |
-
st.markdown("##### This app allows you to compare, from a given picture, the results of different solutions:")
|
11 |
-
st.markdown("##### *EasyOcr, PaddleOCR, MMOCR, Tesseract*")
|
12 |
-
st.write("")
|
13 |
-
st.write("")
|
14 |
-
|
15 |
-
st.markdown(''' The 1st step is to choose the language for the text recognition (not all solutions \
|
16 |
-
support the same languages), and then choose the picture to consider. It is possible to upload a file, \
|
17 |
-
to take a picture, or to use a demo file. \
|
18 |
-
It is then possible to change the default values for the text area detection process, \
|
19 |
-
before launching the detection task for each solution.''')
|
20 |
-
st.write("")
|
21 |
-
|
22 |
-
st.markdown(''' The different results are then presented. The 2nd step is to choose one of these \
|
23 |
-
detection results, in order to carry out the text recognition process there. It is also possible to change \
|
24 |
-
the default settings for each solution.''')
|
25 |
-
st.write("")
|
26 |
-
|
27 |
-
st.markdown("###### The recognition results appear in 2 formats:")
|
28 |
-
st.markdown(''' - a visual format resumes the initial image, replacing the detected areas with \
|
29 |
-
the recognized text. The background is + or - strongly colored in green according to the \
|
30 |
-
confidence level of the recognition.
|
31 |
-
A slider allows you to change the font size, another \
|
32 |
-
allows you to modify the confidence threshold above which the text color changes: if it is at \
|
33 |
-
70% for example, then all the texts with a confidence threshold higher or equal to 70 will appear \
|
34 |
-
in white, in black otherwise.''')
|
35 |
-
|
36 |
-
st.markdown(" - a detailed format presents the results in a table, for each text box detected. \
|
37 |
-
It is possible to download this results in a local csv file.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
CHANGED
@@ -13,4 +13,5 @@ paddlepaddle==2.3.2
|
|
13 |
mycolorpy==1.5.1
|
14 |
plotly==5.10.0
|
15 |
plotly-express==0.4.1
|
16 |
-
pytesseract==0.3.10
|
|
|
|
13 |
mycolorpy==1.5.1
|
14 |
plotly==5.10.0
|
15 |
plotly-express==0.4.1
|
16 |
+
pytesseract==0.3.10
|
17 |
+
streamlit_option_menu
|