【Python】顔画像をPOST 、 顔検出 、 canvasで顔にお絵かき【JS】


※こちらに移行しました。 ← 2018/11/24


概要

「顔検出をして、顔に絵を描く」というもの。

具体的には、

顔写真の画像をAPIサーバへアップロードし、顔検出を行う。

サーバは顔座標を返し、それを元にcanvasでお絵かきする。


参考

【Python】顔画像をPOST 、 顔検出 、 canvasで顔にお絵かき【JS】

【Python】Apache + WSGI + Flask でWebアプリケーション構築


環境


フロント

html + JS + canvas

axios.jsでAPIを叩く


サーバサイド

Ubutnu 16.04

Python + Flask

OpenCV 3.2

など


アプリケーション

face_detection

こんなイメージ。

とりあえず、顔に枠線を書いている。

画像の描画、顔へのお絵かきは全てJSで実装。

サーバ側は顔検出するだけ。

下記にソース。


ディレクトリ構成

./

├── face_detect.py # 顔検出の処理
├── index.py # リクエスト処理
├── templates # html(テンプレート)
│   └── index.html
└── tmp # アップロードされた画像格納ディレクトリ
└── sample.jpg


フロント

ファイルが選択されたら、canvasに画像を描画。

ボタン押下時にPOST。

POST処理はJSで。


html


index.html


<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.js"></script>
</head>
<body>
<div class="container">
<canvas id="canvas"></canvas>
<hr>
<label>
画像
<input type="file" class="form-control" id="image">
</label>
<button id="run">
submit
</button>
</div>
<script src="index.js">
</script>
</body>
</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】

【Python】Apache + WSGI + Flask でWebアプリケーション構築