TensorFlowを使ってDir en greyの顔分類器を作ってみた - ⑪Web公開準備編

# はじめに
ここからは周りに自慢するためだけのものなので、自慢したい人だけ使ってください。

# 準備
## ディレクトリ構成
```
ドキュメントルート
├ template
│ ├ index.html
│ └ layout.html
├ static
│ └ images
├ eval.py
├ main.py
├ style.css
└ web.py
```

## プログラム
```py:web.py
#!/usr/local/bin/python
#! -*- coding: utf-8 -*-

import tensorflow as tf
import multiprocessing as mp
from flask import Flask, render_template, request, redirect, url_for
import numpy as np
from werkzeug import secure_filename
import os
import eval

# 自身の名称を app という名前でインスタンス化する
app = Flask(__name__)
app.config['DEBUG'] = True

# 投稿画像の保存先
UPLOAD_FOLDER = '{ドキュメントルートパス}/static/images/'

# ルーティング。/にアクセス時
@app.route('/')
def index():
  return render_template('index.html')

# 画像投稿時のアクション
@app.route('/post', methods=['GET','POST'])
def post():
  if request.method == 'POST':
    if not request.files['file'].filename == u'':
      # アップロードされたファイルを保存
      f = request.files['file']
      img_path = os.path.join(UPLOAD_FOLDER, secure_filename(f.filename))
      f.save(img_path)

      # eval.pyへアップロードされた画像を渡す
      result = eval.evaluation(img_path, '{main.py実行ディレクトリ}パス/model2.ckpt')
    else:
      result = []
    return render_template('index.html', result=result)
  else:
    # エラーなどでリダイレクトしたい場合
    return redirect(url_for('index'))

if __name__ == '__main__':
  app.debug = True
  app.run(host='127.0.0.1')
```

```html:index.html
{% extends "layout.html" %}
{% block content %}
<div class="form">
  <div class="container">
    <div class="row">
      <div class="col-md-12">
        <p style="margin-left:15px;">
          AIが顔写真からDir en greyの顔を検出します。(京、薫、Shinyaに対応)
        </p>
        {% if result %}
          {% if result[0][0]['rate'] > 90 %}
            {% if result[0][0]['label'] == 0 %}
              <h2 style="margin-left:10px;">「<span class="red">{{result[0][0]['name']}}</span>の確率<span class="red">{{result[0][0]['rate']}}</span>%です。」</h2>
              <div class="col-md-7">
                <img src="./static/images/{{result[1]}}" class="detect_img">
              </div>
              <div class="col-md-5">
                <p class="logo_container">
                  <img src='./static/images/kyo.jpg' class="logo">
                </p>
                <p><img src="./static/images/{{result[2]}}" class="cut_image"></p>
                <p class="detail_container">
                  <解析詳細><br>
                  {{result[0][0]['name']}}：{{result[0][0]['rate']}}%<br>
                  {{result[0][1]['name']}}：{{result[0][1]['rate']}}%<br>
                  {{result[0][2]['name']}}：{{result[0][2]['rate']}}%<br>
                </p>
              </div>
            {% elif result[0][0]['label'] == 1 %}
              <h2 style="margin-left:10px;">「<span class="red">{{result[0][0]['name']}}</span>の確率<span class="red">{{result[0][0]['rate']}}</span>%です。」</h2>
              <div class="col-md-7">
                <img src="./static/images/{{result[1]}}" class="detect_img">
              </div>
              <div class="col-md-5">
                <p class="logo_container">
                  <img src='./static/images/kaoru.jpg' class="logo">
                </p>
                <p><img src="./static/images/{{result[2]}}" class="cut_image"></p>
                <p class="detail_container">
                  <解析詳細><br>
                  {{result[0][0]['name']}}：{{result[0][0]['rate']}}%<br>
                  {{result[0][1]['name']}}：{{result[0][1]['rate']}}%<br>
                  {{result[0][2]['name']}}：{{result[0][2]['rate']}}%<br>
                </p>
              </div>
            {% elif result[0][0]['label'] == 2 %}
              <h2 style="margin-left:10px;">「<span class="red">{{result[0][0]['name']}}</span>の確率<span class="red">{{result[0][0]['rate']}}</span>%です。」</h2>
              <div class="col-md-7">
                <img src="./static/images/{{result[1]}}" class="detect_img">
              </div>
              <div class="col-md-5">
                <div>
                  <p class="logo_container"><img src='./static/images/shinya.jpg' class="logo"></p>
                  <p><img src="./static/images/{{result[2]}}" class="cut_image"></p>
                  <p class="detail_container">
                    <解析詳細><br>
                    {{result[0][0]['name']}}：{{result[0][0]['rate']}}%<br>
                    {{result[0][1]['name']}}：{{result[0][1]['rate']}}%<br>
                    {{result[0][2]['name']}}：{{result[0][2]['rate']}}%<br>
                  </p>
                </div>
              </div>
            {% endif %}
          {% else %}
            <h2 style="margin-left:10px;">「どうやら<span class="red">Dir en greyではなさそう</span>です。」</h2>
            <div class="col-md-7">
              <img src="./static/images/{{result[1]}}" class="detect_img">
            </div>
            <div class="col-md-5">
              <p style="margin-top:70px;">
                　　　Who I am?<br>
                <img src="./static/images/{{result[2]}}" class="cut_image"></p>
              <p class="detail_container">
                <解析詳細><br>
                {{result[0][0]['name']}}:{{result[0][0]['rate']}}%<br>
                {{result[0][1]['name']}}:{{result[0][1]['rate']}}%<br>
                {{result[0][2]['name']}}：{{result[0][2]['rate']}}%<br>
              </p>
            </div>
          {% endif %}
        {% else %}
          <div class="col-md-12">
            <h3>顔写真をアップロードしてください！</h3>
          </div>
        {% endif %}
        <div class="col-md-12" style="margin-top:10px; margin-bottom:20px;">
          <form action="/post" method="post" class="form-inline" enctype = "multipart/form-data">
            <input type = "file" name = "file" />
            <button type="submit" class="btn btn-primary" style="margin-top:5px;">Dir en greyの顔をチェック！</button>
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
{% endblock %}
```

```html:layout.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Dir en grey顔チェッカー</title>
    <link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
    <!-- Bootstrap -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css" integrity="sha384-aUGj/X2zp5rLCbBxumKTCw2Z50WgIr1vs/PFN4praOTvYXWlVyh2UtNUU0KAUhAX" crossorigin="anonymous">
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" integrity="sha512-K1qjQ+NcF2TYO/eI3M6v8EiNYZfA95pQumfvcVrTHtwQVDG+aHRqLi/ETn2uB+1JqwYqVG3LIvdm9lj6imS/pQ==" crossorigin="anonymous"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular-animate.min.js"></script>
    <script src="https://use.fontawesome.com/83341aec39.js"></script>
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <nav class="navbar navbar-inverse">
      <div class="container-fluid">
        <div class="navbar-header" style="padding-left:120px;">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbarEexample7">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="/">
          Dir en grey顔チェッカー
          </a>
        </div>
        <div class="collapse navbar-collapse" id="navbarEexample7">
          <ul class="nav navbar-nav">
          <!-- <li><a href="#">メニューＡ</a></li>
          <li class="active"><a href="#">メニューＢ</a></li>
          <li><a href="#">メニューＣ</a></li> -->
          </ul>
          <p class="navbar-text navbar-right">ようこそ <a href="#" class="navbar-link">ゲスト</a> さん。</p>
        </div>
      </div>
    </nav>
    {% block content %}{% endblock %}
  </body>
</html>
```

```css:style.css
.red {
  color: red;
}
.detect_img {
  width: 100%;
  height:400px;
  border: 1px solid #808080;
}
.cut_image {
  width: 150px;
  height: 150px;
}
.logo {
  width:150px;
  height:35px;
}
.logo_container {
  margin-top:50px;
}
.detail_container {
  background-color:#dcdcdc;
  padding:5px; width:200px;
  border:1px solid #a9a9a9;
}
```

## Apacheの設定
```apache:python.conf
LoadModule wsgi_module /usr/local/lib/python2.7/site-packages/mod_wsgi/server/mod_wsgi-py27.so

<VirtualHost *:80>
    ServerName localhost:80
    WSGIScriptAlias /dir {ドキュメントルート}/web.py

    <Directory "{ドキュメントルート}">
      Options Indexes FollowSymLinks ExecCGI
      SetHandler wsgi-script
      AddHandler wsgi-script .wsgi
      AddHandler wsgi-script .py
      Require all granted
      AllowOverride all
    </Directory>
</VirtualHost>
```

# 補足と言い訳
- なかなか上手く起動できず試行錯誤しました。
- 起動後の画像が正しくとれず、staticディレクトリ以下の画像しか見れませんでした。（理由は探っておりません）

# 全ページリンク
- [TensorFlowを使ってDir en greyの顔分類器を作ってみた - ①紹介編](http://qiita.com/neriai/items/bd7bc36ec42c8ef65b2e)
- [TensorFlowを使ってDir en greyの顔分類器を作ってみた - ②環境構築編](http://qiita.com/neriai/items/c0114af9c2eae627b6ce)
- [TensorFlowを使ってDir en greyの顔分類器を作ってみた - ③画像収集編](http://qiita.com/neriai/items/bac92c54ca77ebb32ecc)
- [TensorFlowを使ってDir en greyの顔分類器を作ってみた - ④顔抽出編](http://qiita.com/neriai/items/cedc0de9e3722f53287a)
- [TensorFlowを使ってDir en greyの顔分類器を作ってみた - ⑤学習データ準備編](http://qiita.com/neriai/items/b525b6c9beb5b5d2f8fb)
- [TensorFlowを使ってDir en greyの顔分類器を作ってみた - ⑥学習プログラム編](http://qiita.com/neriai/items/6a662a49054bc544806d)
- [TensorFlowを使ってDir en greyの顔分類器を作ってみた - ⑦学習モデル編](http://qiita.com/neriai/items/bd4b880e968fd41119f1)
- [TensorFlowを使ってDir en greyの顔分類器を作ってみた - ⑧学習実行編](http://qiita.com/neriai/items/791e6f4dd8d08775542b)
- [TensorFlowを使ってDir en greyの顔分類器を作ってみた - ⑨データ可視化編](http://qiita.com/neriai/items/a7b47127462ecf0fcc1d)
- [TensorFlowを使ってDir en greyの顔分類器を作ってみた - ⑩顔分類試験編](http://qiita.com/neriai/items/652ced2227b0283ce35e)
- [TensorFlowを使ってDir en greyの顔分類器を作ってみた - ⑪Web公開準備編](http://qiita.com/neriai/items/bb88858cb5004cbb24d9)
- [TensorFlowを使ってDir en greyの顔分類器を作ってみた - ⑫Web公開編](http://qiita.com/neriai/items/808ee49e276060457c14)
- [TensorFlowを使ってDir en greyの顔分類器を作ってみた - ⑬遊んでみる編（最終回）](http://qiita.com/neriai/items/6c984fa1e7876e5140cf)