S3 に画像が保存されたら自動でAmazon Rekognitionの画像分析を実行する

Webサービスから投稿された画像をS3に格納することも増えてきていると思います。
格納した画像でそのまま画像分析を実施し、顔分析や不適切な画像かどうかの判定を行ってみましょう。

なお、この記事は先日noteに投稿した「[結婚式でLINE Botと画像解析を使った余興をしました](https://note.mu/kiwi26/n/n993b22cb9781)」の技術的な補足記事です。

# Amazon Rekognition について
https://aws.amazon.com/jp/rekognition/

Amazon Rekognitionは、画像分析や動画分析をAPIで手軽に利用することができるAWSのサービスです。
物体認識（画像に何が写っているか）、顔の分析、安全でない画像かどうかの分析、動線検出やOCRなどを行うことができます。

## 仕組み
以下の図は、LINE Botまで含めた構成図になっていますが、この記事は右側の部分だけ紹介します。
![picture_pc_c79b54f828962fb48fa886ef4ce644f6.png](https://qiita-image-store.s3.amazonaws.com/0/43540/c3d8a840-0076-17c4-50f8-15d10f269f55.png)

## S3 -> Lambda
格納後に自動で処理をする部分はAWSの仕組みに任せます。Lambda画像を格納するS3にトリガーを仕込みます。

![スクリーンショット-2018-12-01-15.19.48.jpg](https://qiita-image-store.s3.amazonaws.com/0/43540/dde52591-34b7-c301-0115-e27f8043de99.jpeg)

## Lambda で Rekogition を呼び出す
Rekognitionの呼び出しはPythonのサンプルが多いのですが、個人的に書き慣れているnode.jsのサンプルを紹介します。
S3に格納されているオブジェクトの場合、バケットとキーを指定するだけで実行可能です。また `Attributes` を指定すると、感情データを含めたデータを取得可能です　（SDKのリファレンスは[こちら](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Rekognition.html#detectFaces-property)）。

ほぼリファレンスまんまですが、以下のようなコードで呼び出しが可能です(node8.10)。

```javascript
const params = {
    Image: {
        S3Object: {
            Bucket: bucket, 
            Name: key
        }
    },
    Attributes: ["ALL"]
};

try {
    // Detect face using rekognition
    const data = await rekognition.detectFaces(params).promise();

    // use data...
}
```

不適切な画像が含まれているかどうかの検出は、[detectModerationLabels](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Rekognition.html#detectModerationLabels-property)を呼び出すと実行できます。

## 結果をWebhookにpostする部分まで含めたソースコード

DynamoDBへの保存とかであれば結果をそのまま格納すればよいのですが、上記記事のBotではWebhookに結果を通知する必要があったので、そこも含めた全体のコードを紹介します。

```javascript
const aws = require('aws-sdk');
const rekognition = new aws.Rekognition();
const https = require('https');

exports.handler = async (event, context) => {
    //console.log('Received event:', JSON.stringify(event, null, 2));

    // Get the object from the event
    const bucket = event.Records[0].s3.bucket.name;
    const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
    const paths = key.split('/');
    const rekognitionParams = {
        Image: {
            S3Object: {
                Bucket: bucket, 
                Name: key
            }
        },
        Attributes: ["ALL"]
    };

    try {
        // Detect face using rekognition
        const data = await rekognition.detectFaces(rekognitionParams).promise();
        var json = JSON.stringify(data);

        // Send result to webhook
        var result = await new Promise((resolve, reject) => {
            var options = {
                hostname: 'example.com',
                path: '/webhook/',
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Content-Length': Buffer.byteLength(json)
                }
            };
            
            var req = https.request(options, function(res) {
                res.setEncoding('utf8');
                res.on('data', function (body) {
                    console.log(body);
                    resolve('Success');
                });
            }).on('error', function(e) {
                reject(e);
            });
            
            req.write(json);
            req.end();
        });
        
        console.log(result);
    } catch (err) {
        console.log(err);
        const message = `Error detecting face ${key} from bucket ${bucket}.`;
        throw new Error(message);
    }
};

```

Amazon Rekognition は特にS3に格納した画像に対して呼び出すのが非常に簡単です。最近のアップデートで精度がさらに上がっているようですので、画像を使ったサービスを提供している方はぜひ利用してみてはいかがでしょうか。

この記事は ニフティグループ AdventCalendar の１日目の記事でした。
２日目は @motaHack さんです。お楽しみに！