見出し画像

【Part6】遠隔でのカメラ撮影&画像をS3に転送する

AWSでエッジコンピューティング環境を作る  Part6です。

Part5までで、エッジ端末からのメッセージをS3に保存することができました。エッジからクラウドストレージまでつながったわけです。

しかし、S3に保存していたのは単調な文字列です。せっかくエッジの端末があるんだったら、エッジから取得したデータを格納したいですね。今回は、ラズパイカメラで写真を撮影して、S3に保存していきます。

画像13

すべき事が結構たくさんあるので、順を追って説明しますね

・Lambda関数の変更
・サブスクリプションの設定(AWS IoT⇨ラズパイ方向)
・リソースの設定
・デプロイ・確認
・S3に保存

Lambda関数の変更

※今回は、Part5まで使っていたGreengrass_Helloworld関数を使い回します。

カメラで写真を撮り、そのデータをMQTTで送信するように、関数の中身を書き換えます。

import greengrasssdk

import StringIO
from io import BytesIO

import picamera
import time
import logging

import json
import base64

# Initialize logger
customer_logger = logging.getLogger(__name__)
# Create MQTT client
iot_client = greengrasssdk.client('iot-data')
topic_mes = "/part6/message"
topic_pic = "/part6/picture"

class Camera(object):
   # Capture Image
   def capture_image(self):
       camera = picamera.PiCamera()
       imageData = StringIO.StringIO()

       try:
           camera.resolution = (224, 224)
           camera.start_preview()
           time.sleep(2)
           camera.capture(imageData, format = "jpeg", resize = (224, 224))
           camera.stop_preview()

           imageData.seek(0)
           return imageData

       finally:
           camera.close()
       raise RuntimeError("There is problem to use your camera.")

def send_mqtt_message(mes):
   iot_client.publish(topic=topic_mes,payload=mes)

def send_mqtt_picture(imgdata):
   iot_client.publish(topic=topic_pic, payload=json.dumps({"data": imgdata}))


def take_pic():
   """
   take picture with picamera
   """
   send_mqtt_message("Taking a Photo")
   my_camera = Camera()
   imagebinary = my_camera.capture_image()
   # DataEncode
   image64 = base64.b64encode(imagebinary.getvalue())
   image_str = image64.decode("utf-8")
   return image_str


# The lambda to be invoked in Greengrass
def function_handler(event, context):
   try:
       img = take_pic()
       send_mqtt_picture(img)
       send_mqtt_message("Finish sending bin of picture")
   except Exception as e:
       customer_logger.exception(e)
       send_mqtt_message('Exception occurred during prediction. Please check logs for troubleshooting: /greengrass/ggc/var/log.')

これにより、メッセージが"/part6/message"に、撮った写真(のbase64文字列)が"/part6/picture"に送られます。

picameraは写真をラズパイで撮るだけなので、まあ良いとして、ややこしいのは撮った画像の取り扱いです。推論用にも使うことを考え、↓のように変換してやりました。MQTTで送るのは文字列なので、上手くエンコードする必要があります。(この辺、試行錯誤した結果なので、もっと効率良い方法があれば教えてもらえると泣いて喜びます。)

画像12

【リソース】Lambdaでラズパイのカメラにアクセスするための設定

さて、ローカルのラズパイであれば、あまり意識せずpythonのpicameraライブラリを使えばよいのですが、クラウド上からラズパイのカメラを利用するためには、Lambdaがラズパイのローカルリソース(今回はカメラ)にアクセスする必要があります。Part4の図を再掲しますが、ラズパイのローカルリソースにアクセスするためには、Greengrassの"リソース"を設定します。

画像1

下記になるように、リソースを2つ作成します。それぞれ作成時の入力欄を埋めていってください。

画像2

Lambda関数を指定する箇所がありますが、カメラ画像をリソースに書き込むので、"読み取りと書き込みを許可"にチェックを入れておきましょう。

画像3

サブスクリプションの設定

デプロイ前に、サブスクリプションを設定し直します(詳しくはPart4参照)
今回は、下記のトピックを設定します

AWS IoT -> Lambda のトリガー用 : "/part6/trigger"
Lambda -> AWS IoT メッセージ送信用 : "/part6/message"
Lambda -> AWS IoT 画像送信用 : "/part6/picture"

画像4

カメラ発火のtopicだけ画像を貼っておきます。

画像5

最終的に、下図のようなサブスクリプションが作られていれば、上手く動作するはずです。

画像6

デプロイ・確認

ここまで設定が完了したら、デプロイして、AWS IoTのテストで動作確認しましょう。上手くいけばこのように、それぞれのトピックにそれぞれのデータが送られているはずです!

画像7

画像8

S3に保存

さて、最後に、S3にこの画像も保存してやりましょう。S3保存時に、文字列型から、画像ファイルに変換したいので、Part5で説明した通り、AWS IoTにLambdaの処理を噛ましてからS3に保存します。

AWS IoTのルールは下図の様にしてください。利用するLambdaは前回作った"test-fromIoTtoS3"を利用します

画像11

次はLambdaの書き換えです。ルールを新しく作ったので、Lambdaを発火するタイミングを下記の様に変更します。

画像9

トリガーを設定したら、S3に保存する関数を書きます。前回と違って画像ファイルを保存するので、それ用のコードを貼っておきます。

import os
import boto3
from datetime import datetime
from io import BytesIO
from base64 import b64decode

def upload_img(img_binary):
   s3 = boto3.resource('s3')
   bucket = os.environ["BUCKET"]
   dir = "images"
   filename = 'img_{}.jpg'.format(datetime.now().strftime('%Y%m%d-%H%M%S'))
   obj = s3.Object(bucket, os.path.join(dir,filename))
   print("put",filename,"to",bucket)
   obj.put(Body=BytesIO(img_binary),ContentType="image/jpg")
   return


def lambda_handler(event, context):
  print("test",event)
  img = event["data"]
  img_binary = b64decode(img)
  upload_img(img_binary)
  return 0

成功していれば、s3のバケットにimages/<オブジェクト名>.jpgとして、保存されているはずです!

画像10

まとめ

これで、ラズパイの写真をクラウド上のS3に保存することができました。もちろん画像ではなく、センサーデータなどでも応用可能です(というか、画像みたいにエンコード/デコードがないのでそっちのほうが簡単です...笑)

次回はいよいよ推論部を作っていきたいと思います!いよいよエッジコンピューティングのさわり部分です。ではではっ

Part5. S3転送編  
Part7. モデル圧縮専用ライブラリDistiller

サポートいただけると励みになります! よろしくおねがいします!!