Table of Contents Show
What is FPEG?
Using the face detection API at RapidAPI to reduce the background quality of images while maintaining the resolution of faces and reduce the image size considerably. The name is a play on “Faces JPEG”. This library is based on the strategy of FPEG by Andrew Schreiber. Connect to the Face Detection API Using Face Detection with PHP ExampleThis is a single page PHP script that takes a URL to a jpg, png, webp, bmp, or gif and finds all the faces in the image then reduces the quality of the background while saving the resolution of the faces. The effect of this transformation is an image that appears to maintain the resolution of the original image because the faces in the image are the focus and the resolution of the faces has not changed. The example image we are using can be found at https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png Output size is flexible based on the
Architecture
The RapidAPI Face Detection API is used to find all faces in the image, then each face is copied from the original image into a working image at the same location. After all the faces have been copied the original image is reduced in quality through jpeg compression. The compressed image is then loaded back into the script and the faces from the working image are copied onto the original image. Then the original image is saved as output.jpg. RapidAPI offers several other face detection, facial recognition APIs, and OCR APIs, but for this script, we only need to perform facial detection. Connect to the Face Detection API How to Perform Facial Detection with PHP (using a Face Detector API)Making requests to the API is uncomplicated with only 2 endpoints and 2 parameters. There is an endpoint for detecting faces and calculating age and gender and an endpoint for just detecting faces. In this article, we’ll be using the second endpoint because we are only interested in the positions of faces and not the details of each face. The endpoint URL is located at https://face-detection6.p.rapidapi.com/img/face which only accepts a POST. The POST parameters are url: "path-to-image" accuracy_boost: default 2; range 1-4 The API returns a response like { "detected_faces": [ { "BoundingBox": { "startX": 151, "startY": 113, "endX": 402, "endY": 479 }, "Probability": 83.6599349975586 } ] } This JSON result tells us:
Parameters-i Url to input image (required) -a Accuracy Boost [1-4] default 2 (optional) -b Background JPEG Quality default 20 (optional) -f Foreground JPEG Quality default 80 (optional) ExecuteCopy the code to a local file php fpeg.php -i=https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png -b=20 -f=80 and a
new file, 1. Set Your API Key// Set your RapidAPI key $rapidApiKey = '1234567890123456789012345678901234567890'; 2. Set Command Line Parameters// Command Line Parameters $options = getopt("" . "i:" // Image URL . "a::" // Accuracy Boost 1-4 . "b::" // Background Quality (optional) . "f::" // Foreground Quality (optional) , [] ); 3. Set the image URL and JPEG quality for the output image// Set the image url and jpeg quality for the output image $imageUrl = $options['i'] ?? ''; if (! filter_var($imageUrl, FILTER_VALIDATE_URL)) { throw new Exception('Invalid URL'); } 4. Fetch accuracy boost, background quality, and foreground quality// Fetch accuracy boost $accuracyBoost = $options['a'] ?? 2; if ($accuracyBoost < 1) { $accuracyBoost = 1; } elseif ($accuracyBoost > 4) { $accuracyBoost = 4; } // Fetch background quality and validate $backgroundQuality = $options['b'] ?? 20; if ($backgroundQuality < 1) { $backgroundQuality = 1; } elseif ($backgroundQuality > 100) { $backgroundQuality = 100; } // Fetch foreground quality and validate $foregroundQuality = $options['f'] ?? 80; if ($foregroundQuality < 1) { $foregroundQuality = 1; } elseif ($foregroundQuality > 100) { $foregroundQuality = 100; } 5. Get the file size of the image// Get the file size of the remote image $curl = curl_init($imageUrl); curl_setopt_array($curl, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => true, CURLOPT_NOBODY => true, ]); curl_exec($curl); $error = curl_error($curl); if ($error) { throw new Exception( "Unable to fetch remote image size. Curl Error #:" . $error ); } $imageFileSize = curl_getinfo($curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD); curl_close($curl); // Init curl for the request to RapidAPI $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => "https://face-detection6.p.rapidapi.com/img/face", CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "{"url":"$imageUrl","accuracy_boost":$accuracyBoost}", CURLOPT_HTTPHEADER => array( "accept: application/json", "content-type: application/json", "x-rapidapi-host: face-detection6.p.rapidapi.com", "x-rapidapi-key: $rapidApiKey" ), )); // Execute the curl and decode the response $response = curl_exec($curl); $error = curl_error($curl); curl_close($curl); if ($error) { throw new Exception( "Error response from Face Detection API. curl Error #:" . $error ); } $response = json_decode($response, true); 6. Init and execute curl request// Init curl for the request to RapidAPI $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => "https://face-detection6.p.rapidapi.com/img/face", CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "{"url":"$imageUrl","accuracy_boost":$accuracyBoost}", CURLOPT_HTTPHEADER => array( "accept: application/json", "content-type: application/json", "x-rapidapi-host: face-detection6.p.rapidapi.com", "x-rapidapi-key: $rapidApiKey" ), )); // Execute the curl and decode the response $response = curl_exec($curl); $error = curl_error($curl); curl_close($curl); if ($error) { throw new Exception( "Error response from Face Detection API. curl Error #:" . $error ); } $response = json_decode($response, true); 7. Initialize the working images// Initialize the working images $imageDimentions = getimagesize($imageUrl); switch($imageDimentions['mime']) { case 'image/gif': $imageResource = imagecreatefromgif($imageUrl); break; case 'image/png': $imageResource = imagecreatefrompng($imageUrl); break; case 'image/webp': $imageResource = imagecreatefromwebp($imageUrl); break; case 'image/x-ms-bmp': $imageResource = imagecreatefrombmp($imageUrl); break; case 'image/jpeg': $imageResource = imagecreatefromjpeg($imageUrl); break; default: throw new Exception('Unsupported image type'); } $workingImageResource = imagecreatetruecolor($imageDimentions[0], $imageDimentions[1]); 8. Copy faces from the initial image onto the working image// Copy faces from initial image onto working image $faceCount = 0; foreach ($response['detected_faces'] as $face) { $boundingBox = $face['BoundingBox']; $success = imagecopy( $workingImageResource, $imageResource, $boundingBox['startX'], // Source X $boundingBox['startY'], // Source Y $boundingBox['startX'], // Destination X $boundingBox['startY'], // Destination Y $boundingBox['endX'] - $boundingBox['startX'], // width $boundingBox['endY'] - $boundingBox['startY'] // height ); $faceCount ++; if (! $success) { throw new Exception(error_get_last()['message']); } } // All faces are now copied into the working image 9. Reduce image quality of the original image and Apply faces to the reduced background image// Reduce image quality of Source image $imageTempName = tempnam(sys_get_temp_dir(), 'fpeg'); imagejpeg($imageResource, $imageTempName, $backgroundQuality); // Load quality reduced image $imageResource = imagecreatefromjpeg($imageTempName); unlink($imageTempName); // Apply faces to reduced background quality image foreach ($response['detected_faces'] as $face) { $boundingBox = $face['BoundingBox']; $success = imagecopy( $imageResource, $workingImageResource, $boundingBox['startX'], // Source X $boundingBox['startY'], // Source Y $boundingBox['startX'], // Destination X $boundingBox['startY'], // Destination Y $boundingBox['endX'] - $boundingBox['startX'], // width $boundingBox['endY'] - $boundingBox['startY'] // height ); if (! $success) { throw new Exception(error_get_last()['message']); } } 10. Verify faces were found and save the image// Verify faces were found if (! $faceCount) { throw new Exception('No faces were found in image'); } // Save the created image and output statistics imagejpeg($imageResource, 'output.jpg', $foregroundQuality); $imageOutputSize = filesize('output.jpg'); if ($imageFileSize <= $imageOutputSize) { throw new Exception("FPEG DID NOT IMPROVE COMPRESSION"); } echo 'Original Size: ' . $imageFileSize . "n"; echo 'FPEG Size: ' . $imageOutputSize . "n"; echo 'Faces: ' . $faceCount . "n"; imagedestroy($imageResource); imagedestroy($workingImageResource); Connect to the Face Detection API The Full Code<?php /** * Copyright (c) 2020 API Skeletons <> * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Set your RapidAPI key $rapidApiKey = '1234567890123456789012345678901234567890'; // Command Line Parameters $options = getopt("" . "i:" // Image URL . "a::" // Accuracy Boost 1-4 . "b::" // Background Quality (optional) . "f::" // Foreground Quality (optional) , [] ); // Set the image url and jpeg quality for the output image $imageUrl = $options['i'] ?? ''; if (! filter_var($imageUrl, FILTER_VALIDATE_URL)) { throw new Exception('Invalid URL'); } // Fetch accuracy boost $accuracyBoost = $options['a'] ?? 2; if ($accuracyBoost < 1) { $accuracyBoost = 1; } elseif ($accuracyBoost > 4) { $accuracyBoost = 4; } // Fetch background quality and validate $backgroundQuality = $options['b'] ?? 20; if ($backgroundQuality < 1) { $backgroundQuality = 1; } elseif ($backgroundQuality > 100) { $backgroundQuality = 100; } // Fetch foreground quality and validate $foregroundQuality = $options['f'] ?? 80; if ($foregroundQuality < 1) { $foregroundQuality = 1; } elseif ($foregroundQuality > 100) { $foregroundQuality = 100; } // Get the file size of the remote image $curl = curl_init($imageUrl); curl_setopt_array($curl, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => true, CURLOPT_NOBODY => true, ]); curl_exec($curl); $error = curl_error($curl); if ($error) { throw new Exception( "Unable to fetch remote image size. Curl Error #:" . $error ); } $imageFileSize = curl_getinfo($curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD); curl_close($curl); // Init curl for the request to RapidAPI $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => "https://face-detection6.p.rapidapi.com/img/face", CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "{"url":"$imageUrl","accuracy_boost":$accuracyBoost}", CURLOPT_HTTPHEADER => array( "accept: application/json", "content-type: application/json", "x-rapidapi-host: face-detection6.p.rapidapi.com", "x-rapidapi-key: $rapidApiKey" ), )); // Execute the curl and decode the response $response = curl_exec($curl); $error = curl_error($curl); curl_close($curl); if ($error) { throw new Exception( "Error response from Face Detection API. curl Error #:" . $error ); } $response = json_decode($response, true); // Initialize the working images $imageDimentions = getimagesize($imageUrl); switch($imageDimentions['mime']) { case 'image/gif': $imageResource = imagecreatefromgif($imageUrl); break; case 'image/png': $imageResource = imagecreatefrompng($imageUrl); break; case 'image/webp': $imageResource = imagecreatefromwebp($imageUrl); break; case 'image/x-ms-bmp': $imageResource = imagecreatefrombmp($imageUrl); break; case 'image/jpeg': $imageResource = imagecreatefromjpeg($imageUrl); break; default: throw new Exception('Unsupported image type'); } $workingImageResource = imagecreatetruecolor($imageDimentions[0], $imageDimentions[1]); // Copy faces from initial image onto working image $faceCount = 0; foreach ($response['detected_faces'] as $face) { $boundingBox = $face['BoundingBox']; $success = imagecopy( $workingImageResource, $imageResource, $boundingBox['startX'], // Source X $boundingBox['startY'], // Source Y $boundingBox['startX'], // Destination X $boundingBox['startY'], // Destination Y $boundingBox['endX'] - $boundingBox['startX'], // width $boundingBox['endY'] - $boundingBox['startY'] // height ); $faceCount ++; if (! $success) { throw new Exception(error_get_last()['message']); } } // All faces are now copied into the working image // Reduce image quality of Source image $imageTempName = tempnam(sys_get_temp_dir(), 'fpeg'); imagejpeg($imageResource, $imageTempName, $backgroundQuality); // Load quality reduced image $imageResource = imagecreatefromjpeg($imageTempName); unlink($imageTempName); // Apply faces to reduced background quality image foreach ($response['detected_faces'] as $face) { $boundingBox = $face['BoundingBox']; $success = imagecopy( $imageResource, $workingImageResource, $boundingBox['startX'], // Source X $boundingBox['startY'], // Source Y $boundingBox['startX'], // Destination X $boundingBox['startY'], // Destination Y $boundingBox['endX'] - $boundingBox['startX'], // width $boundingBox['endY'] - $boundingBox['startY'] // height ); if (! $success) { throw new Exception(error_get_last()['message']); } } // Verify faces were found if (! $faceCount) { throw new Exception('No faces were found in image'); } // Save the created image and output statistics imagejpeg($imageResource, 'output.jpg', $foregroundQuality); $imageOutputSize = filesize('output.jpg'); if ($imageFileSize <= $imageOutputSize) { throw new Exception("FPEG DID NOT IMPROVE COMPRESSION"); } echo 'Original Size: ' . $imageFileSize . "n"; echo 'FPEG Size: ' . $imageOutputSize . "n"; echo 'Faces: ' . $faceCount . "n"; imagedestroy($imageResource); imagedestroy($workingImageResource); Connect to the Face Detection API ConclusionThe clever technique this script creates using the face detection API at RapidAPI will reduce your website’s load time across any device. If you have a large number of images primarily of faces (such as LinkedIn), then this technique could really change your company’s offering.
|