“FPEG” for PHP using a Face Detection API

RapidAPI Team
The Era of APIs
Published in
6 min readFeb 14, 2020

FPEG detects faces in an image and compresses those regions less than the surrounding pixels. In theory the human visual cortex is more sensitive to compression artifacts on faces then surrounding context, therefore using higher compression in non-facial regions will lead to smaller images with comparable perceived quality. — Andrew Schreiber

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.

See Full Article on the RapidAPI Blog

Using Face Detection with PHP Example

This 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 -b=backgroundQuality and -f=foregroundQuality variables. The effect of this transformation on an example image measured backgroundQuality/foregroundQuality @ 20/80 is:

Original Image FPEG Image @ 20/80 quality

Size: 32,161

Size: 473,831

Architecture

  • An image is loaded from a URL.
  • The settings for the script are the image URL and optionally the foreground image quality, the background image quality, and the accuracy boost.
  • Adjust the image quality as desired.

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.

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:

  • where each face is,
  • where it starts,
  • and the dimensions from the start.

"detected_faces" is an array of all the faces found in the url image.

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)

Execute

Copy the code to a local file fpeg.php. Then run the script with the image and quality parameters

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, output.jpg, will be created in the same directory.

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);

The Full Code

See the full code at: https://rapidapi.com/blog/php-face-detection-fpeg/

Conclusion

The 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.

Related Resources

Originally published at https://rapidapi.com on February 14, 2020.

--

--