Neural Artwork Style Transfer

Cloudinary is a cloud-based service that provides solutions for image and video management, including server or client-side upload, on-the-fly image and video manipulations, quick CDN delivery, and a variety of asset management options.

The Neural Artwork Style Transfer add-on takes Cloudinary image transformations to a new level with the style_transfer effect. This effect applies a complex deep learning neural network algorithm that extracts artistic styles from a source image and applies them to the content of a target photograph.

Gatys et al is credited with using the VGG neural network to demonstrate how different abstractions of the source and target images can be filtered at different layers, so that the essential elements of the input image can be applied without losing the essence of the target content. Cloudinary's algorithm takes advantage of Xun Huange and Serge Belongie's enhancement on the Gatys algorithm, which make it possible to use any image for both source and target, and still deliver a good quality style transfer in real time, using a single feed-forward neural network.

To apply this style transfer effect on any photograph, specify the public ID of the source artwork as an image overlay (l_ in URLs) and style_transfer as the overlay effect (e_style_transfer in URLs). The target photograph is the public ID of the image to deliver.

In the example below, the styles of the Sailing Angel artwork are transferred to the Golden Gate Bridge photo:

Ruby:
cl_image_tag("golden_gate.jpg", :transformation=>[
  {:width=>700, :height=>700, :crop=>"fill"},
  {:effect=>"style_transfer", :overlay=>"sailing_angel"}
  ])
PHP:
cl_image_tag("golden_gate.jpg", array("transformation"=>array(
  array("width"=>700, "height"=>700, "crop"=>"fill"),
  array("effect"=>"style_transfer", "overlay"=>"sailing_angel")
  )))
Python:
CloudinaryImage("golden_gate.jpg").image(transformation=[
  {"width": 700, "height": 700, "crop": "fill"},
  {"effect": "style_transfer", "overlay": "sailing_angel"}
  ])
Node.js:
cloudinary.image("golden_gate.jpg", {transformation: [
  {width: 700, height: 700, crop: "fill"},
  {effect: "style_transfer", overlay: "sailing_angel"}
  ]})
Java:
cloudinary.url().transformation(new Transformation()
  .width(700).height(700).crop("fill").chain()
  .effect("style_transfer").overlay("sailing_angel")).imageTag("golden_gate.jpg")
JS:
cl.imageTag('golden_gate.jpg', {transformation: [
  {width: 700, height: 700, crop: "fill"},
  {effect: "style_transfer", overlay: "sailing_angel"}
  ]}).toHtml();
jQuery:
$.cloudinary.image("golden_gate.jpg", {transformation: [
  {width: 700, height: 700, crop: "fill"},
  {effect: "style_transfer", overlay: "sailing_angel"}
  ]})
React:
<Image publicId="golden_gate.jpg" >
  <Transformation width="700" height="700" crop="fill" />
  <Transformation effect="style_transfer" overlay="sailing_angel" />
</Image>
Angular:
<cl-image public-id="golden_gate.jpg" >
  <cl-transformation width="700" height="700" crop="fill">
  </cl-transformation>
  <cl-transformation effect="style_transfer" overlay="sailing_angel">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Width(700).Height(700).Crop("fill").Chain()
  .Effect("style_transfer").Overlay("sailing_angel")).BuildImageTag("golden_gate.jpg")
Android:
MediaManager.get().url().transformation(new Transformation()
  .width(700).height(700).crop("fill").chain()
  .effect("style_transfer").overlay("sailing_angel")).generate("golden_gate.jpg")

Sailing angel - source artwork Source artwork Golden gate bridge - target photo Target photo Style transfer result Style transfer result

Tip: To apply this transformation using the Media Library, first select to Add overlay & watermark and specify the source artwork's Image ID. Then select Style transfer as the effect of the overlay image.

Adjusting style transformation preferences

The algorithm is able to recognize styles in the source painting, such as brush stroke style, textures, and dominant colors. It can then apply those styles to the content elements of the target photograph. In the resulting image, there is some content loss, and some style loss, but the neural network algorithm optimizes these losses so that the main elements of the artwork's style come through while ensuring that the content of the target photo is clearly recognizable.

If you want to retain even more of the target photograph's colors or photographic essense, you can include the Boolean preserve_color option or adjust the style_strength (1-100, default: 100). For example, if you transfer the styles of the lighthouse artwork (shown on the left below) to the beach_2_kids photo (right), you clearly get a result (middle) that is heavily influenced by the lighthouse image's colors and brushstroke styles. Then take a look at the next three images to see how the result changes with the use of the adjustment settings:

Lighthouse - source artwork Source artwork Style transfer result Default style transfer Beach - target photo Target photo Style transfer with colors preserved Preserve original colors Style transfer with strength 60 Adjust style strength to 60 Style transfer with adjusted strength and colors preserved Adjust strength and preserve colors

Here's the transformation code for that last image, using both the preserve_color and style_strength options:

Ruby:
cl_image_tag("beach_2_kids.jpg", :transformation=>[
  {:height=>700, :width=>700, :crop=>"fill"},
  {:effect=>"style_transfer:preserve_color:40", :overlay=>"lighthouse"}
  ])
PHP:
cl_image_tag("beach_2_kids.jpg", array("transformation"=>array(
  array("height"=>700, "width"=>700, "crop"=>"fill"),
  array("effect"=>"style_transfer:preserve_color:40", "overlay"=>"lighthouse")
  )))
Python:
CloudinaryImage("beach_2_kids.jpg").image(transformation=[
  {"height": 700, "width": 700, "crop": "fill"},
  {"effect": "style_transfer:preserve_color:40", "overlay": "lighthouse"}
  ])
Node.js:
cloudinary.image("beach_2_kids.jpg", {transformation: [
  {height: 700, width: 700, crop: "fill"},
  {effect: "style_transfer:preserve_color:40", overlay: "lighthouse"}
  ]})
Java:
cloudinary.url().transformation(new Transformation()
  .height(700).width(700).crop("fill").chain()
  .effect("style_transfer:preserve_color:40").overlay("lighthouse")).imageTag("beach_2_kids.jpg")
JS:
cl.imageTag('beach_2_kids.jpg', {transformation: [
  {height: 700, width: 700, crop: "fill"},
  {effect: "style_transfer:preserve_color:40", overlay: "lighthouse"}
  ]}).toHtml();
jQuery:
$.cloudinary.image("beach_2_kids.jpg", {transformation: [
  {height: 700, width: 700, crop: "fill"},
  {effect: "style_transfer:preserve_color:40", overlay: "lighthouse"}
  ]})
React:
<Image publicId="beach_2_kids.jpg" >
  <Transformation height="700" width="700" crop="fill" />
  <Transformation effect="style_transfer:preserve_color:40" overlay="lighthouse" />
</Image>
Angular:
<cl-image public-id="beach_2_kids.jpg" >
  <cl-transformation height="700" width="700" crop="fill">
  </cl-transformation>
  <cl-transformation effect="style_transfer:preserve_color:40" overlay="lighthouse">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Height(700).Width(700).Crop("fill").Chain()
  .Effect("style_transfer:preserve_color:40").Overlay("lighthouse")).BuildImageTag("beach_2_kids.jpg")
Android:
MediaManager.get().url().transformation(new Transformation()
  .height(700).width(700).crop("fill").chain()
  .effect("style_transfer:preserve_color:40").overlay("lighthouse")).generate("beach_2_kids.jpg")

Setting the image size

The Neural Artwork add-on supports generating images with the style_transfer effect for any resolution up to 3000x3000, and it's capable of rendering the new image very quickly even at large sizes. However, because of the way the algorithm analyzes the content of the target photo, you will get different results for different sizes of the target photo. Also, keep in mind that the neural network algorithm behind our Neural Artwork add-on was initially designed for optimum output of images at resolutions in the range of 600x600 - 800x800.

Therefore, when this optimum resolution range is appropriate for your intended usage, use resize or cropping transformations to bring the target photo into this range in one transformation component, and then apply the style_transfer effect in a later transformation component.

For example: ....w_700/e_style_transfer,l_your_artwork/your_target_photo.jpg

Likewise, if you want to output images that are significantly smaller than the above recommended resolution range, you may want to apply the style_transfer effect in an earlier transformation component, and then apply the resizing to the small size in a later transformation component.

For example: ....w_700/e_style_transfer,l_your_artwork/w_200/your_target_photo.jpg

Signed URLs

Cloudinary's dynamic image manipulation URLs are powerful tools for agile web and mobile development. However, due to the potential costs of your customers accessing unplanned dynamic URLs that apply the neural art algorithm, you must either sign your image manipulation delivery URLs or eagerly generate the requested derived images using Cloudinary's authenticated API.

To create a signed Cloudinary URL, set the sign_url parameter to true when building a URL or creating an image tag.

The following code example generates a neural artwork by overlaying the davinci_mona_lisa artwork with the coffee_cup_st photo, including a signed Cloudinary URL:

Ruby:
cl_image_tag("coffee_cup_st.jpg", :effect=>"style_transfer", :overlay=>"davinci_mona_lisa", :sign_url=>true)
PHP:
cl_image_tag("coffee_cup_st.jpg", array("effect"=>"style_transfer", "overlay"=>"davinci_mona_lisa", "sign_url"=>true))
Python:
CloudinaryImage("coffee_cup_st.jpg").image(effect="style_transfer", overlay="davinci_mona_lisa", sign_url=True)
Node.js:
cloudinary.image("coffee_cup_st.jpg", {effect: "style_transfer", overlay: "davinci_mona_lisa", sign_url: true})
Java:
cloudinary.url().transformation(new Transformation().effect("style_transfer").overlay("davinci_mona_lisa")).signed(true).imageTag("coffee_cup_st.jpg")
JS:
cl.imageTag('coffee_cup_st.jpg', {effect: "style_transfer", overlay: "davinci_mona_lisa", sign_url: true}).toHtml();
jQuery:
$.cloudinary.image("coffee_cup_st.jpg", {effect: "style_transfer", overlay: "davinci_mona_lisa"})
React:
<Image publicId="coffee_cup_st.jpg" sign_url="true">
  <Transformation effect="style_transfer" overlay="davinci_mona_lisa" />
</Image>
Angular:
<cl-image public-id="coffee_cup_st.jpg" sign_url="true">
  <cl-transformation effect="style_transfer" overlay="davinci_mona_lisa">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation().Effect("style_transfer").Overlay("davinci_mona_lisa")).Signed(true).BuildImageTag("coffee_cup_st.jpg")
Android:
MediaManager.get().url().transformation(new Transformation().effect("style_transfer").overlay("davinci_mona_lisa")).signed(true).generate("coffee_cup_st.jpg")
Code for generating neural artwork with signed URL

The generated Cloudinary URL shown below includes a signature component (/s--yNvfjq2e--/). Only URLs with a valid signature that matches the requested image manipulation will be approved for on-the-fly image manipulation and delivery.

For more details on signed URLs, see Signed delivery URLs.

(If you need to remove the signed delivery URL restriction, contact Cloudinary support

More on Cloudinary transformations

You can create even more unique results by combining the Neural Artwork style_transfer effect with other transformations. For details, see Image transformations and the Image transformation reference.