皆!バトルしようぜ!
カードゲームでバトルした思い出が皆さんあると思いますが如何でしょうか?
○戯王カード、○ケモンカード、マジッ○ザギャザ○ング色々とありますね。
子供心を忘れてしまった人もいるのではないでしょうか。
争いとか嫌い....平和が一番好き☆
一人カラオケ、一人焼肉、一人キャンプ、一人筋トレ、一人迷走、一人サウナ、一人キャンプ
お一人で遊べる遊びも増えましたね。
丁度、一人でも遊べる遊びを思いつきました。
その名も画像バトラー
使う技術
今回はAmazonRekognitionとlaravelを組み合わせて画像が投稿できる機能?アプリ?を作りました(簡易的なため、まだまだ未完成)
laravel: 8.74.0
AmazonRekognition: DetectLabels
AmazonRekognitionとは
公式ページから一部引用させてもらいます。
Amazon Rekognition では、イメージ分析とビデオ分析をアプリケーションに簡単に追加することができます。Amazon Rekognition API にイメージやビデオを指定するだけで、このサービスによってモノ、人物、テキスト、シーン、アクティビティを識別できます。不適切なコンテンツも検出できます。Amazon Rekognition では、高精度な顔分析、顔の比較、および顔の検索機能も備えています。顔の検出、分析、比較は、ユーザー検証、カタログ作成、人数計数、公共安全など、多岐にわたって活用できます。
Amazon Rekognition は、Amazon のコンピュータビジョン科学者が日々何十億ものイメージを分析するために開発したものと同じ、実証済みで高度にスケーラブルな深層学習テクノロジに基づいています。使用する機械学習の専門知識は必要ありません
つまり高度な知識がなくても機械学習が使えるということですね。
その中で今回、使ってみるのがActionsのDetectLabelsです。
入力として提供されるイメージ (JPEG または PNG) 内の実際のエンティティのインスタンスを検出します。これには、花、木、テーブルなどのオブジェクト、結婚式、卒業式、誕生日パーティーなどのイベント、風景、夕方、自然などの概念が含まれます。
[DetectLabels説明ページ]
(https://docs.aws.amazon.com/ja_jp/rekognition/latest/dg/API_DetectLabels.html)
他にもたくさんの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サービスからユーザーをクリック
ページ遷移後にユーザーを追加
ユーザー名とlaravelからアクセスするため、「プログラムによるアクセス」にチェック
次の画面に行きグループの作成
グループ名にrekognitionを入力して検索し「Access to All Amazon Rekognition」の項目にチェック
成功したら「アクセスキー」と「シークレットアクセスキー」を取得
アプリケーションの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>
本題
デュエル(一人決闘)の開始です。
非常にお待たせしました。
今回は未完成のためlabelのdd($resultLabels)で値の中身を確認して決闘します。
#ドォオォォロー!
俺の画像は!!!
ハッピーバースデーモンスターα!!!!!
"Name" => "Birthday Party"
"Confidence" => 56.966209411621
56.966209411621か.....
#俺のターン!ドロー!
パリピ!
"Name" => "Birthday Party"
"Confidence" => 65.341262817383
やっぱり、パリピには勝てない...
#最後に
一つの画像のlabelで以下の画像のような出力になりました(一部抜粋)
AWSサービスはたくさんあるので、作ったり試してみて慣れていきたいですね。