dlib(face_recognition)で顔画像認識

face_recognition 顔画像認識

以前から、opencvを使用した顔の判定プログラムを作ったことはありましたが、今回は、pythonライブラリである「face_recognition」を使用して、事前収集した画像データを基に、個人を識別するプログラムに挑戦しましたので、ご紹介します。

face_recognitionについて

face_recognitionは、著名な顔認識ライブラリである「dlib」(C++)を、pythonで簡易的に使用するために開発されたライブラリです。顔画像に特化したメソッドが豊富に用意されており、CNNを使用した顔の識別、近似値を使用した顔の比較、顔の部分取得(目・鼻・口・輪郭など)を行うことができます。

pypi.org

opencvとface_recognition

大雑把にいうと、opencvよりも、face_recognition(dlib)の方が、より精密な顔識別が可能です。ただ、精度が高い分、検出速度とはトレードオフの関係にあり、face_recognition、特にCNN方式で顔画像を識別しようとした場合、GPUのサポートがないと、1枚の写真から顔を特定するのに数秒~数十秒の時間を要します。

他方、opencvの顔画像検出では、デモンストレーションデータとしてライブラリとともに提供される「haarcascade_frontalface_alt.xml」が用いられます。これは「Haarアルゴリズム」という画像の特徴量を算出する方法を用いた分類データですが、あくまで「frontal(正面)」の顔識別用であるため、顔を傾けたり、少し横を向いただけで顔が判別できなくなります。

2つの詳細な差分については、次のサイトが非常に参考になりました。

qiita.com

サンプルプログラム

今回作成したプログラムは、予め収集した顔画像データとの比較を、次の2つのモードで実現する機能を持っています。

  1. ファイル検出モード(静止画)

    入力された画像イメージ(集合写真など)から、顔画像を検出し、それが誰なのかを識別します。

  2. カメラ検出モード(動画)

    バイスのカメラを起動し、カメラ動画に移る人を識別して名前を表示します(自分の顔を映すのがイヤだったので、下の動画はカメラの先で動画再生をしています…)

なお、画像の収集も自動で行えるよう、複数のWebサイトを巡回して画像を集めてくるプログラムも提供しています(01_get_model_data.py

github.com

使用環境・主なライブラリ

  • python 3.9
  • face_recognition(精密な顔認識)
  • opencv(軽量な顔認識)
  • selenium(画像収集に使用)

プログラム解説

01.データ収集

  • ChromeSelenium を使用して、モデルデータを作成するための画像データを収集する。

  • 以下のコマンドを実行すると、入力欄が表示されるので、検索ワード、人物ラベル(半角英字)、取得画像枚数を指定する。

    python 01_get_model_data.py

  • ./model_rawdata ディレクトリに、人物ラベルのディレクトリが作られ、取得した画像が格納される。


02.顔画像切り出し

  • 収集した画像から特徴が明確になるように、顔部分だけを取り出した画像を作成する。

  • 以下のコマンドを実行すると、./model_rawdata ディレクトリ内のすべての画像に対して、自動でトリミングが行われる。

    python 02_triming_face.py

  • ./model_dataset ディレクトリに、人物ラベルのディレクトリが作られ、トリミングした結果が格納される。


03.モデルデータの水増し

  • 深層学習の精度を高めるため、顔画像に以下の加工を施してデータを増産(水増し)する。

    • +30° 傾ける

    • -30° 傾ける

    • 灰色にする

    • 左右対称とする

  • 以下のコマンドを実行することで、./model_rawdata ディレクトリ内のすべての画像に対して、上記の加工が自動で行われる。

  • ./model_dataset ディレクトリに、上記の加工を行った画像が追加される。


04.モデル学習

  • 以下のコマンドでモデルデータを作成する。

    python 04_train_model.py

  • 実行するにはかなりの負荷がかかるため、以下いずれかの環境を推奨する。

  • 正常に終了した場合は、モデルデータ encodings.pickle ファイルが作成される。


05.検出テスト

ファイル検出モード(静止画)

  • 以下のコマンドを実行すると、画像からモデルデータ作成した対象者の顔検出を実行する。

    python 05_detect_face.py [検出対象の画像ファイル]

  • 検出した結果は、ディレクトリ「photo_detected」に格納される。検出用の jpg 画像の中で、顔と識別された箇所には黄色い □ 枠が表示され、モデルデータと一致した場合波枠の上部にモデル名が表示される。

カメラ検出モード(動画)

  • 以下のコマンドを実行すると、PC に接続しているカメラ動画から、モデルデータとして作成した対象者の検出を実行する。

    python 05_detect_face.py

  • カメラの動画がウィンドウ背面に出る場合があります。

  • プログラムを止めるには、ウィンドウ上で「q」キーを押下してください。

  • ウインドウで「+」「-」キーを押すと「tolerance」値を変更することができ、識別精度が変わります(小さい方がシビアに識別します)


今後の課題

カメラ検出モードだと、画像がカクつく。

やはり、CUDAモジュール搭載のGPUがないと、動画にするのは厳しいことが判明しています。年末ボーナスを受けて、Jetson nanoを購入したので、環境が整ったら、そちらでリトライしてみようと思います。

強化学習への進化

今回の識別(顔の比較)は、face_recognitionのメソッドを使用しており、比較方法も集積画像の数値による「パターンマッチング」でしかない認識です。今後、深層学習によるモデルの作成と比較を学び、自力での画像比較を行っていきたいと考えています。

画像生成AIを使って遊んでみよう!

最近話題になっているらしい、画像生成AIというものを使ってみたので、レポートします。

AI作「鮭を食べている熊が川辺にいるイラスト 油絵」

鮭はどこ行ったんだろう・・・。

用意するもの

GPUを使うといっても、クラウドのサービスを活用して行うので、高スペックのPCなどは必要ありません。以下のものを準備してください。

手順

ライブラリのインストール

最初にブラウザを開き、Google colaboratoryにアクセスします。

ノートブックを新規作成したら、メニューから「ランタイム」-「ランタイムのタイプを変更」を選択します。

サブ画面が表示されるので「ハードウェア アクセラレータ」に「GPU」を選択して保存します。

次に別のブラウザページを開き、Hugging Faceにアクセスします。検索エリアに「japanese-stable-diffusion」と入力します。アクセスすると、下の画面が表示されます。

この画面をずーっと下まで進めると、「Examples」に、以下のインストールコマンド(pipコマンド)が書かれているので、これをコピーします。

!pip install git+https://github.com/rinnakk/japanese-stable-diffusion

上のコマンドを、Google colaboratoryのコード欄に貼り付けて実行します。貼り付ける時に、先頭に「!」を入力してください。これにより、環境にjapanese-stable-diffusionライブラリがインストールされます(少しかかった後、Success...と表示されたらOK)

HuggingFaceのアクセストークン取得・設定

Google colaboratory上部の「+コード」をクリックしてコード欄を追加し、ここに「!」に加えて、HugginFaceにCLIログインするためのコマンドを貼り付けて実行します。コマンドは、先ほど参照したHuggingFaceページの、pipコマンドのすぐ下にあります。

!huggingface-cli login

実行すると、以下の画面になりますので、画面内のハイパーリンクをクリックしてください。

リンク先に行くと、トークンの作成画面が表示されますので「New token」を押します。サブ画面で「Name(なんでも良い)」を登録して、「Generate Token」を押すと、トークンが表示されるので、そのままクリップボードにコピーしてください。

Google colaboratory画面に戻り「Token:」入力欄にトークンを貼り付けて実行してください。下のような画面になったらトークン設定は終了で、この後のpythonコードからHuggingFaceのサービスが使用できるようになります。

Pythonコードの実行

HuggingFaceのページ下部に、サンプルソースコードが表示されていますので、これをクリップボードにコピーして、Google colaboratoryのコード欄に貼り付けます。

import torch
from torch import autocast
from diffusers import LMSDiscreteScheduler
from japanese_stable_diffusion import JapaneseStableDiffusionPipeline

model_id = "rinna/japanese-stable-diffusion"
device = "cuda"
# Use the K-LMS scheduler here instead
scheduler = LMSDiscreteScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", num_train_timesteps=1000)
pipe = JapaneseStableDiffusionPipeline.from_pretrained(model_id, scheduler=scheduler, use_auth_token=True)
pipe = pipe.to(device)

prompt = "猫の肖像画 油絵"
with autocast("cuda"):
    image = pipe(prompt, guidance_scale=7.5).images[0]  
    
image.save("output.png")

最初に、一番下を以下のとおり変更してください。これにより、実行結果を画面上で確認することができるようになります。

# image.save("output.png") 
image

あとは、コード内のprompt = "猫の肖像画 油絵"の部分を好きに書き換え得て、実行ボタンを押すだけです。最初は2〜3分ほどかかりますが、AIが適当な画像を自動生成して、画面に表示してくれます。

色々出してみた。

"京都の五重塔を遠くから撮影した写真 雪が降っている"

悪くないですね。降ってはいませんが、足元に雪が積もっているようです。



"オーロラを真上から見た映像, 鮮明な写真"

これは綺麗ですね。オーロラは、学習資料が色々あるんでしょうか。



"大都会のスクランブル交差点,たくさんの人がいる 油絵"

それっぽく描かれていますが、よく見ると人が崩れてしまっていて、正確に描けていませんね。



なお、日本語の指定にこだわらなければ、イラストに特化した描画エンジンを使用することもできます。以下のURLにアクセスして、サンプルソースを入手して、指定するワードを変更してみましょう。

huggingface.co

"extermely detailed CG wallpaper, blonde hair, long hair, fantasy, pretty girl, slight smile, soft focus, beautiful composition, wearing armor"
(非常に詳細な CG の壁紙、ブロンドの髪、長い髪、ファンタジー、美少女、わずかな笑顔、ソフト フォーカス、美しい構図、鎧を着ています)

すごく綺麗に描かれました。

しばらく遊んでても飽きなそうですw

ユニ◯ロの無人レジを作ってみようとして挫折した話

RFIDを使用した無人レジの実践

今更ながらユニ◯ロの店頭で活用されている無人レジに関心を持って、このレジシステムをRaspberryPiなどで安価に再現できないか、と調べて情報収集を行いました。タイトルの通り、他のIoT機器とは別の問題にぶち当たって挫折しまったので、それについて知り得た情報をアウトプットします。

前提知識

無人レジの仕組み

上記のレジでは、商品を入れたカゴを所定の読み取り棚にセットするだけで、機械が商品の内容と価格を自動で算出して、お客に金額を提示するようになっています。この原理は、次の仕組みが活用されています。

  • 商品の値札には、RFIDタグが埋め込まれていること。
  • 読み取り棚にはRFIDのリーダー(読み取り機)が備わっていること。
  • お客がカゴを入れると、読み取り機がRFIDを読み取ることで、カゴの中に何の商品(IDを識別)が、何個入っているか識別すること。
  • コンピュータが商品のIDとデータベースを照合して価格を取得し、料金を算出すること。

従来の無人レジに比べて「バーコードをスキャンする必要がない」というのが大きなポイントとなっています。

これに使用されている値札は、下のような構造になっています。

表面的には普通の厚紙に見えるので気づきずらいですが、紙の間に薄い電極(アンテナ)とICチップが内蔵されており、これが読み取り機からの電波を受信して、チップ内の情報を送信しています。

値札に添付するタグは非常にローコストであり、大量に購入すれば1枚あたり24円程度で済むようです。

また、2018年にはこのような宣言も出ているらしく、再現できれば大きなビジネスチャンスにつけそうだと思いました。

news.yahoo.co.jp

ここまでの知識をもとに「Raspberry PiRFIDタグを使えば、自分でも安価に無人レジが作れるのでは?」と言うことから、調査を始めたのですが・・・。

今回のトライ

今回は、RaspberryPiを使用したRFIDタグの識別をテストしました。購入したのは次の2つです。

左のRFIDリーダーには、サンプルとなるICカードと、RFIDタグが付随しており、こちらにデータの追記をしたり、読み込んだりすることができます。

※ 注意:結論で言うと、これらを購入しても目的は果たせませんでした。また、日本国内でこちらの製品を使用した場合は「試験的な使用」であっても、後述する「電波法」に抵触する可能性があります。当方は一切責任を負いませんので、自己責任でお願いします。

上述の事情もあり、今回は、実践した結果は掲載しません。こちらを使用することで次のような結果が得られる「はず」です。

  • こちらのサイトを参考にすることで、リーダー(RFID-RC522)に付属しているICカードから、個別のIDが読み込めること。
  • 右のUHFタグに対しては、このリーダーでは読み書きはできないこと。

問題発覚

購入してから気づいたのですが、今回の検証で購入した「RFID-RC522」には大きく2つの問題があったことに気づきました。

  • 国内で使用できる、明確な法的根拠(技適)がないこと
    国外の製品であり、発信している磁界強度が明記されていないため、電波法で許可された「微弱無線局(322MHz以下 500uV/m 以下)」の範囲を超えていないことがわからないこと。

  • この製品はHF帯(13.56MHz)のリーダライタであって、一緒に購入した右のUHFタグと互換性がないこと
    そもそも、受信の方式がHF帯(電磁誘導式)とUHF帯(電波式)で異なっており、その点を理解していなかった。

特に、前者に関しては盲点でした。中国製品あるあるですね(T-T

総務省が下図に規定しているとおり、(横軸は13.56MHzと製品ページにあるため)縦軸の磁界強度は500uV/m以内でなくてはならないのですが、この値が製品ページに示されていませんでした。

いくつかネット記事を探しましたが、本製品については「不明」であり「使用しない方が無難」という解釈がほとんどです(参考ページ

(出典:総務省ホームページ

本製品を使用した場合の電波法問題は、こちらの記事で細かく説明がされていますので、参考にご確認ください。

こちらのクリア方法は、以下の2つの製品を使用すること。

www.switch-science.com

ソニーが出しているNFCのリーダーであり、技適もクリアしているらしいです。総額にして¥5,000程度なので、「NFCをやりたいなら」これで良いと思うのですが、そもそもの目的が違っています。後者の話に繋がるので、「HF帯」「UHF帯」の違いについて、以下に記載します。

そもそも必要だった知識(RFIDとは)

RFIDとは「Radio Frequency IDentification」の略称であり、無線通信を使用した個体識別技術の総称です。身近なものでは、Suicaや運転免許証ICカード、入室カードなどにも使われています。

RFIDの種類 ①アクティブ型とパッシブ型

RFIDの受信デバイス(タグ)には、アクティブ型とパッシブ型が存在します。

  • アクティブ型:タグ自ら電波を出し、情報を発信するタイプ。身近なところでは、AirTagなどが該当します。電池を内蔵しており、パッシブタグに対して長距離の通信が可能ですが、一定期間の使用で、電池の交換が必要です。

  • パッシブ型:読み取り機(リーダー)からの電波を受けて、それに応答することで情報を発信するタイプ。電力を必要としません。読み取り機との間で、電磁誘導(コイルによる発電)して発電して駆動することから、アクティブ型に比べると遠距離での通信ができません。

アクティブ型はそれ自体に発信機器が必要となるため割高で、電池交換も必要であるため、今回のような用途には不向きです。

以降では、今回の対象である「パッシブ型」を中心に話を進めます。

RFID(パッシブ型)の種類 ②電波の種類

パッシブ型のRFIDには、通信原理は周波数帯に応じて、いくつかの種類が存在します。下表で分類していますが、前述のICカードSuica等)は「HF」上記の無人レジは「UHF」に該当します。

電波法の表示 通信原理 周波数帯 通信距離 RFIDの用途
LF
(長波)
電磁誘導 ~135kHz ~10cm スキーゲート、リフト回数券 、自動倉庫、食堂、回転すし精算、イモビライザー(自動車盗難防止システム)など
HF
(短波)
電磁誘導 13.56MHz ~10cm 交通系カードシステム、行政カードシステム、入退室管理システム等、NFCなど
UHF
(極超短波)
電波 860~960MHz ~10m RFID、商品検品・仕分け、在庫管理、物流管理、コンテナ内状況管理などなど

余談ですが、技術用語でよく出る「NFC」は、HFのRFIDを使用した電磁誘導による近距離無線通信技術であり、今回の対象とは異なります。詳細は以下を参照ください。

【参考】RFIDとNFCの違い、特徴とは?UHF、HFなど分類もふまえて解説

「非接触」だけど数cm距離で「接触

2001年にSuicaが導入されて以来、HF帯を使用した非接触カードは広く普及しており、我々の身近でも入室カードや、ICパスポートといった「非接触」カードとしての活用がされてきました。

しかし、HF帯は検知距離が短いため、「非接触」と謳いながら、実態として読み取り機から数cmの距離で「接触」させることが前提となっています。

この解決として、UHF帯を使用すれば、検知距離は最大で10m(規格上)となっていることから、読み取り機から離れた「非接触」の状態であっても、個体の識別が可能です。また、距離が離れていることで、複数個体をまとめて読み取ることもできるのです。






・・・ここまできて、そもそも購入している機器に誤りがあったことに気づきました。上表の通り、HF帯とUHF帯では、受信するための方式が全く違うので、通信できるわけがないんですよね・・・。

一般的にはどうなのよ?

こちらのサイトによれば、UHF帯のリーダーを使用するには、大きく次のいずれかを使用するのが一般的なようです。

  • 電波強度 250mW以下のリーダーを使用する(申請不要)
  • 電波強度 1Wのリーダーを使用する(総務省への申請が必要)

これらをざっとネットを調べてみましたが、安価に入手できる製品はありませんでした。国内の製品ではUSB接続が前提であり価格帯は¥50,000前後。

paypaymall.yahoo.co.jp

安価なGPIO製品もありますが、いずれも海外製であり、出力電波強度が明記されていないことから、下手に手を出すと今回と同じ轍を踏みそうです。

以上のことから、今回は購入した部品類は勉強代として諦めました。海外の製品に手を出して失敗するってのはあるあるなんでしょうが、法務に絡むと後が怖いので、皆さんもよく注意して使用しましょうね。

Go言語始めました。

Go言語始めました

環境準備(Mac

  • 以下の公式サイトからGoのダウンロードを行う
    https://go.dev/dl/
  • インストール後に、Pathを通す必要あり。 nanoを起動してパスを記載。
$ sudo nano ~/.bashrc

# 以下、~/.bashrcの内容
export GOPATH=$(go env GOPATH)
export PATH=$PATH:$GOPATH/bin
  • ~/.bashrcへの登録内容を環境に反映する。
$ source ~/.bashrc
  • go install golang.org/x/tools/cmd/godoc@v0.1.10 「go get」はVer1.16で廃止されているため、パッケージのInstallは「go install」で行う。@の後ろでVersionを指定すること。

初歩

Hello World

以下の通りコーディングして実行する。

package main

import "fmt"

func init() {
    fmt.Println("init")
}
func bazz() {
    fmt.Println("Bazz")
}

func main() {
    bazz()
    fmt.Println("Hello world!")
}
  • 実行するには、main()が必要であること。
  • init()は、最初に(mainよりも先に)呼び出されること。
  • Publicメソッドは、冒頭大文字で始めるのが原則であること
  • IDE「Go Land」では、文字列変数には「a....」というガイドが表示されること
  • コメントは、「//」でインラインコメント、「//」でブロックコメント。
  • 実行ショートカットは、Macの場合、デフォルトは「Control+R」。Preferenceから変更可能。

パッケージのインポート

  • importを複数行う場合は、import()で記載する
import (
    "fmt"
    "os/user"
    "time"
)
  • 上記「os/user」のように、階層下がある場合は「/」で区切ること.
    標準パッケージは、以下のサイトを参照する。

pkg.go.dev

  • メソッドの説明を確認する場合は上のドキュメントを参照するか、ターミナルから次のコマンドを実行する。
# go doc パッケージ名 メソッド名
$ go doc fmt Println
package fmt // import "fmt"

func Println(a ...any) (n int, err error)
    Println formats using the default formats for its operands and writes to
    standard output. Spaces are always added between operands and a newline is
    appended. It returns the number of bytes written and any write error
    encountered.

特徴的なポイント

宣言時のデータ型は、前ではなく後ろで行う(VBっぽい?)

// 関数宣言
func(param int) float64 {
  // :
}

// 変数宣言
var variable int

// 変数宣言(配列)
var ary []int

配列とスライス

素数が予め固定なのを「配列」と呼び、要素数が動的なものを「スライス」と呼ぶ(ようです)

ファンクションは変数に代入できる(最近珍しくはない)

add := func(x int ,y int){
    return x+y
}

result := add(3,5)
fmt.Println(result) // -> 8

クロージャってなんじゃ?

昔から名前だけは聞いていたけど、出会ったことはなかったクロージャ。Static、というかPrivateメンバ変数を持ったクラスと理解したけど、ちょっと違いそう。そもそもGoにクラスがないことをここで知った。

func incrementGenerator() func() int {
    x := 0
    return func() int {
        x++
        return x
    }
}

func main() {
    counter := incrementGenerator()
    fmt.Println(counter()) // -> 1
    fmt.Println(counter()) // -> 2
    fmt.Println(counter()) // -> 3
    fmt.Println(counter()) // -> 4
}

遅延処理を行う defer

ファンクション単位の最後に実行を行うDefer。

func main(){
    defer fmt.Println("test1")
    fmt.Println("test2")
    fmt.Println("test3")
    fmt.Println("test4")
}
// -> test2
// -> test3
// -> test4
// -> test1 ← defer を書いた行がこちらが後に出る

主な用途としては、ファイルのOpen/Close処理。Try~Finallyみたいなイメージ?

func main(){
    file, _ := os.Open("./test.go")
    defer file.Close() // <- 処理後にファイルクローズする行われる
    data := make([]byte ,100)
    file.Read(data)
    fmt.Println(string(data))
}

エラーハンドリング。

GoにはTry~Catch、Exceptionが存在しない。エラーは、ファンクションの戻り値として規定し、その値を単純にIFで比較する。

func main() {
    file, err := os.Open("./tsest.go")
    defer file.Close()
    // ↓ 単純に、err を Ifで判定。
    if err != nil {
        log.Fatalln("Error!", err)
    }
}

panicとrecover

panicはPGの強制終了。recoverはpanicで終了されることを防ぐもの。ただし、コード原則としてエラーは適切にハンドリングするべきであり、panicは作らないようにすべき。

func DBConnect() {
    // PG強制終了
    panic("Unable to Connect Database!")
}

func save() {
    // deferのため、DBConnect()後に処理
    defer func() {
        s := recover() // DBConnect()のPanicをキャッチ
        fmt.Println(s)
    }()

    DBConnect()
}

func main() {
    save()
    fmt.Println("OK?")
}

AWSのクラウドAIで顔画像情報を分析する

AWSの「Rekognition」サービスを使用して、顔画像の分析情報を取得してみました。
Raspberry Pi等のエッジデバイスで撮影した画像に対し、エッジではなくクラウド側で処理した場合に、どの程度ラグが出るのかを確認したいと考えた次第です。

「Rekognition」サービスについて

AWSが提供しているマネージドな視覚分析(画像分析)サービスです。顔画像をアップロードする、WebAPIとしてデータをPOSTする等データの受け渡しを行うことで、年齢、性別の他、多くの情報を分析してくれます(笑顔、表情、サングラス・顎鬚の有無など)。 また今回は使用していませんが、これ以外にも、画像データから次のような分析も可能です。

  • ラベル検出(物体検出)
  • 画像の節度(倫理的に不適切な画像をモザイク処理する)
  • 有名人の認識(似ている有名人を探す)
  • 顔の比較(複数の顔画像の類似性を示す)
  • イメージ内のテキスト(画像から文字を判定)← 現時点で日本語は未対応

AWS Rekognition(顔の分析)>

処理の流れ

全体構造を図示すると、以下のようになります。

① PCのカメラで顔を撮影し、OpenCVのカスケード分類器で顔を検出。
② 顔画像をAWSIoTCoreに送信(Publish)する。顔画像はBase64エンコード
③ ルールエンジンを使用して画像をBase64のままDynamoDBに登録。
④ テーブルのStreamでLambdaを起動。
⑤ LambdaでBase64をデコードしてRekognition(画像分析AI)に渡す。
JSONで認識結果が返却される。Lambdaでデータを取得。
⑦⑧ MQTTでPCに分析した結果を戻す(Publish)。
OpenCVで画面に分析結果文字を合成して、画面に表示。

処理結果

実際に実装してみた結果で、画像撮影 → 画面への分析結果表示までを何度か試してみました。
※実装方法については、こちらのGitHubをご確認ください。

<分析結果の画面表示イメージ>

画像の取得から、分析した情報を画面に表示するまでのタイムラグは、2秒~3秒 程度でした。

以下のGitHubにアニメーションGIFを掲載しています。
github.com

結論

応答速度は予想以上に早かったです。 運転時の画像判断といったミリ秒単位のアクションはできませんが、それ以外の用途であれば、十分使用に耐えうるレベルということがわかりました。

実装方式の補足

このような機能を実装する場合、データの受け渡し方法がいくつかあります。

  1. クライアント<jpg画像を保存>→(AWS SDK)→S3→lambda→Rekognition
  2. クライアント<jpg画像を保存>→(Web API)→Rekognition
  3. クライアント(AWS WebRTC SDK)→Kenesis Video Streams→Rekognition

今回は上記のいずれでもなく、ちょっと特殊な方法を実装してみました。

  クライアント<Base64 Encode>
   →(MQTT)→IoT Core
    → DynamoDB → Stream
     → lambda<Base64 Decode>
      → Rekognition

本来のベストプラクティスは「1」(動画なら3)であり、MQTTはパケットサイズ上限やデータ損失等の問題から、おそらく画像送信には向いていません。今回これを採用した理由は以下のような事情からです。

  • AWS SDK、Web APIと異なり、IAMのAccess Key や Secret Access Keyを使用せずに済む
  • 画像バイナリのデータ送受・変換方法を理解したかった(OpenCV→ndArray→jpg)
  • データの送受信ルートを1方式に絞りたかった

ESP32 EN(Reset) PINを使用した消費電力化

ESP32の動作検証について

最近、ESP32を本格的に動かす機会が増えたため、実践した部分を備忘として書き出していこうと思います。ESP32が何者かについては、割愛しますので、Wikipedia等の情報をご確認ください。
なお、自身はハードの専門家ではなく電子工作の知識も不十分。「動けばいいな」程度の知識しかなく、検証に使用したESP32もすでに2台がご臨終しました。検証サンプルをマネされる場合は自己責任でお願いします…。

ESP32のスリープモード

今回はESP32を電池やバッテリで駆動させる場合に、可能な限り電力を長持ちさせる「スリープモード」を調べました。
ESP32には、消費電力を抑えるための「スリープモード」が、大きく3種類存在します。

  • Modem-sleep mode :CPUの動作を維持したまま、非通信時にWiFi用のRF回路をオフにして電力をおさえる。WiFiとの接続は維持。
  • Ligth-sleep mode : 通信が行われないときにはWiFi用のRF回路をオフにし、CPUの実行をサスペンド。GPIOなどの入力情報をトリガーに何かを実行するのに向いている。
  • Deep-sleep mode : RTCのみの電源がオンでCPUは停止状態。復旧時に再起動されて、setup()から実行される。一定間隔(タイマー)で何かを実行するのに向いている。

電力消費仕様

上記の消費電力は、公式データシートの、以下の章に記載されています。

ポイントを要約すると、通常(『Active mode』)では 100mA 前後消費(WifiやBLE状況の使用状況に依存)する電力を、『Light-sleep mode』で動作させた場合は 0.8mA(125分の1)、『Deep-sleep mode』で動作させた場合は 0.15mA(666分の1) まで下げることができる、ということ。

サンプルPG

配線図

ソース(ESP32)

void setup() {
  // シリアル出力初期化
  Serial.begin(115200);

  // シリアル出力初期化
  Serial.println("Sleep!!");
  esp_deep_sleep_start();
  Serial.println("Wake?(on setup)"); // ← 出力されない
}

void loop(){
  // ダミー出力
  Serial.println("Wake?(on loop)"); // ← 出力されない
}

ここで照会するサンプルは、次のような動作をする。
リードスイッチは普段ONの(磁石が近づいている)状態が前提である。
このとき、プルアップによりEN(Reset)ピンへの入力はHIGHである。

  • ESP32は起動時にSetup()処理を行い、直後にDeepSleepに移行する。
  • DeepSleep中は、上表のとおり電力消費が最低に抑えられている。
  • リードスイッチが磁石から離れる(スイッチがOFFになる)と、EN(Reset)ピンへの入力がHIGH→LOWに変わる。
  • EN(Reset)ピンへの入力変化により、ハードウェアリセットがかかる。
  • 再度Setup()の処理が実行される。
  • その後、再度DeepSleepに移行する。

基本動作がDeepSleep状態であるため、相当に消費電力を抑えられるはずである。

Microsoft Azure Fundamentals (AZ-900) 合格記

Azure 資格合格

この度、Microsoftパブリッククラウド Azure の入門資格である、「AZ-900 Azure Fundamentals」に合格しました。今回は、その合格記を以下に記そうと思います。

f:id:camelrush:20220325224102p:plain

。。。AWSに比べると、あっさり目の認定証でした。。。

受験のきっかけ

パブリッククラウドでは、すでにAWSのSAA(Architect Associate)を持っていましたが、そちらとの違いを学んでおいた方がよかろうと思い、受講しました。

資格体系

Azureでは、下図のような資格体系が採られています。

f:id:camelrush:20220325232159p:plain

一番下の「基礎トレーニング」層に「AZ-900」があり、その上位にはAssociateレベルとして、次の3つがあります。

  • AZ-104 Azure Administrator
  • AZ-204 Azure Developer
  • AZ-500 Azure Security Engineer

さらにその上にはExpartレベルとして次の2つがあります。

  • AZ-304 Azure Solutions Architect
  • AZ-400 DevOpt Engineer

受験料(¥12,500/回 が完全無料に)

Microsoftの『Fundamentals: Azureの基礎 - 【AZ-900無料試験特典付き】』という、6時間(3時間✖️2日)のオンライン講義を受講するだけで、¥12,500/回の受験料が無料になります。
『受講』といっても構える必要はなく、指定時間にオンライン動画にアクセスしてを再生するだけでチケットがもらえるので、やらない手はないです。知らずにお金を払った人がかわいそう!

www.microsoft.com

対策

今回はUdemyで、以下の問題集を全てやり切りました。

www.udemy.com

私の場合、AWSパブリッククラウドの基礎を理解していたので、問題集の消化で対処できた感じです。クラウド未経験の方は、これと別にテキスト勉強など準備した方が良いかもしれません。

結果

スコアは700点満点中、871点 で合格となりました。

f:id:camelrush:20220325234504p:plain

受験当日の印象ですが、上のUdemyよりは内容は簡単だった印象です。戸惑ったのが、サービス名の改訂。Udemy「Azure Security Center」→試験「Microsoft Defender for Cloud」に変わっており、面食らいました。

余談

受験動機であったAWSとAzureの差異ですが、結局、あまりわかりませんでした。試験対策勉強に特化させてしまったので。サービス名称は違うけどほとんど同じかな、基礎の範疇では、と。
1点だけ、以下の点は違うと理解しました。

  • ✖️ AWS : コスト上限に達してもサービスは継続される(通知はくる)
  • ◯ Azure : コスト上限に達するとサービスが停止し、課金が止まる

万が一とはいえ、クラウド破産は怖い。リスクが抑えられるってのは、微妙にありがたいと思います。