Cloudinary Blog

The many faces of on-the-fly face detection

Perform Face-Detection Manipulations Techniques On-the-Fly

With the decreasing price-performance ratio of computing, research efforts in face detection and face recognition algorithms are rapidly expanding and new techniques for both of these are achieving greater accuracy and reduced processing time.

Face detection is a technology that identifies whether and where human faces are located in digital images. It’s commonly used in cameras, security applications, graphic applications, and a variety of other web and mobile apps. It is also a prerequisite for face recognition, which uses a database and additional algorithms to match a detected face with a specific individual.

A large percentage of the images in most websites and apps include photos of people -- from profile pics to news articles to group selfies. These photos need to be displayed in sizes, shapes, and styles that match the site design. Performing automatic face cropping or otherwise programmatically modifying images that contain faces necessitates a reliable face detection technology. The reliability can be affected by the colors, or lack of colors in the image, the direction a person is facing, the tilt of the head, the size of a face, the complexity of the background, lighting, and more.

Cloudinary provides a complete image and video management solution for web and mobile app programmers. Our solution includes a built-in image face detection functionality and several face-detection features you can take advantage of in your own apps. In most cases, applying this functionality is just a question of adding a parameter or two to your image delivery URLs… and your own creativity, of-course.

Cloudinary recently updated its face detection technology. The new technology is now very efficient and precise, including many "difficult" scenarios such as side portraits, blurry faces, tricky lighting, and more.

For example, the people in these images are now easily detected despite low lighting, unusual shadows, black and white images, turned heads and closed eyes:

low-lighting face detected
 

face in shadow detected

side-facing, black and white faces detected

 

When you deliver an image URL that includes face-detection manipulations, the faces in the original photo are detected on-the-fly, the requested manipulations are performed in the cloud, and then the final image is delivered via CDN.

The rest of this blog will cover some of the many ways that developers can automatically manipulate proprietary and user-generated photos containing faces to fit the needs and design of a website or app.

Facing it head on

Perhaps one of the most common uses of face detection is for cropping. A large percentage of images, especially with user-generated content, contain photos of people.

Headshots are needed for profile pictures, chat heads, and more, but the original uploaded photo may include much more than just a face, and that face may not even be the central element in the photo. Group selfies are also popular, and rarely centered, so again, we need to be very careful that even if we crop the photo to a different aspect ratio, we don’t lose any of the crew.

In short, it’s critical in most situations that when we resize and crop uploaded photos, we keep our users’ faces up front and center. There are a variety of features you can use or combine to ensure this.

Gravity is the key

When cropping photos intended for profile pictures or other headshots, you will usually want to use face as your cropping gravity (g_face in URLs). This ensures that the detected face (or largest face if there is more than one) will be the center of the cropped photo, regardless of its initial location.

If in conjunction with face gravity, you use thumb as your crop method, you will get a crop that’s as tight as possible (given the cropping dimensions) to the detected face coordinates.

You can further adjust your thumbnail cropping by setting a zoom value, to zoom in or out from the detected face coordinates. And then of-course you can add any other transformations you want.

Original photo Original photo Cropped to a square using face detection Cropped to a square using face detection Cropped using face detection with thumbnail cropping Cropped using face detection
with thumbnail cropping
Face detection, thumbnail crop, zoomed out a bit Face detection, thumbnail crop,
zoomed out a bit
Same as previous with circle shape, shadow, and improve effect Same as previous with circle shape,
shadow, and improve effect

Here's what the delivery code looks like for that last photo:

Ruby:
cl_image_tag("teen_facedown", :transformation=>[
  {:width=>200, :height=>200, :gravity=>"face", :zoom=>0.65, :radius=>"max", :effect=>"improve", :crop=>"thumb"},
  {:effect=>"shadow"}
  ])
PHP:
cl_image_tag("teen_facedown", array("transformation"=>array(
  array("width"=>200, "height"=>200, "gravity"=>"face", "zoom"=>0.65, "radius"=>"max", "effect"=>"improve", "crop"=>"thumb"),
  array("effect"=>"shadow")
  )))
Python:
CloudinaryImage("teen_facedown").image(transformation=[
  {"width": 200, "height": 200, "gravity": "face", "zoom": 0.65, "radius": "max", "effect": "improve", "crop": "thumb"},
  {"effect": "shadow"}
  ])
Node.js:
cloudinary.image("teen_facedown", {transformation: [
  {width: 200, height: 200, gravity: "face", zoom: "0.65", radius: "max", effect: "improve", crop: "thumb"},
  {effect: "shadow"}
  ]})
Java:
cloudinary.url().transformation(new Transformation()
  .width(200).height(200).gravity("face").zoom(0.65).radius("max").effect("improve").crop("thumb").chain()
  .effect("shadow")).imageTag("teen_facedown");
JS:
cloudinary.imageTag('teen_facedown', {transformation: [
  {width: 200, height: 200, gravity: "face", zoom: "0.65", radius: "max", effect: "improve", crop: "thumb"},
  {effect: "shadow"}
  ]}).toHtml();
jQuery:
$.cloudinary.image("teen_facedown", {transformation: [
  {width: 200, height: 200, gravity: "face", zoom: "0.65", radius: "max", effect: "improve", crop: "thumb"},
  {effect: "shadow"}
  ]})
React:
<Image publicId="teen_facedown" >
  <Transformation width="200" height="200" gravity="face" zoom="0.65" radius="max" effect="improve" crop="thumb" />
  <Transformation effect="shadow" />
</Image>
Angular:
<cl-image public-id="teen_facedown" >
  <cl-transformation width="200" height="200" gravity="face" zoom="0.65" radius="max" effect="improve" crop="thumb">
  </cl-transformation>
  <cl-transformation effect="shadow">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Width(200).Height(200).Gravity("face").Zoom(0.65).Radius("max").Effect("improve").Crop("thumb").Chain()
  .Effect("shadow")).BuildImageTag("teen_facedown")
Android:
MediaManager.get().url().transformation(new Transformation()
  .width(200).height(200).gravity("face").zoom(0.65).radius("max").effect("improve").crop("thumb").chain()
  .effect("shadow")).generate("teen_facedown");
iOS:
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setWidth(200).setHeight(200).setGravity("face").setZoom(0.65).setRadius("max").setEffect("improve").setCrop("thumb").chain()
  .setEffect("shadow")).generate("teen_facedown")!, cloudinary: cloudinary)

Everything mentioned above works equally well for multiple faces. Just use faces gravity instead of face, and your cropping will be based on a rectangle that includes all detected faces.

All of this assumes you can reasonably expect that the uploaded image is going to contain one or multiple faces as the main subject.

Sometimes the main subject of an image isn't necessarily expected to be a person, but you still need to ensure you aren’t cutting off people or other important content of the image. In this case, you can take advantage of the auto gravity feature. With this automated cropping method, the most prominent elements of the picture determine the cropping coordinates. Unless otherwise specified, any detected faces get a high priority in this cropping decision, but other prominent elements are also included.

You can learn lots more about auto gravity in this blog article and this documentation.

Losing face

There may be situations where you'd like to keep the people in a photograph anonymous. In these cases, you can pixelate or blur all detected faces just by adding a single parameter to your image URL.

In the example below, the faces that Cloudinary detects in the concert audience are generally those that could likely be identified by a human viewer. All of these faces are automatically blurred before the image is delivered, using the blur_faces effect.

Ruby:
cl_image_tag("concert_crowd", :effect=>"blur_faces:500")
PHP:
cl_image_tag("concert_crowd", array("effect"=>"blur_faces:500"))
Python:
CloudinaryImage("concert_crowd").image(effect="blur_faces:500")
Node.js:
cloudinary.image("concert_crowd", {effect: "blur_faces:500"})
Java:
cloudinary.url().transformation(new Transformation().effect("blur_faces:500")).imageTag("concert_crowd");
JS:
cloudinary.imageTag('concert_crowd', {effect: "blur_faces:500"}).toHtml();
jQuery:
$.cloudinary.image("concert_crowd", {effect: "blur_faces:500"})
React:
<Image publicId="concert_crowd" >
  <Transformation effect="blur_faces:500" />
</Image>
Angular:
<cl-image public-id="concert_crowd" >
  <cl-transformation effect="blur_faces:500">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation().Effect("blur_faces:500")).BuildImageTag("concert_crowd")
Android:
MediaManager.get().url().transformation(new Transformation().effect("blur_faces:500")).generate("concert_crowd");
iOS:
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setEffect("blur_faces:500")).generate("concert_crowd")!, cloudinary: cloudinary)
blurred faces

And here’s an example of an ice skating scene where a couple of childrens' faces are clearly visible. This time, we use the pixelate option to protect the kids’ identities:

Ruby:
cl_image_tag("ice_skating.jpg", :effect=>"pixelate_faces:4", :width=>500, :crop=>"scale")
PHP:
cl_image_tag("ice_skating.jpg", array("effect"=>"pixelate_faces:4", "width"=>500, "crop"=>"scale"))
Python:
CloudinaryImage("ice_skating.jpg").image(effect="pixelate_faces:4", width=500, crop="scale")
Node.js:
cloudinary.image("ice_skating.jpg", {effect: "pixelate_faces:4", width: 500, crop: "scale"})
Java:
cloudinary.url().transformation(new Transformation().effect("pixelate_faces:4").width(500).crop("scale")).imageTag("ice_skating.jpg");
JS:
cloudinary.imageTag('ice_skating.jpg', {effect: "pixelate_faces:4", width: 500, crop: "scale"}).toHtml();
jQuery:
$.cloudinary.image("ice_skating.jpg", {effect: "pixelate_faces:4", width: 500, crop: "scale"})
React:
<Image publicId="ice_skating.jpg" >
  <Transformation effect="pixelate_faces:4" width="500" crop="scale" />
</Image>
Angular:
<cl-image public-id="ice_skating.jpg" >
  <cl-transformation effect="pixelate_faces:4" width="500" crop="scale">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation().Effect("pixelate_faces:4").Width(500).Crop("scale")).BuildImageTag("ice_skating.jpg")
Android:
MediaManager.get().url().transformation(new Transformation().effect("pixelate_faces:4").width(500).crop("scale")).generate("ice_skating.jpg");
iOS:
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setEffect("pixelate_faces:4").setWidth(500).setCrop("scale")).generate("ice_skating.jpg")!, cloudinary: cloudinary)
pixelated faces

Tip: For cases like these, you may want to take advantage of one of the access control options to prevent users from accessing the non-blurred or non-pixelated versions of the image.

Saving face

There’s no such thing as a face detection technology that will detect 100% of the faces 100% of the time, so what if you notice that a particular face you need was not detected? No problem. You can always update the detected coordinates explicitly.

For example, when a user uploads an image to your site, you can retrieve and display the detected face coordinates and then enable your users to adjust the coordinates or add a new face via your UI. You can then pass the updated coordinates to Cloudinary via the Update method of the Admin API.

For your own images, you can also manually change the coordinates using the Media library UI.

In your face

Sometimes, just blurring or pixelating a face isn’t enough. Instead, you want to completely cover the face with another image. Or, maybe you just want to add a fun mask. Whatever the reason, it’s simple to add the same image to all faces in a photo.

To do this, you take advantage of the region_relative flag and faces gravity when you specify the overlay image. That tells Cloudinary that you want the overlay to be placed on all faces, and that the specified size of each overlay is a percentage relative to the size of each detected face.

For example, here’s a quick way to get your family dressed up in costume:

Ruby:
cl_image_tag("family_portrait.jpg", :gravity=>"faces", :overlay=>"spiderman_mask", :width=>1.1, :flags=>"region_relative")
PHP:
cl_image_tag("family_portrait.jpg", array("gravity"=>"faces", "overlay"=>"spiderman_mask", "width"=>1.1, "flags"=>"region_relative"))
Python:
CloudinaryImage("family_portrait.jpg").image(gravity="faces", overlay="spiderman_mask", width=1.1, flags="region_relative")
Node.js:
cloudinary.image("family_portrait.jpg", {gravity: "faces", overlay: "spiderman_mask", width: "1.1", flags: "region_relative"})
Java:
cloudinary.url().transformation(new Transformation().gravity("faces").overlay("spiderman_mask").width(1.1).flags("region_relative")).imageTag("family_portrait.jpg");
JS:
cloudinary.imageTag('family_portrait.jpg', {gravity: "faces", overlay: "spiderman_mask", width: "1.1", flags: "region_relative"}).toHtml();
jQuery:
$.cloudinary.image("family_portrait.jpg", {gravity: "faces", overlay: "spiderman_mask", width: "1.1", flags: "region_relative"})
React:
<Image publicId="family_portrait.jpg" >
  <Transformation gravity="faces" overlay="spiderman_mask" width="1.1" flags="region_relative" />
</Image>
Angular:
<cl-image public-id="family_portrait.jpg" >
  <cl-transformation gravity="faces" overlay="spiderman_mask" width="1.1" flags="region_relative">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation().Gravity("faces").Overlay("spiderman_mask").Width(1.1).Flags("region_relative")).BuildImageTag("family_portrait.jpg")
Android:
MediaManager.get().url().transformation(new Transformation().gravity("faces").overlay("spiderman_mask").width(1.1).flags("region_relative")).generate("family_portrait.jpg");
iOS:
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setGravity("faces").setOverlay("spiderman_mask").setWidth(1.1).setFlags("region_relative")).generate("family_portrait.jpg")!, cloudinary: cloudinary)

Original photo spiderman mask overlay on faces

You probably already noticed that we gave anonymous (happy) faces to our roller coaster riders at the beginning of this article using the same technique.

And remember, the overlay you use doesn’t have to cover the whole face or even be centered. Below, we add a ranger hat to a man’s head using a relative y- coordinate to offset the location of the hat about 30% above the center of the face.

Ruby:
cl_image_tag("smiling_man", :transformation=>[
  {:gravity=>"face", :zoom=>0.6, :crop=>"crop"},
  {:overlay=>"ranger_hat", :width=>1.1, :flags=>"region_relative", :gravity=>"face", :y=>-0.3}
  ])
PHP:
cl_image_tag("smiling_man", array("transformation"=>array(
  array("gravity"=>"face", "zoom"=>0.6, "crop"=>"crop"),
  array("overlay"=>"ranger_hat", "width"=>1.1, "flags"=>"region_relative", "gravity"=>"face", "y"=>-0.3)
  )))
Python:
CloudinaryImage("smiling_man").image(transformation=[
  {"gravity": "face", "zoom": 0.6, "crop": "crop"},
  {"overlay": "ranger_hat", "width": 1.1, "flags": "region_relative", "gravity": "face", "y": -0.3}
  ])
Node.js:
cloudinary.image("smiling_man", {transformation: [
  {gravity: "face", zoom: "0.6", crop: "crop"},
  {overlay: "ranger_hat", width: "1.1", flags: "region_relative", gravity: "face", y: "-0.3"}
  ]})
Java:
cloudinary.url().transformation(new Transformation()
  .gravity("face").zoom(0.6).crop("crop").chain()
  .overlay("ranger_hat").width(1.1).flags("region_relative").gravity("face").y(-0.3)).imageTag("smiling_man");
JS:
cloudinary.imageTag('smiling_man', {transformation: [
  {gravity: "face", zoom: "0.6", crop: "crop"},
  {overlay: "ranger_hat", width: "1.1", flags: "region_relative", gravity: "face", y: "-0.3"}
  ]}).toHtml();
jQuery:
$.cloudinary.image("smiling_man", {transformation: [
  {gravity: "face", zoom: "0.6", crop: "crop"},
  {overlay: "ranger_hat", width: "1.1", flags: "region_relative", gravity: "face", y: "-0.3"}
  ]})
React:
<Image publicId="smiling_man" >
  <Transformation gravity="face" zoom="0.6" crop="crop" />
  <Transformation overlay="ranger_hat" width="1.1" flags="region_relative" gravity="face" y="-0.3" />
</Image>
Angular:
<cl-image public-id="smiling_man" >
  <cl-transformation gravity="face" zoom="0.6" crop="crop">
  </cl-transformation>
  <cl-transformation overlay="ranger_hat" width="1.1" flags="region_relative" gravity="face" y="-0.3">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Gravity("face").Zoom(0.6).Crop("crop").Chain()
  .Overlay("ranger_hat").Width(1.1).Flags("region_relative").Gravity("face").Y(-0.3)).BuildImageTag("smiling_man")
Android:
MediaManager.get().url().transformation(new Transformation()
  .gravity("face").zoom(0.6).crop("crop").chain()
  .overlay("ranger_hat").width(1.1).flags("region_relative").gravity("face").y(-0.3)).generate("smiling_man");
iOS:
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setGravity("face").setZoom(0.6).setCrop("crop").chain()
  .setOverlay("ranger_hat").setWidth(1.1).setFlags("region_relative").setGravity("face").setY(-0.3)).generate("smiling_man")!, cloudinary: cloudinary)
hat overlay

At face value

If you want to check the face detection status of uploaded images programmatically, you can request to return face coordinate data when you or your users upload images, or you can request them upon demand for already uploaded images using the explicit method of the upload API, or with the list details of a single resource functionality of the Admin API. The following shows an excerpt from the JSON response of an upload call where the faces parameter was set to true.

{
  ...
  "faces":  [ [513, 19, 38, 52], [409, 26, 40, 54], [79, 31, 43, 59], [232, 32, 40, 54], [321, 33, 41, 57], [160, 37, 43, 59]
}

For example, you could use this data to calculate the ideal location for a text overlay so that it won’t cover any faces on a photo.

Two-faced

Cloudinary enables you to create programmatically complex manipulations by adding conditions to your transformations. One of the things you can base your conditions on is face_count.

For example, you can’t always be sure that a profile picture will be of a person. Some people choose to upload family portraits, scenery, or other images to represent themselves. The following images use the identical conditional transformation, where thumbnail cropping is applied if one or more faces is found, but scaled cropping is used on images without faces. We’ve also added a shadow vs black border for the alternative conditions to highlight the differences.

(The code shown here is for the nice_couple on the left, but you can click the bridge picture to see that it uses the identical transformation URL except for the image name (public ID).)

Ruby:
cl_image_tag("nice_couple", :transformation=>[
  {:if=>"fc_gte_1", :gravity=>"faces", :zoom=>0.5, :width=>200, :height=>200, :effect=>"shadow:10", :color=>"#acb2b9", :x=>7, :y=>7, :crop=>"thumb"},
  {:if=>"else", :width=>200, :height=>200, :border=>"3px_solid_black", :crop=>"scale"}
  ])
PHP:
cl_image_tag("nice_couple", array("transformation"=>array(
  array("if"=>"fc_gte_1", "gravity"=>"faces", "zoom"=>0.5, "width"=>200, "height"=>200, "effect"=>"shadow:10", "color"=>"#acb2b9", "x"=>7, "y"=>7, "crop"=>"thumb"),
  array("if"=>"else", "width"=>200, "height"=>200, "border"=>"3px_solid_black", "crop"=>"scale")
  )))
Python:
CloudinaryImage("nice_couple").image(transformation=[
  {"if": "fc_gte_1", "gravity": "faces", "zoom": 0.5, "width": 200, "height": 200, "effect": "shadow:10", "color": "#acb2b9", "x": 7, "y": 7, "crop": "thumb"},
  {"if": "else", "width": 200, "height": 200, "border": "3px_solid_black", "crop": "scale"}
  ])
Node.js:
cloudinary.image("nice_couple", {transformation: [
  {if: "fc_gte_1", gravity: "faces", zoom: "0.5", width: 200, height: 200, effect: "shadow:10", color: "#acb2b9", x: 7, y: 7, crop: "thumb"},
  {if: "else", width: 200, height: 200, border: "3px_solid_black", crop: "scale"}
  ]})
Java:
cloudinary.url().transformation(new Transformation()
  .if("fc_gte_1").gravity("faces").zoom(0.5).width(200).height(200).effect("shadow:10").color("#acb2b9").x(7).y(7).crop("thumb").chain()
  .if("else").width(200).height(200).border("3px_solid_black").crop("scale")).imageTag("nice_couple");
JS:
cloudinary.imageTag('nice_couple', {transformation: [
  {if: "fc_gte_1", gravity: "faces", zoom: "0.5", width: 200, height: 200, effect: "shadow:10", color: "#acb2b9", x: 7, y: 7, crop: "thumb"},
  {if: "else", width: 200, height: 200, border: "3px_solid_black", crop: "scale"}
  ]}).toHtml();
jQuery:
$.cloudinary.image("nice_couple", {transformation: [
  {if: "fc_gte_1", gravity: "faces", zoom: "0.5", width: 200, height: 200, effect: "shadow:10", color: "#acb2b9", x: 7, y: 7, crop: "thumb"},
  {if: "else", width: 200, height: 200, border: "3px_solid_black", crop: "scale"}
  ]})
React:
<Image publicId="nice_couple" >
  <Transformation if="fc_gte_1" gravity="faces" zoom="0.5" width="200" height="200" effect="shadow:10" color="#acb2b9" x="7" y="7" crop="thumb" />
  <Transformation if="else" width="200" height="200" border="3px_solid_black" crop="scale" />
</Image>
Angular:
<cl-image public-id="nice_couple" >
  <cl-transformation if="fc_gte_1" gravity="faces" zoom="0.5" width="200" height="200" effect="shadow:10" color="#acb2b9" x="7" y="7" crop="thumb">
  </cl-transformation>
  <cl-transformation if="else" width="200" height="200" border="3px_solid_black" crop="scale">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .If("fc_gte_1").Gravity("faces").Zoom(0.5).Width(200).Height(200).Effect("shadow:10").Color("#acb2b9").X(7).Y(7).Crop("thumb").Chain()
  .If("else").Width(200).Height(200).Border("3px_solid_black").Crop("scale")).BuildImageTag("nice_couple")
Android:
MediaManager.get().url().transformation(new Transformation()
  .if("fc_gte_1").gravity("faces").zoom(0.5).width(200).height(200).effect("shadow:10").color("#acb2b9").x(7).y(7).crop("thumb").chain()
  .if("else").width(200).height(200).border("3px_solid_black").crop("scale")).generate("nice_couple");
iOS:
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setIf("fc_gte_1").setGravity("faces").setZoom(0.5).setWidth(200).setHeight(200).setEffect("shadow:10").setColor("#acb2b9").setX(7).setY(7).setCrop("thumb").chain()
  .setIf("else").setWidth(200).setHeight(200).setBorder("3px_solid_black").setCrop("scale")).generate("nice_couple")!, cloudinary: cloudinary)

image with one or more faces image without faces

You can learn more about conditional transformations here.

Face to face

Just a reminder that in addition to applying all this cool stuff on images that you or your users directly upload, you can also use the same tricks with remotely fetched images, such as Facebook profile pictures.

For example, you can allow your users to select to use their Facebook profile photo as the basis for their account profile photo in your app and then apply resizing, rounding, artistic effects, or any other transformation to fit your site's art direction, while ensuring that the detected face of the fetched photo remains the main focus of the final photo.

Here we apply cropping and several other transformations to the Facebook profile photo from the Remembering JFK page:

Ruby:
cl_image_tag("268587306614095", :type=>"facebook", :transformation=>[
  {:width=>200, :height=>200, :gravity=>"face", :zoom=>0.65, :radius=>"max", :effect=>"art:sizzle", :crop=>"thumb"},
  {:effect=>"shadow"}
  ])
PHP:
cl_image_tag("268587306614095", array("type"=>"facebook", "transformation"=>array(
  array("width"=>200, "height"=>200, "gravity"=>"face", "zoom"=>0.65, "radius"=>"max", "effect"=>"art:sizzle", "crop"=>"thumb"),
  array("effect"=>"shadow")
  )))
Python:
CloudinaryImage("268587306614095").image(type="facebook", transformation=[
  {"width": 200, "height": 200, "gravity": "face", "zoom": 0.65, "radius": "max", "effect": "art:sizzle", "crop": "thumb"},
  {"effect": "shadow"}
  ])
Node.js:
cloudinary.image("268587306614095", {type: "facebook", transformation: [
  {width: 200, height: 200, gravity: "face", zoom: "0.65", radius: "max", effect: "art:sizzle", crop: "thumb"},
  {effect: "shadow"}
  ]})
Java:
cloudinary.url().transformation(new Transformation()
  .width(200).height(200).gravity("face").zoom(0.65).radius("max").effect("art:sizzle").crop("thumb").chain()
  .effect("shadow")).type("facebook").imageTag("268587306614095");
JS:
cloudinary.imageTag('268587306614095', {type: "facebook", transformation: [
  {width: 200, height: 200, gravity: "face", zoom: "0.65", radius: "max", effect: "art:sizzle", crop: "thumb"},
  {effect: "shadow"}
  ]}).toHtml();
jQuery:
$.cloudinary.image("268587306614095", {type: "facebook", transformation: [
  {width: 200, height: 200, gravity: "face", zoom: "0.65", radius: "max", effect: "art:sizzle", crop: "thumb"},
  {effect: "shadow"}
  ]})
React:
<Image publicId="268587306614095" type="facebook">
  <Transformation width="200" height="200" gravity="face" zoom="0.65" radius="max" effect="art:sizzle" crop="thumb" />
  <Transformation effect="shadow" />
</Image>
Angular:
<cl-image public-id="268587306614095" type="facebook">
  <cl-transformation width="200" height="200" gravity="face" zoom="0.65" radius="max" effect="art:sizzle" crop="thumb">
  </cl-transformation>
  <cl-transformation effect="shadow">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Width(200).Height(200).Gravity("face").Zoom(0.65).Radius("max").Effect("art:sizzle").Crop("thumb").Chain()
  .Effect("shadow")).Type("facebook").BuildImageTag("268587306614095")
Android:
MediaManager.get().url().transformation(new Transformation()
  .width(200).height(200).gravity("face").zoom(0.65).radius("max").effect("art:sizzle").crop("thumb").chain()
  .effect("shadow")).type("facebook").generate("268587306614095");
iOS:
imageView.cldSetImage(cloudinary.createUrl().setType( "facebook").setTransformation(CLDTransformation()
  .setWidth(200).setHeight(200).setGravity("face").setZoom(0.65).setRadius("max").setEffect("art:sizzle").setCrop("thumb").chain()
  .setEffect("shadow")).generate("268587306614095")!, cloudinary: cloudinary)

Original FB profile photo

Original Facebook profile photo
     Cropped to a circle using face detection Manipulated photo: face thumbnail
slight zoom, artistic filter,
rounding, shadow

You can do the same with images fetched from other sites, like Twitter, Google+, or from any image URL.

Face the facts

By now, the many potential uses for face detection techniques have probably become obvious to you, as plain as the nose on your face, you might say…. OK, I'm done with the painful face puns.

The fact is that almost every Website includes both local and user-generated content that centers around people. It’s essential that those people remain the focus of the displayed pictures regardless of how you resize, crop, add images and text overlays, etc.

Cloudinary’s face detection capabilities and updated mechanism enable you to accomplish all of these things programmatically, using simple transformation parameters, and with very reliable results.

Ready to see how far your creativity can take these face detection features? These features are available in all plans including the free plan, with no add-ins required. If you don’t have a Cloudinary account yet, you can sign up for a free one, and give it a go!

Recent Blog Posts

Reimaging DAM--The Next-Gen DAM for Marketing & Dev

There are great digital asset management (DAM) products out there for uploading, storing, managing, organizing, and sharing digital assets. With Cloudinary's new end-to-end DAM solution, you can also upload and manage your assets efficiently, but the journey doesn't end there. It continues on to the development and delivery stages, so that your assets can be seamlessly manipulated, optimized, and delivered to create an engaging user experience that will in turn, increase conversion and loyalty.

Read more
Integrating Cloudinary with Forestry’s Media Library

At Forestry, we believe that there is a bright future for static HTML sites built with tools like Jekyll and Hugo. These tools can create sites that run well, and are easy to host and maintain, because they don’t require any server-side code.

Read more
Video Optimization With the HTML5 <video> Player

Lack of experience and compression knowhow can cause significant user-experience problems. For instance, on a major retail site, I recently ran into a 48 MB video-hero banner. Pulling out the video and encoding it as an H.264 MP4 reduces the size to 1.9 MB. So, despite the desire for more video content, developers have not yet caught up to best practices. How do we get the best of both worlds without creating a disaster like the one above?

Read more
Build a Facial Emotion Recognition Based Video Suggestion App

Developers are always looking for new and creative ways to deliver content that resonates with the way users feel. Often using the latest technical innovations the market has to offer such as Artificial Intelligence (AI) and Machine Learning (ML). What better way to demonstrate innovative uses of these technology in a consumer market than capturing expressions from your users and then serving content based on that expression!

Read more
Improve Customer Data Protection with GDPR Implementation

TL;DR

Yay! We've done it! Gold-Star for us! We've talked with all the people, made all the changes, paid all the lawyers and checked all the boxes. GDPR? ✅Done!

Not so fast. Of course, conforming to the GDPR regulations introduced in Europe is just the beginning. This is a process and a state of mind that must become part of our long-term cultural ethos.

Read more