今天要做的是...
做一个前端网页,支援拖动图片上传,
把图片转成 base64 送给服务器,服务器将 base64 转回图片後进行辨识传回结果。
这边是 index.html,新增了一个 250x250 的 mycanvas,并改写拖动事件,
mycanvas 在drop事件後会呼叫 fileReader 读取档案,
fileReader 读取档案後会写入 img 变数,
image 物件被写入後,会将内容画在 mycanvas 上。
fileReader.result 和 image.src 都是字串,而格式为 data:image/png;base64, 後接 base64 字串,如下范例。
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA....
mybutton 被按下後,会将上段字串送至後端的 /mnist 路径。
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<canvas id="mycanvas" width="250" height="250">
Your browser does not support the HTML5 canvas tag.</canvas>
<button id="mybutton">送出</button>
</body>
</html>
<script>
var mycanvas = document.getElementById("mycanvas");
var image = new Image();
var ctx = document.getElementById("mycanvas").getContext("2d");
var fileReader = new FileReader();
mycanvas.ondragover = function (e) {
e.preventDefault();
}
mycanvas.ondrop = function (e) {
e.preventDefault();
let f = e.dataTransfer.files[0];
fileReader.readAsDataURL(f);
}
fileReader.onload = function () {
image.src = fileReader.result;
}
image.onload = function () {
ctx.drawImage(image, 0, 0, 250, 250);
};
var mybutton = document.getElementById("mybutton");
mybutton.onclick = function() {
$.post("/mnist",
{
"base64_str": image.src
},
function(data, status){
alert("Data: " + data + "\nStatus: " + status);
console.log(data);
});
}
</script>
後端这里则是新增了一个路径 /mnist,作为辨识网址,它会接收 base64_str 变数并依照","裁切。 (因为辨识只需要 base64 字串)
成功後 flask jsonify 会将物件以 json 格式回传。
# a01_flask_server.py
import base64
from flask import Flask, render_template, request, jsonify
app = Flask("mnist")
import a06_mnist_api
@app.route("/")
def hello_world():
return render_template('index.html')
@app.route("/mnist", methods = ['POST'])
def mnist():
# base64tag = "data:image/png;base64"
data = request.form.get("base64_str").split(",", 1)
if len(data) == 2:
return jsonify(a06_mnist_api.predict_from_base64(data[1]))
return jsonify([False])
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5050)
这边则是进行影像处理的部分,先将 base64_str 转成 bytes-like object,
後使用 np.frombuffer 把 bytes-like object 转成 numpy array,
使用 cv2.imdecode 灰阶模式读取 numpy array,
然後缩放图片至 28x28,最後丢进模型预测。
flask jsonify 不支援将 numpy 的数值直接转为 json,所以在最後用两层回圈将预测结果转成 float,并四舍五入至小数点二位。
# a06_mnist_api.py
import tensorflow as tf
import numpy as np
import base64
import cv2
saved_model_path = "mnist"
model = tf.keras.models.load_model(saved_model_path)
def predict_from_base64(base64_str):
decoded = base64.b64decode(base64_str)
np_arr = np.frombuffer(decoded,np.uint8)
imggray = cv2.imdecode(np_arr, cv2.IMREAD_GRAYSCALE)
resized = cv2.resize(imggray, (28, 28))
return predict_from_img_array(resized)
def predict_from_img_array(img_array):
input_arr = np.array([img_array]) # Convert single image to a batch.
predictions = model.predict(input_arr)
return [ [round(float(j), 2) for j in i] for i in predictions]
最後结果
我们的前端并不是一个精美的UI,在本次Lab中实做了前端有两个目的 方便测试 好的前端能减经後端的负...
雇用问题 假设你要雇用新的办公助理,而你找了一个雇用代理人去帮你推荐应聘的人,雇用代理人每天会给你推...
今天我们来聊聊生成对抗网路 (Generative Adversarial Network, GAN...
在疫情期间相信大家都有在线上上课或会议的经验, 有时候我们会觉得老师上课的声音(或会议应用程序拨放的...
大家好,我是乌木白,今天是铁人赛最後一天,谢谢大家在这些天不管是无意或是有意的点进来参观,都非常感...