つまりなにしたの?
Flaskで作られたWebサーバに画像が投稿されたらOpenCVで加工して結果をブラウザに表示するようにした。
環境
% python --version Python 3.6.4 % pip freeze Flask==1.0.2 opencv-python==3.4.0.12 numpy==1.14.1
大まかな手順
- Indexでフォームを表示する
- フォームで追加されたファイルを受け取る
- OpenCVで読み込む
- ファイルを加工する(縮小とか、色を変えたりとか)
- 元画像と加工画像を保存する
- 加工した画像と元画像のURLを返して元のフォームと一緒に表示する
ディレクトリ構造と実行方法
- ディレクトリ構造
% tree . . ├── templates │ └── index.html ├── uploads └── app.py
- 実行方法
python app.py
コード
アプリケーションサーバのコード
- app.py
import os import io import time import numpy as np import cv2 from flask import Flask, render_template, request, redirect, url_for, send_from_directory, session from werkzeug import secure_filename app = Flask(__name__) UPLOAD_FOLDER = './uploads' ALLOWED_EXTENSIONS = set(['png', 'jpg', 'PNG', 'JPG']) IMAGE_WIDTH = 640 app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER app.config['SECRET_KEY'] = os.urandom(24) def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS @app.route('/') def index(): return render_template('index.html') @app.route('/send', methods=['GET', 'POST']) def send(): if request.method == 'POST': img_file = request.files['img_file'] # 変なファイル弾き if img_file and allowed_file(img_file.filename): filename = secure_filename(img_file.filename) else: return ''' <p>許可されていない拡張子です</p> ''' # BytesIOで読み込んでOpenCVで扱える型にする f = img_file.stream.read() bin_data = io.BytesIO(f) file_bytes = np.asarray(bytearray(bin_data.read()), dtype=np.uint8) img = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR) # とりあえずサイズは小さくする raw_img = cv2.resize(img, (IMAGE_WIDTH, int(IMAGE_WIDTH*img.shape[0]/img.shape[1]))) # サイズだけ変えたものも保存する raw_img_url = os.path.join(app.config['UPLOAD_FOLDER'], 'raw_'+filename) cv2.imwrite(raw_img_url, raw_img) # なにがしかの加工 gray_img = cv2.cvtColor(raw_img, cv2.COLOR_BGR2GRAY) # 加工したものを保存する gray_img_url = os.path.join(app.config['UPLOAD_FOLDER'], 'gray_'+filename) cv2.imwrite(gray_img_url, gray_img) return render_template('index.html', raw_img_url=raw_img_url, gray_img_url=gray_img_url) else: return redirect(url_for('index')) @app.route('/uploads/<filename>') def uploaded_file(filename): return send_from_directory(app.config['UPLOAD_FOLDER'], filename) if __name__ == '__main__': app.debug = True app.run()
テンプレートファイル(index.html)のコード
- index.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>File</title> </head> <body> <form method="post" action="/send" enctype="multipart/form-data"> <input type="file" id="img_file" name="img_file"> <input type="submit" value="送信"> </form> <p> {% if raw_img_url %} <img src="{{ raw_img_url }}"> {% endif %} {% if gray_img_url %} <img src="{{ gray_img_url }}"> {% endif %} </p> </body> </html>
実行結果
名古屋の辛いラーメンを白黒画像にしてやることができました。