Tanaanan commited on
Commit
395d323
·
verified ·
1 Parent(s): 3a0968b

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +176 -0
app.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ from PIL import Image
3
+ import streamlit as st
4
+ from streamlit_drawable_canvas import st_canvas
5
+ import numpy as np
6
+ from keras.models import load_model
7
+ from keras.preprocessing import image
8
+ import keras.utils as image
9
+ import cv2
10
+ from data import Getdetail
11
+
12
+ st.title('JLPTN5 handwriting Kanji recognition.')
13
+
14
+ labels = ['一', '七', '万', '三', '上', '下', '中', '九', '二', '五', '人', '今', '休', '何', '先', '入', '八', '六', '円', '出', '分', '前', '北', '十', '千', '午', '半', '南', '友', '右', '名', '四', '国', '土', '外', '大', '天', '女', '子', '学', '小', '山', '川', '左', '年', '後', '日', '明', '時', '書', '月', '木', '本', '来', '東', '校', '母', '毎', '気', '水', '火', '父', '生', '男', '白', '百', '聞', '行', '西', '見', '話', '語', '読', '車', '金', '長', '間', '雨', '電', '食', '高']
15
+ model = load_model("./Lenet5_Dropout2.h5")
16
+
17
+ st.sidebar.title("NihonGO !")
18
+ st.sidebar.caption("Handwriting kanji recognition system.")
19
+ options = ("Sketchpad input", "Image input", "about JLPTN5", "about NihonGO !")
20
+ choice = st.sidebar.selectbox("Select input options",options)
21
+ st.sidebar.caption("Dev by : Tanaanan Chalermpan")
22
+ st.sidebar.caption("Computer Science Kasetsart U. Thailand")
23
+
24
+
25
+
26
+ def predict_img_sketch(img_path):
27
+ st.write("Predicted result.")
28
+ if img_path is not None:
29
+ img = Image.fromarray(img_path) # use pillow to load a image
30
+ img = img.convert('L')
31
+ img = np.array(img) # convert img to an array
32
+ ret, thresh1 = cv2.threshold(img, 110, 255, cv2.THRESH_BINARY) # Apply binary threshold
33
+ thresh1 = cv2.cvtColor(thresh1, cv2.COLOR_GRAY2RGB) # Convert back to RGB
34
+ img_array = cv2.resize(thresh1, (120, 120)) # Resize the image
35
+ img_array = np.expand_dims(img_array, axis=0)
36
+ preds = model.predict(img_array)
37
+ return preds
38
+
39
+ def image_display(img_path):
40
+ st.write("Predicted image.")
41
+ if img_path is not None:
42
+ img = Image.open(img_path)
43
+ img = img.resize((120,120)).convert('L')
44
+ st.image(img, caption='Uploaded Image', use_column_width=True)
45
+
46
+ def predict_img_input(img_path):
47
+ st.write("Predicted result.")
48
+ if img_path is not None:
49
+ img = Image.open(img_path) # use pillow to load a image
50
+ img = img.convert('L')
51
+ img = np.array(img) # convert img to an array
52
+ ret, thresh1 = cv2.threshold(img, 110, 255, cv2.THRESH_BINARY) # Apply binary threshold
53
+ thresh1 = cv2.cvtColor(thresh1, cv2.COLOR_GRAY2RGB) # Convert back to RGB
54
+ img_array = cv2.resize(thresh1, (120, 120)) # Resize the image
55
+ img_array = np.expand_dims(img_array, axis=0)
56
+ preds = model.predict(img_array)
57
+ return preds
58
+
59
+ if choice == "Sketchpad input":
60
+
61
+
62
+ col1,col2 = st.columns(2)
63
+ with col2:
64
+ stroke_width = st.slider("Stroke width: ", 8, 25, 8)
65
+
66
+ with col1:
67
+ # ref : https://github.com/andfanilo/streamlit-drawable-canvas
68
+ canvas_result = st_canvas(
69
+ fill_color="rgba(255, 165, 0, 0.3)", # Fixed fill color with some opacity
70
+ stroke_width=stroke_width,
71
+ stroke_color="#000000", # stroke to black
72
+ background_color="#FFFFFF", # background to write
73
+ background_image= None,
74
+ update_streamlit=False,
75
+ height=300,
76
+ width=300,
77
+ drawing_mode="freedraw",
78
+ point_display_radius=0,
79
+ key="canvas",
80
+ )
81
+ # Do something interesting with the image data and paths
82
+ if canvas_result.image_data is not None:
83
+ st.image(canvas_result.image_data, caption='display_show')
84
+
85
+ with col2:
86
+ # check if sketchinput is empty from len json_data
87
+ is_empty = 0
88
+ if canvas_result.image_data is not None: # beware of slow loading
89
+ is_empty = canvas_result.json_data["objects"] # need to convert obj to str because PyArrow
90
+
91
+ if is_empty:
92
+ # display prediction
93
+ pred_raw = predict_img_sketch(canvas_result.image_data)
94
+ if pred_raw is not None:
95
+ pred_class, accuracy = labels[np.argmax(pred_raw)], np.max(pred_raw)*100
96
+ st.write(f"Class : {labels[np.argmax(pred_raw)]}")
97
+ st.write(f"with accuracy : {accuracy:.2f} %")
98
+
99
+ st.divider()
100
+ strokes = Getdetail()[pred_class]['Strokes']
101
+ meaning = Getdetail()[pred_class]['Meaning']
102
+ onyoumi = Getdetail()[pred_class]['Onyoumi']
103
+ kunyomi = Getdetail()[pred_class]['Kunyoumi']
104
+ link_ref = Getdetail()[pred_class]['Reference']
105
+
106
+ st.write(f"Strokes : {strokes}")
107
+ st.write(f"Meaning : {meaning.capitalize()}")
108
+ st.write(f"Onyoumi : {onyoumi}")
109
+ st.write(f"Kunyoumi : {kunyomi}")
110
+ st.write(f"for more detail : [Shirabe jisho]({link_ref})")
111
+
112
+ elif choice == "Image input":
113
+ upload_img = st.file_uploader("Choose a kanji image", type=['.jpg', '.png', '.jpeg'])
114
+ col1,col2 = st.columns(2)
115
+
116
+ with col1:
117
+ image_display(upload_img)
118
+
119
+ with col2:
120
+ # display prediction
121
+ pred_raw = predict_img_input(upload_img)
122
+ if pred_raw is not None:
123
+ pred_class, accuracy = labels[np.argmax(pred_raw)], np.max(pred_raw)*100
124
+ st.write(f"Class : {labels[np.argmax(pred_raw)]}")
125
+ st.write(f"with accuracy : {accuracy:.2f} %")
126
+
127
+ st.write('---------------------------------------')
128
+ strokes = Getdetail()[pred_class]['Strokes']
129
+ meaning = Getdetail()[pred_class]['Meaning']
130
+ onyoumi = Getdetail()[pred_class]['Onyoumi']
131
+ kunyomi = Getdetail()[pred_class]['Kunyoumi']
132
+ link_ref = Getdetail()[pred_class]['Reference']
133
+
134
+ st.write(f"Strokes : {strokes}")
135
+ st.write(f"Meaning : {meaning.capitalize()}")
136
+ st.write(f"Onyoumi : {onyoumi}")
137
+ st.write(f"Kunyoumi : {kunyomi}")
138
+ st.write(f"for more detail : [Shirabe jisho]({link_ref})")
139
+
140
+ elif choice == "about JLPTN5":
141
+ df = pd.read_csv('./passjapanesetest.com_N5_Kanji.csv', encoding='cp932')
142
+ st.subheader("JLPT คืออะไร")
143
+ detail_1 = '''ย่อมาจาก Japanese Language Proficiency Test การสอบวัดระดับภาษาญี่ปุ่น คือ การสอบที่จัดขึ้นเพื่อวัดความสามารถทางภาษาญี่ปุ่น ของชาวต่างชาติผู้เรียนภาษาญี่ปุ่น
144
+
145
+ การสอบวัดระดับภาษาญี่ปุ่นครั้งแรก จัดขึ้นในปี ค.ศ. 1984 มีผู้สมัครสอบ 7,998 คน และมีผู้สมัครสอบเพิ่มขึ้นมากทุกปี สถิติในปี ค.ศ. 2019 มีผู้สมัครสอบถึง 1,362,167 คนทั่วโลก'''
146
+ st.markdown(detail_1)
147
+ st.markdown('''- โดยระดับ N5 ถือเป็นระดับที่ง่ายที่สุดในการสอบ แต่พาร์ทที่หินที่สุดส่วนหนึ่งก็คือ พาร์ท คันจิ N5 ***ผู้พัฒนาจึงสร้างระบบที่วิเคราะห์ตัวอักษรคันจิได้จากลายมือเขียน
148
+ เพื่อที่จะเป็นตัวช่วยหนึ่งในการให้ผู้ใช้งานได้ใช้ในการฝึกฝนได้***''')
149
+
150
+ st.caption("List of JLPTN5 Kanji")
151
+ st.write(df)
152
+
153
+ st.caption('ref : [jeducation](https://jeducation.com/main/education/jlpt/) , [passjapanesetest](http://www.passjapanesetest.com/jlpt-n5-kanji-list/)')
154
+
155
+ elif choice == "about NihonGO !":
156
+ st.subheader("NihonGO ! คืออะไร")
157
+ detail_2 = """NihonGO ! : เป็นระบบที่ใช้ในการวิเคราะห์ตัวอักษรคันจิจากลายมือเขียนโดยอัติโนมัติ โดยใช้หลักการของ Deep learning (Convolutional Neural Network) ในการแยกแยะตัวอักษรคันจิ
158
+ เพื่อใช้เป็นตัวช่วยในการฝึกฝนการเขียนคันจิ และเป็นตัวช่วยในการฝึกฝนในการเตรียมสอบวัดระดับ JLPT"""
159
+ st.markdown(detail_2)
160
+ st.caption("Development.")
161
+ st.markdown("- JLPTN5 : ระบบสามารถแยกแยะคันจิจำนวน 80 ตัวพื้นฐานตามเนื้อหาคันจิจากการสอบวัดระดับ JLPTN5")
162
+ st.image('total_kanji.png', caption='JLPTN5 Kanji detail')
163
+ st.subheader("Feature")
164
+ st.markdown(""" 1. บอกคันจิที่ระบบตรวจจับได้พร้อมกับค่าความเชื่อมั่น (accuracy score.)
165
+
166
+ 2. จำนวนเส้น stroke ที่ใช้ในการเขียนคันจิ
167
+
168
+ 3. เสียงอ่านแบบ Onyoumi กับ Kunyoumi พร้อมกับตัวอักษร Romanji
169
+
170
+ 4. Link เนื้อหาเพิ่มเติมโดยระเอียดกับ website Shirabe jisho""")
171
+ st.subheader("Guideline")
172
+ st.markdown(""" - เพื่อความแม่นยำของระบบ ตอนนำข้อมูลรูปภาพเข้า หรือเขียนในระบบแนะนำให้ผู้ใช้งานเขียนตัวคันจิให้อยู่ตรงกลาง และมีขนาดที่ใหญ่พอดีกับขนาดของกรอบ""")
173
+ st.caption("ref : [kanshudo](https://www.kanshudo.com/collections/jlpt_kanji)")
174
+
175
+
176
+