File size: 4,043 Bytes
3b86270
 
09633a1
3b86270
d05d4ae
 
8837f64
d05d4ae
 
 
8837f64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3b86270
 
8837f64
09633a1
 
 
 
 
 
 
 
 
 
8837f64
09633a1
8837f64
 
 
 
 
 
 
 
 
 
 
09633a1
8837f64
 
3b86270
 
 
 
09633a1
 
 
 
8837f64
 
09633a1
d05d4ae
 
8837f64
 
 
 
 
 
 
 
 
 
 
 
 
 
3b86270
8837f64
 
 
 
 
 
d05d4ae
 
 
 
8837f64
 
 
 
 
 
 
 
d05d4ae
 
3b86270
 
 
 
8837f64
d05d4ae
09633a1
 
 
d05d4ae
ba0dd03
 
 
09633a1
 
 
8837f64
ba0dd03
8837f64
 
09633a1
 
8837f64
 
 
 
 
09633a1
 
8837f64
 
 
 
09633a1
 
8837f64
 
d05d4ae
 
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import os
import random
from copy import deepcopy

import gradio as gr
import numpy as np
from romkan import to_roma

from ocr import Recognizer

kana_list = """
あいうえお
かきくけこ
がぎぐげご
さしすせそ
ざじずぜぞ
たちつてと
だぢづでど
なにぬねの
はひふへほ
ばびぶべぼ
ぱぴぷぺぽ
まみむめも
やゆよ
らりるれろ
わを


アイウエオ
カキクケコ
ガギグゲゴ
サシスセソ
ザジズゼゾ
タチツテト
ダヂヅデド
ナニヌネノ
ハヒフヘホ
バビブベボ
パピプペポ
マミムメモ
ヤユヨ
ラリルレロ
ワヲ

"""
kana_list = [c for c in kana_list if c.strip()]

chars = [os.path.join(dn, fn) for dn, _, ff in os.walk("chars") for fn in ff]


def init_chars():
    curr_chars = deepcopy(chars)
    random.shuffle(curr_chars)
    return curr_chars


def get_char(ch=None, assist=True, kana=True, curr_chars: list = []):
    if not curr_chars:
        curr_chars = init_chars()

    if ch is None:
        img_path = curr_chars.pop()
        ch = img_path[-5]
    else:
        img_path = f"chars/{ch}.png"

    if not assist:
        img_path = "bg.png"

    info = f"{ch} ({to_roma(ch)})"
    if not kana:
        info = f"{to_roma(ch)}"

    return ch, img_path, info, curr_chars


font = gr.themes.GoogleFont("Noto Sans")
theme = gr.themes.Soft(font=font)

with gr.Blocks(theme=theme, title="Kana Writer") as app:
    ch = "あ"
    char_img = "chars/あ.png"
    roma = "あ (a)"

    curr_img_path = gr.State(char_img)
    curr_char = gr.State(ch)
    curr_chars = gr.State([])
    recog = Recognizer("model/model.xml", "model/char_list.txt")

    with gr.Tab("寫字練習"):
        brush = gr.Brush(default_color="#111", default_size=15)
        sketch = gr.Sketchpad(
            char_img,
            type="numpy",
            brush=brush,
            layers=False,
            image_mode="RGB",
            eraser=False,
            show_label=False,
        )
        with gr.Row():
            header = gr.Textbox(roma, label="目標")
            result = gr.Textbox(label="辨識結果")

        with gr.Row():
            with gr.Row():
                assist = gr.Checkbox(True, label="輔助")
                kana = gr.Checkbox(True, label="假名")
            rand_btn = gr.Button("隨機")
            check_btn = gr.Button("辨識")

    def parse_item(item):
        prob = item["prob"]
        char = item["char"]
        return f"{char} ({to_roma(char)}): {prob:.2%}"

    def valid_item(item):
        if item["prob"] < 1e-2:
            return False
        if item["char"] not in kana_list:
            return False
        return True

    def do_recog(img: dict[str, np.ndarray]):
        img: np.ndarray = img["layers"][0]
        img[img == 0] = 255
        img[img != 255] = 0
        _, nbest = recog(img)
        return ", ".join(parse_item(item) for items in nbest for item in items if valid_item(item))

    def rand_char(assist, kana, chars):
        char, img, roma, chars = get_char(None, assist, kana, chars)
        return char, img, img, roma, None, chars

    def clear(curr_char):
        return curr_char

    def change_opt(char, assist, kana, chars):
        char, img, roma, chars = get_char(char, assist, kana, chars)
        return char, img, img, roma, chars

    check_btn.click(do_recog, sketch, result, show_progress="minimal")
    rand_btn.click(
        rand_char,
        [assist, kana, curr_chars],
        [curr_char, sketch, curr_img_path, header, result, curr_chars],
        show_progress="minimal",
    )
    sketch.clear(clear, curr_img_path, sketch, show_progress="minimal")
    assist.change(
        change_opt,
        [curr_char, assist, kana, curr_chars],
        [curr_char, sketch, curr_img_path, header, curr_chars],
        show_progress="minimal",
    )
    kana.change(
        change_opt,
        [curr_char, assist, kana, curr_chars],
        [curr_char, sketch, curr_img_path, header, curr_chars],
        show_progress="minimal",
    )

app.launch()