--- title: 【Python】顔画像をPOST 、 顔検出 、 canvasで顔にお絵かき【JS】 tags: Python JavaScript canvas OpenCV axios author: s-yoshiki slide: false --- ### [※こちらに移行しました。 ← 2018/11/24](https://tech-blog.s-yoshiki.com/entry/19/) # 概要 「顔検出をして、顔に絵を描く」というもの。 具体的には、 顔写真の画像をAPIサーバへアップロードし、顔検出を行う。 サーバは顔座標を返し、それを元にcanvasでお絵かきする。 ### 参考 [【Python】顔画像をPOST 、 顔検出 、 canvasで顔にお絵かき【JS】](https://tech-blog.s-yoshiki.com/entry/19) [【Python】Apache + WSGI + Flask でWebアプリケーション構築](https://tech-blog.s-yoshiki.com/entry/9) # 環境 ### フロント html + JS + canvas axios.jsでAPIを叩く ### サーバサイド Ubutnu 16.04 Python + Flask OpenCV 3.2 など # アプリケーション ![face_detection](https://qiita-image-store.s3.amazonaws.com/0/82419/a99e665d-5cc3-f2cc-482b-bbe1c99d7c2c.png) こんなイメージ。 とりあえず、顔に枠線を書いている。 画像の描画、顔へのお絵かきは全てJSで実装。 サーバ側は顔検出するだけ。 下記にソース。 # ディレクトリ構成 ```sh ./ ├── face_detect.py # 顔検出の処理 ├── index.py # リクエスト処理 ├── templates # html(テンプレート) │   └── index.html └── tmp # アップロードされた画像格納ディレクトリ └── sample.jpg ``` # フロント ファイルが選択されたら、canvasに画像を描画。 ボタン押下時にPOST。 POST処理はJSで。 #### html ```index.html

``` #### js requestを投げるのにaxiosを使ってみた。 ```index.js (function(){ document.getElementById("run").addEventListener("click", function(){ var params = new FormData(); var file = document.getElementById("image").files[0] params.append('image', file) axios.post('/api', params).then(function(response) { response.data.forEach((e) => { var v = e.face drawRect(v.x, v.y, v.w, v.h) e.eyes.forEach((eye) => { eye.x += v.x eye.y += v.y drawRect(eye.x, eye.y, eye.w, eye.h) }) }) }).catch(function(error) { alert("error") }); }) document.getElementById("image").addEventListener("change", function(e) { var file = e.target.files; var reader = new FileReader(); reader.readAsDataURL(file[0]); reader.onload = function() { var source = reader.result; drawImage(reader.result) } }, false); function drawImage(src) { var canvas = document.getElementById("canvas") var context = canvas.getContext('2d') var image = new Image() image.src = src; image.onload = function() { canvas.width = image.width canvas.height = image.height context.drawImage(image, 0, 0) } } function drawRect(x, y, w, h) { var canvas = document.getElementById("canvas") var context = canvas.getContext('2d') context.rect(x, y, w, h); context.stroke(); } })() ``` ##### メモ drawRectが顔画像の描画処理を行なっている。 # サーバ サーバサイドはPython + Flaskで実装。 顔画像処理はOpenCV、numpyなどで実装。 顔検出のサンプルソース - OpenCV #### index.py ```index.py import os,sys from flask import Flask, render_template, request, jsonify from jinja2 import FileSystemLoader import base64 from face_detect import get_facepos app = Flask(__name__) app.config['MAX_CONTENT_LENGTH'] = 1 * 1024 * 1024 app.config['UPLOAD_FOLDER'] = './tmp' @app.route("/", methods=['GET']) def get_index(): return render_template('index.html') @app.route("/api", methods=['POST']) def face_detect(): img = request.files['image'] name = img.filename path = os.path.join(app.config['UPLOAD_FOLDER'], name) img.save(path) face_pos = get_facepos(path) return jsonify(face_pos) ``` #### face_detect.py ```face_detect.py import numpy as np import cv2 def get_facepos(img_path): face_cascade = cv2.CascadeClassifier('/path/to/haarcascade_frontalface_default.xml') eye_cascade = cv2.CascadeClassifier('/path/to/haarcascades/haarcascade_eye_tree_eyeglasses.xml') img = cv2.imread(img_path) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3, 5) result = [] for (x,y,w,h) in faces: face_dst = { "x": np.asscalar(x), "y": np.asscalar(y), "w": np.asscalar(w), "h": np.asscalar(h) } eyes_dst = [] roi_gray = gray[y:y+h, x:x+w] eyes = eye_cascade.detectMultiScale(roi_gray) for (ex,ey,ew,eh) in eyes: eye_pos = { "x": np.asscalar(ex), "y": np.asscalar(ey), "w": np.asscalar(ew), "h": np.asscalar(eh) } eyes_dst.append(eye_pos) result.append({ "face": face_dst, "eyes": eyes_dst }) return result ``` ##### メモ1 カスケードファイルであるhaarcascade_frontalface_default.xmlなどは、 フルパスではなくファイル名だけで読み込めるはずですが、 特殊な環境など、読めない環境では、パスを記載する。 ##### メモ2 face_detect.pyで宣言している顔検出ご座標`(x,y,w,h)`をそのままListに格納し、 JSONに変換して出力しようとすると、エラーが発生する。(int32がなんたら...って言ってた) とりあえず、`np.asscalar()`を使って回避することができた。 # 参考 [【Python】顔画像をPOST 、 顔検出 、 canvasで顔にお絵かき【JS】](https://tech-blog.s-yoshiki.com/2018/07/210/) [【Python】Apache + WSGI + Flask でWebアプリケーション構築](https://tech-blog.s-yoshiki.com/2018/05/104/)