AWS Lambda FunctionをNative Moduleを含んだ形で作成してみた

2015.07.22

はじめに

好物はインフラとフロントエンドのかじわらゆたかです。 社内で北海道中山峠のあげいもの顔ハメ看板が一部で流行しました。

それほぼと同時にAmazon API Gatewayがリリースされたので、 Ageimo ジェネレータつくろうって話になったので、まずは技術的なところを実装してみます。

OpenCV

OpenCVはC/C++で実装されたライブラリです。 OpenCVには顔認識が実装されているため、 インターネット上では笑い男を作るサンプル等で用いられています。

AWS LambdaでOpenCVを用いるためには、 OpenCVのライブラリのビルドを実施し、ビルドしたライブラリを含んだ形で、 Node.jsのライブラリのインストールを実施します。

最後に、これらのライブラリを含んだ形で、 AWS LambdaにUploadを実施することになります。

OpenCVのビルドを実施

以下はAmazon Linux上で実施します。 まずC/C++のビルド環境を構築します。

$ sudo yum update
$ sudo yum install -y gcc44 gcc-c++ libgcc44 cmake 
$ sudo yum install -y libjpeg-devel  libtiff-devel  libpng-devel jasper-devel

次にOpenCVのダウンロードとビルドを実施します。

$ curl -O -L https://github.com/Itseez/opencv/archive/2.4.11.zip
$ mkdir opencv_install
$ unzip ./2.4.11.zip -d ./opencv_install/ && cd ./opencv_install/
$ cmake -D CMAKE_BUILD_TYPE=RELEASE -D BUILD_SHARED_LIBS=NO -D CMAKE_INSTALL_PREFIX=~/opencv opencv-2.4.11/
$ make && make install

Node.jsのインストール & OpenCV(Native Module)の取込み

最終的にLambdaへのデプロイをするので、いつものひな形を用いたいと思います。 またその際に、epelリポジトリからNode.js npmをインストールします。

$ sudo yum install -y git
$ sudo yum install --enablerepo=epel nodejs npm
$ git clone https://github.com/CM-Kajiwara/myFirstLambda.git ~/opencvNativeLambda && cd ~/opencvNativeLambda
$ PKG_CONFIG_PATH=~/opencv/lib/pkgconfig/  npm install --prefix=~/opencvNativeLambda/ opencv --save

EPELレポジトリを用いてのNode.jsのインストールに関して

今現在(2015/07.21) Node.jsはVersion 0.12.7がリリースされています。 ですが、AWS Lambdaに採用されているNode.jsはVersion 0.10.36となります。

epelレポジトリを用いてインストールされるNode.jsもVersion 0.10.36のため、 今現在においては上記の方法で問題はないと思われます。

今後AWS Lambdaのアップグレード等でNode.jsのバージョンが上がった際には この点は注意が必要です。

OpenCVを用いた顔認識の実装・確認

OpenCVの挙動を確認するのが目的なので、 顔認識を実施しその結果をBase64エンコードされた文字列で返すことにします。

app.js

/*jslint node: true */
/*eslint-env node, mocha */

'use strict';
var cv = require('opencv');
var fs = require('fs');
exports.handler = function(event, context) {

    cv.readImage('./node_modules/opencv/examples/files/mona.png', function(err, im) {
        if (err) throw err;
        if (im.width() < 1 || im.height() < 1) throw new Error('Image has no size');

        im.detectObject('./node_modules/opencv/data/haarcascade_frontalface_alt.xml', {}, function(err, faces) {
            if (err) throw err;

            for (var i = 0; i < faces.length; i++) {
                var face = faces[i];
                im.ellipse(face.x + face.width / 2, face.y + face.height / 2, face.width / 2, face.height / 2);
            }

            im.save('/tmp/face-detection.png');
            fs.readFile('/tmp/face-detection.png', function(err, original_data) {
                var base64Image = new Buffer(original_data, 'binary').toString('base64');
                console.log(self.event);
                context.done(null, base64Image);
            });
        });
    });
};

結果

AWS Management Consoleで上記のサンプルを動かしてみた結果と、 出力されたBase64を加工してHTMLに貼り付けて表示した結果が下記になります。

今回のサンプルを動かす際にタイムアウトをデフォルトの3秒から少し伸ばしてあげる必要がありました。 上記の作例だと30秒にしています。

Aws Management Console

AWS_Lambda

HTML

Base_64_Result

まとめ

ビルドでハマったりもしたのですが、顔認識を行うことができました。 あとは画像のアップロードを行い、出力を行えばAgeimo ジェネレータもつくれそうです。

参考

Using Packages and Native nodejs Modules in AWS Lambda | AWS Compute Blog