Cloudinary Blog

Unboxing Images to Discover Their Content

Object Detection Tutorial with Cloudinary

Over recent years, 'unboxing' videos have become a popular internet phenomenon. Mostly, these involve people discovering what's inside physical packages, with great anticipation and excitement. They can be strangely addictive!

Cloudinary's AI Content Analysis add-on effectively does the same thing, automatically, for images. Using highly-trained AI models, it can discover what's present in an image, and even provide further details about the objects it finds.

I decided to create an object detection demo for the docs to expose the add-on's capabilities. You can see me trying it out in my own 'unboxing' video, here:

Why Unbox Images?

So, you're probably thinking, that's a cute demo, but what is object detection used for in the real world? Why do you need to automatically detect objects when you can clearly see what's in the image yourself?

Well, for a start, not everyone can see what's in an image. Visually impaired people may be using a screen reader to digest content, and the more descriptive you can make your alt text for each image, the more they'll understand what the image is showing. You can certainly use the detected content for that.

Another use case is for user-generated content - the general public uploading images to your website. You may want to implement an automatic check to make sure the images contain expected content, like a car for a car sales site. Then your app can use the location of the object to center a crop on it, or avoid overlaying text on it.

For e-commerce, wouldn't it be great to categorize your products automatically, adding metadata to the images based on detected attributes? Then you could search for say, garments with full-length sleeves, or dresses with pockets.

Model Behavior

At present, there are six content-aware detection models to choose from, each focusing on different objects.

As with any AI, mistakes can happen, and sometimes objects can appear to be something they're not. The confidence score can help you or your app make decisions about whether to trust a model's detections. You may find that some models work better than others, depending on the content of your images, due to how the model has been trained.

I invoked each model on the same ice skating image to show how the different models detect different objects. You can see the results below.

Note
In the following images, only the first 20 detected items alphabetically are shown. So, for example, in the human-anatomy example only the left body parts are highlighted, but the response does also contain right body parts. If you want to see for yourself, upload this image to the demo and take a look at the JSON.

Model Description Detected objects (click for full size)
lvis The Large Vocabulary Instance Segmentation model contains thousands of general objects. In this example, it finds mainly items of clothing, but also detects a couple of banners. Ice skating with lvis bounding boxes
coco The Common Objects in Context model contains just 80 common objects. In this example, the only 'objects' found are the people. Ice skating with coco bounding boxes
openimages Google's Open Images Dataset model contains 600 general objects. In this example, it detects mainly the people and footwear, and even identifies one of the ice-skates as sports equipment. Ice skating with openimages bounding boxes
cld-fashion Cloudinary's fashion model is specifically dedicated to items of clothing. As shown in the video, the response also contains more specific attributes of each clothing item. Ice skating with cld-fashion bounding boxes
cld-text Cloudinary's text model specifically looks for blocks of text in an image. In this example, it finds two text blocks. Ice skating with cld-text bounding boxes
human-anatomy The human anatomy model specifically looks for parts of the human body. In this example, you'll see it looks very one-sided, but that's just a limitation of this demo (see the note above). Ice skating with human-anatomy bounding boxes

If none of these models are specific enough to meet your needs, you can also request to have your own private models integrated, for your use only, to cater to objects that you're interested in.

Unboxing the Demo

In the rest of this post I'm going to unbox the object detection demo itself, and show you the numerous Cloudinary features that I put into it.

Its contents include:

The Upload Widget

Cloudinary's upload widget is a prime example of the adage, "good things come in small packages". With a ridiculously small amount of JavaScript, you can implement this fully-customizable widget, which lets you upload all types of media files to Cloudinary from numerous sources.

Cloudinary's upload widget

Check out the upload widget demo to get a feel for how it's implemented.

Upload Presets

Upload presets are a set of predefined upload options. You can set the uploadPreset parameter of the widget to the name of an upload preset, so that it uploads everything in the same way. In the case of the demo, I created six upload presets, one for each content-aware detection model, and the widget gets updated based on the user's model selection:

Copy to clipboard
function updateWidget() {
  myWidget.update({uploadPreset: document.getElementById("model").value});
}

where the model select element is defined as follows:

Copy to clipboard
<select class="select-css" id="model" name="model" onchange="updateWidget()">
  <option value="docs_detect_lvis" id="lvis" selected="true">lvis</option>
  <option value="docs_detect_coco" id="coco">coco</option>
  <option value="docs_detect_openimages" id="openimages">openimages</option>
  <option value="docs_detect_cld-fashion" id="cldfashion">cld-fashion</option>
  <option value="docs_detect_cld-text" id="cldtext">cld-text</option>
  <option value="docs_detect_human-anatomy" id="humananatomy">human-anatomy</option>
</select>

Each upload preset differs only in the upload method's detection parameter. Setting it to a model name invokes the automatic image tagging feature of the Cloudinary AI Content Analysis add-on.

This is the upload preset for the cld-fashion model:

Upload preset settings

I used unsigned upload presets, because the demo is implemented purely on the client side, with no server to provide a signature. The auto_tagging parameter is set to add a tag to the image for each detected object that has a confidence score of over 0.6. These tags aren't actually required for this demo, but I included it anyway as it could be useful for some analysis at a later date.

Image and Text Overlays

The bounding boxes added to the displayed image in the demo are applied as overlays using the coordinates and dimensions returned in the upload response. So, a response like this:

Copy to clipboard
"bounding-box": [
597.1850564726325,
202.6171875,
354.7523892267594,
220.4296875
],

would mean overlaying a box at x=597, y=202 (assuming a gravity of northwest) with a width of 355 pixels and and a height of 220 pixels, like this:

Ruby:
Copy to clipboard
cl_image_tag("ice_skating.jpg", :transformation=>[
  {:overlay=>"docs:filled-square"},
  {:height=>220, :width=>355, :crop=>"scale"},
  {:flags=>"layer_apply", :gravity=>"north_west", :x=>597, :y=>202}
  ])
PHP v1:
Copy to clipboard
cl_image_tag("ice_skating.jpg", array("transformation"=>array(
  array("overlay"=>"docs:filled-square"),
  array("height"=>220, "width"=>355, "crop"=>"scale"),
  array("flags"=>"layer_apply", "gravity"=>"north_west", "x"=>597, "y"=>202)
  )))
PHP v2:
Copy to clipboard
(new ImageTag('ice_skating.jpg'))
  ->overlay(
      Overlay::source(Source::image('docs/filled-square')
        ->transformation((new ImageTransformation())
          ->resize(Resize::scale()->width(355)->height(220))))
      ->position((new Position())
        ->gravity(Gravity::compass(Compass::northWest()))
        ->offsetX(597)->offsetY(202)
  ));
Python:
Copy to clipboard
CloudinaryImage("ice_skating.jpg").image(transformation=[
  {'overlay': "docs:filled-square"},
  {'height': 220, 'width': 355, 'crop': "scale"},
  {'flags': "layer_apply", 'gravity': "north_west", 'x': 597, 'y': 202}
  ])
Node.js:
Copy to clipboard
cloudinary.image("ice_skating.jpg", {transformation: [
  {overlay: "docs:filled-square"},
  {height: 220, width: 355, crop: "scale"},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 202}
  ]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
  .overlay(new Layer().publicId("docs:filled-square")).chain()
  .height(220).width(355).crop("scale").chain()
  .flags("layer_apply").gravity("north_west").x(597).y(202)).imageTag("ice_skating.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('ice_skating.jpg', {transformation: [
  {overlay: new cloudinary.Layer().publicId("docs:filled-square")},
  {height: 220, width: 355, crop: "scale"},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 202}
  ]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("ice_skating.jpg", {transformation: [
  {overlay: new cloudinary.Layer().publicId("docs:filled-square")},
  {height: 220, width: 355, crop: "scale"},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 202}
  ]})
React:
Copy to clipboard
<Image publicId="ice_skating.jpg" >
  <Transformation overlay="docs:filled-square" />
  <Transformation height="220" width="355" crop="scale" />
  <Transformation flags="layer_apply" gravity="north_west" x="597" y="202" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="ice_skating.jpg" >
  <cld-transformation :overlay="docs:filled-square" />
  <cld-transformation height="220" width="355" crop="scale" />
  <cld-transformation flags="layer_apply" gravity="north_west" x="597" y="202" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="ice_skating.jpg" >
  <cl-transformation overlay="docs:filled-square">
  </cl-transformation>
  <cl-transformation height="220" width="355" crop="scale">
  </cl-transformation>
  <cl-transformation flags="layer_apply" gravity="north_west" x="597" y="202">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Overlay(new Layer().PublicId("docs:filled-square")).Chain()
  .Height(220).Width(355).Crop("scale").Chain()
  .Flags("layer_apply").Gravity("north_west").X(597).Y(202)).BuildImageTag("ice_skating.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
  .overlay(new Layer().publicId("docs:filled-square")).chain()
  .height(220).width(355).crop("scale").chain()
  .flags("layer_apply").gravity("north_west").x(597).y(202)).generate("ice_skating.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setOverlay("docs:filled-square").chain()
  .setHeight(220).setWidth(355).setCrop("scale").chain()
  .setFlags("layer_apply").setGravity("north_west").setX(597).setY(202)).generate("ice_skating.jpg")!, cloudinary: cloudinary)
Ice-skating image with red box overlaid on the jacket

Similarly, the text overlay, stating the object and confidence score, is applied to the top of the box in white font with a colored background (in this case red):

b_red,co_white,l_text:Arial_17:jacket%25200.85/fl_layer_apply,g_north_west,x_597,y_185

Ruby:
Copy to clipboard
cl_image_tag("ice_skating.jpg", :transformation=>[
  {:overlay=>"docs:filled-square"},
  {:height=>220, :width=>355, :crop=>"scale"},
  {:flags=>"layer_apply", :gravity=>"north_west", :x=>597, :y=>202},
  {:background=>"red", :color=>"white", :overlay=>{:font_family=>"Arial", :font_size=>17, :text=>"jacket%200.85"}},
  {:flags=>"layer_apply", :gravity=>"north_west", :x=>597, :y=>185}
  ])
PHP v1:
Copy to clipboard
cl_image_tag("ice_skating.jpg", array("transformation"=>array(
  array("overlay"=>"docs:filled-square"),
  array("height"=>220, "width"=>355, "crop"=>"scale"),
  array("flags"=>"layer_apply", "gravity"=>"north_west", "x"=>597, "y"=>202),
  array("background"=>"red", "color"=>"white", "overlay"=>array("font_family"=>"Arial", "font_size"=>17, "text"=>"jacket%200.85")),
  array("flags"=>"layer_apply", "gravity"=>"north_west", "x"=>597, "y"=>185)
  )))
PHP v2:
Copy to clipboard
(new ImageTag('ice_skating.jpg'))
  ->overlay(
      Overlay::source(Source::image('docs/filled-square')
        ->transformation((new ImageTransformation())
          ->resize(Resize::scale()->width(355)->height(220))))
      ->position((new Position())
        ->gravity(Gravity::compass(Compass::northWest()))
        ->offsetX(597)->offsetY(202)))
    ->overlay(
        Overlay::source(Source::text('jacket 0.85', (new TextStyle('Arial', 17)))
          ->textColor(Color::WHITE)->backgroundColor(Color::RED))
        ->position((new Position())
          ->gravity(Gravity::compass(Compass::northWest()))
          ->offsetX(597)->offsetY(185)
      
    ));
Python:
Copy to clipboard
CloudinaryImage("ice_skating.jpg").image(transformation=[
  {'overlay': "docs:filled-square"},
  {'height': 220, 'width': 355, 'crop': "scale"},
  {'flags': "layer_apply", 'gravity': "north_west", 'x': 597, 'y': 202},
  {'background': "red", 'color': "white", 'overlay': {'font_family': "Arial", 'font_size': 17, 'text': "jacket%200.85"}},
  {'flags': "layer_apply", 'gravity': "north_west", 'x': 597, 'y': 185}
  ])
Node.js:
Copy to clipboard
cloudinary.image("ice_skating.jpg", {transformation: [
  {overlay: "docs:filled-square"},
  {height: 220, width: 355, crop: "scale"},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 202},
  {background: "red", color: "white", overlay: {font_family: "Arial", font_size: 17, text: "jacket%200.85"}},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 185}
  ]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
  .overlay(new Layer().publicId("docs:filled-square")).chain()
  .height(220).width(355).crop("scale").chain()
  .flags("layer_apply").gravity("north_west").x(597).y(202).chain()
  .background("red").color("white").overlay(new TextLayer().fontFamily("Arial").fontSize(17).text("jacket%200.85")).chain()
  .flags("layer_apply").gravity("north_west").x(597).y(185)).imageTag("ice_skating.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('ice_skating.jpg', {transformation: [
  {overlay: new cloudinary.Layer().publicId("docs:filled-square")},
  {height: 220, width: 355, crop: "scale"},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 202},
  {background: "red", color: "white", overlay: new cloudinary.TextLayer().fontFamily("Arial").fontSize(17).text("jacket%200.85")},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 185}
  ]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("ice_skating.jpg", {transformation: [
  {overlay: new cloudinary.Layer().publicId("docs:filled-square")},
  {height: 220, width: 355, crop: "scale"},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 202},
  {background: "red", color: "white", overlay: new cloudinary.TextLayer().fontFamily("Arial").fontSize(17).text("jacket%200.85")},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 185}
  ]})
React:
Copy to clipboard
<Image publicId="ice_skating.jpg" >
  <Transformation overlay="docs:filled-square" />
  <Transformation height="220" width="355" crop="scale" />
  <Transformation flags="layer_apply" gravity="north_west" x="597" y="202" />
  <Transformation background="red" color="white" overlay={{fontFamily: "Arial", fontSize: 17, text: "jacket%200.85"}} />
  <Transformation flags="layer_apply" gravity="north_west" x="597" y="185" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="ice_skating.jpg" >
  <cld-transformation :overlay="docs:filled-square" />
  <cld-transformation height="220" width="355" crop="scale" />
  <cld-transformation flags="layer_apply" gravity="north_west" x="597" y="202" />
  <cld-transformation background="red" color="white" :overlay="{fontFamily: 'Arial', fontSize: 17, text: 'jacket%200.85'}" />
  <cld-transformation flags="layer_apply" gravity="north_west" x="597" y="185" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="ice_skating.jpg" >
  <cl-transformation overlay="docs:filled-square">
  </cl-transformation>
  <cl-transformation height="220" width="355" crop="scale">
  </cl-transformation>
  <cl-transformation flags="layer_apply" gravity="north_west" x="597" y="202">
  </cl-transformation>
  <cl-transformation background="red" color="white" overlay="text:Arial_17:jacket%200.85">
  </cl-transformation>
  <cl-transformation flags="layer_apply" gravity="north_west" x="597" y="185">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Overlay(new Layer().PublicId("docs:filled-square")).Chain()
  .Height(220).Width(355).Crop("scale").Chain()
  .Flags("layer_apply").Gravity("north_west").X(597).Y(202).Chain()
  .Background("red").Color("white").Overlay(new TextLayer().FontFamily("Arial").FontSize(17).Text("jacket%200.85")).Chain()
  .Flags("layer_apply").Gravity("north_west").X(597).Y(185)).BuildImageTag("ice_skating.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
  .overlay(new Layer().publicId("docs:filled-square")).chain()
  .height(220).width(355).crop("scale").chain()
  .flags("layer_apply").gravity("north_west").x(597).y(202).chain()
  .background("red").color("white").overlay(new TextLayer().fontFamily("Arial").fontSize(17).text("jacket%200.85")).chain()
  .flags("layer_apply").gravity("north_west").x(597).y(185)).generate("ice_skating.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setOverlay("docs:filled-square").chain()
  .setHeight(220).setWidth(355).setCrop("scale").chain()
  .setFlags("layer_apply").setGravity("north_west").setX(597).setY(202).chain()
  .setBackground("red").setColor("white").setOverlay("text:Arial_17:jacket%200.85").chain()
  .setFlags("layer_apply").setGravity("north_west").setX(597).setY(185)).generate("ice_skating.jpg")!, cloudinary: cloudinary)
Ice-skating image with red box overlaid on the jacket and text overlay

Effects and Visual Enhancements

Obviously, we want to be able to see the image beneath the bounding box, so I tried using an image of a frame, but because it gets stretched and squashed according to the dimensions, it didn't look good. Instead, I decided to make the red square transparent using the background removal effect (e_bgremoval:red) and apply a border to it (bo_3px_solid_blue), resulting in the border being the only visible part of the overlay:

Ruby:
Copy to clipboard
cl_image_tag("ice_skating.jpg", :transformation=>[
  {:overlay=>"docs:filled-square"},
  {:height=>220, :width=>355, :crop=>"scale"},
  {:effect=>"bgremoval:red"},
  {:border=>"3px_solid_blue"},
  {:flags=>"layer_apply", :gravity=>"north_west", :x=>597, :y=>202},
  {:background=>"blue", :color=>"white", :overlay=>{:font_family=>"Arial", :font_size=>17, :text=>"jacket%200.85"}},
  {:flags=>"layer_apply", :gravity=>"north_west", :x=>597, :y=>185}
  ])
PHP v1:
Copy to clipboard
cl_image_tag("ice_skating.jpg", array("transformation"=>array(
  array("overlay"=>"docs:filled-square"),
  array("height"=>220, "width"=>355, "crop"=>"scale"),
  array("effect"=>"bgremoval:red"),
  array("border"=>"3px_solid_blue"),
  array("flags"=>"layer_apply", "gravity"=>"north_west", "x"=>597, "y"=>202),
  array("background"=>"blue", "color"=>"white", "overlay"=>array("font_family"=>"Arial", "font_size"=>17, "text"=>"jacket%200.85")),
  array("flags"=>"layer_apply", "gravity"=>"north_west", "x"=>597, "y"=>185)
  )))
PHP v2:
Copy to clipboard
(new ImageTag('ice_skating.jpg'))
  ->overlay(
      Overlay::source(Source::image('docs/filled-square')
        ->transformation((new ImageTransformation())
          ->resize(Resize::scale()->width(355)->height(220))
          ->effect(Effect::removeBackground()->colorToRemove(Color::RED))
          ->border(Border::solid(3, Color::BLUE))))
      ->position((new Position())
        ->gravity(Gravity::compass(Compass::northWest()))
        ->offsetX(597)->offsetY(202)))
    ->overlay(
        Overlay::source(Source::text('jacket 0.85', (new TextStyle('Arial', 17)))
          ->textColor(Color::WHITE)->backgroundColor(Color::BLUE))
        ->position((new Position())
          ->gravity(Gravity::compass(Compass::northWest()))
          ->offsetX(597)->offsetY(185)
      
    ));
Python:
Copy to clipboard
CloudinaryImage("ice_skating.jpg").image(transformation=[
  {'overlay': "docs:filled-square"},
  {'height': 220, 'width': 355, 'crop': "scale"},
  {'effect': "bgremoval:red"},
  {'border': "3px_solid_blue"},
  {'flags': "layer_apply", 'gravity': "north_west", 'x': 597, 'y': 202},
  {'background': "blue", 'color': "white", 'overlay': {'font_family': "Arial", 'font_size': 17, 'text': "jacket%200.85"}},
  {'flags': "layer_apply", 'gravity': "north_west", 'x': 597, 'y': 185}
  ])
Node.js:
Copy to clipboard
cloudinary.image("ice_skating.jpg", {transformation: [
  {overlay: "docs:filled-square"},
  {height: 220, width: 355, crop: "scale"},
  {effect: "bgremoval:red"},
  {border: "3px_solid_blue"},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 202},
  {background: "blue", color: "white", overlay: {font_family: "Arial", font_size: 17, text: "jacket%200.85"}},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 185}
  ]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
  .overlay(new Layer().publicId("docs:filled-square")).chain()
  .height(220).width(355).crop("scale").chain()
  .effect("bgremoval:red").chain()
  .border("3px_solid_blue").chain()
  .flags("layer_apply").gravity("north_west").x(597).y(202).chain()
  .background("blue").color("white").overlay(new TextLayer().fontFamily("Arial").fontSize(17).text("jacket%200.85")).chain()
  .flags("layer_apply").gravity("north_west").x(597).y(185)).imageTag("ice_skating.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('ice_skating.jpg', {transformation: [
  {overlay: new cloudinary.Layer().publicId("docs:filled-square")},
  {height: 220, width: 355, crop: "scale"},
  {effect: "bgremoval:red"},
  {border: "3px_solid_blue"},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 202},
  {background: "blue", color: "white", overlay: new cloudinary.TextLayer().fontFamily("Arial").fontSize(17).text("jacket%200.85")},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 185}
  ]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("ice_skating.jpg", {transformation: [
  {overlay: new cloudinary.Layer().publicId("docs:filled-square")},
  {height: 220, width: 355, crop: "scale"},
  {effect: "bgremoval:red"},
  {border: "3px_solid_blue"},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 202},
  {background: "blue", color: "white", overlay: new cloudinary.TextLayer().fontFamily("Arial").fontSize(17).text("jacket%200.85")},
  {flags: "layer_apply", gravity: "north_west", x: 597, y: 185}
  ]})
React:
Copy to clipboard
<Image publicId="ice_skating.jpg" >
  <Transformation overlay="docs:filled-square" />
  <Transformation height="220" width="355" crop="scale" />
  <Transformation effect="bgremoval:red" />
  <Transformation border="3px_solid_blue" />
  <Transformation flags="layer_apply" gravity="north_west" x="597" y="202" />
  <Transformation background="blue" color="white" overlay={{fontFamily: "Arial", fontSize: 17, text: "jacket%200.85"}} />
  <Transformation flags="layer_apply" gravity="north_west" x="597" y="185" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="ice_skating.jpg" >
  <cld-transformation :overlay="docs:filled-square" />
  <cld-transformation height="220" width="355" crop="scale" />
  <cld-transformation effect="bgremoval:red" />
  <cld-transformation border="3px_solid_blue" />
  <cld-transformation flags="layer_apply" gravity="north_west" x="597" y="202" />
  <cld-transformation background="blue" color="white" :overlay="{fontFamily: 'Arial', fontSize: 17, text: 'jacket%200.85'}" />
  <cld-transformation flags="layer_apply" gravity="north_west" x="597" y="185" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="ice_skating.jpg" >
  <cl-transformation overlay="docs:filled-square">
  </cl-transformation>
  <cl-transformation height="220" width="355" crop="scale">
  </cl-transformation>
  <cl-transformation effect="bgremoval:red">
  </cl-transformation>
  <cl-transformation border="3px_solid_blue">
  </cl-transformation>
  <cl-transformation flags="layer_apply" gravity="north_west" x="597" y="202">
  </cl-transformation>
  <cl-transformation background="blue" color="white" overlay="text:Arial_17:jacket%200.85">
  </cl-transformation>
  <cl-transformation flags="layer_apply" gravity="north_west" x="597" y="185">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Overlay(new Layer().PublicId("docs:filled-square")).Chain()
  .Height(220).Width(355).Crop("scale").Chain()
  .Effect("bgremoval:red").Chain()
  .Border("3px_solid_blue").Chain()
  .Flags("layer_apply").Gravity("north_west").X(597).Y(202).Chain()
  .Background("blue").Color("white").Overlay(new TextLayer().FontFamily("Arial").FontSize(17).Text("jacket%200.85")).Chain()
  .Flags("layer_apply").Gravity("north_west").X(597).Y(185)).BuildImageTag("ice_skating.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
  .overlay(new Layer().publicId("docs:filled-square")).chain()
  .height(220).width(355).crop("scale").chain()
  .effect("bgremoval:red").chain()
  .border("3px_solid_blue").chain()
  .flags("layer_apply").gravity("north_west").x(597).y(202).chain()
  .background("blue").color("white").overlay(new TextLayer().fontFamily("Arial").fontSize(17).text("jacket%200.85")).chain()
  .flags("layer_apply").gravity("north_west").x(597).y(185)).generate("ice_skating.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setOverlay("docs:filled-square").chain()
  .setHeight(220).setWidth(355).setCrop("scale").chain()
  .setEffect("bgremoval:red").chain()
  .setBorder("3px_solid_blue").chain()
  .setFlags("layer_apply").setGravity("north_west").setX(597).setY(202).chain()
  .setBackground("blue").setColor("white").setOverlay("text:Arial_17:jacket%200.85").chain()
  .setFlags("layer_apply").setGravity("north_west").setX(597).setY(185)).generate("ice_skating.jpg")!, cloudinary: cloudinary)
Ice-skating image with blue bounding-box overlaid on the jacket

User Defined Variables

Clearly, each bounding box is different, so having created a specific transformation for one, I needed to generalize it to work for any bounding box. This is where user defined variables came into play. Each value in the bounding box would need its own variable:

  • $tlx - top left x coordinate
  • $tly - top left y coordinate
  • $boxw - width of the bounding box
  • $boxh - height of the bounding box
  • $color - the color of the bounding box and background to the text overlay
  • $object - the detected object
  • $conf - the confidence score
  • $fontsize - the font size of the text overlay
  • $pix - the size of the border
  • $style - the style of the text overlay

To cater for different image resolutions, I decided to make the font size and border size dependent on the height of the image - this was calculated in the JavaScript.

This is the transformation with variables:

Ruby:
Copy to clipboard
cl_image_tag("ice_skating.jpg", :variables=>[["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]], :transformation=>[
  {:overlay=>"docs:filled-square"},
  {:height=>"$boxh", :width=>"$boxw", :crop=>"scale"},
  {:effect=>"bgremoval:red"},
  {:border=>"$pix_solid_$color"},
  {:flags=>"layer_apply", :gravity=>"north_west", :x=>"$tlx", :y=>"$tly"},
  {:background=>"$color", :color=>"white", :overlay=>{:public_id=>"%24style", :text=>"%24%28object%29%20%24%28conf%29"}},
  {:flags=>"layer_apply", :gravity=>"north_west", :x=>"$tlx", :y=>"$tly - $fontsize"}
  ])
PHP v1:
Copy to clipboard
cl_image_tag("ice_skating.jpg", array("variables"=>array("$tlx"=>"597", "$tly"=>"202", "$boxw"=>"355", "$boxh"=>"220", "$color"=>"!blue!", "$object"=>"!jacket!", "$conf"=>"0.85", "$fontsize"=>"17", "$pix"=>"3", "$style"=>"!Arial_17!"), "transformation"=>array(
  array("overlay"=>"docs:filled-square"),
  array("height"=>"$boxh", "width"=>"$boxw", "crop"=>"scale"),
  array("effect"=>"bgremoval:red"),
  array("border"=>"$pix_solid_$color"),
  array("flags"=>"layer_apply", "gravity"=>"north_west", "x"=>"$tlx", "y"=>"$tly"),
  array("background"=>"$color", "color"=>"white", "overlay"=>array("public_id"=>"%24style", "text"=>"%24%28object%29%20%24%28conf%29")),
  array("flags"=>"layer_apply", "gravity"=>"north_west", "x"=>"$tlx", "y"=>"$tly - $fontsize")
  )))
PHP v2:
Copy to clipboard
(new ImageTag('ice_skating.jpg'))
  ->addVariable(Variable::set('tlx', 597))
  ->addVariable(Variable::set('tly', 202))
  ->addVariable(Variable::set('boxw', 355))
  ->addVariable(Variable::set('boxh', 220))
  ->addVariable(Variable::set('color', 'blue'))
  ->addVariable(Variable::set('object', 'jacket'))
  ->addVariable(Variable::set('conf', 0.85))
  ->addVariable(Variable::set('fontsize', 17))
  ->addVariable(Variable::set('pix', 3))
  ->addVariable(Variable::set('style', 'Arial_17'))
  ->overlay(
      Overlay::source(Source::image('docs/filled-square')
        ->transformation((new ImageTransformation())
          ->resize(Resize::scale()->width('$boxw')->height('$boxh'))
          ->effect(Effect::removeBackground()->colorToRemove(Color::RED))
          ->border(Border::solid('$pix', '$color'))))
      ->position((new Position())
        ->gravity(Gravity::compass(Compass::northWest()))
        ->offsetX('$tlx')->offsetY('$tly')))
    ->overlay(
        Overlay::source(Source::text('$(object) $(conf)', '$style')
          ->textColor(Color::WHITE)->backgroundColor('$color'))
        ->position((new Position())
          ->gravity(Gravity::compass(Compass::northWest()))
          ->offsetX('$tlx')
          ->offsetY(Expression::expression('$tly - $fontsize'))
      
    ));
Python:
Copy to clipboard
CloudinaryImage("ice_skating.jpg").image(variables={"$tlx": "597", "$tly": "202", "$boxw": "355", "$boxh": "220", "$color": "!blue!", "$object": "!jacket!", "$conf": "0.85", "$fontsize": "17", "$pix": "3", "$style": "!Arial_17!"}, transformation=[
  {'overlay': "docs:filled-square"},
  {'height': "$boxh", 'width': "$boxw", 'crop': "scale"},
  {'effect': "bgremoval:red"},
  {'border': "$pix_solid_$color"},
  {'flags': "layer_apply", 'gravity': "north_west", 'x': "$tlx", 'y': "$tly"},
  {'background': "$color", 'color': "white", 'overlay': {'public_id': "%24style", 'text': "%24%28object%29%20%24%28conf%29"}},
  {'flags': "layer_apply", 'gravity': "north_west", 'x': "$tlx", 'y': "$tly - $fontsize"}
  ])
Node.js:
Copy to clipboard
cloudinary.image("ice_skating.jpg", {variables: [["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]], transformation: [
  {overlay: "docs:filled-square"},
  {height: "$boxh", width: "$boxw", crop: "scale"},
  {effect: "bgremoval:red"},
  {border: "$pix_solid_$color"},
  {flags: "layer_apply", gravity: "north_west", x: "$tlx", y: "$tly"},
  {background: "$color", color: "white", overlay: {public_id: "%24style", text: "%24%28object%29%20%24%28conf%29"}},
  {flags: "layer_apply", gravity: "north_west", x: "$tlx", y: "$tly - $fontsize"}
  ]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
.variables(variable("$tlx","597"),variable("$tly","202"),variable("$boxw","355"),variable("$boxh","220"),variable("$color","!blue!"),variable("$object","!jacket!"),variable("$conf","0.85"),variable("$fontsize","17"),variable("$pix","3"),variable("$style","!Arial_17!")).chain()
  .overlay(new Layer().publicId("docs:filled-square")).chain()
  .height("$boxh").width("$boxw").crop("scale").chain()
  .effect("bgremoval:red").chain()
  .border("$pix_solid_$color").chain()
  .flags("layer_apply").gravity("north_west").x("$tlx").y("$tly").chain()
  .background("$color").color("white").overlay(new TextLayer().text("%24%28object%29%20%24%28conf%29").publicId("%24style")).chain()
  .flags("layer_apply").gravity("north_west").x("$tlx").y("$tly - $fontsize")).imageTag("ice_skating.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('ice_skating.jpg', {variables: [["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]], transformation: [
  {overlay: new cloudinary.Layer().publicId("docs:filled-square")},
  {height: "$boxh", width: "$boxw", crop: "scale"},
  {effect: "bgremoval:red"},
  {border: "$pix_solid_$color"},
  {flags: "layer_apply", gravity: "north_west", x: "$tlx", y: "$tly"},
  {background: "$color", color: "white", overlay: new cloudinary.TextLayer().text("%24%28object%29%20%24%28conf%29").publicId("%24style")},
  {flags: "layer_apply", gravity: "north_west", x: "$tlx", y: "$tly - $fontsize"}
  ]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("ice_skating.jpg", {variables: [["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]], transformation: [
  {overlay: new cloudinary.Layer().publicId("docs:filled-square")},
  {height: "$boxh", width: "$boxw", crop: "scale"},
  {effect: "bgremoval:red"},
  {border: "$pix_solid_$color"},
  {flags: "layer_apply", gravity: "north_west", x: "$tlx", y: "$tly"},
  {background: "$color", color: "white", overlay: new cloudinary.TextLayer().text("%24%28object%29%20%24%28conf%29").publicId("%24style")},
  {flags: "layer_apply", gravity: "north_west", x: "$tlx", y: "$tly - $fontsize"}
  ]})
React:
Copy to clipboard
<Image publicId="ice_skating.jpg" variables={[["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]]}>
  <Transformation overlay="docs:filled-square" />
  <Transformation height="$boxh" width="$boxw" crop="scale" />
  <Transformation effect="bgremoval:red" />
  <Transformation border="$pix_solid_$color" />
  <Transformation flags="layer_apply" gravity="north_west" x="$tlx" y="$tly" />
  <Transformation background="$color" color="white" overlay={{text: "%24%28object%29%20%24%28conf%29", publicId: "%24style"}} />
  <Transformation flags="layer_apply" gravity="north_west" x="$tlx" y="$tly - $fontsize" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="ice_skating.jpg" :variables="[['$tlx', '597'], ['$tly', '202'], ['$boxw', '355'], ['$boxh', '220'], ['$color', '!blue!'], ['$object', '!jacket!'], ['$conf', '0.85'], ['$fontsize', '17'], ['$pix', '3'], ['$style', '!Arial_17!']]">
  <cld-transformation :overlay="docs:filled-square" />
  <cld-transformation height="$boxh" width="$boxw" crop="scale" />
  <cld-transformation effect="bgremoval:red" />
  <cld-transformation border="$pix_solid_$color" />
  <cld-transformation flags="layer_apply" gravity="north_west" x="$tlx" y="$tly" />
  <cld-transformation background="$color" color="white" :overlay="{text: '%24%28object%29%20%24%28conf%29', publicId: '%24style'}" />
  <cld-transformation flags="layer_apply" gravity="north_west" x="$tlx" y="$tly - $fontsize" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="ice_skating.jpg" variables="[['$tlx', '597'], ['$tly', '202'], ['$boxw', '355'], ['$boxh', '220'], ['$color', '!blue!'], ['$object', '!jacket!'], ['$conf', '0.85'], ['$fontsize', '17'], ['$pix', '3'], ['$style', '!Arial_17!']]">
  <cl-transformation overlay="docs:filled-square">
  </cl-transformation>
  <cl-transformation height="$boxh" width="$boxw" crop="scale">
  </cl-transformation>
  <cl-transformation effect="bgremoval:red">
  </cl-transformation>
  <cl-transformation border="$pix_solid_$color">
  </cl-transformation>
  <cl-transformation flags="layer_apply" gravity="north_west" x="$tlx" y="$tly">
  </cl-transformation>
  <cl-transformation background="$color" color="white" overlay="text:%24style:%24%28object%29%20%24%28conf%29">
  </cl-transformation>
  <cl-transformation flags="layer_apply" gravity="north_west" x="$tlx" y="$tly - $fontsize">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Overlay(new Layer().PublicId("docs:filled-square")).Chain()
  .Height("$boxh").Width("$boxw").Crop("scale").Chain()
  .Effect("bgremoval:red").Chain()
  .Border("$pix_solid_$color").Chain()
  .Flags("layer_apply").Gravity("north_west").X("$tlx").Y("$tly").Chain()
  .Background("$color").Color("white").Overlay(new TextLayer().Text("%24%28object%29%20%24%28conf%29").PublicId("%24style")).Chain()
  .Flags("layer_apply").Gravity("north_west").X("$tlx").Y("$tly - $fontsize")).BuildImageTag("ice_skating.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
.variables(variable("$tlx","597"),variable("$tly","202"),variable("$boxw","355"),variable("$boxh","220"),variable("$color","!blue!"),variable("$object","!jacket!"),variable("$conf","0.85"),variable("$fontsize","17"),variable("$pix","3"),variable("$style","!Arial_17!")).chain()
  .overlay(new Layer().publicId("docs:filled-square")).chain()
  .height("$boxh").width("$boxw").crop("scale").chain()
  .effect("bgremoval:red").chain()
  .border("$pix_solid_$color").chain()
  .flags("layer_apply").gravity("north_west").x("$tlx").y("$tly").chain()
  .background("$color").color("white").overlay(new TextLayer().text("%24%28object%29%20%24%28conf%29").publicId("%24style")).chain()
  .flags("layer_apply").gravity("north_west").x("$tlx").y("$tly - $fontsize")).generate("ice_skating.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setOverlay("docs:filled-square").chain()
  .setHeight("$boxh").setWidth("$boxw").setCrop("scale").chain()
  .setEffect("bgremoval:red").chain()
  .setBorder("$pix_solid_$color").chain()
  .setFlags("layer_apply").setGravity("north_west").setX("$tlx").setY("$tly").chain()
  .setBackground("$color").setColor("white").setOverlay("text:%24style:%24%28object%29%20%24%28conf%29").chain()
  .setFlags("layer_apply").setGravity("north_west").setX("$tlx").setY("$tly - $fontsize")).generate("ice_skating.jpg")!, cloudinary: cloudinary)
Ice-skating image with blue bounding-box overlaid on the jacket

Named Transformations

The (rather huge) generic transformation could now be saved as a named transformation to allow for easy re-use and to make the final URL less complex.

I used the Cloudinary CLI to create the named transformation:

Copy to clipboard
cld admin create_transformation bboxup 'l_docs:filled-square/c_scale,h_$boxh,w_$boxw/e_bgremoval:red/bo_$pixpx_solid_$color/fl_layer_apply,g_north_west,x_$tlx,y_$tly/b_$color,co_white,l_text:$style:$(object)%2520$(conf)/fl_layer_apply,g_north_west,x_$tlx,y_$tly_sub_$fontsize'

Here's the much shorter transformation, passing the variable values to the named transformation (t_bboxup):

Ruby:
Copy to clipboard
cl_image_tag("ice_skating.jpg", :transformation=>["bboxup"], :variables=>[["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]])
PHP v1:
Copy to clipboard
cl_image_tag("ice_skating.jpg", array("transformation"=>array("bboxup"), "variables"=>array("$tlx"=>"597", "$tly"=>"202", "$boxw"=>"355", "$boxh"=>"220", "$color"=>"!blue!", "$object"=>"!jacket!", "$conf"=>"0.85", "$fontsize"=>"17", "$pix"=>"3", "$style"=>"!Arial_17!")))
PHP v2:
Copy to clipboard
(new ImageTag('ice_skating.jpg'))
  ->addVariable(Variable::set('tlx', 597))
  ->addVariable(Variable::set('tly', 202))
  ->addVariable(Variable::set('boxw', 355))
  ->addVariable(Variable::set('boxh', 220))
  ->addVariable(Variable::set('color', 'blue'))
  ->addVariable(Variable::set('object', 'jacket'))
  ->addVariable(Variable::set('conf', 0.85))
  ->addVariable(Variable::set('fontsize', 17))
  ->addVariable(Variable::set('pix', 3))
  ->addVariable(Variable::set('style', 'Arial_17'))
  ->namedTransformation(NamedTransformation::name('bboxup'));
Python:
Copy to clipboard
CloudinaryImage("ice_skating.jpg").image(transformation=["bboxup"], variables={"$tlx": "597", "$tly": "202", "$boxw": "355", "$boxh": "220", "$color": "!blue!", "$object": "!jacket!", "$conf": "0.85", "$fontsize": "17", "$pix": "3", "$style": "!Arial_17!"})
Node.js:
Copy to clipboard
cloudinary.image("ice_skating.jpg", {transformation: ["bboxup"], variables: [["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
.variables(variable("$tlx","597"),variable("$tly","202"),variable("$boxw","355"),variable("$boxh","220"),variable("$color","!blue!"),variable("$object","!jacket!"),variable("$conf","0.85"),variable("$fontsize","17"),variable("$pix","3"),variable("$style","!Arial_17!")).chain().named("bboxup")).imageTag("ice_skating.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('ice_skating.jpg', {transformation: ["bboxup"], variables: [["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("ice_skating.jpg", {transformation: ["bboxup"], variables: [["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]]})
React:
Copy to clipboard
<Image publicId="ice_skating.jpg" variables={[["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]]}>
  <Transformation transformation={["bboxup"]} />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="ice_skating.jpg" :variables="[['$tlx', '597'], ['$tly', '202'], ['$boxw', '355'], ['$boxh', '220'], ['$color', '!blue!'], ['$object', '!jacket!'], ['$conf', '0.85'], ['$fontsize', '17'], ['$pix', '3'], ['$style', '!Arial_17!']]">
  <cld-transformation transformation={["bboxup"]} />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="ice_skating.jpg" variables="[['$tlx', '597'], ['$tly', '202'], ['$boxw', '355'], ['$boxh', '220'], ['$color', '!blue!'], ['$object', '!jacket!'], ['$conf', '0.85'], ['$fontsize', '17'], ['$pix', '3'], ['$style', '!Arial_17!']]">
  <cl-transformation transformation={{["bboxup"]}}>
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Named("bboxup")).BuildImageTag("ice_skating.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
.variables(variable("$tlx","597"),variable("$tly","202"),variable("$boxw","355"),variable("$boxh","220"),variable("$color","!blue!"),variable("$object","!jacket!"),variable("$conf","0.85"),variable("$fontsize","17"),variable("$pix","3"),variable("$style","!Arial_17!")).chain().named("bboxup")).generate("ice_skating.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setNamed("bboxup")).generate("ice_skating.jpg")!, cloudinary: cloudinary)
Ice-skating image with blue bounding-box overlaid on the jacket

I created a similar one for adding the object and confidence score text overlay to the bottom of the bounding box, rather than the top, in case the detected object is near the top of the image. The only difference is the arithmetic used for the y-coordinate of the text layer:

  • For bboxup: y_$tly_sub_$fontsize
  • For bboxdown: y_$tly_add_$boxh_add_$pix

Ruby:
Copy to clipboard
cl_image_tag("ice_skating.jpg", :transformation=>["bboxdown"], :variables=>[["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]])
PHP v1:
Copy to clipboard
cl_image_tag("ice_skating.jpg", array("transformation"=>array("bboxdown"), "variables"=>array("$tlx"=>"597", "$tly"=>"202", "$boxw"=>"355", "$boxh"=>"220", "$color"=>"!blue!", "$object"=>"!jacket!", "$conf"=>"0.85", "$fontsize"=>"17", "$pix"=>"3", "$style"=>"!Arial_17!")))
PHP v2:
Copy to clipboard
(new ImageTag('ice_skating.jpg'))
  ->addVariable(Variable::set('tlx', 597))
  ->addVariable(Variable::set('tly', 202))
  ->addVariable(Variable::set('boxw', 355))
  ->addVariable(Variable::set('boxh', 220))
  ->addVariable(Variable::set('color', 'blue'))
  ->addVariable(Variable::set('object', 'jacket'))
  ->addVariable(Variable::set('conf', 0.85))
  ->addVariable(Variable::set('fontsize', 17))
  ->addVariable(Variable::set('pix', 3))
  ->addVariable(Variable::set('style', 'Arial_17'))
  ->namedTransformation(NamedTransformation::name('bboxdown'));
Python:
Copy to clipboard
CloudinaryImage("ice_skating.jpg").image(transformation=["bboxdown"], variables={"$tlx": "597", "$tly": "202", "$boxw": "355", "$boxh": "220", "$color": "!blue!", "$object": "!jacket!", "$conf": "0.85", "$fontsize": "17", "$pix": "3", "$style": "!Arial_17!"})
Node.js:
Copy to clipboard
cloudinary.image("ice_skating.jpg", {transformation: ["bboxdown"], variables: [["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
.variables(variable("$tlx","597"),variable("$tly","202"),variable("$boxw","355"),variable("$boxh","220"),variable("$color","!blue!"),variable("$object","!jacket!"),variable("$conf","0.85"),variable("$fontsize","17"),variable("$pix","3"),variable("$style","!Arial_17!")).chain().named("bboxdown")).imageTag("ice_skating.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('ice_skating.jpg', {transformation: ["bboxdown"], variables: [["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("ice_skating.jpg", {transformation: ["bboxdown"], variables: [["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]]})
React:
Copy to clipboard
<Image publicId="ice_skating.jpg" variables={[["$tlx", "597"], ["$tly", "202"], ["$boxw", "355"], ["$boxh", "220"], ["$color", "!blue!"], ["$object", "!jacket!"], ["$conf", "0.85"], ["$fontsize", "17"], ["$pix", "3"], ["$style", "!Arial_17!"]]}>
  <Transformation transformation={["bboxdown"]} />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="ice_skating.jpg" :variables="[['$tlx', '597'], ['$tly', '202'], ['$boxw', '355'], ['$boxh', '220'], ['$color', '!blue!'], ['$object', '!jacket!'], ['$conf', '0.85'], ['$fontsize', '17'], ['$pix', '3'], ['$style', '!Arial_17!']]">
  <cld-transformation transformation={["bboxdown"]} />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="ice_skating.jpg" variables="[['$tlx', '597'], ['$tly', '202'], ['$boxw', '355'], ['$boxh', '220'], ['$color', '!blue!'], ['$object', '!jacket!'], ['$conf', '0.85'], ['$fontsize', '17'], ['$pix', '3'], ['$style', '!Arial_17!']]">
  <cl-transformation transformation={{["bboxdown"]}}>
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Named("bboxdown")).BuildImageTag("ice_skating.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
.variables(variable("$tlx","597"),variable("$tly","202"),variable("$boxw","355"),variable("$boxh","220"),variable("$color","!blue!"),variable("$object","!jacket!"),variable("$conf","0.85"),variable("$fontsize","17"),variable("$pix","3"),variable("$style","!Arial_17!")).chain().named("bboxdown")).generate("ice_skating.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setNamed("bboxdown")).generate("ice_skating.jpg")!, cloudinary: cloudinary)
Ice-skating image with blue bounding-box overlaid on the jacket

Wrapping It Up

Cloudinary is a box full of tricks, a few of which I used in my object detection demo. I hope you enjoy using it to unbox some of your own images!

In terms of Cloudinary features, there's so much more to unwrap. Head over to the docs to learn about uploading media, image transformations, video transformations, media delivery, asset administration, widgets and players, add-ons and much, much more...

Recent Blog Posts

The Pros and Cons of AVIF for Websites

AVIF is a 2019 spinoff from the AV1 video format developed by the Alliance for Open Media (AOM), whose members include Amazon, Apple, ARM, Facebook, Google, Huawei, Mozilla, Microsoft, Netflix, and Intel. As an open-source and royalty-free video codec, AVIF delivers much higher compression rates than the older image codecs like JPEG and WebP, and is on par with the brand-new JPEG-XL format, which does not work on any browser yet.

Read more
Get Your Media Moving Faster with Cloudinary’s Media Optimizer

So, your boss comes to you in a panic: he's just heard about Google's Core Web Vitals initiative and needs you to optimize the company website right now! "No problem," you say, hiding your fear that it's not something that can be done overnight. Just taking the first metric, Largest Contentful Paint (LCP), how can you possibly identify all the large elements - most likely images or video posters - of the many hundreds of pages that make up your site? There are already thousands of high-resolution (read massive) media files stored away, which marketing could use any time. How are you going to make sure they're all compressed to a size small enough to be delivered within the threshold? Not to mention all the new images and videos that will be created over time...

Read more
How to Tap Into the Value of User-Generated Content (UGC)

User-generated content (UGC) took off with, first of all, the advent of the internet and, subsequently, social networks. Everyday consumers were given keys to the kingdom, so to speak, so that they, too, could compose and post content, simultaneously engaging with others online. Twitter, Facebook, Instagram, Snapchat, TikTok—the networks through which we can create and publish content have grown exponentially, and brands are becoming aware of the benefits of tapping into the gold mines offered by those networks.

Read more
Identifying Countries by IP Address in Columnar Databases Through SQL

Cloudinary reaps a myriad of open web traffic, from ad networks to e-commerce sites. Our Data Science team is dedicated to analyzing the data for use internally and externally.

A glance at any General Data Protection Regulation (GDPR) article would reveal that—unlike Android device IDs (AID), through which users can reset their web address—keeping user identifiers, such as Internal Protocol (IP) and Media Access Control (MAC) addresses, as well as International Mobile Equipment Identity (IMEI), violates privacy. As a solution, you can discard all privacy identifications or make them visible to users for reset.

Read more
Digital-First Asset Management Explained

As the world changes, so does technology. I don’t need to name more than a handful of antiquated technologies before you nod in agreement: floppy disks, Walkmans, phone booths, VHS tapes, each of which have been phased out or rendered useless by new solutions that meet the same need but much more effectively.

Read more