chakokuのブログ(rev4)

テック・コミック・DTM・・・ごくまれにチャリ

試作:Amazon RekognisionのComparing facesを使ってみる

(別の課題もあって)いつまでもこれにかかっているワケにはいかないのだが、気になる(+結果が分かりやすい)ので引き続きCompare facesを調査
AWSが提供しているサンプルコードは以下。めちゃくちゃシンプル。S3上ではなく、ローカルに存在するイメージファイルを2つ指定して画像間の一致を計算するサンプルと理解。

# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# PDX-License-Identifier: MIT-0 (For details, see https://github.com/awsdocs/amazon-rekognition-developer-guide/blob/master/LICENSE-SAMPLECODE.)

import boto3
def compare_faces(sourceFile, targetFile):

    session = boto3.Session(profile_name='profile-name')
    client = session.client('rekognition')
    imageSource = open(sourceFile, 'rb')
    imageTarget = open(targetFile, 'rb')
    response = client.compare_faces(SimilarityThreshold=80,
                                    SourceImage={'Bytes': imageSource.read()},
                                    TargetImage={'Bytes': imageTarget.read()})

    for faceMatch in response['FaceMatches']:
        position = faceMatch['Face']['BoundingBox']
        similarity = str(faceMatch['Similarity'])
        print('The face at ' +
              str(position['Left']) + ' ' +
              str(position['Top']) +
              ' matches with ' + similarity + '% confidence')

    imageSource.close()
    imageTarget.close()
    return len(response['FaceMatches'])

def main():
    source_file = 'source-file-name'
    target_file = 'target-file-name'
    face_matches = compare_faces(source_file, target_file)
    print("Face matches: " + str(face_matches))

if __name__ == "__main__":
    main()

Boto3の仕様書によると、対象ファイルはローカルに置かれている場合、S3に置かれている場合の両方が可能。教材としては、まずS3に画像をアップしてから、S3上のSourceとTargetを比較する方法で実装する方針
JSのサンプルは以下。前回作成した、Face Detectとほぼ同じ手順で実行できるので、ファイルを2つにして、API名を変えるだけでNodeを流用できそうだ

// Load the SDK
var AWS = require('aws-sdk');
const bucket = 'bucket-name' // the bucketname without s3://
const photo_source  = 'photo-source-name' // the name of file
const photo_target = 'photo-target-name'

var credentials = new AWS.SharedIniFileCredentials({profile: 'profile-name'});
AWS.config.credentials = credentials;
AWS.config.update({region:'region-name'});

const client = new AWS.Rekognition();
   const params = {
     SourceImage: {
       S3Object: {
         Bucket: bucket,
         Name: photo_source
       },
     },
     TargetImage: {
       S3Object: {
         Bucket: bucket,
         Name: photo_target
       },
     },
     SimilarityThreshold: 70
   }
   client.compareFaces(params, function(err, response) {
     if (err) {
       console.log(err, err.stack); // an error occurred
     } else {
       response.FaceMatches.forEach(data => {
         let position   = data.Face.BoundingBox
         let similarity = data.Similarity
         console.log(`The face at: ${position.Left}, ${position.Top} matches with ${similarity} % confidence`)
       }) // for response.faceDetails
     } // if
   });

Node-REDのオリジナルNodeのソースは以下

module.exports = (RED) => {
    function compareFacesNode(config) {
        RED.nodes.createNode(this,config);
        var node = this;
        node.on('input', function(msg) {
            cmpFaces(node, msg);
        });
    }
    RED.nodes.registerType("compareFaces", compareFacesNode);
}

function cmpFaces(node, msg) {

   const AWS = require('aws-sdk');

   const REGION = 'us-east-1';
   const BUCKET =   <bucket_name>;   // e.g  'rekognition-bucket'
   const PHOTO_SRC =  <src_photo_path_filename>;  //  e.g.  'face001.jpg'
   const PHOTO_TGT =  <src_photo_path_filename>;  //  e.g.  'face002.jpg'
   const PROFILENAME = 'default';

   const credentials = new AWS.SharedIniFileCredentials({profile: PROFILENAME});
   AWS.config.credentials = credentials;
   AWS.config.update({region:REGION});

   const client = new AWS.Rekognition();
   const params = {
     SourceImage: {
       S3Object: { Bucket: BUCKET, Name: PHOTO_SRC},
     },
     TargetImage: {
       S3Object: { Bucket: BUCKET, Name: PHOTO_TGT},
     },
     SimilarityThreshold: 70
   }
   console.log("i'll call AWS Recognition (comparing faces)");

   client.compareFaces(params, (err, response) => {
        if (err) {
           console.log(err, err.stack); // an error occurred
           msg.payload = "Error at AWS Rekognition (comparing faces)";
           msg.payload = err;
           node.send(msg);
        } else {
           console.log(`comparing faces with: ${PHOTO_SRC}/${PHOTO_TGT}`);
           msg.payload = response.FaceMatches[0];  // care...  take first object without check
           node.send(msg);
       }
   });
   return (true);            // no need return value
}

上記オリジナルNodeをNode-REDに登録して、2枚の写真をS3にアップして比較してみた。適当に自分の顔を撮影した2枚の写真ですが、類似度は99.996と判定された。上記JSソースは、一致度配列の要素が1以上を前提に組んでしまっているので、一致しないケースを想定して、sizeチェックしてから、先頭要素を取り出すべし

残作業

  1. ソースの仕上げ(要素数確認、エラー処理等)
  2. S3アップロードNodeにおいて、ファイルが固定なので、上流Nodeでファイル名指定できるように改良
  3. 全体を1フローにまとめた場合に正常に動作するのかを確認
  4. compareFacesでは、ループで連続的に一致判断できるかを確認

おまけ
この4日間は、JS三昧であった(Pythonをほとんど使っていない)


■参考URL
イメージ間の顔の比較 - Amazon Rekognition
compare_faces - Boto3 1.28.35 documentation
Amazon Rekognition(高精度の画像・動画分析サービス)| AWS