鄭宇翔
commited on
Commit
·
d171e6f
0
Parent(s):
Initial commit with LFS
Browse files- .DS_Store +0 -0
- .gitattributes +1 -0
- README.md +13 -0
- app.py +34 -0
- letter_cnn_model.h5 +3 -0
- requirements.txt +5 -0
- static/script.js +44 -0
- templates/index.html +20 -0
.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
.gitattributes
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
title: Boddyletter Recognizer
|
3 |
+
emoji: 👀
|
4 |
+
colorFrom: pink
|
5 |
+
colorTo: indigo
|
6 |
+
sdk: gradio
|
7 |
+
sdk_version: 5.36.2
|
8 |
+
app_file: app.py
|
9 |
+
pinned: false
|
10 |
+
license: mit
|
11 |
+
---
|
12 |
+
|
13 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from flask import Flask, render_template, request, jsonify
|
2 |
+
import numpy as np
|
3 |
+
from PIL import Image
|
4 |
+
import io
|
5 |
+
import base64
|
6 |
+
from tensorflow.keras.models import load_model
|
7 |
+
|
8 |
+
app = Flask(__name__)
|
9 |
+
model = load_model("letter_cnn_model.h5")
|
10 |
+
labels = [chr(ord('a') + i) for i in range(26)]
|
11 |
+
|
12 |
+
@app.route("/")
|
13 |
+
def index():
|
14 |
+
return render_template("index.html")
|
15 |
+
|
16 |
+
@app.route("/predict", methods=["POST"])
|
17 |
+
def predict():
|
18 |
+
data = request.json["image"]
|
19 |
+
image_data = base64.b64decode(data.split(",")[1])
|
20 |
+
img = Image.open(io.BytesIO(image_data)).convert("L").resize((28, 28))
|
21 |
+
img = 255 - np.array(img)
|
22 |
+
img = img / 255.0
|
23 |
+
img = img.reshape(1, 28, 28, 1)
|
24 |
+
pred = model.predict(img)
|
25 |
+
index = np.argmax(pred[0])
|
26 |
+
label = labels[index].upper()
|
27 |
+
confidence = float(pred[0][index])
|
28 |
+
return jsonify({
|
29 |
+
"label": label,
|
30 |
+
"confidence": confidence
|
31 |
+
})
|
32 |
+
|
33 |
+
if __name__ == "__main__":
|
34 |
+
app.run(debug=True)
|
letter_cnn_model.h5
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:bbcde11cd7b8cad7236355ab641b31f1b9d6c00cb21acabee1c5dd8f7b0d9ae8
|
3 |
+
size 1514752
|
requirements.txt
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
flask
|
3 |
+
tensorflow
|
4 |
+
pillow
|
5 |
+
numpy
|
static/script.js
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
const canvas = document.getElementById("canvas");
|
3 |
+
const ctx = canvas.getContext("2d");
|
4 |
+
ctx.fillStyle = "black";
|
5 |
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
6 |
+
ctx.strokeStyle = "white";
|
7 |
+
ctx.lineWidth = 16;
|
8 |
+
ctx.lineCap = "round";
|
9 |
+
|
10 |
+
let drawing = false;
|
11 |
+
|
12 |
+
canvas.onmousedown = () => drawing = true;
|
13 |
+
canvas.onmouseup = () => drawing = false;
|
14 |
+
canvas.onmousemove = (e) => {
|
15 |
+
if (drawing) {
|
16 |
+
const rect = canvas.getBoundingClientRect();
|
17 |
+
ctx.lineTo(e.clientX - rect.left, e.clientY - rect.top);
|
18 |
+
ctx.stroke();
|
19 |
+
ctx.beginPath();
|
20 |
+
ctx.moveTo(e.clientX - rect.left, e.clientY - rect.top);
|
21 |
+
}
|
22 |
+
};
|
23 |
+
|
24 |
+
function clearCanvas() {
|
25 |
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
26 |
+
ctx.beginPath();
|
27 |
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
28 |
+
document.getElementById("result").innerText = "";
|
29 |
+
}
|
30 |
+
|
31 |
+
function submit() {
|
32 |
+
const image = canvas.toDataURL();
|
33 |
+
fetch("/predict", {
|
34 |
+
method: "POST",
|
35 |
+
headers: { "Content-Type": "application/json" },
|
36 |
+
body: JSON.stringify({ image })
|
37 |
+
})
|
38 |
+
.then(res => res.json())
|
39 |
+
.then(data => {
|
40 |
+
const text = `辨識結果:${data.label}\n信心值:${(data.confidence * 100).toFixed(2)}%`;
|
41 |
+
document.getElementById("result").innerText = text;
|
42 |
+
});
|
43 |
+
|
44 |
+
}
|
templates/index.html
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<!DOCTYPE html>
|
3 |
+
<html lang="en">
|
4 |
+
<head>
|
5 |
+
<meta charset="UTF-8">
|
6 |
+
<title>手寫字母辨識</title>
|
7 |
+
<style>
|
8 |
+
canvas { background: black; border: 1px solid white; }
|
9 |
+
body { text-align: center; background: #222; color: #eee; font-family: sans-serif; }
|
10 |
+
</style>
|
11 |
+
</head>
|
12 |
+
<body>
|
13 |
+
<h1>手寫字母辨識</h1>
|
14 |
+
<canvas id="canvas" width="280" height="280"></canvas><br>
|
15 |
+
<button onclick="clearCanvas()">清除</button>
|
16 |
+
<button onclick="submit()">辨識</button>
|
17 |
+
<h2 id="result"></h2>
|
18 |
+
<script src="/static/script.js"></script>
|
19 |
+
</body>
|
20 |
+
</html>
|