LoginSignup
1
0

More than 1 year has passed since last update.

Amazon Rekognitionで一人画像バトル(一人決闘)を開催した

Last updated at Posted at 2021-12-18

皆!バトルしようぜ!

カードゲームでバトルした思い出が皆さんあると思いますが如何でしょうか?

○戯王カード、○ケモンカード、マジッ○ザギャザ○ング色々とありますね。
子供心を忘れてしまった人もいるのではないでしょうか。

争いとか嫌い....平和が一番好き☆
一人カラオケ、一人焼肉、一人キャンプ、一人筋トレ、一人迷走、一人サウナ、一人キャンプ
お一人で遊べる遊びも増えましたね。

丁度、一人でも遊べる遊びを思いつきました。

その名も画像バトラー

使う技術

今回はAmazonRekognitionとlaravelを組み合わせて画像が投稿できる機能?アプリ?を作りました(簡易的なため、まだまだ未完成)

laravel: 8.74.0
AmazonRekognition: DetectLabels

AmazonRekognitionとは

公式ページから一部引用させてもらいます。

Amazon Rekognition では、イメージ分析とビデオ分析をアプリケーションに簡単に追加することができます。Amazon Rekognition API にイメージやビデオを指定するだけで、このサービスによってモノ、人物、テキスト、シーン、アクティビティを識別できます。不適切なコンテンツも検出できます。Amazon Rekognition では、高精度な顔分析、顔の比較、および顔の検索機能も備えています。顔の検出、分析、比較は、ユーザー検証、カタログ作成、人数計数、公共安全など、多岐にわたって活用できます。
Amazon Rekognition は、Amazon のコンピュータビジョン科学者が日々何十億ものイメージを分析するために開発したものと同じ、実証済みで高度にスケーラブルな深層学習テクノロジに基づいています。使用する機械学習の専門知識は必要ありません

AmazonRekognition説明ページ

つまり高度な知識がなくても機械学習が使えるということですね。
その中で今回、使ってみるのがActionsのDetectLabelsです。

入力として提供されるイメージ (JPEG または PNG) 内の実際のエンティティのインスタンスを検出します。これには、花、木、テーブルなどのオブジェクト、結婚式、卒業式、誕生日パーティーなどのイベント、風景、夕方、自然などの概念が含まれます。

DetectLabels説明ページ

他にもたくさんのActionsがありますが、今回は上記のlabelを使います。

リクエスト、レスポンスパラメーター

リクエストパラメーター
{
   "Image": { 
      "Bytes": blob,
      "S3Object": { 
         "Bucket": "string",
         "Name": "string",
         "Version": "string"
      }
   },
   "MaxLabels": number,
   "MinConfidence": number
}
レスポンスパラメーター
"LabelModelVersion": "string",
   "Labels": [ 
      { 
         "Confidence": number,
         "Instances": [ 
            { 
               "BoundingBox": { 
                  "Height": number,
                  "Left": number,
                  "Top": number,
                  "Width": number
               },
               "Confidence": number
            }
         ],
         "Name": "string",
         "Parents": [ 
            { 
               "Name": "string"
            }
         ]
      }
   ],
   "OrientationCorrection": "string"

今回のバトル内容はレスポンスパラメーターの
"Name": "string"
"Confidence": number

Nameが同じ名前でnumberがより高いものが勝利という条件にします。

AWS準備

IAMサービスからユーザーをクリック
スクリーンショット 2021-12-12 15.11.43.png
ページ遷移後にユーザーを追加
スクリーンショット 2021-12-12 15.12.04.png
ユーザー名とlaravelからアクセスするため、「プログラムによるアクセス」にチェック
スクリーンショット 2021-12-12 15.16.31.png
次の画面に行きグループの作成
スクリーンショット 2021-12-12 15.16.54.png
グループ名にrekognitionを入力して検索し「Access to All Amazon Rekognition」の項目にチェック
スクリーンショット 2021-12-12 15.18.12.png
成功したら「アクセスキー」と「シークレットアクセスキー」を取得
スクリーンショット 2021-12-12 15.19.19.png
アプリケーションのenvに入力

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=ap-northeast-1

アプリケーションのターミナルにてAWSにアクセスするためのパッケージをインストール

composer require aws/aws-sdk-php

これでAWSを使う準備は終わりました

アプリケーション開発

laravel newをして
PostsTableを作成

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('user_id');
            $table->string('title');
            $table->longText('description')->nullable();
            $table->string('image_path')->nullable();
            $table->timestamps();

            $table->foreign('user_id')->references('id')->on('users');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }

PostModelを作成

class Post extends Model
{
    use HasFactory;

    protected $fillable = [
        'title',
        'description'
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Routeを編集

Route::get('/', function () {
    return view('welcome');
});

Route::middleware(['auth:sanctum', 'verified'])->get('/dashboard', function () {
    return redirect()->route('posts.index');
})->name('dashboard');

Route::group(['middleware' => 'auth'], function(){

    Route::resource('posts',PostController::class);

});

PostControllerを作成し、storeメソッドを編集

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate($request, [
            'title' => 'required',
            'image'=> 'nullable|sometimes|file',
            'description' => 'nullable|sometimes'
        ]);

        $newPost = auth()->user()->posts()->create([
            'title' => $request->input('title'),
            'description' => $request->input('description')
        ]);

        if($request->hasFile('image')) {

            $client = new RekognitionClient([
                'region' => env('AWS_DEFAULT_REGION'),
                'version' => 'latest'
            ]);

            $image = fopen($request->file('image')->getPathName(), 'r');
            $bytes = fread($image, $request->file('image')->getSize());

            // rekognitionのメソッド
            $results = $client->DetectLabels([
                'Image' => ['Bytes' => $bytes],
                // 指定された値よりも低い信頼水準のラベルは返却しない
                'MinConfidence' => 0
            ]);

            $resultLabels = $results->get('Labels');

            $imagePath = $request->file('image')->store('public/posts');

            if($imagePath === null) {
              return redirect()->back()->withErrors([
                 'image_upload_files' => '画像アップロードを失敗しました'
              ]);
            }

            $newPost->image_path = $imagePath;
            $newPost->save();
        }

        return redirect()->back();
    }

bladeファイルを作成

<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            投稿
        </h2>
    </x-slot>

    <div class="py-12">
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
            <div>
                @if ($errors->any())
                    <div class="alert alert-danger">
                        <ul>
                            @foreach ($errors->all() as $error)
                                <li>{{ $error }}</li>
                            @endforeach
                        </ul>
                    </div>
                @endif
            </div>
            <div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
                <form action="{{ route('posts.store') }}" method="post" enctype="multipart/form-data">
                    @csrf
                <div>
                    <label for="title">投稿タイトル</label>
                    <input type="text" id="title" name="title">
                </div>
                <div>
                    <label for="image">画像</label>
                    <input type="file" id="image" name="image">
                </div>
                <div>
                    <label for="description">説明文</label>
                    <textarea name="description"  id="description" cols="30" rows="10"></textarea>
                </div>
                <div>
                    <button type="submit">投稿</button>
                </div>
                </form>
            </div>
        </div>
    </div>
</x-app-layout>

すごく簡単な投稿する画面ができました
スクリーンショット 2021-12-18 16.57.38.png

本題

デュエル(一人決闘)の開始です。

非常にお待たせしました。
今回は未完成のためlabelのdd($resultLabels)で値の中身を確認して決闘します。

ドォオォォロー!

俺の画像は!!!
ダウンロード (7).jpeg
ハッピーバースデーモンスターα!!!!!

"Name" => "Birthday Party"
"Confidence" => 56.966209411621

56.966209411621か.....

俺のターン!ドロー!

publicdomainq-0016959glt.jpeg
パリピ!

"Name" => "Birthday Party"
"Confidence" => 65.341262817383

やっぱり、パリピには勝てない...

最後に

一つの画像のlabelで以下の画像のような出力になりました(一部抜粋)
スクリーンショット 2021-12-18 17.24.16.png

AWSサービスはたくさんあるので、作ったり試してみて慣れていきたいですね。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0