概要
今回はフロントエンドにVue.js、バックエンドにFlaskを用いた画像認識アプリを作ります。
ひとまず今回は画像アップロード機能までの実装です。
環境
- Docker
- Vue-cli
- flask (pipenv)
上記の環境で環境構築しました。
手順や詳細は以下のリンクを参照してください。
要所の説明
Vue
詳細を説明するのは、以下のコード。
Home.vue
// 画像をサーバーへアップロード
onUploadImage () {
var params = new FormData()
params.append('image', this.uploadedImage)
// Axiosを用いてFormData化したデータをFlaskへPostしています。
axios.post(`${API_URL}/classification`, params).then(function (response) {
console.log(response)
})
- 取得した画像はBase64化がなされている。「data:image/jpeg:base64,〜」
- FormDataにより、データをHTTPリクエストで「キー:値」の形式へ。
- Axiosを適用し、'127.0.0.1:5000/classification'+ POSTメソッドでデータを送信。
Flask
詳細を説明するのは、以下のコード。
app.py
@app.route('/classification', methods=['POST'])
def uploadImage():
if request.method == 'POST':
base64_png = request.form['image']
code = base64.b64decode(base64_png.split(',')[1])
image_decoded = Image.open(BytesIO(code))
image_decoded.save(Path(app.config['UPLOAD_FOLDER']) / 'image.png')
return make_response(jsonify({'result': 'success'}))
else:
return make_response(jsonify({'result': 'invalid method'}), 400)
- FormDataの内部に「data:image/jpeg:base64,〜」が存在。ファイル名を取得。
- Pillow(PIL)で画像を取得。
- 画像の保存。
#全体像
Vue
Home.vue
<template>
<div>
<div class="imgContent">
<div class="imagePreview">
<img :src="uploadedImage" style="width:100%;" />
</div>
<input type="file" class="file_input" name="photo" @change="onFileChange" accept="image/*" />
<button @click='onUploadImage'>画像判定してくだちい・・・</button>
</div>
</div>
</template>
<script>
import axios from 'axios'
const API_URL = 'http://127.0.0.1:5000'
export default {
data () {
return {
uploadedImage: ''
}
},
methods: {
// 選択した画像を反映
onFileChange (e) {
let files = e.target.files || e.dataTransfer.files
this.createImage(files[0])
},
// アップロードした画像を表示
createImage (file) {
let reader = new FileReader()
reader.onload = (e) => {
this.uploadedImage = e.target.result
}
reader.readAsDataURL(file)
},
// 画像をサーバーへアップロード
onUploadImage () {
var params = new FormData()
params.append('image', this.uploadedImage)
// Axiosを用いてFormData化したデータをFlaskへPostしています。
axios.post(`${API_URL}/classification`, params).then(function (response) {
console.log(response)
})
}
}
}
</script>
Flask
###留意点
- CORSにより、異なるオリジン(プロトコルやドメイン、ポート)でもリソースを共有できる。
- CORSは異なるWebアプリケーションを持つ場合、必須。
- app.config['JSON_AS_ASCII'] = False により日本語対応可能。
app.py
# render_template:参照するテンプレートを指定
# jsonify:json出力
from flask import Flask, render_template, jsonify, request, make_response
# CORS:Ajax通信するためのライブラリ
from flask_restful import Api, Resource
from flask_cors import CORS
from random import *
from PIL import Image
from pathlib import Path
from io import BytesIO
import base64
# static_folder:vueでビルドした静的ファイルのパスを指定
# template_folder:vueでビルドしたindex.htmlのパスを指定
app = Flask(__name__, static_folder = "./../frontend/dist/static", template_folder="./../frontend/dist")
#日本語
app.config['JSON_AS_ASCII'] = False
#CORS=Ajaxで安全に通信するための規約
api = Api(app)
CORS(app)
UPLOAD_FOLDER = './uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
# 任意のリクエストを受け取った時、index.htmlを参照
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def index(path):
return render_template("index.html")
@app.route('/classification', methods=['POST'])
def uploadImage():
if request.method == 'POST':
base64_png = request.form['image']
code = base64.b64decode(base64_png.split(',')[1])
image_decoded = Image.open(BytesIO(code))
image_decoded.save(Path(app.config['UPLOAD_FOLDER']) / 'image.png')
return make_response(jsonify({'result': 'success'}))
else:
return make_response(jsonify({'result': 'invalid method'}), 400)
# app.run(host, port):hostとportを指定してflaskサーバを起動
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
こんな感じ
#非常に参考になりました
https://developer.mozilla.org/ja/docs/Web/HTTP/CORS
画像をPOST、顔検出、canvasで顔にお絵かき