読者です 読者をやめる 読者になる 読者になる

順次、選択、そして繰り返し

プログラミングのことやITのこと、たまに演劇のことも書きます。

AWS Amazon Rekognitionを使ってみた

Amazon RekognitionはAWSが提供しているサービスの1つで
深層学習に基づく画像分析を行ってくれるサービス。

このサービスを用いることで元の画像と比較対象の画像を
照らし合わせて同一人物がいるか探すことも可能である。

今回は複数の画像を用いた顔比較(同一人物かどうかを判定)を
試してみた。

大まかな流れは以下の感じ

①S3のバケットに事前に画像を格納する
②S3のバケットから画像を取得し、Collectionに格納する
③S3のバケットから1枚、比較対象の画像を取得して比較する
④顔比較の結果と画像を表示する

まず①の準備。
S3のバケットに適当な画像を格納しておく。
f:id:sndstudy:20170226224823p:plain

次は②
「rekognition.createCollection」でCollectionを作成する。
パラメータとして、「CollectionId(コレクションを識別するID)」が必要
Class: AWS.Rekognition — AWS SDK for JavaScript

「rekognition.indexFaces」でCollectionに画像を追加する。
Class: AWS.Rekognition — AWS SDK for JavaScript

普通に「rekognition.indexFaces」をループさせて画像を追加しようとしたが、非同期処理のため
Collectionに全ての画像が追加される前に次の処理に行ってしまう問題があったため
JavaScriptの「yield」を用いて処理を制御した。(コールバック地獄回避のため)
yield - JavaScript リダイレクト 1 | MDN

/********************************************/
//Rekognitionテスト処理
/********************************************/
var addFunction;

function rekognitionTest() {

    //Collection作成
    var paramsCreate = {
        CollectionId: "photos"
    };

    rekognition.createCollection(paramsCreate, function (err, data) {
        if (err) {
            console.log(err, err.stack);
        } else {
            addFunction = addImage();
            addFunction.next();
        }
    });

}

/********************************/
//Collectionに画像を追加する処理
/********************************/
function* addImage() {

    for (var cnt = 2; cnt <= 6; cnt++) {
        var paramsAdd = {
            CollectionId: "photos",
            Image: {
                S3Object: {
                    Bucket: "storage-keya-us",
                    Name: 'yone_san_' + cnt + '.jpg'
                }
            },
            ExternalImageId: 'yone_san_' + cnt + '.jpg'
        };

        rekognition.indexFaces(paramsAdd, function (err, data) {
            if (err) {
                console.log(err, err.stack);
            } else {
                console.log(data);
                addFunction.next();
            }
        });

        yield;
    }

    searchImg();
}

次は③
「rekognition.searchFacesByImage」で顔検索を行う。
Class: AWS.Rekognition — AWS SDK for JavaScript
「MaxFaces」は確か、似ている画像上位10枚までを表示するみたいな設定だったと思う。

/********************************/
//画像認識(元画像と似ている画像を探す)
/********************************/
var searchImg = function () {
    var params = {
        CollectionId: 'photos',

        Image: {
            S3Object: {
                Bucket: 'storage-keya-us',
                Name: 'yone_san_1.jpg'
            }
        },
        FaceMatchThreshold: 0.0,
        MaxFaces: 10
    };
    rekognition.searchFacesByImage(params, function (err, data) {
        if (err) {
            console.log(err, err.stack);
        } else {
            console.log(data);
            showImgs(data);
            deleteCollectiom();

        }
    });
}

最後は④
ここはS3から画像のURL取得と
画像の似ている度合いを表示する処理

/********************************/
//画像表示処理(画像認識結果)
/********************************/
function showImgs(data) {
    var s3 = new AWS.S3({
        params: {
            Bucket: 'storage-keya-us',
            Region: s3RegionName
        }
    });
    var htmlImg ="";
    for (var i = 0; i < data.FaceMatches.length;i++) {
        //URL取得
        var paramsSource = {
            Bucket: 'storage-keya-us',
            Key: data.FaceMatches[i].Face.ExternalImageId
        };

        var sourceUrl = s3.getSignedUrl('getObject', paramsSource);

        htmlImg += "<img src='" + sourceUrl + "'/><br/>" + "<span>" + "Similarity:" + data.FaceMatches[i].Similarity + "%" + "</span><br/>";
    }

    $("#imgList2").html(htmlImg);
    
    $('img').css('width','150px');
}

全体のソースコードはこんな感じ

$("#rekognitionButton").on("click", rekognitionTest);

var s3BucketName = 'translator-app-bucket';
var s3RegionName = 'us-east-1';

AWS.config.update({
    accessKeyId: 'your_accessKeyId',
    secretAccessKey: 'your_secretAccessKey'
});

var rekognition = new AWS.Rekognition({
    region: 'us-east-1'
});

/********************************************/
//Rekognitionテスト処理
/********************************************/
var addFunction;

function rekognitionTest() {

    //Collection作成
    var paramsCreate = {
        CollectionId: "photos"
    };

    rekognition.createCollection(paramsCreate, function (err, data) {
        if (err) {
            console.log(err, err.stack);
        } else {
            addFunction = addImage();
            addFunction.next();
        }
    });

}

/********************************/
//Collectionに画像を追加する処理
/********************************/
function* addImage() {

    for (var cnt = 2; cnt <= 6; cnt++) {
        var paramsAdd = {
            CollectionId: "photos",
            Image: {
                S3Object: {
                    Bucket: "storage-keya-us",
                    Name: 'yone_san_' + cnt + '.jpg'
                }
            },
            ExternalImageId: 'yone_san_' + cnt + '.jpg'
        };

        rekognition.indexFaces(paramsAdd, function (err, data) {
            if (err) {
                console.log(err, err.stack);
            } else {
                console.log(data);
                addFunction.next();
            }
        });

        yield;
    }

    searchImg();
}

/********************************/
//Collection削除処理
/********************************/
var deleteCollectiom = function () {
    var paramsDelete = {
        CollectionId: "photos"
    };
    rekognition.deleteCollection(paramsDelete, function (err, data) {
        if (err) {
            console.log(err, err.stack);
        } else {
            console.log(data);
        }
    });
}

/********************************/
//画像認識(元画像と似ている画像を探す)
/********************************/
var searchImg = function () {
    var params = {
        CollectionId: 'photos',

        Image: {
            S3Object: {
                Bucket: 'storage-keya-us',
                Name: 'yone_san_1.jpg'
            }
        },
        FaceMatchThreshold: 0.0,
        MaxFaces: 10
    };
    rekognition.searchFacesByImage(params, function (err, data) {
        if (err) {
            console.log(err, err.stack);
        } else {
            console.log(data);
            showImgs(data);
            deleteCollectiom();

        }
    });
}

/********************************/
//画像表示処理(画像認識結果)
/********************************/
function showImgs(data) {
    var s3 = new AWS.S3({
        params: {
            Bucket: 'storage-keya-us',
            Region: s3RegionName
        }
    });
    var htmlImg ="";
    for (var i = 0; i < data.FaceMatches.length;i++) {
        //URL取得
        var paramsSource = {
            Bucket: 'storage-keya-us',
            Key: data.FaceMatches[i].Face.ExternalImageId
        };

        var sourceUrl = s3.getSignedUrl('getObject', paramsSource);

        htmlImg += "<img src='" + sourceUrl + "'/><br/>" + "<span>" + "Similarity:" + data.FaceMatches[i].Similarity + "%" + "</span><br/>";
    }

    $("#imgList2").html(htmlImg);
    
    $('img').css('width','150px');
}

htmlファイルはこんな感じ

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>Test</title>

    <!-- jQueryCDN -->
    <script src="https://code.jquery.com/jquery-3.1.1.js"></script>

    <!-- AWS SDK for JavaScript -->
    <script src="https://sdk.amazonaws.com/js/aws-sdk-2.7.27.min.js"></script>
    <script type="text/javascript" src="./js/main.js"></script>

</head>

<body>

    <h3>Rekognitionテスト</h3>
    <img src="https://s3.amazonaws.com/storage-keya-us/yone_san_1.jpg" style="width:150px"/>
    <br>
    <input type="button" value="searchFaces" id="rekognitionButton">

    <div id="imgList2"></div>

    <script type="text/javascript" src="./js/main.js"></script>

</body>

</html>


表示画面はこんな感じ
f:id:sndstudy:20170226231050p:plain

ボタンを押下すると画像と似ている度合いを表示してくれる
f:id:sndstudy:20170226231211p:plain

※一応同一人物だけどSimilarity(信頼度)にもの凄い差がある……。
 ちなみに二人セゾン時のアー写もS3に格納したはずが、
 似てなさ過ぎて表示されないらしい。
 まぁ成長したと捉えればいいのか。

今回はブラウザのJavaScriptで実装してみたけど、意外と簡単に
実装することができた。
これぐらい簡単なら画像認識系の機能は自分で実装せず、
クラウドサービスに任せるのもアリかもしれない。

他の値とかを取得したければ、自分で画像認識の機能を
実装するしかないんだけどね……。

■参考サイト
Class: AWS.Rekognition — AWS SDK for JavaScript
yield - JavaScript リダイレクト 1 | MDN
米谷奈々未 - エケペディア
→画像を拝借