Cloudinary Blog
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

Overlaying Glasses Or Masks on Avatars With Vue.js and Cloudinary

Deep learning, a subset of machine learning, breaks down tasks in ways that make all kinds of machine assists possible. With deep learning, you can identify images by machine, i.e., instead of hand-coding software with specific instructions for a task, you train the machine with large amounts of data and algorithms that enable it to learn how to perform the task.

Read more
On-Demand Viewing of Live Video Presents New Opportunities

In early 2020, Cloudinary was planning its fourth annual ImageCon conference, a two-day event in the heart of San Francisco, where we’d congregate with curious digital-media minds to brainstorm best practices for media management. Instead, the COVID-19 pandemic forced the entirety of ImageCon 2020 online. As with all other events being planned, we had to overhaul the content to be communicated on video. Gratifyingly, we found the right partner—the event platform Bizzabo—to turn that into a reality.

Read more
Why the Future of E-commerce Is Live

In a previous post, I discussed how “going live” is gaining popularity across industries and verticals. What began as a way for gamers to jam together has evolved into a medium for broader entertainment and business purposes. To continue the conversation, this post unpacks the current trends of shoppable live streams to shine a light on how brands are leveraging “lives” to connect with shoppers in new ways.

Read more
An Overview of Live-Streaming Video Trends

“Let’s go live.” For decades, that’s what newscasters say as they cut to real-time footage of a colleague reporting in the field. The live-video feed adds visual interest and perspective to a story beyond what can be communicated by someone sitting behind the news desk. In the same way, live-streaming video nowadays adds context to other consumer environments. From gaming and events to shopping and social media, “going live” enhances everyday experiences, and it’s something anyone can do with relative ease.

Read more