ゲレの工房

ゲーム好きの中の人が、自分が作りたいアプリを作る記録です

FF14雑記:言語を超える力Web環境構築:AWS S3に画像ファイルをAWS Lambdaで画像処理する部分までの勉強

やりたいことはこちら。簡単に言うと、FF14というゲームのスクリーンショットをTensorFlow・Object Detection APIを使って加工するLambda関数を作りたいということです。

blog.gelehrte.com

前回の記事はこちらです

blog.gelehrte.com

前回は、AWS ECRを使ってAWS Lambda関数のイメージを作ってアップロードしてテストするところまでをやりました。今回はAWS S3に画像を置いて、その画像をAWS Lambdaで加工するテストをしたいです。

参考にした記事

AWS ECR + Lambdaを使ってみる

前回に引き続き、この記事を参考にしています。
zenn.dev

AWS Lambdaで画像ファイル加工~環境構築から実行確認まで~ 手順紹介

画像加工のスクリプトや、S3を使う方法などの参考にしました。
business.ntt-east.co.jp

Docker コンテナの中に入ってBashなどでコマンド実行をする

デバッグ作業で使いました。
zukucode.com

AWS Lambda関数を実行してS3にファイルを保存、追記してみる

テキストファイルを実際にS3に入れてみました。
sugimonblog.com

AWSのLambdaとS3連携でハマる所

IAM権限などでハマったので私も参考にしました。
lets-hack.tech

やったこと

画像加工を行うスクリプトのDockerイメージを作る

AWS ECR + Lambdaで作業を行いたいので(おそらくその方が管理が楽なので)、Dockerイメージを作成。前回はecr-tutorialでしたが、今回は自作のイメージを。ほぼ前回のecr-tutorialのマネですが。

実際にapp.pyを書いてみた
import json
import os	
import sys	
import uuid	
from urllib.parse import unquote_plus	
from PIL import Image	
import PIL.Image


def handler(event, context):
    resize_image('/tmp/input.png', '/tmp/output.png')

    return {
        "statusCode": 200,
        "body": json.dumps({"tokens": "ok"})
    }

	
	
def resize_image(image_path, resized_path):	//Pillowの機能を使用した画像データ処理用関数
    with Image.open(image_path) as image:	//画像ファイルから画像データを取得
        image.thumbnail(tuple(x / 2 for x in image.size)	//画像データサイズを1/2に縮小
        image.save(resized_path)	//Lambda内の一時保存先に保存
これを実行
> docker-compose up -d --build
> curl -d '{\"sentence\":\"I am Taro Yamada.\"}' -H "Content-Type: application/json" http://localhost:9000/2015-03-31/functions/function/invocations
{"errorMessage": "Syntax error in module 'app': invalid syntax (app.py, line 21)", "errorType": "Runtime.UserCodeSyntaxError", "stackTrace": ["  File \"/var/task/app.py\" Line 21\n    def resize_image(image_path, resized_path):\t//Pillow\u306e\u6a5f\u80fd\u3092\u4f7f\u7528\u3057\u305f\u753b\u50cf\u30c7\u30fc\u30bf\u51e6\u7406\u7528\u95a2\u6570\n"]}

なぞのエラーメッセージが返ってくる

Dockerの中身を覗きに行ってくる

bashの起動

上記サイトを参考にDocker内のbashを起動

> docker exec -it c77ce06fc615 /bin/bash
bash-4.2# ls
app.py
bash-4.2# pwd
/var/task
bash-4.2# python app.py
  File "app.py", line 21
    def resize_image(image_path, resized_path): //Pillowの機能を使用した画像データ処理用関数
                                                ^
SyntaxError: invalid syntax

ああ、なるほどね。日本語ね。Dockerの中に入るとエラーメッセージやデバッグがやりやすくていいですね。

色々修正

app.pyを修正
import json
import os	
import sys	
import uuid	
from urllib.parse import unquote_plus	
from PIL import Image	
import PIL.Image

def handler(event, context):
    resize_image('/tmp/input.png', '/tmp/output.png')

    return {
        "statusCode": 200,
        "body": json.dumps({"tokens": "ok"})
    }
	
def resize_image(image_path, resized_path):
    with Image.open(image_path) as image:
        image.thumbnail(tuple(x / 2 for x in image.size))
        image.save(resized_path)

実行

> curl -d '{\"sentence\":\"I am Taro Yamada.\"}' -H "Content-Type: application/json" http://localhost:9000/2015-03-31/functions/function/invocations
{"statusCode": 200, "body": "{\"tokens\": \"ok\"}"}
bashで入って、/tmp/output.pngが作られているか確認
> docker container ls
CONTAINER ID   IMAGE                 COMMAND                  CREATED         STATUS         PORTS                      NAMES
4dafbd65075f   languageecho-lambda   "/lambda-entrypoint.…"   4 minutes ago   Up 4 minutes   127.0.0.1:9000->8080/tcp   languageecho-lambda_languageecho-lambda_1
> docker exec -it 4dafbd65075f /bin/bash
bash-4.2# ls /tmp
init.py  input.png  output.png

無事確認。

実際にファイルをS3に書き込んでみる

コードを少し修正
import boto3
import json
import os
import sys
import uuid
from urllib.parse import unquote_plus
from PIL import Image
import PIL.Image
from datetime import datetime

s3 = boto3.resource('s3') 
bucket = s3.Bucket('languageecho')

def handler(event, context):
    bucket = 'languageecho'
    key = 'output/test_' + datetime.now().strftime('%Y-%m-%d-%H-%M-%S') + '.txt'
    file_contents = json.dumps(event)
    
    obj = s3.Object(bucket,key)   
    obj.put( Body=file_contents )
    #resize_image('/tmp/input.png', '/tmp/output.png')

    return {
        "statusCode": 200,
        "body": json.dumps({"tokens": "ok"})
    }
合わせて Dockerfileも修正

以下を追記

RUN pip3 install boto3
S3にバケットを作成し、実行IAMロールで許可を与える

バケット名は「languageecho」。予め作っておいたIAMロールが「arn:aws:iam::****:role/languageechoIAM」になります。このポリシーだとS3に対して全許可になるので、本当はもう少し直したほうが良いかなとは思っています。

{
    "Version": "2012-10-17",
    "Id": "Policy1653113200209",
    "Statement": [
        {
            "Sid": "Stmt1653113194115",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::****:role/languageechoIAM"
            },
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::languageecho/*"
        }
    ]
}
実際にテストする

Lambdaからテストすると、S3にファイルが作成されていました。


実際に画像処理して画像ファイルをS3を書き込む

設定時間を少し長くする

タイムアウトを10秒にしました。多分TensorFlowを動かすときはもっと長くする必要があるかと思います。
qiita.com

プログラムを直し

関数を修正

import boto3
import json
import os
import sys
import uuid
from urllib.parse import unquote_plus
from PIL import Image
import PIL.Image
from datetime import datetime

s3 = boto3.resource('s3') 

def handler(event, context):
    bucket = s3.Bucket('languageecho')
    bucket.download_file('input/input.png', '/tmp/input.png')
    resize_image('/tmp/input.png', '/tmp/output.png')
    bucket.upload_file('/tmp/output.png', 'output/output.png')

    return {
        "statusCode": 200,
        "body": json.dumps({"tokens": "ok"})
    }

def resize_image(image_path, resized_path):
    with Image.open(image_path) as image:
        image.thumbnail(tuple(x / 2 for x in image.size))
        image.save(resized_path)
実際に実行してみる

画像サイズが小さめのファイルが、ちゃんと書き出されていました。

終わりに、ECRの中身を整理

多分、イメージさえ消しておけば課金されないので、ECRのイメージを消して作業終了。

今後の予定

前回の記事の予定の部分から画像処理の部分を抜いた話になるのですが、一応転載を。

JavaScriptAmazon S3にファイルをアップロード

このあたりが参考になりそうです
qiita.com
S3に画像ファイルを置けば、Lambdaから読み込んで加工できるという寸法です。

S3に処理された画像が書き込まれたら、画像を表示するWeb UIを作る

S3の特定のURLにファイルが書き込まれるはずです、Web UI側でファイルの存在をJavaScriptで(1秒ごとにチェックしにいくとかで)検知し、表示させます。

LambdaでTensorFlowを動かす

ファイル加工部分をTensorFlowにし、TensorFlowさえ動けば「言語を超える力」の処理が行なえます。書き込みはS3にそのまま書き込みます。

あと追記で

S3に溜まっていく一時ファイルを消すようにしたい

1日に1回ぐらいは整理するようにしたいです。ライフサイクルというのでできるようです
www.kabegiwablog.com

終わりに

今回もFF14とは関係のない、AWSの記事になってしまいました。備忘録としては良かったかなと。最後にサムネ用に、半分のサイズに出力された画像ファイルを載せておきます。少しずつ頑張りたいですね。


広告