├── src ├── config │ └── main.php ├── RekognitionFacade.php ├── RekognitionServiceProvider.php └── Rekognition.php ├── composer.json └── README.md /src/config/main.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'key' => env('YOUR_AWS_ACCESS_KEY_ID'), 6 | 'secret' => env('YOUR_AWS_SECRET_ACCESS_KEY'), 7 | ], 8 | 'region' => 'us-east-1', 9 | 'version' => 'latest' 10 | ]; -------------------------------------------------------------------------------- /src/RekognitionFacade.php: -------------------------------------------------------------------------------- 1 | publishes([ 17 | __DIR__ . '/config/main.php' => config_path('rekognition.php'), 18 | ]); 19 | 20 | $file = __DIR__ . '/../vendor/autoload.php'; 21 | 22 | if (file_exists($file)) { 23 | require $file; 24 | } 25 | } 26 | 27 | /** 28 | * Register the application services. 29 | * 30 | * @return void 31 | */ 32 | public function register() 33 | { 34 | $this->app->bind('aws-rekognition', function() { 35 | return new Rekognition; 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # larareko/aws-rekognition 2 | 3 | A Laravel package/facade for the Rekognition API PHP SDK. 4 | 5 | This repository implements a simple Service Provider of the AWS Rekognition client, and makes it easily accessible via a Facade in Laravel >= 5. 6 | 7 | See [AWS Rekognition](https://aws.amazon.com/rekognition/) for more information. 8 | 9 | ## Requirements 10 | 11 | Create an account at [AWS](https://aws.amazon.com/console/) and take note of your API keys. 12 | 13 | ## Installation using [Composer](https://getcomposer.org) 14 | 15 | In your terminal application move to the root directory of your laravel project using the cd command and require the project as a dependency using composer. 16 | 17 | composer require larareko/aws-rekognition 18 | 19 | This will add the following lines to your composer.json and download the project and its dependencies to your projects ./vendor directory: 20 | 21 | ```javascript 22 | // 23 | 24 | ./composer.json 25 | { 26 | "name": "larareko/larareko-demo", 27 | "description": "A dummy project used to test the Laravel Larareko (AWS Rekognition) Facade.", 28 | 29 | // ... 30 | 31 | "require": { 32 | "php": ">=5.5.9", 33 | "laravel/framework": "5.2.*", 34 | "larareko/aws-rekognition": "0.1*", 35 | // ... 36 | }, 37 | 38 | //... 39 | } 40 | ``` 41 | 42 | ## Usage 43 | 44 | In order to use the static interface we must customize the application configuration to tell the system where it can find the new service. Open the file config/app.php and add the following lines ([a], [b]): 45 | 46 | ```php 47 | 48 | // config/app.php 49 | 50 | return [ 51 | 52 | // ... 53 | 54 | 'providers' => [ 55 | 56 | // ... 57 | 58 | /* 59 | * Package Service Providers... 60 | */ 61 | Larareko\Rekognition\RekognitionServiceProvider::class, // [a] 62 | 63 | /* 64 | * Application Service Providers... 65 | */ 66 | App\Providers\AppServiceProvider::class, 67 | App\Providers\AuthServiceProvider::class, 68 | App\Providers\EventServiceProvider::class, 69 | App\Providers\RouteServiceProvider::class, 70 | 71 | ], 72 | 73 | // ... 74 | 75 | 'aliases' => [ 76 | 77 | 'App' => Illuminate\Support\Facades\App::class, 78 | 'Artisan' => Illuminate\Support\Facades\Artisan::class, 79 | 80 | // ... 81 | 82 | 'Rekognition' => 'Larareko\Rekognition\RekognitionFacade', // [b] 83 | 'Hash' => Illuminate\Support\Facades\Hash::class, 84 | 85 | // ... 86 | ], 87 | 88 | ]; 89 | 90 | 91 | ``` 92 | 93 | ## Publish Vendor 94 | 95 | aws-rekognition requires a connection configuration. To get started, you'll need to publish all vendor assets running: 96 | 97 | php artisan vendor:publish 98 | 99 | This will create a config/rekognition.php file in your app that you can modify to set your configuration. Make sure you check for changes compared to the original config file after an upgrade. 100 | 101 | Now you should be able to use the facade within your application. Ex: 102 | 103 | ```php 104 | 105 | class LabelDetectionImage extends Model 106 | { 107 | /** 108 | * Upload image to S3 109 | * 110 | * @param Illuminate\Http\UploadedFile $file 111 | * 112 | * @return string 113 | */ 114 | public function upload(UploadedFile $file) : string 115 | { 116 | $name = time() . $file->getClientOriginalName(); 117 | 118 | \Rekognition::uploadImageToS3(file_get_contents($file), null, self::BUCKET, $name); 119 | 120 | return $name; 121 | } 122 | } 123 | 124 | ``` 125 | 126 | ## Testing 127 | 128 | Unit Tests are created with PHPunit and orchestra/testbench, they can be ran with ./vendor/bin/phpunit. 129 | 130 | ## Contributing 131 | 132 | Find an area you can help with and do it. Open source is about collaboration and open participation. 133 | Try to make your code look like what already exists or better and submit a pull request. Also, if 134 | you have any ideas on how to make the code better or on improving the scope and functionality please 135 | contact any of the contributors. 136 | 137 | ## License 138 | 139 | MIT License. 140 | -------------------------------------------------------------------------------- /src/Rekognition.php: -------------------------------------------------------------------------------- 1 | args = [ 26 | 'credentials' => config('rekognition.credentials'), 27 | 'region' => config('rekognition.region'), 28 | 'version' => config('rekognition.version') 29 | ]; 30 | 31 | $this->client = new RekognitionClient($this->args); 32 | } 33 | 34 | /** 35 | * @return RekognitionClient 36 | */ 37 | public function getClient() 38 | { 39 | return $this->client; 40 | } 41 | 42 | /** 43 | * Detects instances of real-world labels within an image (JPEG or PNG) 44 | * provided as input 45 | * 46 | * @param array $params 47 | * @return array 48 | */ 49 | public function detectLabels(array $params = []) 50 | { 51 | return $this->client->detectLabels($params); 52 | } 53 | 54 | /** 55 | * @param array $params 56 | * @return array 57 | */ 58 | public function detectLabelsAsync(array $params = []) 59 | { 60 | return $this->client->detectLabelsAsync($params); 61 | } 62 | 63 | /** 64 | * Detects faces within an image (JPEG or PNG) that is provided as input 65 | * 66 | * @param array $params 67 | * @return array 68 | */ 69 | public function detectFaces(array $params = []) 70 | { 71 | return $this->client->detectFaces($params); 72 | } 73 | 74 | /** 75 | * @param array $params 76 | * @return array 77 | */ 78 | public function detectFacesAsync(array $params = []) 79 | { 80 | return $this->client->detectFacesAsync($params); 81 | } 82 | 83 | /** 84 | * Creates a collection in an AWS Region 85 | * 86 | * @param string $collectionId 87 | * @return array 88 | */ 89 | public function createCollection($collectionId) 90 | { 91 | return $this->client->createCollection(['CollectionId' => $collectionId]); 92 | } 93 | 94 | /** 95 | * @param array $params 96 | * @return array 97 | */ 98 | public function createCollectionAsync($collectionId) 99 | { 100 | return $this->client->createCollectionAsync(['CollectionId' => $collectionId]); 101 | } 102 | 103 | /** 104 | * Deletes a specified collection 105 | * 106 | * @param string $collectionId 107 | * @return int 108 | */ 109 | public function deleteCollection($collectionId) 110 | { 111 | return $this->client->deleteCollection(['CollectionId' => $collectionId]); 112 | } 113 | 114 | /** 115 | * @param string $collectionId 116 | * @return int 117 | */ 118 | public function deleteCollectionAsync($collectionId) 119 | { 120 | return $this->client->deleteCollectionAsync(['CollectionId' => $collectionId]); 121 | } 122 | 123 | /** 124 | * Detects faces in the input image and adds them to the specified 125 | * collection 126 | * 127 | * @param array $params 128 | * @return array 129 | */ 130 | public function indexFaces(array $params =[]) 131 | { 132 | return $this->client->indexFaces($params); 133 | } 134 | 135 | /** 136 | * @param array $params 137 | * @return array 138 | */ 139 | public function indexFacesAsync(array $params =[]) 140 | { 141 | return $this->client->indexFacesAsync($params); 142 | } 143 | 144 | /** 145 | * Deletes faces from a collection 146 | * 147 | * @param string $collectionId 148 | * @param array $faceIds 149 | * @return array 150 | */ 151 | public function deleteFaces($collectionId, array $faceIds) 152 | { 153 | return $this->client->deleteFaces([ 154 | 'CollectionId' => $collectionId, 155 | 'FacesIds' => $faceIds 156 | ]); 157 | } 158 | 159 | /** 160 | * @param string $collectionId 161 | * @param array $faceIds 162 | * @return array 163 | */ 164 | public function deleteFacesAsync($collectionId, array $faceIds) 165 | { 166 | return $this->client->deleteFacesAsync([ 167 | 'CollectionId' => $collectionId, 168 | 'FacesIds' => $faceIds 169 | ]); 170 | } 171 | 172 | /** 173 | * Returns list of collection IDs in your account 174 | * 175 | * @param int $maxResults 176 | * @param string $nextToken 177 | * @return array 178 | */ 179 | public function listCollections($maxResults = null, $nextToken = null) 180 | { 181 | return $this->client->listCollections([ 182 | 'maxResults' => $maxResults, 183 | 'NextToken' => $nextToken 184 | ]); 185 | } 186 | 187 | /** 188 | * @param int $maxResults 189 | * @param string $nextToken 190 | * @return array 191 | */ 192 | public function listCollectionsAsync($maxResults = null, $nextToken = null) 193 | { 194 | return $this->client->listCollectionsAsync([ 195 | 'maxResults' => $maxResults, 196 | 'NextToken' => $nextToken 197 | ]); 198 | } 199 | 200 | /** 201 | * Returns metadata for faces in the specified collection. 202 | * 203 | * @param string $collectionId 204 | * @param int $maxResults 205 | * @param string $nextToken 206 | * @return array 207 | */ 208 | public function listFaces($collectionId, $maxResults = null, $nextToken = null) 209 | { 210 | return $this->client->listFaces([ 211 | 'CollectionId' => $collectionId, 212 | 'MaxResults' => $maxResults, 213 | 'NextToken' => $nextToken 214 | ]); 215 | } 216 | 217 | /** 218 | * @param string $collectionId 219 | * @param int $maxResults 220 | * @param string $nextToken 221 | * @return array 222 | */ 223 | public function listFacesAsync($collectionId, $maxResults = null, $nextToken = null) 224 | { 225 | return $this->client->listFacesAsync([ 226 | 'CollectionId' => $collectionId, 227 | 'MaxResults' => $maxResults, 228 | 'NextToken' => $nextToken 229 | ]); 230 | } 231 | 232 | /** 233 | * Compares a face in the source input image with each face detected in the 234 | * target input image 235 | * 236 | * @param array $params 237 | * @return array 238 | */ 239 | public function compareFaces(array $params = []) 240 | { 241 | return $this->client->compareFaces($params); 242 | } 243 | 244 | /** 245 | * @param array $params 246 | * @return array 247 | */ 248 | public function compareFacesAsync(array $params = []) 249 | { 250 | return $this->client->compareFacesAsync($params); 251 | } 252 | 253 | /** 254 | * For a given input face ID, searches for matching faces in the collection 255 | * the face belongs to 256 | * 257 | * @param array $params 258 | * @return array 259 | */ 260 | public function searchFaces(array $params = []) 261 | { 262 | return $this->client->searchFaces($params); 263 | } 264 | 265 | /** 266 | * @param array $params 267 | * @return array 268 | */ 269 | public function searchFacesAsync(array $params = []) 270 | { 271 | return $this->client->searchFacesAsync($params); 272 | } 273 | 274 | /** 275 | * For a given input image, first detects the largest face in the image, 276 | * and then searches the specified collection for matching faces. 277 | * 278 | * @param array $params 279 | * @return array 280 | */ 281 | public function searchFacesByImage(array $params = []) 282 | { 283 | return $this->client->searchFacesByImage($params); 284 | } 285 | 286 | /** 287 | * @param array $params 288 | * @return array 289 | */ 290 | public function searchFacesByImageAsync(array $params = []) 291 | { 292 | return $this->client->searchFacesByImageAsync($params); 293 | } 294 | 295 | /** 296 | * Encodes an image to base64 encode format 297 | * 298 | * @param string $path 299 | * @return mixed 300 | */ 301 | public function encodeImage($path) 302 | { 303 | return (new \Imagick($path))->getImageBlob(); 304 | } 305 | 306 | /** 307 | * @param string || resource || Psr\Http\Message\StreamInterface $bytes 308 | * @param array $s3Object 309 | * @param int $maxLabels 310 | * @param float $minConfidence 311 | * @return array 312 | */ 313 | public function setDetectLabelsParams($maxLabels, $minConfidence, $bytes = null, $s3Object = []) 314 | { 315 | $image = ['S3Object' => $s3Object]; 316 | 317 | if(!is_null($bytes)) $image = ['Bytes' => $bytes]; 318 | 319 | return [ 320 | 'Image' => $image, 321 | 'MaxLabels' => $maxLabels, 322 | 'MinConfidence' => $minConfidence 323 | ]; 324 | 325 | } 326 | 327 | /** 328 | * @param array $attributes 329 | * @param string || resource || Psr\Http\Message\StreamInterface $bytes 330 | * @param array $s3Object 331 | * @return array 332 | */ 333 | public function setDetectFacesParams($attributes = ['ALL', 'DEFAULT'], $bytes = null, $s3Object = []) 334 | { 335 | $image = ['S3Object' => $s3Object]; 336 | 337 | if(!is_null($bytes)) $image = ['Bytes' => $bytes]; 338 | 339 | return [ 340 | 'Attributes' => $attributes, 341 | 'Image' => $image 342 | ]; 343 | } 344 | 345 | /** 346 | * @param string $collectionId 347 | * @param array $attributes 348 | * @param string $imageId 349 | * @param string || resource || Psr\Http\Message\StreamInterface $bytes 350 | * @param array $s3Object 351 | * @return array 352 | */ 353 | public function setIndexFaceParams($collectionId, $attributes = [], $imageId = null, $bytes = null, $s3Object = []) 354 | { 355 | $image = ['S3Object' => $s3Object]; 356 | 357 | if(!is_null($bytes)) $image = ['Bytes' => $bytes]; 358 | 359 | return [ 360 | 'CollectionId' => $collectionId, 361 | 'DetectionAttributes' => $attributes, 362 | 'ExternalImageId' => $imageId, 363 | 'Image' => $image 364 | ]; 365 | } 366 | 367 | /** 368 | * @param float $similarityTreshold 369 | * @param string || resource || Psr\Http\Message\StreamInterface $srcBytes 370 | * @param array $srcS3Object 371 | * @param string || resource || Psr\Http\Message\StreamInterface $tgtBytes 372 | * @param array $tgtS3Object 373 | * @return array 374 | */ 375 | public function setCompareFacesParams( 376 | $similarityTreshold, 377 | $srcBytes = null, 378 | $srcS3Object = [], 379 | $tgtBytes = null, 380 | $tgtS3Object = []) 381 | { 382 | $srcImage = $srcS3Object; 383 | $tgtImage = $tgtS3Object; 384 | 385 | if(!is_null($tgtBytes)) $tgtImage = ['Bytes' => $tgtBytes]; 386 | 387 | if(!is_null($srcBytes)) $srcImage = ['Bytes' => $srcBytes]; 388 | 389 | return [ 390 | 'SimilarityThreshold' => $similarityTreshold, 391 | 'SourceImage' => $srcImage, 392 | 'TargetImage' => $tgtImage 393 | ]; 394 | } 395 | 396 | /** 397 | * @param string $collectionId 398 | * @param string $faceId 399 | * @param float $similarityTreshold 400 | * @param int $maxFaces 401 | * @return array 402 | */ 403 | public function setSearchFacesParams($collectionId, $faceId, $similarityTreshold = null, $maxFaces = null) 404 | { 405 | return [ 406 | 'CollectionId' => $collectionId, 407 | 'FaceId' => $faceId, 408 | 'FaceMatchThreshold' => $similarityTreshold, 409 | 'MaxFaces' => $maxFaces 410 | ]; 411 | } 412 | 413 | /** 414 | * @param string $collectionId 415 | * @param float $similarityTreshold 416 | * @param string || resource || Psr\Http\Message\StreamInterface $srcBytes 417 | * @param array $srcS3Object 418 | * @return array 419 | */ 420 | public function setSearchFacesByImageParams($collectionId, $similarityTreshold, $bytes = null, $s3Object = [], $maxFaces) 421 | { 422 | $image = ['S3Object' => $s3Object]; 423 | 424 | if(!is_null($bytes)) $image = ['Bytes' => $bytes]; 425 | 426 | return [ 427 | 'CollectionId' => $collectionId, 428 | 'FaceMatchThreshold' => $similarityTreshold, 429 | 'Image' => $image, 430 | 'MaxFaces' => $maxFaces 431 | ]; 432 | } 433 | 434 | /** 435 | * @param string $bucket 436 | * @param string $name 437 | * @param string $version 438 | * @return array 439 | */ 440 | public function setS3Object($bucket, $name) 441 | { 442 | return [ 443 | 'Bucket' => $bucket, 444 | 'Name' => $name 445 | ]; 446 | } 447 | 448 | private function setS3() 449 | { 450 | $this->s3 = new S3Client($this->args); 451 | } 452 | 453 | /** 454 | * Uploads images to S3 455 | * 456 | * @param object $file 457 | * @param string $path 458 | * @param string $bucket 459 | * @param string $name 460 | * @return mixed 461 | */ 462 | public function uploadImageToS3($file = null, $path = null, $bucket, $key) 463 | { 464 | $this->setS3(); 465 | 466 | $body = $file; 467 | 468 | if(!is_null($path)) $body = $this->encodeImage($path); 469 | 470 | return $this->s3->putObject(['ACL' => 'public-read', 'Body' => $body, 'Bucket' => $bucket, 'Key' => $key]); 471 | } 472 | 473 | /** 474 | * Delete images from S3 475 | * 476 | * @param string $bucket 477 | * @param array $keys 478 | * @return mixed 479 | */ 480 | public function deleteS3Objects($bucket, $keys) 481 | { 482 | $this->setS3(); 483 | 484 | $objects = []; 485 | 486 | foreach($keys as $key) 487 | { 488 | $objects[] = ['Key' => $key]; 489 | } 490 | 491 | return $this->s3->deleteObjects([ 492 | 'Bucket' => $bucket, 493 | 'Delete' =>[ 494 | 'Objects' => $objects 495 | ] 496 | ]); 497 | } 498 | } --------------------------------------------------------------------------------