Cloudinary Blog

The Object-Oriented Approach to Automatic Image Cropping

By
AI-based Automatic Image Cropping for E-Commerce

If you’ve come across this post and, based on the title, are expecting insights into object-oriented programming languages, then please forgive me for overloading the term object-oriented. I hope you don’t object when you discover that the objects in this post are not so much the instantiated class types, but real-life objects found in images. It is helpful though if you’re familiar with the likes of Java, PHP, Javascript or other popular frameworks, as you’ll be able to implement these automatic image cropping techniques in your code. Anyway, let’s cut to the chase - or should that be crop to the object...?

Automatic AI-driven object-aware cropping is a very powerful feature that can save you time, money and a lot of hassle when it comes to displaying images on your website or app. For example, a typical e-commerce website may have 10,000 products in its catalog, with four images per product. So, unless AI is used, it's an expensive proposition to ensure that 40,000 images of different sizes and aspect ratios best portray the objects you are selling.

Cloudinary's Object-Aware Cropping add-on applies advanced AI-based object detection algorithms on-the-fly during the crop process to keep specific objects in the picture. Like many of Cloudinary’s image transformation features, all you need to do is add a few parameters to the image delivery URL. In this case, you specify what you want to keep in your image along with one of Cloudinary’s many cropping options to suit your design and usability constraints. With an additional 600 objects now supported, you can spend less time focusing your efforts on image cropping and more time looking at the bigger picture.

The Simple Crop

Let’s say your website allows users to upload photos of cars that they want to sell. You know nothing about the content of the photos, except that they are expected to contain cars. You want to save time for your users by automatically positioning the cars front and center, even if you will be displaying their photos in a different aspect ratio and size to the originally uploaded image. The simplest way to do this is to tell Cloudinary to keep only the car in the crop by using the crop parameter and setting the gravity to car (c_crop,g_car in URLs). You don’t even need to specify any dimensions:

Ruby:
Copy to clipboard
cl_image_tag("docs/automotive-1846910_1920.jpg", :gravity=>"car", :crop=>"crop")
PHP v1:
Copy to clipboard
cl_image_tag("docs/automotive-1846910_1920.jpg", array("gravity"=>"car", "crop"=>"crop"))
PHP v2:
Copy to clipboard
(new ImageTag('docs/automotive-1846910_1920.jpg'))
  ->resize(Resize::crop()
    ->gravity(Gravity::focusOn(FocusOn::car())));
Python:
Copy to clipboard
CloudinaryImage("docs/automotive-1846910_1920.jpg").image(gravity="car", crop="crop")
Node.js:
Copy to clipboard
cloudinary.image("docs/automotive-1846910_1920.jpg", {gravity: "car", crop: "crop"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().gravity("car").crop("crop")).imageTag("docs/automotive-1846910_1920.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('docs/automotive-1846910_1920.jpg', {gravity: "car", crop: "crop"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("docs/automotive-1846910_1920.jpg", {gravity: "car", crop: "crop"})
React:
Copy to clipboard
<Image publicId="docs/automotive-1846910_1920.jpg" >
  <Transformation gravity="car" crop="crop" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="docs/automotive-1846910_1920.jpg" >
  <cld-transformation gravity="car" crop="crop" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="docs/automotive-1846910_1920.jpg" >
  <cl-transformation gravity="car" crop="crop">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Gravity("car").Crop("crop")).BuildImageTag("docs/automotive-1846910_1920.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().gravity("car").crop("crop")).generate("docs/automotive-1846910_1920.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setGravity("car").setCrop("crop")).generate("docs/automotive-1846910_1920.jpg")!, cloudinary: cloudinary)

Original image of a car, offset from center Original Image cropped to the car c_crop,g_car

You’ll notice that the crop is very exact, so to give the car a bit of room to breathe, you may want to zoom out slightly: z_0.9. And you’ll probably want to limit the dimensions of the image too, so having kept only the car, you can then scale the image, say to a width of 200 pixels: c_scale,w_200. Here’s the full URL:

Ruby:
Copy to clipboard
cl_image_tag("docs/automotive-1846910_1920.jpg", :transformation=>[
  {:gravity=>"car", :zoom=>0.9, :crop=>"crop"},
  {:width=>200, :crop=>"scale"}
  ])
PHP v1:
Copy to clipboard
cl_image_tag("docs/automotive-1846910_1920.jpg", array("transformation"=>array(
  array("gravity"=>"car", "zoom"=>"0.9", "crop"=>"crop"),
  array("width"=>200, "crop"=>"scale")
  )))
PHP v2:
Copy to clipboard
(new ImageTag('docs/automotive-1846910_1920.jpg'))
  ->resize(Resize::crop()->zoom(0.9)->gravity(Gravity::focusOn(FocusOn::car())))
  ->resize(Resize::scale()->width(200));
Python:
Copy to clipboard
CloudinaryImage("docs/automotive-1846910_1920.jpg").image(transformation=[
  {'gravity': "car", 'zoom': "0.9", 'crop': "crop"},
  {'width': 200, 'crop': "scale"}
  ])
Node.js:
Copy to clipboard
cloudinary.image("docs/automotive-1846910_1920.jpg", {transformation: [
  {gravity: "car", zoom: "0.9", crop: "crop"},
  {width: 200, crop: "scale"}
  ]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
  .gravity("car").zoom(0.9).crop("crop").chain()
  .width(200).crop("scale")).imageTag("docs/automotive-1846910_1920.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('docs/automotive-1846910_1920.jpg', {transformation: [
  {gravity: "car", zoom: "0.9", crop: "crop"},
  {width: 200, crop: "scale"}
  ]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("docs/automotive-1846910_1920.jpg", {transformation: [
  {gravity: "car", zoom: "0.9", crop: "crop"},
  {width: 200, crop: "scale"}
  ]})
React:
Copy to clipboard
<Image publicId="docs/automotive-1846910_1920.jpg" >
  <Transformation gravity="car" zoom="0.9" crop="crop" />
  <Transformation width="200" crop="scale" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="docs/automotive-1846910_1920.jpg" >
  <cld-transformation gravity="car" zoom="0.9" crop="crop" />
  <cld-transformation width="200" crop="scale" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="docs/automotive-1846910_1920.jpg" >
  <cl-transformation gravity="car" zoom="0.9" crop="crop">
  </cl-transformation>
  <cl-transformation width="200" crop="scale">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Gravity("car").Zoom(0.9).Crop("crop").Chain()
  .Width(200).Crop("scale")).BuildImageTag("docs/automotive-1846910_1920.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
  .gravity("car").zoom(0.9).crop("crop").chain()
  .width(200).crop("scale")).generate("docs/automotive-1846910_1920.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setGravity("car").setZoom(0.9).setCrop("crop").chain()
  .setWidth(200).setCrop("scale")).generate("docs/automotive-1846910_1920.jpg")!, cloudinary: cloudinary)
Zoomed out crop of car, scaled to 300 pixels

You’ve now got a reusable transformation that can be applied to any car picture (if there’s no car in the picture, the image won’t be cropped, only resized):

Original (scaled to fit this table) Keep only the car (with a slight zoom out)
c_crop,g_car,z_0.9/
c_scale,w_200
Original image of a car, offset from center Image cropped to the car
Original image of a car, offset from center Image cropped to the car
Original image of a car, offset from center Image cropped to the car
Original image of a car, offset from center Image cropped to the car

One Size Fits All

If your website design calls for all images in a particular page or layout to be exactly the same size, then you’ll want to set the aspect ratio too (together with the width we’ve already added). You need to decide if you’re happy for more of the original image to be shown, or if you still only want to see the chosen object.

If you don’t mind more of the original image being in the picture, then set the aspect ratio (ar) in the c_crop component (c_crop,g_car,z_0.9,ar_1.5/c_scale,w_200). Otherwise, instead of c_scale, you could use the padding crop, c_pad and set the aspect ratio in that component (c_crop,g_car,z_0.9/c_pad,w_200,ar_1.5). This adds padding to the image to reach the required size. You can either choose the color of the background padding yourself, or let Cloudinary decide automatically (b_auto).

Show more of the picture in the crop
c_crop,g_car,z_0.9,ar_1.5/
c_scale,w_200
Keep only the car (with a slight zoom out),
and add automatically colored padding

c_crop,g_car,z_0.9/
c_pad,w_200,ar_1.5,b_auto
Image cropped to the car, with set aspect ratio Image cropped to the car
Image cropped to the car, with set aspect ratio Image cropped to the car
Image cropped to the car, with set aspect ratio Image cropped to the car
Image cropped to the car, with set aspect ratio Image cropped to the car

Order of Precedence

Now imagine it’s not just cars that you’re interested in, but vans and motorbikes too. You can add all three of these objects to your URL, but you’ll need to define an order of precedence in case a photo has more than one of these in it. If you’d prefer to see vans rather than cars, and cars rather than motorbikes, then specify this order: g_van:car:motorbike. Applying this to the image of the car and van above gives this result:

Ruby:
Copy to clipboard
cl_image_tag("docs/addons/objectdetection/vw-3638825_1920.jpg", :transformation=>[
  {:gravity=>"van:car:motorbike", :zoom=>0.9, :aspect_ratio=>"1.5", :crop=>"crop"},
  {:width=>200, :crop=>"scale"}
  ])
PHP v1:
Copy to clipboard
cl_image_tag("docs/addons/objectdetection/vw-3638825_1920.jpg", array("transformation"=>array(
  array("gravity"=>"van:car:motorbike", "zoom"=>"0.9", "aspect_ratio"=>"1.5", "crop"=>"crop"),
  array("width"=>200, "crop"=>"scale")
  )))
PHP v2:
Copy to clipboard
(new ImageTag('docs/addons/objectdetection/vw-3638825_1920.jpg'))
  ->resize(Resize::crop()->aspectRatio(1.5)->zoom(0.9)
    ->gravity(
        Gravity::focusOn(FocusOn::van(),
         FocusOn::car(),
         FocusOn::motorbike()))
      )
  ->resize(Resize::scale()->width(200));
Python:
Copy to clipboard
CloudinaryImage("docs/addons/objectdetection/vw-3638825_1920.jpg").image(transformation=[
  {'gravity': "van:car:motorbike", 'zoom': "0.9", 'aspect_ratio': "1.5", 'crop': "crop"},
  {'width': 200, 'crop': "scale"}
  ])
Node.js:
Copy to clipboard
cloudinary.image("docs/addons/objectdetection/vw-3638825_1920.jpg", {transformation: [
  {gravity: "van:car:motorbike", zoom: "0.9", aspect_ratio: "1.5", crop: "crop"},
  {width: 200, crop: "scale"}
  ]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
  .gravity("van:car:motorbike").zoom(0.9).aspectRatio("1.5").crop("crop").chain()
  .width(200).crop("scale")).imageTag("docs/addons/objectdetection/vw-3638825_1920.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('docs/addons/objectdetection/vw-3638825_1920.jpg', {transformation: [
  {gravity: "van:car:motorbike", zoom: "0.9", aspectRatio: "1.5", crop: "crop"},
  {width: 200, crop: "scale"}
  ]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("docs/addons/objectdetection/vw-3638825_1920.jpg", {transformation: [
  {gravity: "van:car:motorbike", zoom: "0.9", aspect_ratio: "1.5", crop: "crop"},
  {width: 200, crop: "scale"}
  ]})
React:
Copy to clipboard
<Image publicId="docs/addons/objectdetection/vw-3638825_1920.jpg" >
  <Transformation gravity="van:car:motorbike" zoom="0.9" aspectRatio="1.5" crop="crop" />
  <Transformation width="200" crop="scale" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="docs/addons/objectdetection/vw-3638825_1920.jpg" >
  <cld-transformation gravity="van:car:motorbike" zoom="0.9" aspectRatio="1.5" crop="crop" />
  <cld-transformation width="200" crop="scale" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="docs/addons/objectdetection/vw-3638825_1920.jpg" >
  <cl-transformation gravity="van:car:motorbike" zoom="0.9" aspect-ratio="1.5" crop="crop">
  </cl-transformation>
  <cl-transformation width="200" crop="scale">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Gravity("van:car:motorbike").Zoom(0.9).AspectRatio("1.5").Crop("crop").Chain()
  .Width(200).Crop("scale")).BuildImageTag("docs/addons/objectdetection/vw-3638825_1920.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
  .gravity("van:car:motorbike").zoom(0.9).aspectRatio("1.5").crop("crop").chain()
  .width(200).crop("scale")).generate("docs/addons/objectdetection/vw-3638825_1920.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setGravity("van:car:motorbike").setZoom(0.9).setAspectRatio("1.5").setCrop("crop").chain()
  .setWidth(200).setCrop("scale")).generate("docs/addons/objectdetection/vw-3638825_1920.jpg")!, cloudinary: cloudinary)
Giving precedence to the van over the car

Changing the order, to give precedence to the car, gives the result we had before:

Ruby:
Copy to clipboard
cl_image_tag("docs/addons/objectdetection/vw-3638825_1920.jpg", :transformation=>[
  {:gravity=>"car:van:motorbike", :zoom=>0.9, :aspect_ratio=>"1.5", :crop=>"crop"},
  {:width=>200, :crop=>"scale"}
  ])
PHP v1:
Copy to clipboard
cl_image_tag("docs/addons/objectdetection/vw-3638825_1920.jpg", array("transformation"=>array(
  array("gravity"=>"car:van:motorbike", "zoom"=>"0.9", "aspect_ratio"=>"1.5", "crop"=>"crop"),
  array("width"=>200, "crop"=>"scale")
  )))
PHP v2:
Copy to clipboard
(new ImageTag('docs/addons/objectdetection/vw-3638825_1920.jpg'))
  ->resize(Resize::crop()->aspectRatio(1.5)->zoom(0.9)
    ->gravity(
        Gravity::focusOn(FocusOn::car(),
         FocusOn::van(),
         FocusOn::motorbike()))
      )
  ->resize(Resize::scale()->width(200));
Python:
Copy to clipboard
CloudinaryImage("docs/addons/objectdetection/vw-3638825_1920.jpg").image(transformation=[
  {'gravity': "car:van:motorbike", 'zoom': "0.9", 'aspect_ratio': "1.5", 'crop': "crop"},
  {'width': 200, 'crop': "scale"}
  ])
Node.js:
Copy to clipboard
cloudinary.image("docs/addons/objectdetection/vw-3638825_1920.jpg", {transformation: [
  {gravity: "car:van:motorbike", zoom: "0.9", aspect_ratio: "1.5", crop: "crop"},
  {width: 200, crop: "scale"}
  ]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
  .gravity("car:van:motorbike").zoom(0.9).aspectRatio("1.5").crop("crop").chain()
  .width(200).crop("scale")).imageTag("docs/addons/objectdetection/vw-3638825_1920.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('docs/addons/objectdetection/vw-3638825_1920.jpg', {transformation: [
  {gravity: "car:van:motorbike", zoom: "0.9", aspectRatio: "1.5", crop: "crop"},
  {width: 200, crop: "scale"}
  ]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("docs/addons/objectdetection/vw-3638825_1920.jpg", {transformation: [
  {gravity: "car:van:motorbike", zoom: "0.9", aspect_ratio: "1.5", crop: "crop"},
  {width: 200, crop: "scale"}
  ]})
React:
Copy to clipboard
<Image publicId="docs/addons/objectdetection/vw-3638825_1920.jpg" >
  <Transformation gravity="car:van:motorbike" zoom="0.9" aspectRatio="1.5" crop="crop" />
  <Transformation width="200" crop="scale" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="docs/addons/objectdetection/vw-3638825_1920.jpg" >
  <cld-transformation gravity="car:van:motorbike" zoom="0.9" aspectRatio="1.5" crop="crop" />
  <cld-transformation width="200" crop="scale" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="docs/addons/objectdetection/vw-3638825_1920.jpg" >
  <cl-transformation gravity="car:van:motorbike" zoom="0.9" aspect-ratio="1.5" crop="crop">
  </cl-transformation>
  <cl-transformation width="200" crop="scale">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Gravity("car:van:motorbike").Zoom(0.9).AspectRatio("1.5").Crop("crop").Chain()
  .Width(200).Crop("scale")).BuildImageTag("docs/addons/objectdetection/vw-3638825_1920.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
  .gravity("car:van:motorbike").zoom(0.9).aspectRatio("1.5").crop("crop").chain()
  .width(200).crop("scale")).generate("docs/addons/objectdetection/vw-3638825_1920.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setGravity("car:van:motorbike").setZoom(0.9).setAspectRatio("1.5").setCrop("crop").chain()
  .setWidth(200).setCrop("scale")).generate("docs/addons/objectdetection/vw-3638825_1920.jpg")!, cloudinary: cloudinary)
Giving precedence to the car over the van

If there are no cars or vans present in the picture, but there is a motorbike, the motorbike will be the focus of the crop:

Ruby:
Copy to clipboard
cl_image_tag("docs/addons/objectdetection/farm-1264761_1280.jpg", :transformation=>[
  {:gravity=>"car:van:motorbike", :zoom=>0.9, :aspect_ratio=>"1.5", :crop=>"crop"},
  {:width=>200, :crop=>"scale"}
  ])
PHP v1:
Copy to clipboard
cl_image_tag("docs/addons/objectdetection/farm-1264761_1280.jpg", array("transformation"=>array(
  array("gravity"=>"car:van:motorbike", "zoom"=>"0.9", "aspect_ratio"=>"1.5", "crop"=>"crop"),
  array("width"=>200, "crop"=>"scale")
  )))
PHP v2:
Copy to clipboard
(new ImageTag('docs/addons/objectdetection/farm-1264761_1280.jpg'))
  ->resize(Resize::crop()->aspectRatio(1.5)->zoom(0.9)
    ->gravity(
        Gravity::focusOn(FocusOn::car(),
         FocusOn::van(),
         FocusOn::motorbike()))
      )
  ->resize(Resize::scale()->width(200));
Python:
Copy to clipboard
CloudinaryImage("docs/addons/objectdetection/farm-1264761_1280.jpg").image(transformation=[
  {'gravity': "car:van:motorbike", 'zoom': "0.9", 'aspect_ratio': "1.5", 'crop': "crop"},
  {'width': 200, 'crop': "scale"}
  ])
Node.js:
Copy to clipboard
cloudinary.image("docs/addons/objectdetection/farm-1264761_1280.jpg", {transformation: [
  {gravity: "car:van:motorbike", zoom: "0.9", aspect_ratio: "1.5", crop: "crop"},
  {width: 200, crop: "scale"}
  ]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
  .gravity("car:van:motorbike").zoom(0.9).aspectRatio("1.5").crop("crop").chain()
  .width(200).crop("scale")).imageTag("docs/addons/objectdetection/farm-1264761_1280.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('docs/addons/objectdetection/farm-1264761_1280.jpg', {transformation: [
  {gravity: "car:van:motorbike", zoom: "0.9", aspectRatio: "1.5", crop: "crop"},
  {width: 200, crop: "scale"}
  ]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("docs/addons/objectdetection/farm-1264761_1280.jpg", {transformation: [
  {gravity: "car:van:motorbike", zoom: "0.9", aspect_ratio: "1.5", crop: "crop"},
  {width: 200, crop: "scale"}
  ]})
React:
Copy to clipboard
<Image publicId="docs/addons/objectdetection/farm-1264761_1280.jpg" >
  <Transformation gravity="car:van:motorbike" zoom="0.9" aspectRatio="1.5" crop="crop" />
  <Transformation width="200" crop="scale" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="docs/addons/objectdetection/farm-1264761_1280.jpg" >
  <cld-transformation gravity="car:van:motorbike" zoom="0.9" aspectRatio="1.5" crop="crop" />
  <cld-transformation width="200" crop="scale" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="docs/addons/objectdetection/farm-1264761_1280.jpg" >
  <cl-transformation gravity="car:van:motorbike" zoom="0.9" aspect-ratio="1.5" crop="crop">
  </cl-transformation>
  <cl-transformation width="200" crop="scale">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Gravity("car:van:motorbike").Zoom(0.9).AspectRatio("1.5").Crop("crop").Chain()
  .Width(200).Crop("scale")).BuildImageTag("docs/addons/objectdetection/farm-1264761_1280.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
  .gravity("car:van:motorbike").zoom(0.9).aspectRatio("1.5").crop("crop").chain()
  .width(200).crop("scale")).generate("docs/addons/objectdetection/farm-1264761_1280.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setGravity("car:van:motorbike").setZoom(0.9).setAspectRatio("1.5").setCrop("crop").chain()
  .setWidth(200).setCrop("scale")).generate("docs/addons/objectdetection/farm-1264761_1280.jpg")!, cloudinary: cloudinary)

Original image of a motorbike, offset from center Original Image cropped to the motorbike c_crop,g_car:van:motorbike

Object Categories

If you don’t care what type of vehicle is kept in the crop, specifying the category, vehicle, rather than specific objects will keep the most prominent vehicle in the crop. In this case, it’s the van that wins.

Ruby:
Copy to clipboard
cl_image_tag("docs/addons/objectdetection/vw-3638825_1920.jpg", :transformation=>[
  {:gravity=>"vehicle", :zoom=>0.9, :crop=>"crop"},
  {:width=>200, :crop=>"scale"}
  ])
PHP v1:
Copy to clipboard
cl_image_tag("docs/addons/objectdetection/vw-3638825_1920.jpg", array("transformation"=>array(
  array("gravity"=>"vehicle", "zoom"=>"0.9", "crop"=>"crop"),
  array("width"=>200, "crop"=>"scale")
  )))
PHP v2:
Copy to clipboard
(new ImageTag('docs/addons/objectdetection/vw-3638825_1920.jpg'))
  ->resize(Resize::crop()->zoom(0.9)->gravity(Gravity::focusOn(FocusOn::vehicle())))
  ->resize(Resize::scale()->width(200));
Python:
Copy to clipboard
CloudinaryImage("docs/addons/objectdetection/vw-3638825_1920.jpg").image(transformation=[
  {'gravity': "vehicle", 'zoom': "0.9", 'crop': "crop"},
  {'width': 200, 'crop': "scale"}
  ])
Node.js:
Copy to clipboard
cloudinary.image("docs/addons/objectdetection/vw-3638825_1920.jpg", {transformation: [
  {gravity: "vehicle", zoom: "0.9", crop: "crop"},
  {width: 200, crop: "scale"}
  ]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
  .gravity("vehicle").zoom(0.9).crop("crop").chain()
  .width(200).crop("scale")).imageTag("docs/addons/objectdetection/vw-3638825_1920.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('docs/addons/objectdetection/vw-3638825_1920.jpg', {transformation: [
  {gravity: "vehicle", zoom: "0.9", crop: "crop"},
  {width: 200, crop: "scale"}
  ]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("docs/addons/objectdetection/vw-3638825_1920.jpg", {transformation: [
  {gravity: "vehicle", zoom: "0.9", crop: "crop"},
  {width: 200, crop: "scale"}
  ]})
React:
Copy to clipboard
<Image publicId="docs/addons/objectdetection/vw-3638825_1920.jpg" >
  <Transformation gravity="vehicle" zoom="0.9" crop="crop" />
  <Transformation width="200" crop="scale" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="docs/addons/objectdetection/vw-3638825_1920.jpg" >
  <cld-transformation gravity="vehicle" zoom="0.9" crop="crop" />
  <cld-transformation width="200" crop="scale" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="docs/addons/objectdetection/vw-3638825_1920.jpg" >
  <cl-transformation gravity="vehicle" zoom="0.9" crop="crop">
  </cl-transformation>
  <cl-transformation width="200" crop="scale">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Gravity("vehicle").Zoom(0.9).Crop("crop").Chain()
  .Width(200).Crop("scale")).BuildImageTag("docs/addons/objectdetection/vw-3638825_1920.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
  .gravity("vehicle").zoom(0.9).crop("crop").chain()
  .width(200).crop("scale")).generate("docs/addons/objectdetection/vw-3638825_1920.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setGravity("vehicle").setZoom(0.9).setCrop("crop").chain()
  .setWidth(200).setCrop("scale")).generate("docs/addons/objectdetection/vw-3638825_1920.jpg")!, cloudinary: cloudinary)
Crop to the most prominent vehicle

If you want to keep all vehicles in the crop then it’s as simple as adding an ‘s’ (this works for specific objects too):

Ruby:
Copy to clipboard
cl_image_tag("docs/addons/objectdetection/vw-3638825_1920.jpg", :transformation=>[
  {:gravity=>"vehicles", :zoom=>0.9, :crop=>"crop"},
  {:width=>200, :crop=>"scale"}
  ])
PHP v1:
Copy to clipboard
cl_image_tag("docs/addons/objectdetection/vw-3638825_1920.jpg", array("transformation"=>array(
  array("gravity"=>"vehicles", "zoom"=>"0.9", "crop"=>"crop"),
  array("width"=>200, "crop"=>"scale")
  )))
PHP v2:
Copy to clipboard
(new ImageTag('docs/addons/objectdetection/vw-3638825_1920.jpg'))
  ->resize(Resize::crop()->zoom(0.9)->gravity(Gravity::focusOn(FocusOn::vehicles())))
  ->resize(Resize::scale()->width(200));
Python:
Copy to clipboard
CloudinaryImage("docs/addons/objectdetection/vw-3638825_1920.jpg").image(transformation=[
  {'gravity': "vehicles", 'zoom': "0.9", 'crop': "crop"},
  {'width': 200, 'crop': "scale"}
  ])
Node.js:
Copy to clipboard
cloudinary.image("docs/addons/objectdetection/vw-3638825_1920.jpg", {transformation: [
  {gravity: "vehicles", zoom: "0.9", crop: "crop"},
  {width: 200, crop: "scale"}
  ]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
  .gravity("vehicles").zoom(0.9).crop("crop").chain()
  .width(200).crop("scale")).imageTag("docs/addons/objectdetection/vw-3638825_1920.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('docs/addons/objectdetection/vw-3638825_1920.jpg', {transformation: [
  {gravity: "vehicles", zoom: "0.9", crop: "crop"},
  {width: 200, crop: "scale"}
  ]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("docs/addons/objectdetection/vw-3638825_1920.jpg", {transformation: [
  {gravity: "vehicles", zoom: "0.9", crop: "crop"},
  {width: 200, crop: "scale"}
  ]})
React:
Copy to clipboard
<Image publicId="docs/addons/objectdetection/vw-3638825_1920.jpg" >
  <Transformation gravity="vehicles" zoom="0.9" crop="crop" />
  <Transformation width="200" crop="scale" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="docs/addons/objectdetection/vw-3638825_1920.jpg" >
  <cld-transformation gravity="vehicles" zoom="0.9" crop="crop" />
  <cld-transformation width="200" crop="scale" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="docs/addons/objectdetection/vw-3638825_1920.jpg" >
  <cl-transformation gravity="vehicles" zoom="0.9" crop="crop">
  </cl-transformation>
  <cl-transformation width="200" crop="scale">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Gravity("vehicles").Zoom(0.9).Crop("crop").Chain()
  .Width(200).Crop("scale")).BuildImageTag("docs/addons/objectdetection/vw-3638825_1920.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
  .gravity("vehicles").zoom(0.9).crop("crop").chain()
  .width(200).crop("scale")).generate("docs/addons/objectdetection/vw-3638825_1920.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setGravity("vehicles").setZoom(0.9).setCrop("crop").chain()
  .setWidth(200).setCrop("scale")).generate("docs/addons/objectdetection/vw-3638825_1920.jpg")!, cloudinary: cloudinary)
Keep all vehicles in the crop

Currently, the list of supported categories and objects comes from two models: Common Objects in Context (COCO) and Google's Open Images Dataset (OID). Included are a wide variety of objects, from home appliances to food, electronics to furniture, people to animals, sports balls to handbags.... The list is ever-expanding - object models enabling you to specify fashion items and parts of the body are coming soon. Additionally, in the near future, you'll be able to specify custom object models that cater specifically to your needs.

Tailor-Made For Different Experiences

We’ve seen how to fit different images into the same space, so now we’ll look at how to fit the same image into different spaces, while still keeping the desired object as the focus of attention.

An e-commerce website typically requires a handful of image crops for the same product images (thumbnails, product listing, detail view, and zoom). If you want your images to be responsive to different viewport sizes, yet more variations are required. Factor in social channels, and the number of different crops required quickly multiplies.

To ensure that in each situation, your product, be it a handbag, a shoe or a vase, remains fully in view is a huge undertaking, one which requires creative teams to manage different crops, very painstakingly, and often manually.

To help address this pain point, Cloudinary’s Object-Aware Cropping add-on automatically ensures that the object of interest, your product, is front and center for any crop, no matter which channel or device it’s being viewed on.

Let’s take a look at a product image of a handbag. Here’s the original image:

Product image of a handbag

A square crop is required for a website product detail and here we can use the fill cropping method to fill the specified dimensions. To ensure that the handbag is kept in the crop we can choose between object-based automatic gravity (g_auto:handbag) and object-specific gravity (g_handbag). Object-based automatic gravity takes the whole picture into account, weighted by the handbag, whereas object-specific gravity focuses on the handbag over anything else, so the two can give different results. In this case, automatic gravity gives a slightly better crop because more of the hand, and less of the coat on the right is shown. Compare the two:

Auto-gravity crop keeping handbag c_fill,g_auto:handbag,h_800,w_800 Object specific crop keeping the handbag c_fill,g_handbag,h_800,w_800

Thumbnail crops are another option, and work well to scale down an image to fit the dimensions specified. Here's an example for a Pinterest board crop:

Ruby:
Copy to clipboard
cl_image_tag("docs/addons/objectdetection/model-993911_1280.jpg", :gravity=>"handbag", :height=>150, :width=>222, :crop=>"thumb")
PHP v1:
Copy to clipboard
cl_image_tag("docs/addons/objectdetection/model-993911_1280.jpg", array("gravity"=>"handbag", "height"=>150, "width"=>222, "crop"=>"thumb"))
PHP v2:
Copy to clipboard
(new ImageTag('docs/addons/objectdetection/model-993911_1280.jpg'))
  ->resize(Resize::thumbnail()->width(222)->height(150)
    ->gravity(Gravity::focusOn(FocusOn::handbag())));
Python:
Copy to clipboard
CloudinaryImage("docs/addons/objectdetection/model-993911_1280.jpg").image(gravity="handbag", height=150, width=222, crop="thumb")
Node.js:
Copy to clipboard
cloudinary.image("docs/addons/objectdetection/model-993911_1280.jpg", {gravity: "handbag", height: 150, width: 222, crop: "thumb"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().gravity("handbag").height(150).width(222).crop("thumb")).imageTag("docs/addons/objectdetection/model-993911_1280.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('docs/addons/objectdetection/model-993911_1280.jpg', {gravity: "handbag", height: 150, width: 222, crop: "thumb"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("docs/addons/objectdetection/model-993911_1280.jpg", {gravity: "handbag", height: 150, width: 222, crop: "thumb"})
React:
Copy to clipboard
<Image publicId="docs/addons/objectdetection/model-993911_1280.jpg" >
  <Transformation gravity="handbag" height="150" width="222" crop="thumb" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="docs/addons/objectdetection/model-993911_1280.jpg" >
  <cld-transformation gravity="handbag" height="150" width="222" crop="thumb" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="docs/addons/objectdetection/model-993911_1280.jpg" >
  <cl-transformation gravity="handbag" height="150" width="222" crop="thumb">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Gravity("handbag").Height(150).Width(222).Crop("thumb")).BuildImageTag("docs/addons/objectdetection/model-993911_1280.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().gravity("handbag").height(150).width(222).crop("thumb")).generate("docs/addons/objectdetection/model-993911_1280.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setGravity("handbag").setHeight(150).setWidth(222).setCrop("thumb")).generate("docs/addons/objectdetection/model-993911_1280.jpg")!, cloudinary: cloudinary)
Thumbnail crop of a handbag

This video demonstrates how different cropping methods and dimensions result in various crops of the same photo, all giving priority to the handbag:

The same image, presented in many different forms - sounds like polymorphism to me!

One-To-Many Resizing

In addition to those already mentioned, Cloudinary offers many other types of resizing and cropping methods that you may want to use. To get a feel for how they behave, try out the interactive demo below. Be aware that not all combinations of cropping and gravity are valid, for example, gravity can't be used together with 'scale', or any of the 'fit' or 'pad' options (except 'fill with padding'), and 'fill with padding' only works with auto-gravity options. The demo lets you choose from two sizes of each image to show how some modes can give different results depending on the resolution.

Choose your starting image, viewport dimensions, cropping mode and gravity, then click the button to generate the new image.

Original image size: 640 x 427

Large
Small
Large
Small

Viewport width (100 to 650 pixels): 300

Viewport height (100 to 650 pixels): 300

Finalization

Remember that Cloudinary supports a wide range of programming languages and frameworks, so have a go and see how easy it is to implement these cropping methods in your preferred environment. To use object-aware cropping, you’ll need to subscribe to the Cloudinary Object-Aware Cropping add-on (there's a free tier you can use for experimenting), and also bear in mind that unless you’ve allowed unsigned add-on transformations in your account security settings, you’ll need to sign your delivery URLs. Find out more about the add-on and signing URLs in our documentation.

If you're new to Cloudinary, you might also want to check out the many other image and video transformations that we support, providing more great ways to automate your media delivery and make your website or app first class!

Recent Blog Posts

Our $2B Valuation

By
Blackstone Growth Invests in Cloudinary

When we started our journey in 2012, we were looking to improve our lives as developers by making it easier for us to handle the arduous tasks of handling images and videos in our code. That initial line of developer code has evolved into a full suite of media experience solutions driven by a mission that gradually revealed itself over the course of the past 10 years: help companies unleash the full potential of their media to create the most engaging visual experiences.

Read more
Direct-to-Consumer E-Commerce Requires Compelling Visual Experiences

When brands like you adopt a direct–to-consumer (DTC) e-commerce approach with no involvement of retailers or marketplaces, you gain direct and timely insight into evolving shopping behaviors. Accordingly, you can accommodate shoppers’ preferences by continually adjusting your product offering and interspersing the shopping journey with moments of excitement and intrigue. Opportunities abound for you to cultivate engaging customer relationships.

Read more
Automatically Translating Videos for an International Audience

No matter your business focus—public service, B2B integration, recruitment—multimedia, in particular video, is remarkably effective in communicating with the audience. Before, making video accessible to diverse viewers involved tasks galore, such as eliciting the service of production studios to manually dub, transcribe, and add subtitles. Those operations were costly and slow, especially for globally destined content.

Read more
Cloudinary Helps Minted Manage Its Image-Generation Pipeline at Scale

Shoppers return time and again to Minted’s global online community of independent artists and designers because they know they can count on unique, statement-making products of the highest quality there. Concurrently, the visual imagery on Minted.com must do justice to the designs into which the creators have poured their hearts and souls. For Minted’s VP of Engineering David Lien, “Because we are a premium brand, we need to ensure that every single one of our product images matches the selected configuration exactly. For example, if you pick an 18x24 art print on blue canvas, we will show that exact combination on the hero images in the PDF.”

Read more
Highlights on ImageCon 2021 and a Preview of ImageCon 2022

New year, same trend! Visual media will continue to play a monumental role in driving online conversions. To keep up with visual-experience trends and best practices, Cloudinary holds an annual conference called ImageCon, a one-of-a-kind event that helps attendees create the most engaging visual experiences possible.

Read more