
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Thu, 09 Apr 2026 07:57:08 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Evaluating image segmentation models for background removal for Images]]></title>
            <link>https://blog.cloudflare.com/background-removal/</link>
            <pubDate>Thu, 28 Aug 2025 14:00:00 GMT</pubDate>
            <description><![CDATA[ An inside look at how the Images team compared dichotomous image segmentation models to identify and isolate subjects in an image from the background. ]]></description>
            <content:encoded><![CDATA[ <p>Last week, we wrote about <a href="https://blog.cloudflare.com/ai-face-cropping-for-images/"><u>face cropping for Images</u></a>, which runs an open-source face detection model in <a href="https://developers.cloudflare.com/workers-ai/"><u>Workers AI</u></a> to automatically crop images of people at scale.</p><p>It wasn’t too long ago when deploying AI workloads was prohibitively complex. Real-time inference previously required specialized (and costly) hardware, and we didn’t always have standard abstractions for deployment. We also didn’t always have Workers AI to enable developers — including ourselves — to ship AI features without this additional overhead.</p><p>And whether you’re skeptical or celebratory of AI, you’ve likely seen its explosive progression. New benchmark-breaking computational models are released every week. We now expect a fairly high degree of accuracy — the more important differentiators are how well a model fits within a product’s infrastructure and what developers do with its predictions.</p><p>This week, we’re introducing <a href="https://developers.cloudflare.com/images/transform-images/transform-via-url/#segment">background removal for Images</a>. This feature runs a dichotomous image segmentation model on Workers AI to isolate subjects in an image from their backgrounds. We took a controlled, deliberate approach to testing models for efficiency and accuracy.</p><p>Here’s how we evaluated various image segmentation models to develop background removal.</p>
    <div>
      <h2>A primer on image segmentation</h2>
      <a href="#a-primer-on-image-segmentation">
        
      </a>
    </div>
    <p>In computer vision, image segmentation is the process of splitting an image into meaningful parts.</p><p>Segmentation models produce a mask that assigns each pixel to a specific category. This differs from detection models, which don’t classify every pixel but instead mark regions of interest. A face detection model, such as the one that informs <a href="https://developers.cloudflare.com/images/transform-images/transform-via-url/#gravity"><u>face cropping</u></a>, draws bounding boxes based on where it thinks there are faces. (If you’re curious, <a href="https://blog.cloudflare.com/ai-face-cropping-for-images/#from-pixels-to-people"><u>our post on face cropping</u></a> discusses how we use these bounding boxes to perform crop and zoom operations.)</p><p>Salient object detection is a type of segmentation that highlights the parts of an image that most stand out. Most salient detection models create a binary mask that categorizes the most prominent (or salient) pixels as the “foreground” and all other pixels as the “background”. In contrast, a multi-class mask considers the broader context and labels each pixel as one of several possible classes, like “dog” or “chair”. These multi-class masks are the basis of content analysis models, which distinguish which pixels belong to specific objects or types of objects.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/qV2QVZYEdqdigCTuqBuHu/cf4873dddf3b30503aac6643ded1a5ab/image3.png" />
          </figure><p><sub>In this photograph of my dog, a detection model predicts that a bounding box contains a dog; a segmentation model predicts that some pixels belong to a dog, while all other pixels don’t.</sub></p><p>For our use case, we needed a model that could produce a soft saliency mask, which predicts how strongly each pixel belongs to either the foreground (objects of interest) or the background. That is, each pixel is assigned a value on a scale of 0–255, where 0 is completely transparent and 255 is fully opaque. Most background pixels are labeled at (or near) 0; foreground pixels may vary in opacity, depending on its degree of saliency.</p><p>In principle, a background removal feature must be able to accurately predict saliency across a broad range of contexts. For example, e-commerce and retail vendors want to display all products on a uniform, white background; in creative and image editing applications, developers want to enable users to create stickers and cutouts from uploaded content, including images of people or avatars.</p><p>In our research, we focused primarily on the following four image segmentation models:</p><ul><li><p><a href="https://arxiv.org/abs/2005.09007"><b><u>U</u></b><b><u><sup>2</sup></u></b><b><u>-Net (U Square Net)</u></b></a>: Trained on the largest saliency dataset (<a href="https://saliencydetection.net/duts/"><u>DUST-TR</u></a>) of 10,553 images, which were then horizontally flipped to reach a total of 21,106 training images.</p></li><li><p><a href="https://arxiv.org/abs/2203.03041"><b><u>IS-Net (Intermediate Supervision Network)</u></b></a>: A novel, two-step approach from the same authors of U2-Net; this model produces cleaner boundaries for images with noisy, cluttered backgrounds.</p></li><li><p><a href="https://arxiv.org/abs/2401.03407"><b><u>BiRefNet (Bilateral Reference Network)</u></b></a>: Specifically designed to segment complex and high-resolution images with accuracy by checking that the small details match the big picture.</p></li><li><p><a href="https://arxiv.org/abs/2304.02643"><b><u>SAM (Segment Anything Model)</u></b></a>: Developed by Meta to allow segmentation by providing prompts and input points.</p></li></ul><p>Different scales of information allow computational models to build a holistic view of an image. Global context considers the overall shape of objects and how areas of pixels relate to the entire image, while local context traces fine details like edges, corners, and textures. If local context focuses on the trees and their leaves, then global context represents the entire forest.</p><p><a href="https://github.com/xuebinqin/U-2-Net"><u>U</u><u><sup>2</sup></u><u>-Net</u></a> extracts information using a multi-scale approach, where it analyzes an image at different zoom levels, then combines its predictions in a single step. The model analyzes global and local context at the same time, so it works well on images with multiple objects of varying sizes.</p><p><a href="https://github.com/xuebinqin/DIS"><u>IS-Net</u></a> introduces a new, two-step strategy called intermediate supervision. First, the model separates the foreground from the background, identifying potential areas that likely belong to objects of interest — all other pixels are labeled as the background. Second, it refines the boundaries of the highlighted objects to produce a final pixel-level mask.</p><p>The initial suppression of the background results in cleaner, more precise edges, as the segmentation focuses only on the highlighted objects of interest and is less likely to mistakenly include background pixels in the final mask. This model especially excels when dealing with complex images with cluttered backgrounds.</p><p>Both models output their predictions in a single direction for scale. U<sup>2</sup>-Net interprets the global and local context in one pass, while Is-Net begins with the global context, then focuses on the local context.</p><p>In contrast, <a href="https://github.com/ZhengPeng7/BiRefNet"><u>BiRefNet</u></a> refines its predictions over multiple passes, moving in both contextual directions. Like Is-Net, it initially creates a map that roughly highlights the salient object, then traces the finer details. However, BiRefNet moves from global to local context, then from local context back to global. In other words, after refining the edges of the object, it feeds the output back to the large-scale view. This way, the model can check that the small-scale details align with the broader image structure, providing higher accuracy on high-resolution images.</p><p>U<sup>2</sup>-Net, IS-Net, and BiRefNet are exclusively saliency detection models, producing masks that distinguish foreground pixels from background pixels. However, <a href="https://github.com/facebookresearch/segment-anything"><u>SAM</u></a> was designed to be more extensible and general; its primary goal is to segment any object based on specified inputs, not only salient objects. This means that the model can also be used to create multi-class masks that label various objects within an image, even if they aren’t the primary focus of an image.</p>
    <div>
      <h2>How we measure segmentation accuracy</h2>
      <a href="#how-we-measure-segmentation-accuracy">
        
      </a>
    </div>
    <p>In most saliency datasets, the actual location of the object is known as the ground-truth area. These regions are typically defined by human annotators, who manually trace objects of interest in each image. This provides a reliable reference to evaluate model predictions.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6wAV8lQcsZHosKoFyEIce1/495b3d70960027b795ec1a62f2d46a59/BLOG-2928_3.png" />
          </figure><p><sub>Photograph by </sub><a href="https://www.linkedin.com/in/fang-allen"><sub><u>Allen Fang</u></sub></a></p><p>Each model outputs a predicted area (where it thinks the foreground pixels are), which can be compared against the ground-truth area (where the foreground pixels actually are).</p><p>Models are evaluated for segmentation accuracy based on common metrics like Intersection over Union, Dice coefficient, and pixel accuracy. Each score takes a slightly different approach to quantify the alignment between the predicted and ground-truth areas (“P” and “G”, respectively, in the formulas below).</p>
    <div>
      <h3>Intersection over Union</h3>
      <a href="#intersection-over-union">
        
      </a>
    </div>
    <p>Intersection over Union (IoU), also called the Jaccard index, measures how well the predicted area matches the true object. That is, it counts the number of foreground pixels that are shared in both the predicted and ground-truth masks. Mathematically, IoU is written as:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6zVQSLlKaFuVUQrDcAlf0Y/4254010745caf0d207d8f8e8181f4c9c/BLOG-2928_4.png" />
          </figure><p><sub>Jaccard formula</sub></p><p>The formula divides the intersection (P∩G), or the pixels where the predicted and ground-truth areas overlap, by the union (P∪G), or the total area of pixels that belong to either area, counting the overlapping pixels only once.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7KFLB15btpCQuKuTqakBjp/91e78ec6d565e3723c5d76b3a65a441d/unnamed__23_.png" />
          </figure><p>IoU produces a score between 0 and 1. A higher value indicates a closer overlap between the predicted and ground-truth areas. A perfect match, although rare, would score 1, while a smaller overlapping area brings the score closer to 0.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/oe82x3rPo8XoNnwG3KBRy/22f591adb6ab27b3ad05f91b13eddff7/BLOG-2928_6.png" />
          </figure>
    <div>
      <h3>Dice coefficient</h3>
      <a href="#dice-coefficient">
        
      </a>
    </div>
    <p>The Dice coefficient, also called the Sørensen–Dice index, similarly compares how well the model’s prediction matches reality, but is much more forgiving than the IoU score. It gives more weight to the shared pixels between the predicted and actual foreground, even if the areas differ in size. Mathematically, the Dice coefficient is written as:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4UiJUJrjagwkmQNvdkiPC3/e17eaa8f22f57114a91f1e58fc3a76fb/BLOG-2928_7.png" />
          </figure><p><sub>Sørensen–Dice formula</sub></p><p>The formula divides twice the intersection (P∩G) by the sum of pixels in both predicted and ground-truth areas (P+G), counting any overlapping pixels twice.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7vcFBAoRJ9wpyAt8m4Sn7x/8b1962de717701ff348e90ec8b86286e/BLOG-2928_8.png" />
          </figure><p>Like IoU, the Dice coefficient also produces a value between 0 and 1, indicating a more accurate match as it approaches 1.</p>
    <div>
      <h3>Pixel accuracy</h3>
      <a href="#pixel-accuracy">
        
      </a>
    </div>
    <p>Pixel accuracy measures the percentage of pixels that were correctly labeled as either the foreground or the background. Mathematically, pixel accuracy is written as:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/40HkiVe1a2i1dSguDk1TxO/990e49cd4d40a4eaa29078948bc9d7e8/unnamed__24_.png" />
          </figure><p><sub>Pixel accuracy formula</sub></p><p>The formula divides the number of correctly predicted pixels by the total number of pixels in the image.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1GX83EmXBSLhGlHvGFLqnn/f65fbd110f4b1d201f7585723ced0f34/image10.png" />
          </figure><p>The total area of correctly predicted pixels is the sum of foreground and background pixels that accurately match the ground-truth areas.</p><p>The correctly predicted foreground is the intersection of the predicted and ground-truth areas (P∩G). The inverse of the predicted area (P’, or 1–P) represents the pixels that the model identifies as the background; the inverse of the ground-truth area (G’, or 1–G) represents the actual boundaries of the background. When these two inverted areas overlap (P’∩G’, or (1–P)∩(1–G)), this intersection is the correctly predicted background.</p>
    <div>
      <h2>Interpreting the metrics</h2>
      <a href="#interpreting-the-metrics">
        
      </a>
    </div>
    <p>Of the three metrics, IoU is the most conservative measure of segmentation accuracy. Small mistakes, such as including extra background pixels in the predicted foreground, reduce the score noticeably. This metric is most valuable for applications that require precise boundaries, such as autonomous driving systems.</p><p>Meanwhile, the Dice coefficient rewards the overlapping pixels more heavily, and subsequently tends to be higher than the IoU score for the same prediction. In model evaluations, this metric is favored over IoU when it’s more important to capture the object than to penalize mistakes. For example, in medical imaging, the risk of missing a true positive substantially outweighs the inconvenience of flagging a false positive.</p><p>In the context of background removal, we biased toward the IoU score and Dice coefficient over pixel accuracy. Pixel accuracy can be misleading, especially when processing an image where background pixels comprise the majority of pixels.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7K8TWmRLdJNIza43UoXhD8/c9a42ed7074ce975afd8f7e783db5849/BLOG-2928_11.png" />
          </figure><p>For example, consider an image with 900 background pixels and 100 foreground pixels. A model that correctly predicts only 5 foreground pixels — 5% of all foreground pixels — will score deceptively high in pixel accuracy. Intuitively, we’d likely say that this model performed poorly. However, assuming all 900 background pixels were correctly predicted, the model maintains 90.5% pixel accuracy, despite missing the subject almost entirely.</p>
    <div>
      <h2>Pixels, predictions, and patterns</h2>
      <a href="#pixels-predictions-and-patterns">
        
      </a>
    </div>
    <p>To determine the most suitable model for the Images API, we performed a series of tests using the open-source <a href="https://github.com/danielgatis/rembg"><u>rembg</u></a> library, which combines all relevant models in a single interface.</p><p>Each model was tasked with outputting a prediction mask to label foreground versus background pixels. We pulled images from two saliency datasets: <a href="https://huggingface.co/datasets/schirrmacher/humans"><b><u>Humans</u></b></a> contains over 7,000 images of people with varying skin tones, clothing, and hairstyles, while <a href="https://xuebinqin.github.io/dis/index.html#overview"><b><u>DIS5K</u></b></a> (version 1.5) spans a vast range of objects and scenes. If a model contained variants that were pre-trained on specific types of segmentation (e.g. clothes, humans), then we repeated the tests for the generalized model and each variant.</p><p>Our experiments were executed on a GPU with 23 GB VRAM to mirror realistic hardware constraints, similar to the environment where we already run a face detection model. We also replicated the same tests on a larger GPU instance with 94 GB VRAM; this served as an upper-bound reference point to benchmark potential speed gains if additional compute were available. Cloudflare typically reserves larger GPUs for more compute-intensive <a href="https://developers.cloudflare.com/workers-ai/models/"><u>AI workloads</u></a> — we viewed these tests more as an exploration for comparison than as a production scenario.</p><p>During our analysis, we started to see key trends emerge:</p><p>On the smaller GPU, inference times were generally faster for lightweight models like U<sup>2</sup>-Net (176 MB) and Is-Net (179 MB). The average speed across both datasets were 307 milliseconds for U<sup>2</sup>-Net and 351 milliseconds for Is-Net. On the opposite end, BiRefNet (973 MB) had noticeably slower output times, averaging 821 milliseconds across its two generalized variants.</p><p>BiRefNet ran 2.4 times faster on the larger GPU, reducing its average inference time to 351 milliseconds — comparable to the other models, despite its larger size. In contrast, the lighter models did not show any notable speed gain with additional compute, suggesting that scaling hardware configurations primarily benefits heavier models. In <a href="https://blog.cloudflare.com/background-removal/#appendix-1-inference-time-in-milliseconds">Appendix 1</a> (“Inference Time in Milliseconds”), we compare speed across models and GPU instances.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/55Tk0RjbvoffPVQT85UJQe/ca1f2280768495f3be52425e642fdd25/BLOG-2928_12.png" />
          </figure><p>We also observed distinct patterns when comparing model performance across the two saliency datasets. Most notably, all models ran faster on the Humans dataset, where images of people tend to be single-subject and relatively uniform. The DIS5K dataset, in contrast, includes images with higher complexity — that is, images with more objects, cluttered backgrounds, or multiple objects of varying scales.</p><p>Slower predictions suggest a relationship between visual complexity and the computation needed to identify the important parts of an image. In other words, datasets with simpler, well-separated objects can be analyzed more quickly, while complex scenes require more computation to generate accurate masks.</p><p>Similarly, complexity challenges accuracy as much as it does efficiency. In our tests, all models demonstrated higher segmentation accuracy with the Humans dataset. In <a href="https://blog.cloudflare.com/background-removal/#appendix-2-measures-of-model-accuracy">Appendix 2</a> (“Measures of Model Accuracy”), we present our results for segmentation accuracy across both datasets.</p><p>Specialized variants scored slightly higher in accuracy compared to their generalized counterparts. But in broad, practical applications, selecting a specialized model for every input isn’t realistic, at least for our initial beta version. We favored general-purpose models that can produce accurate predictions without prior classification. For this reason, we excluded SAM — while powerful in its intended use cases, SAM is designed to work with additional inputs. On unprompted segmentation tasks, it produced lower accuracy scores (and much higher inference times) amongst the models we tested.</p><p>All BiRefNet variants showed greater accuracy compared to other models. The generalized variants (<code>-genera</code>l and <code>-dis</code>) were just as accurate as its more specialized variants like <code>-portrait</code>. The <code>birefnet-general</code> variant, in particular, achieved a high IoU score of 0.87 and Dice coefficient of 0.92, averaged across both datasets.</p><p>In contrast, the generalized U<sup>2</sup>-Net model showed high accuracy on the Humans dataset, reaching an IoU score of 0.89 and a Dice coefficient of 0.94, but received a low IoU score of 0.39 and Dice coefficient of 0.52 on the DIS5K dataset. The <code>isnet-general-use</code> model performed substantially better, obtaining an average IoU score of 0.82 and Dice coefficient of 0.89 across both datasets.</p><p>We observed whether models could interpret both the global and local context of an image. In some scenarios, the U<sup>2</sup>-Net and Is-Net models captured the overall gist of an image, but couldn’t accurately trace fine edges. We designed one test around measuring how well each model could isolate bicycle wheels; for variety, we included images across both interior and exterior backgrounds. Lower scoring models, while correctly labeling the area surrounding the wheel, struggled with the pixels between the thin spokes and produced prediction masks that included these background pixels.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6mzRTqXhZRk0GuzwuIRu4p/b251aa4f3dbeecc11dbba931623607e5/BLOG-2928_13.png" />
          </figure><p><sub>Photograph by </sub><a href="https://unsplash.com/photos/person-near-bike-p6OU_gENRL0"><sub><u>Yomex Owo on Unsplash</u></sub></a><sub></sub></p><p>In other scenarios, the models showed the opposite limitation: they produced masks with clean edges, but failed to identify the focus of the image. We ran another test using a photograph of a gray T-shirt against black gym flooring. Both generalized U<sup>2</sup>-Net and Is-Net models labeled only the logo as the salient object, creating a mask that omitted the rest of the shirt entirely. </p><p>Meanwhile, the BiRefNet model achieved high accuracy across both types of tests. Its architecture passes information bidirectionally, allowing details at the pixel level to be informed by the larger scene (and vice versa). In practice, this means that BiRefNet interprets how fine-grained edges fit into the broader object. For our beta version, we opted to use the BiRefNet model to drive decisions for background removal.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/741GSfhMn8MPykb6NkWUJV/1ef5006aea8f67a4faeec73862d97ced/BLOG-2928_14.png" />
          </figure><p><sub>Unlike lower scoring models, the BiRefNet model understood that the entire shirt is the true subject of the image.</sub></p>
    <div>
      <h2>Applying background removal with the Images API</h2>
      <a href="#applying-background-removal-with-the-images-api">
        
      </a>
    </div>
    <p>The Images API now supports <a href="https://developers.cloudflare.com/images/transform-images/transform-via-url/#segment">automatic background removal</a> for <a href="https://developers.cloudflare.com/images/upload-images/"><u>hosted</u></a> and <a href="https://developers.cloudflare.com/images/transform-images/"><u>remote</u></a> images. This feature is available in open beta to all Cloudflare users on <a href="https://developers.cloudflare.com/images/pricing/"><u>Free and Paid plans</u></a>.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3iglNDllwEMvg6ygDvTRNc/a354422efd166cb3b48ee10995e78aa4/unnamed__25_.png" />
          </figure><p>Use the <code>segment</code> parameter when optimizing an image through a <a href="https://developers.cloudflare.com/images/transform-images/transform-via-url/"><u>specially-formatted Images URL</u></a> or a <a href="https://developers.cloudflare.com/images/transform-images/transform-via-workers/"><u>worker</u></a>, and Cloudflare will isolate the subject of your image and convert the background into transparent pixels. This can be combined with <a href="https://developers.cloudflare.com/images/transform-images/transform-via-url/"><u>other optimization operations</u></a>, as shown in the transformation URL below: </p>
            <pre><code>example.com/cdn-cgi/image/gravity=face,zoom=0.5,segment=foreground,background=white/image.png</code></pre>
            <p>This request will:</p><ul><li><p>Crop the image toward the <a href="https://developers.cloudflare.com/images/transform-images/transform-via-url/#gravity"><u>detected face</u></a>.</p></li><li><p>Isolate the subject in the image, replacing the background with transparent pixels.</p></li><li><p><a href="https://developers.cloudflare.com/images/transform-images/transform-via-url/#background"><u>Fill the transparent pixels</u></a> with a solid white color (<code>#FFFFFF</code>).</p></li></ul><p>You can also <a href="https://developers.cloudflare.com/images/transform-images/bindings/"><u>bind the Images API</u></a> to your worker to build programmatic workflows that give more fine-grained control over how images will be optimized. To demonstrate how this works, I made a <a href="https://studio.yaydeanna.workers.dev/"><u>simple image editing app</u></a> for creating cutouts and overlays, built entirely on Images and <a href="https://developers.cloudflare.com/workers/"><u>Workers</u></a>. This can be used to create images <a href="https://studio.yaydeanna.workers.dev/?order=0%2C1%2C2&amp;i0=icecream&amp;vertEdge0=bottom&amp;vertVal0=0&amp;horEdge0=left&amp;h0=400&amp;bg0=1&amp;i1=pete&amp;vertEdge1=top&amp;horEdge1=left&amp;h1=700&amp;bg1=1&amp;i2=iceland&amp;vertEdge2=top&amp;horEdge2=left"><u>like the one below</u></a>. Here, we apply background removal to isolate the dog and ice cream cone, then overlay them on a landscape image.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6Z6t9ov1t3fbbQojbYbGDh/961cef0f06780bfd8c088772a7add796/image11.png" />
          </figure><p><sub>Photographs by </sub><a href="https://www.pexels.com/@guyjoben/"><sub><u>Guy Hurst</u></sub></a><sub> (landscape), </sub><a href="https://www.pexels.com/@oskar-gackowski-2150870625/"><sub><u>Oskar Gackowski</u></sub></a><sub> (ice cream), and me (dog)</sub></p><p>Here is a snippet that you can use to overlay images in a worker:</p>
            <pre><code>export default {
  async fetch(request,env) {
    const baseURL = "{image-url}";
    const overlayURL = "{image-url}";
    
    // Fetch responses from image URLs
    const [base, overlay] = await Promise.all([fetch(baseURL),fetch(overlayURL)]);

    return (
      await env.IMAGES
        .input(base.body)
        .draw(
          env.IMAGES.input(overlay.body)
            .transform({segment: "foreground"}), // Optimize the overlay image
            {top: 0} // Position the overlay
        )
        .output({format:"image/webp"})
    ).response();
  }
};</code></pre>
            <p>Background removal is another step in our ongoing effort to enable developers to build interactive and imaginative products. These features are an iterative process, and we’ll continue to refine our approach even further. We’re looking forward to sharing our progress with you.</p><p>Read more about applying background removal in our <a href="https://developers.cloudflare.com/images/transform-images/transform-via-url/#segment"><u>documentation</u></a>.</p>
    <div>
      <h3>Appendix 1: Inference Time in Milliseconds</h3>
      <a href="#appendix-1-inference-time-in-milliseconds">
        
      </a>
    </div>
    
    <div>
      <h4>23 GB VRAM GPU</h4>
      <a href="#23-gb-vram-gpu">
        
      </a>
    </div>
    
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2e97UAIgglJ3kP3ozm8lZT/6a44de14aa5179071eb7bbb3c8f31feb/BLOG-2928_17.png" />
          </figure>
    <div>
      <h4>94 GB VRAM GPU</h4>
      <a href="#94-gb-vram-gpu">
        
      </a>
    </div>
    
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2viOyCtbzsloUAvY8kXPJV/378feb50a1dd822d7c848133fbac6a3f/BLOG-2928_18.png" />
          </figure>
    <div>
      <h3>Appendix 2: Measures of Model Accuracy</h3>
      <a href="#appendix-2-measures-of-model-accuracy">
        
      </a>
    </div>
    
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2G9hwnFrlT4eF2isWyaEjk/d3418df56dff686c27f46d96fc86c37f/BLOG-2928_19.png" />
          </figure><p></p> ]]></content:encoded>
            <category><![CDATA[AI Week]]></category>
            <category><![CDATA[AI]]></category>
            <category><![CDATA[Image Optimization]]></category>
            <category><![CDATA[Cloudflare Images]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <guid isPermaLink="false">q17H7D8gSkyNAPELuTHl9</guid>
            <dc:creator>Deanna Lam</dc:creator>
            <dc:creator>Diretnan Domnan</dc:creator>
        </item>
        <item>
            <title><![CDATA[How we built AI face cropping for Images]]></title>
            <link>https://blog.cloudflare.com/ai-face-cropping-for-images/</link>
            <pubDate>Wed, 20 Aug 2025 14:00:00 GMT</pubDate>
            <description><![CDATA[ AI face cropping for Images automatically crops around faces in an image. Here’s how we built this feature on Workers AI to scale for general availability. ]]></description>
            <content:encoded><![CDATA[ <p>During Developer Week 2024, we introduced <a href="https://blog.cloudflare.com/whats-next-for-cloudflare-media/"><u>AI face cropping in private beta</u></a>. This feature automatically crops images around detected faces, and marks the first release in our upcoming suite of AI image manipulation capabilities.</p><p><a href="https://developers.cloudflare.com/images/transform-images/transform-via-url/#gravity"><u>AI face cropping</u></a> is now available in <a href="https://developers.cloudflare.com/images/"><u>Images</u></a> for everyone. To bring this feature to general availability, we moved our CPU-based prototype to a GPU-based implementation in Workers AI, enabling us to address a number of technical challenges, including memory leaks that could hamper large-scale use.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1uwRmMEA9LSDoeZgMbYjcM/71b941d57605b0a5286f6f0ccc7dd5e9/1.png" />
          </figure><p><sup><i>Photograph by </i></sup><a href="https://unsplash.com/photos/woman-in-black-cardigan-standing-beside-pink-flowers-UO-82DJ3rcc"><sup><i><u>Suad Kamardeen (@suadkamardeen) on Unsplash</u></i></sup></a></p>
    <div>
      <h2>Turning raw images into production-ready assets</h2>
      <a href="#turning-raw-images-into-production-ready-assets">
        
      </a>
    </div>
    <p>We developed face cropping with two particular use cases in mind:</p><p><b>Social media platforms and AI chatbots.</b> We observed a lot of traffic from customers who use Images to turn unedited images of people into smaller profile pictures in neat, fixed shapes.</p><p><b>E-commerce platforms.</b> The same product photo might appear in a grid of thumbnails on a gallery page, then again on an individual product page with a larger view. The following example illustrates how cropping can change the emphasis from the model’s shirt to their sunglasses.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/zj35mxsUccGShpq5YGHAD/7ffb7b2f8c517be06e2bab6f42aa9a06/2.png" />
          </figure><p><sup><i>Photograph by </i></sup><a href="https://unsplash.com/photos/a-man-wearing-sunglasses-IJozQuMbo3M"><sup><i><u>Media Modifier (@mediamodifier) on Unsplash</u></i></sup></a></p><p>When handling high volumes of media content, preparing images for production can be tedious. With Images, you don’t need to manually generate and store multiple versions of the same image. Instead, we serve copies of each image, each optimized to your specifications, while you continue to <a href="https://developers.cloudflare.com/images/upload-images/"><u>store only the original image</u></a>.</p>
    <div>
      <h2>Crop everything, everywhere, all at once</h2>
      <a href="#crop-everything-everywhere-all-at-once">
        
      </a>
    </div>
    <p>Cloudflare provides a <a href="https://developers.cloudflare.com/images/transform-images/transform-via-url/"><u>library of parameters</u></a> to manipulate how an image is served to the end user. For example, you can crop an image to a square by setting its <code>width</code> and <code>height</code> dimensions to 100x100.</p><p>By default, images are cropped toward the center coordinates of the original image. The <code>gravity</code> parameter can affect how an image gets cropped by changing its focal point. You can specify coordinates to use as the focal point of an image or allow Cloudflare to automatically determine a new focal point.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/78jngtcSCwB80JcZgDsW4d/44bcaf9aa61c6c5c66eb281fba91a472/3.png" />
          </figure><p><sup><i>The gravity parameter is useful when cropping images with off-centered subjects. Photograph by </i></sup><a href="https://unsplash.com/photos/selective-focus-photography-of-pink-petaled-flower-EfhCUc_fjrU"><sup><i><u>Andrew Small (@andsmall) on Unsplash</u></i></sup></a></p><p>The <code>gravity=auto</code> option uses a saliency algorithm to pick the most optimal focal point of an image. Saliency detection identifies the parts of an image that are most visually important; the cropping operation is then applied toward this region of interest. Our algorithm analyzes images using visual cues such as color, luminance, and texture, but doesn’t consider context within an image. While this setting works well on images with inanimate objects like plants and skyscrapers, it doesn’t reliably account for subjects as contextually meaningful as people’s faces.</p><p>And yet, images of people comprise the majority of bandwidth usage for many applications, such as an AI chatbot platform that uses Images to serve over 45 million unique transformations each month. This presented an opportunity for us to improve how developers can optimize images of people.</p><p>AI face cropping can be performed by using the <code>gravity=face</code> option, which automatically detects which pixels represent the face (or faces) and uses this information to crop the image. You can also affect how closely the image is cropped toward the face; the <code>zoom</code> parameter controls the threshold for how much of the surrounding area around the face will be included in the image.</p><p>We carefully designed our model pipeline with privacy and confidentiality top of mind. This feature doesn’t support facial identification or recognition. In other words, when you optimize with Cloudflare, we’ll never know that two different images depict the same person, or identify the specific people in a given image. Instead, AI face cropping with Images is intentionally limited to face detection, or identifying the pixels that represent a human face.</p>
    <div>
      <h2>From pixels to people</h2>
      <a href="#from-pixels-to-people">
        
      </a>
    </div>
    <p>Our first step was to select an open-source model that met our requirements. Behind the scenes, our AI face cropping uses <a href="https://github.com/serengil/retinaface"><u>RetinaFace</u></a>, a convolutional neural network model that classifies images with human faces.</p><p>A <a href="https://www.cloudflare.com/learning/ai/what-is-neural-network/"><u>neural network</u></a> is a type of machine learning process that loosely resembles how the human brain works. A basic neural network has three parts: an input layer, one or more hidden layers, and an output layer. Nodes in each layer form an interconnected network to transmit and process data, where each input node is connected to nodes in the next layer.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6bm2f6z6XoV7KncKSXTTmG/01f9fa9da23a3fb792883d90f180780c/4.png" />
          </figure><p><sup><i>A fully connected layer passes data from one layer to the next.</i></sup></p><p>Data enters through the input layer, where it is analyzed before being passed to the first hidden layer. All of the computation is done in the hidden layers, where a result is eventually delivered through the output layer.</p><p>A convolutional neural network (CNN) mirrors how humans look at things. When we look at other people, we start with abstract features, like the outline of their body, before we process specific features, like the color of their eyes or the shape of their lips.</p><p>Similarly, a CNN processes an image piece-by-piece before delivering the final result. Earlier layers look for abstract features like edges and colors and lines; subsequent layers become more complex and are each responsible for identifying the various features that comprise a human face. The last fully connected layer combines all categorized features to produce one final classification of the entire image. In other words, if an image contains all of the individual features that define a human face (e.g. eyes, nose), then the CNN concludes that the image contains a human face.</p><p>We needed a model that could determine whether an image depicts a person (image classification), as well as exactly where they are in the image (object detection). When selecting a model, some factors we considered were:</p><ul><li><p><b>Performance on the </b><a href="http://shuoyang1213.me/WIDERFACE/index.html"><b><u>WIDERFACE</u></b></a><b> dataset.</b> This is the state-of-the-art face detection benchmark dataset, which contains 32,203 images of 393,703 labeled faces with a high degree of variability in scale, pose, and occlusion.</p></li><li><p><b>Speed (in frames per second).</b> Most of our image optimization requests occur on delivery (rather than before an image gets uploaded to storage), so we prioritized performance for end-user delivery.</p></li><li><p><b>Model size.</b> Smaller model sizes run more efficiently.</p></li><li><p><b>Quality</b>. The performance boost from smaller models often gets traded for the quality—the key is balancing speed with results.</p></li></ul><p>Our initial test sample contained 500 images with varying factors like the number of faces in the image, face size, lighting, sharpness, and angle. We tested various models, including <a href="https://github.com/hollance/BlazeFace-PyTorch"><u>BlazeFast</u></a>, <a href="https://arxiv.org/abs/1311.2524"><u>R-CNN</u></a> (and its successors <a href="https://arxiv.org/abs/1504.08083"><u>Fast R-CNN</u></a> and <a href="https://arxiv.org/abs/1506.01497"><u>Faster R-CNN</u></a>), <a href="https://github.com/serengil/retinaface"><u>RetinaFace</u></a>, and <a href="https://arxiv.org/abs/1506.02640"><u>YOLO</u></a> (You Only Look Once).</p><p>Two-stage detectors like BlazeFast and R-CNN propose potential object locations in an image, then identify objects in those regions of interest. One-stage detectors like RetinaFace and YOLO predict object locations and classes in a single pass. In our research, we observed that two-stage detector methods provided higher accuracy, but performed too slowly to be practical for real traffic. On the other hand, one-stage detector methods were efficient and performant while still highly accurate.</p><p>Ultimately, we selected RetinaFace, which showed the highest precision of 99.4% and performed faster than other models with comparable values. We found that RetinaFace delivered strong results even with images containing multiple blurry faces:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5cCiUcM7S7f1XRo5e8f1L5/696dde02a2de76e176f49f99fc784e11/5.png" />
          </figure><p><sup><i>Photograph by </i></sup><a href="https://unsplash.com/photos/people-in-green-life-vest-on-water-during-daytime-1Ltm4zrGSVg"><sup><i><u>Anne Nygård (@polarmermaid) on Unsplash</u></i></sup></a></p><p><a href="https://www.cloudflare.com/learning/ai/inference-vs-training/"><u>Inference</u></a>—the process of using training models to make decisions—can be computationally demanding, especially with very large images. To maintain efficiency, we set a maximum size limit of 1024x1024 pixels when sending images to the model.</p><p>We pass images within these dimensions directly to the model for analysis. But if either width or height dimension exceeds 1024 pixels, then we instead create an inference image to send to the model; this is a smaller copy that retains the same aspect ratio as the original image and does not exceed 1024 pixels in either dimension. For example, a 125x2000 image will be downscaled to 64x1024. Creating this resized, temporary version reduces the amount of data that the model needs to analyze, enabling faster processing.</p><p>The model draws all of the bounding boxes, or the regions within an image that define the detected faces. From there, we construct a new, outer bounding box that encompasses all of the individual boxes, calculating its <code>top-left</code> and <code>bottom-right</code> points based on the boxes that are closest to the top, left, bottom, and right edges of the image.</p><p>The <code>top-left</code> point uses the <code>x</code> coordinate from the left-most box and the <code>y</code> coordinate from the top-most box. Similarly, the <code>bottom-right</code> point uses the <code>x</code> coordinate from the right-most box and the <code>y</code> coordinate from the bottom-most box. These coordinates can be taken from the same bounding boxes; if a single box is closest to both the top and left edges, then we would use its top-left corner as the <code>top-left</code> point of the outer bounding box.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2vchhlXYoakCiy7S2MglHb/6e5b3c1a36c5fa20cd45122a0a966777/6.png" />
          </figure><p><sup><i>AI face cropping identifies regions that represent faces, then determines an outer bounding box and focal point based on the top-most, left-most, right-most, and bottom-most bounding boxes.</i></sup></p><p>Once we define the outer bounding box, we use its center coordinates as the focal point when cropping the image. From our experiments, we found that this produced better and more balanced results for images with multiple faces compared to other methods, like establishing the new focal point around the largest detected face.</p><p>The cropped image area is calculated based on the dimensions of the outer bounding box (“d”) and a specified zoom level (“z”) in the formula (1 ÷ z) × d. The <code>zoom</code> parameter accepts floating points between 0 and 1, where we crop the image to the bounding box when <code>zoom=1</code> and include more of the area around the box as <code>zoom</code> trends toward <code>0</code>.</p><p>Consider an original image that is 2048x2048. First, we create an inference image that is 1024x1024 to meet our size limits for face detection. Second, we define the outer bounding box using the model’s predictions—we’ll use 100x500 for this example. At <code>zoom=0.5</code>, our formula generates a crop area that is twice as large as the bounding box, with new width (“w”) and height (“h”) dimensions of 200x1000:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5KHvyiB2EYWJ7ZGLKm5q99/7fd39d99324b0fce9148fa1d861cc7fa/7.png" />
          </figure><p>We also apply a <code>min</code> function that chooses the smaller number between the input dimensions and the calculated dimensions, ensuring that the new width and height never exceed the dimensions of the image itself. In other words, if you try to zoom out too much, then we use the full width or height of the image instead of defining a crop area that will extend beyond the edge of the image. For example, at <code>zoom=0.25</code>, our formula yields an initial crop area of 400x2000. Here, since the calculated height (2000) is larger than the input height (1024), we use the input height to set the crop area to 400x1024.</p><p>Finally, we need to scale the crop area back to the size of the original image. This applies only when a smaller inference image is created.</p><p>We initially downscaled the original 2048x2048 image by a factor of 2 to create the 1024x1024 inference image. This means that we need to multiply the dimensions of the crop area—400x1024 in our latest example—by 2 to produce our final result: a cropped image that is 800x2048.</p>
    <div>
      <h2>The architecture behind the earliest build</h2>
      <a href="#the-architecture-behind-the-earliest-build">
        
      </a>
    </div>
    <p>In the beta version, we rewrote the model using <a href="https://github.com/tensorflow/rust"><u>TensorFlow Rust</u></a> to make it compatible with our existing Rust-based stack. All of the computations for inference—where the model classifies and locates human faces—were executed on CPUs within our network.</p><p>Initially, this worked well and we saw near-realtime results.</p><p>However, the underlying limitations of our implementation became apparent when we started receiving consistent alerts that our underlying Images service was nearing its limits for memory usage. The increased memory usage didn’t line up with any recent deployments around this time, but a hunch led us to discover that the face cropping compute time graph had an uptick that matched the uptick in memory usage. Further tracing confirmed that AI face cropping was at the root of the problem.</p><p>When a service runs out of memory, it terminates its processes to free up memory and prevent the system from crashing. Since CPU-based implementations share RAM with other processes, this can potentially cause errors for other image optimization operations. In response, we switched our memory allocator from <a href="https://github.com/iromise/glibc"><u>glibc malloc</u></a> to <a href="https://github.com/jemalloc/jemalloc"><u>jemalloc</u></a>. This allowed us to use less memory at runtime, saving about 20 TiB of RAM globally. We also started culling the number of face cropping requests to limit CPU usage.</p><p>At this point, AI face cropping was already limited to our own internal uses and a small number of beta customers. These steps only temporarily reduced our memory consumption. They weren’t sufficient for handling global traffic, so we looked toward a more scalable design for long-term use.</p>
    <div>
      <h2>Doing more with less (memory)</h2>
      <a href="#doing-more-with-less-memory">
        
      </a>
    </div>
    <p>With memory usage alerts looming in the distance, it became clear that we needed to move to a GPU-based approach.</p><p>Unlike with CPUs, a GPU-based implementation avoids contention with other processes because memory access is typically dedicated and managed more tightly. We partnered with the <a href="https://developers.cloudflare.com/workers-ai/"><u>Workers AI</u></a> team, who created a framework for internal teams to integrate payloads into their model catalog for GPU access.</p><p>Some Workers AI models have their own standalone containers; this isn’t practical for every model, as routing traffic to multiple containers can be expensive. When using a GPU through Workers AI, the data needs to travel over the network, which can introduce latency. This is where model size is especially relevant, as network transport overhead becomes more noticeable with larger models.</p><p>To address this, Workers AI wraps smaller models in a single container and utilizes a latency-sensitive routing algorithm to identify the best instance to serve each payload. This means that models can be offloaded when there is no traffic.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4MGV5N7dnK9H5DleDm1gsf/d9888c3e6f1f9057d69509560967abfd/8.png" />
          </figure><p><sup><i>A scheduler is used to optimize how—and when—models in the same container interact with GPUs.</i></sup></p><p>RetinaFace runs on 1 GB of VRAM on the smallest GPU; it’s small enough that it can be hot swapped at runtime alongside similarly sized models. If there is a call for the RetinaFace model, then the Python code will be loaded into the environment and executed.</p><p>As expected, we saw a significant drop in memory usage after we moved the feature to Workers AI. Now, each instance of our Images service consumes about 150 MiB of memory.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/n8UuvaiShes8W19fn1d4Y/d73d3e5f7e030c5da602af8dba54ed18/9.png" />
          </figure><p>With this new approach, memory leaks pose less concern to the overall availability of our service. Workers AI executes models within containers, so they can be terminated and restarted as needed without impacting other processes. Since face cropping runs separately from our Images service, restarting it won’t halt our other image optimization operations.</p>
    <div>
      <h2>Applying AI face cropping to our blog</h2>
      <a href="#applying-ai-face-cropping-to-our-blog">
        
      </a>
    </div>
    <p>As part of our beta launch, we updated the <a href="https://blog.cloudflare.com/"><u>Cloudflare blog</u></a> to apply AI face cropping on author images.</p><p>Authors can submit their own images, which appear as circular profile pictures in both the main blog feed and individual blog posts. By default, CSS centers images within their containers, making off-centered head positions more obvious. When two profile pictures include different amounts of negative space, this can also lead to a visual imbalance where authors’ faces appear at different scales:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7K6ENlSUrQj3StJYbke65l/63ff7b00802377f8e7913907aef36dd8/10.png" />
          </figure><p><sup><i>AI face cropping makes posts with multiple authors appear more balanced.</i></sup></p><p>In the example above, Austin’s original image is cropped tightly around his face. On the other hand, Taylor’s original image includes his torso and a larger margin of the background. As a result, Austin’s face appears larger and closer to the center than Taylor’s does. After we applied AI face cropping to profile pictures on the blog, their faces appear more similar in size, creating more balance and cohesion on their co-authored post.</p>
    <div>
      <h2>A new era of image editing, now in Images</h2>
      <a href="#a-new-era-of-image-editing-now-in-images">
        
      </a>
    </div>
    <p>Many developers already use Images to build scalable media pipelines. Our goal is to accelerate image workflows by automating rote, manual tasks.</p><p>For the Images team, this is only the beginning. We plan to release new AI capabilities, including features like background removal and generative upscale. You can try AI face cropping for free by <a href="https://dash.cloudflare.com/?to=/:account/images/delivery-zones"><u>enabling transformations in the Images dashboard</u></a>.</p> ]]></content:encoded>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Cloudflare Images]]></category>
            <category><![CDATA[Image Optimization]]></category>
            <category><![CDATA[AI]]></category>
            <guid isPermaLink="false">5j8iAw1mBIHhVkaj0UcbSZ</guid>
            <dc:creator>Deanna Lam</dc:creator>
            <dc:creator>Diretnan Domnan</dc:creator>
        </item>
    </channel>
</rss>