Amazon Rekognitionでねこ画像の判定処理を行う
概要
個人開発中のサービス LGTMeow で Amazon Rekognition を利用したねこ画像判定処理を追加したので、そこで得た知見を書かさせていただきます。
対象読者
- AWSを利用したことがある人
 - 機械学習の知識がない人
 
この記事で説明すること、説明しないこと
説明すること
- Amazon Rekognition(以降はRekognitionと表記します)で何ができるか
 - Rekognitionはどのようなケースで有効活用できるか?
 - Rekognitionをシステムに組み込む際の注意点
 
説明しないこと
- Rekognitionカスタムラベルの話
 
筆者のバックグラウンド
エンジニア歴はもうすぐ8年程です。
今はフリーランスエンジニアで、フロントエンドからバックエンドまで幅広く対応しています。
主にAWS上で開発を行なうことが多いです。
機械学習を利用した案件に参画したことはありますが、自分自信が機械学習モデルを構築した経験はありません。
Rekognitionの概要
機械学習の専門知識がない人でも簡単に扱える画像解析サービスです。
AWSのサービスはS3やECSなど、事前にAWSコンソールやCLIでAWS上にS3バケットなどのリソースを作成しないと利用できないケースが多いです。
しかしRekognitionはAWSアカウントを作成さえすれば、事前準備なしに利用できます。
詳しいAPIの利用方法ですが 公式ドキュメント を見るのが一番確実です。
この記事では実際のユースケースに合わせていくつかのAPIを紹介します。
Rekognitionの基本的な使い方
AWS SDKを使ってRekognitionのAPIにアクセスします。
以下のコードは AWS SDK for Go v2 を利用して DetectLabels を利用して画像の情報を取得する例です。
package main
import (
	"context"
	"log"
	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/rekognition"
	"github.com/aws/aws-sdk-go-v2/service/rekognition/types"
)
func DetectLabels() (*rekognition.DetectLabelsOutput, error) {
	// rekognitionを利用するリージョンと解析画像が存在するS3バケットのリージョンは合わせる必要があります
	region := "ap-northeast-1"
	ctx := context.Background()
	cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(region))
	if err != nil {
		log.Fatalln(err)
	}
	rekognitionClient := rekognition.NewFromConfig(cfg)
	s3Object := &types.S3Object{
		Bucket:  aws.String("検証対象の画像が入っているS3バケットを指定"),
		Name:    aws.String("Objectのパスを指定する"),
		Version: aws.String("S3のバージョニングを有効にしている場合は指定、省略すると最新バージョンが利用される"),
	}
	// 画像解析
	rekognitionImage := &types.Image{
		S3Object: s3Object,
	}
	// 何個までラベルを取得するかの設定、ラベルは信頼度が高い順に並んでいる
	const maxLabels = int32(10)
	// 信頼度の閾値、Confidenceがここで設定した値未満の場合、そのラベルはレスポンスに含まれない
	const minConfidence = float32(85)
	input := &rekognition.DetectLabelsInput{
		Image:         rekognitionImage,
		MaxLabels:     aws.Int32(maxLabels),
		MinConfidence: aws.Float32(minConfidence),
	}
	output, err := rekognitionClient.DetectLabels(ctx, input)
	if err != nil {
		return nil, err
	}
	return output, nil
}
以下のようなレスポンスが返ってきます。
{
  "Labels": [
    {
      "Confidence": 98.68521,
      "Instances": [
        {
          "BoundingBox": {
            "Height": 0.87151253,
            "Left": 0.016100494,
            "Top": 0.078216076,
            "Width": 0.98155206
          },
          "Confidence": 98.68521
        }
      ],
      "Name": "Cat",
      "Parents": [
        {
          "Name": "Pet"
        },
        {
          "Name": "Mammal"
        },
        {
          "Name": "Animal"
        }
      ]
    },
    {
      "Confidence": 98.68521,
      "Instances": [],
      "Name": "Pet",
      "Parents": [
        {
          "Name": "Animal"
        }
      ]
    },
    {
      "Confidence": 98.68521,
      "Instances": [],
      "Name": "Mammal",
      "Parents": [
        {
          "Name": "Animal"
        }
      ]
    },
    {
      "Confidence": 98.68521,
      "Instances": [],
      "Name": "Animal",
      "Parents": []
    },
    {
      "Confidence": 95.80083,
      "Instances": [],
      "Name": "Abyssinian",
      "Parents": [
        {
          "Name": "Cat"
        },
        {
          "Name": "Pet"
        },
        {
          "Name": "Mammal"
        },
        {
          "Name": "Animal"
        }
      ]
    }
  ]
}
解析に利用した画像は下記になります。

レスポンスを見ると、画像に写っているものがラベルとして取得できることがわかります。
重要なのは Confidence と Name です。
Confidence は信頼度を表す値です。
この画像の場合 Name が Cat で Confidence が 98.68521 なので98%以上の確率でねこが写っていると見なすことができます。
LGTMeowのサービス概要とRekognitionをどのように利用したか
LGTMeow は猫のLGTM画像を集めたサービスです。
サービスの詳しい説明に興味がある人は共同開発者の kobayashi-m42 の 猫好きのためのLGTM画像共有サービスを作っています を参照してください。
最初は自分達開発者が集めたねこ画像を使って、LGTM画像を作成して、それらを表示させていただけでした。
最近エンドユーザーがねこ画像をアップロードできる機能を追加しました。
ねこのLGTM画像を共有するサービスをうたっているので、ねこが写っていない画像をアップロードをされる事を避けたかったという事情があります。
そのため DetectLabels を使って画像を解析し Confidence が一定数以下の画像はアップロードさせないように実装しました。
他にもチェックを行なっているのですが、サービスの性質上ここを公開することは難しいので、詳しい内容は非公開とさせていただきます。
代わりに、この機能を作成する際に個人用のリポジトリで色々と実験していました、その際の成果物を共有させていただきます。
こちらのリポジトリを参照すると、何となく裏側でやっていることの雰囲気が伝わるかと思います。
Rekognitionの機能をいくつか紹介
API リファレンス を見るとさまざまなAPIありますが、 いくつかの機能を紹介させていただきます。
DetectFaces(顔の検出)
画像に載っている顔を検出するAPIです。
こちら にサンプルコードがあります。
人の顔が検出されない場合は空の配列が返ってきます。
人の顔をアップロードするとかなり高い精度で検出できますが、以下のようにねこの画像でも顔検出が行なわれる場合があります。

{
  "FaceDetails": [
    {
      "AgeRange": null,
      "Beard": null,
      "BoundingBox": {
        "Height": 0.29183787,
        "Left": 0.07472489,
        "Top": 0.2709639,
        "Width": 0.5417548
      },
      "Confidence": 66.72364,
      "Emotions": null,
      "Eyeglasses": null,
      "EyesOpen": null,
      "Gender": null,
      "Landmarks": [
        {
          "Type": "eyeLeft",
          "X": 0.30981517,
          "Y": 0.33770314
        },
        {
          "Type": "eyeRight",
          "X": 0.50000805,
          "Y": 0.33927107
        },
        {
          "Type": "mouthLeft",
          "X": 0.30706555,
          "Y": 0.50413615
        },
        {
          "Type": "mouthRight",
          "X": 0.46517605,
          "Y": 0.5042505
        },
        {
          "Type": "nose",
          "X": 0.47034857,
          "Y": 0.42010358
        }
      ],
      "MouthOpen": null,
      "Mustache": null,
      "Pose": {
        "Pitch": 12.441085,
        "Roll": 9.164827,
        "Yaw": 6.8097568
      },
      "Quality": {
        "Brightness": 95.53643,
        "Sharpness": 92.22801
      },
      "Smile": null,
      "Sunglasses": null
    },
    {
      "AgeRange": null,
      "Beard": null,
      "BoundingBox": {
        "Height": 0.2223244,
        "Left": 0.7428785,
        "Top": 0.74860626,
        "Width": 0.3278522
      },
      "Confidence": 66.78572,
      "Emotions": null,
      "Eyeglasses": null,
      "EyesOpen": null,
      "Gender": null,
      "Landmarks": [
        {
          "Type": "eyeLeft",
          "X": 0.86015856,
          "Y": 0.7967467
        },
        {
          "Type": "eyeRight",
          "X": 0.91044015,
          "Y": 0.82621884
        },
        {
          "Type": "mouthLeft",
          "X": 0.7535296,
          "Y": 0.8594641
        },
        {
          "Type": "mouthRight",
          "X": 0.7945388,
          "Y": 0.8837279
        },
        {
          "Type": "nose",
          "X": 0.81529987,
          "Y": 0.8392649
        }
      ],
      "MouthOpen": null,
      "Mustache": null,
      "Pose": {
        "Pitch": 9.174266,
        "Roll": 60.05953,
        "Yaw": 24.53278
      },
      "Quality": {
        "Brightness": 85.71859,
        "Sharpness": 4.374837
      },
      "Smile": null,
      "Sunglasses": null
    }
  ],
  "OrientationCorrection": "",
  "ResultMetadata": {}
}
DetectText(イメージ内のテキストの検出)
画像内に写っているテキストを抽出するためのAPIです。
残念ながら日本語には対応していませんが、免許証の番号やマイナンバーの抽出などの用途に利用できそうです。
IndexFaces & SearchFacesByImage
IndexFacesで顔の登録をして、SearchFacesByImageで登録されている顔を検索することで顔認証を実現できます。
実際にいくつかの導入事例があるようです。
- (参考1)身元確認に Amazon Rekognition を使うことで、これまで銀行を利用できなかった人々を自立させた Aella Credit 社
 - (参考2)AWS/Rekognitionを活用した 宿泊施設向け入退室管理システムの構築事例
 
Rekognitionを利用する際の注意点
DetectLabelsに関してですが、検出されるラベル自体が間違っていることがあります。
最初は こちらのコード のように Parents に Cat が含まれていれば、それはねこの種類を表すラベルなので、ねこの種類(マンチカン、スコティッシュフォールド、チンチラシルバー等)ごとに画像の分類もできるかも、と考えていました。
しかし実際に試してみたところ、アビシニアン(Abyssinian)やマンクス (Manx)などは比較的正確に判定できるが、他の種類はほとんど判定できませんでした。
うちのねこのもこちゃん(チンチラシルバー)も種類を判定できませんでした。

成猫なのにKitten(子猫)と判定されたりもしました。
やはりこのレベルの精度を求めてしまうと、標準の解析APIでは不十分で カスタムラベル の利用などを行なう必要があります。
その為、実際にやりたいことができるのか、導入前に十分なテストをすることをオススメします。
画像判定ロジックを作る際にConfidenceの閾値をどこに置くかが重要になります。
Confidenceの閾値はシステム運用フェーズに入った後も常に見直しが必要になるでしょう。
あとがき
実際の利用用途を元にRekognitionの紹介をさせていただきました。
LGTMeow ねこ画像アップロード でもっとも実現したかった、ねこ以外の画像を弾くという処理を標準APIだけで実現できて良かったです。
LGTMeow のサービス開発は今後も継続していきますので、ねこ好きの人は利用してくれると嬉しいです🐱。
ねこの種類判定は個人的に興味があるので、いつかチャレンジしたいと思っています。
以上になります。最後まで読んでいただき、ありがとうございました。
※ この記事に出てくる、うちのもこちゃん以外のねこ画像はフリー画像素材が集まっている https://unsplash.com/s/photos/cat の画像を利用しています。
Discussion