LoginSignup
5
8

More than 5 years have passed since last update.

indico apiを用いたコンテンツフィルタ付き画像アップローダー

Last updated at Posted at 2016-06-16

概要

話題の投稿"3行のソースコードを入れるだけで機械学習できると噂のindicoをNode.jsで使って機械学習入門してみる"でindicoについて初めて知ったのですが、そこのContent Filteringを使えば「アダルト画像を予め排除出来る画像アップローダー」が作れるのではないかと思って試作をしてみました。

要件

  1. ローカル画像を判定し、OKだった物だけをサーバーにアップロードする。
  2. 判定はindicoのContent Filetering APIで行う。
  3. ローカルでの画像プレビュー機能を持たせる。

実際の手順

1. indico APIキーの取得

以下のサイトでアカウントを作成後、Dashboardに移動してAPI Keyを取得します。

https://indico.io/

2. サンプルソース

DocsのページでImage Analysis ⇒ Content Filteringを選択し、さらにjavascriptを選択するとAPI KEYまで含んだ状態のexampleソースが表示されます。

example.
// single example
$.post(
  'https://apiv2.indico.io/contentfiltering',
  JSON.stringify({
    'api_key': "<API_KEY>",
    'data': "<IMAGE>"
  })
).then(function(res) { console.log(res) });

// batch example
$.post(
  'https://apiv2.indico.io/contentfiltering/batch',
  JSON.stringify({
    'api_key': "<API_KEY>",
    'data': [
      "<IMAGE>",
      "<IMAGE>"
    ]
  })
).then(function(res) { console.log(res) });

3. <IMAGE>について

<IMAGE>は画像ファイルのURL、もしくはBase 64でエンコードした画像データです。画像を公開しないで判定を行う必要が有りますので、FileReader()のreadAsDataURL()メソッドを使いローカル画像ファイルから<IMAGE>を作成しました。

4. 判定

結果は実数0~1のJSON形式で返されます。こんな感じです。
{"results": 0.2925722002983093}
アダルトコンテンツとみなされるほど数字が大きくなりますので、予め設定したスレッシュと比較して処理を分岐させています。

ソース全体

プレビューにはcanvasとFileReader()を使い、アップロードはFormData()をAJAXでPOSTすることで行っています。サーバ側の処理はPHPです。

index.html
<!DOCTYPE HTML>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
        <title>画像ファイルをCANVSでプレビュー</title>
    </head>
    <body>
        <h1>画像を選択してください。</h1>
        <form id="my_form">
            <input id="ufile" name="ufile" type="file" accept="image/jpeg,image/png"><br>
            <button id="upload" type="button">アップロード</button>クリックでアップロードを開始します。
        </form>
        <hr>
        <div>
            <h1>プレビュー</h1>
            <canvas id="cnvs"></canvas>
        </div>

        <script>
         $(function(){

             // Global変数
             var fr = new FileReader(); // FileReader()をインスタンス化
             var canvas = $("#cnvs");   // HTMLのCanvas要素の取得
             var gheight = 240;         // Previewイメージの高さ
             var thresh = 0.95;         // 判定基準値 さじ加減

             // id="ufile"の変化でコールバック
             $("#ufile").change(function(){
                 // 選択ファイルの有無をチェック
                 if (!this.files.length) {
                     alert('ファイルが選択されていません');
                     return;
                 }

                 // Formからファイルを取得
                 var file = this.files[0];

                 // getContext()メソッドで描画機能を有効にする
                 var ctx = canvas[0].getContext('2d');

                // 描画イメージインスタンス化
                 var image = new Image();

                // ファイル読み込み読み込み完了後に実行 [非同期処理]
                 fr.onload = function(evt) {

                     // 画像がロードされた後にcanvasに描画を行う [非同期処理]
                     image.onload = function() {
                         // プレビュー(Cnavas)のサイズを指定
                         var cnvsH = gheight;
                         var cnvsW = image.naturalWidth*cnvsH/image.naturalHeight;
                         // Cnavasにサイズアトリビュートを設定する
                         canvas.attr('width', cnvsW);
                         canvas.attr('height', cnvsH);
                         // 描画
                         ctx.drawImage(image, 0, 0, cnvsW, cnvsH);
                     }
                     // 読み込んだ画像をimageのソースに設定
                     image.src = evt.target.result; // == fr.result
                 }

                 // fileを読み込む データはBase64エンコードされる
                 fr.readAsDataURL(file);
             })

             $("#upload").click(function(){
                 if(!fr.result){
                     alert('ファイルを選択して下さい');
                     return;
                 };

                $.post(
                     'https://apiv2.indico.io/contentfiltering',
                     JSON.stringify({
                         'api_key': "<API_KRY>",
                         'data': fr.result
                     })
                 ).then(function(res) {
                     var jst = JSON.parse(res);
                     if (jst.results > thresh) {
                         alert('この画像は規約によりアップロード出来ません rating='+jst.results);
                     } else {
                         console.log(res);
                         // FormDataを用意
                         var fd = new FormData($("#my_form").get(0));
                         // ajaxでphpに送信
                         $.ajax({
                             url: 'uploader.php',
                             type: 'POST',
                             processData: false,
                             contentType: false,
                             dataType: 'html',
                             data: fd
                         }).done(function(data, textStatus, jwXHR){
                             alert(data);
                         }).fail(function(jqXHR, textStatus, errorThrown){
                             alert('エラーが発生しました : ' + textStatus
                                   + "\nHTTP status : " + errorThrown);
                         })
                     }},
                     function() {
                         alert('エラーが発生しました。時間をおいて再試行下さい。');
                     })
             })
         })
        </script>
    </body>
</html>
uploader.php
<?php
define('FILE_PATH','./upload/'); //保存するパスを指定

// アップロードされたファイルが有る事を確認
if (is_uploaded_file($_FILES["ufile"]["tmp_name"])) {
    $saveFilename = FILE_PATH . $_FILES['ufile']['name'];

    // ファイルの移動
    if (move_uploaded_file($_FILES["ufile"]["tmp_name"], $saveFilename)) {
        //chmod($saveFilename, 0644);
        echo $_FILES["ufile"]["name"], "をアップロードしました";
    } else {
        echo $_FILES["ufile"]["name"], "アップロードエラー";
    }
}
?>

結果確認

Firefox 47.0での確認です。
ダメ出しされた場合
NG.jpg

OKの場合
OK.jpg

5
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
8