Skip to main content

remove-background-ai

Remove the background from a photo with OpenAI's GPT Image 2.5 and get a transparent PNG, from the command line or from Python.

export OPENAI_API_KEY=sk-...
uvx remove-background-ai photo.jpg

That writes photo-no-bg.png next to photo.jpg: your original pixels, at their original size, with the background made transparent.

⚠️ Much of this is AI-generated, and not formally reviewed by hand or eye. It's published chiefly for myself: for my own reference, use, and for experimentation with the whole open-source publishing process. I also use this code: I dogfood it. It works, for me. I also write tests, and run them to check that it works, and does what it says.

Installation

Run it without installing, with uv:

uvx remove-background-ai photo.jpg

Or install it:

pip install remove-background-ai

It needs Python 3.14 or later and an OpenAI API key with access to the GPT Image 2.5 models. Set the key in the OPENAI_API_KEY environment variable; the command has no option for it. The OpenAI SDK's other variables, such as OPENAI_BASE_URL, OPENAI_ORG_ID and OPENAI_PROJECT_ID, work too.

Every image is a paid API call, billed by tokens. See OpenAI's pricing. The free tier cannot use GPT Image 2.5. A paid tier can, and OpenAI may ask you to verify your organisation first.

Usage

Remove the background from one image:

remove-background-ai photo.jpg

Say what to keep when the photo has more than one candidate subject, and what else to remove:

remove-background-ai shelf.jpg --keep "the red backpack, including both straps" \
  --remove "the stand and its shadow on the floor"

Process several images into a directory, and get the results as JSON:

remove-background-ai *.jpg --output-dir cutouts --json

Choose where one image goes, or replace an existing output:

remove-background-ai photo.jpg -o cutout.png --force

Keep the model's own image instead of your original pixels (see How it works):

remove-background-ai photo.jpg --mode generated

Use the faster model at a lower quality:

remove-background-ai photo.jpg --model gpt-image-2.5-flare-2026-09-08 --quality medium

The command prints each output path on standard output, one per line, and its progress and errors on standard error. It never overwrites a file unless you pass --force, and it checks for an existing output before it spends money on an API call.

How it works

The command sends your image to the image edit endpoint with a prompt that says what to keep and what to remove, and asks for a PNG with a transparent background. There is no dedicated background-removal endpoint: GPT Image 2.5 redraws the image with the background removed.

The model redraws the whole image, so it can soften a label, move an edge or change a texture. By default the command keeps only the model's transparency and puts it on your original pixels. You choose between two output modes:

Mode What you get Size
original (default) Your pixels, with the model's alpha channel Your image's size
generated The PNG the model returned, byte for byte The size sent to the model

In original mode the transparency is still the model's work. An edge can land a few pixels off, and a thin band of the old background can survive along the subject's outline: in testing, a strip of brick wall stayed along the top of a backpack. generated mode gives cleaner edges, because the model redraws them. Look at the result on a dark and a light backdrop before you rely on it. generated mode keeps the provenance metadata (C2PA) that OpenAI embeds in the PNG. original mode writes a new file, so that metadata is lost.

Image sizes

GPT Image 2.5 only produces images whose width and height are multiples of 16, with an aspect ratio no wider than 3:1 and an area of 655,360 to 8,294,400 pixels. Anything over 3,686,400 pixels (2560×1440) is experimental. The command sends your image at the nearest size the model can produce, never an experimental one, and scales the returned transparency back to your image's size.

Your image Sent to the model Why
1024×1024 1024×1024 Already a size the model produces
1920×1080 1920×1088 1080 is not a multiple of 16
512×512 816×816 Below the minimum area
6000×4000 2336×1552 Above the largest standard area
3000×900 refused Wider than 3:1

Sending 1920×1080 as 1920×1088 changes the aspect ratio slightly. Scaling the transparency back to 1920×1080 undoes that change, so the cutout does not shift.

The command first turns the image upright using its EXIF orientation. It accepts any format Pillow can open (JPEG, PNG, WebP, TIFF and others) in any colour mode, and always writes an 8-bit RGBA PNG. If your image already has transparency, the output never makes it more opaque. An embedded RGB colour profile goes to the model with the image and stays in the original output. Other profiles would describe the wrong colours after conversion, so they are dropped. CMYK images are converted to RGB without colour management, so their colours can shift; convert them to RGB yourself first if colour matters. EXIF data is not copied. Animated images are refused.

Masks

If the model keeps the wrong thing, give it a mask: an image the same size as the photo (after EXIF rotation), white where the subject is and black elsewhere.

remove-background-ai photo.jpg --mask subject.png

Grey at half intensity or brighter counts as white. The mask guides the model, which can still stray over its edges.

JSON output

--json replaces the list of paths with one JSON array. Each image gets an object, in the order given, whether it succeeded or failed:

[
  {
    "input": "mug.jpg",
    "output": "mug-no-bg.png",
    "mode": "original",
    "model": "gpt-image-2.5-sunburst-2026-09-08",
    "quality": "medium",
    "source_size": "1300x1132",
    "model_size": "1312x1136",
    "output_size": "1300x1132",
    "request_id": "req_e4351b4660894c96ad6f08a86fc013aa",
    "usage": {
      "input_tokens": 1618,
      "output_tokens": 440,
      "total_tokens": 2058,
      "input_tokens_details": {"image_tokens": 1476, "text_tokens": 142},
      "output_tokens_details": {"image_tokens": 440, "text_tokens": 0}
    }
  },
  {
    "input": "broken.png",
    "error": "broken.png cannot be read as an image: cannot identify image file 'broken.png'"
  }
]

usage is whatever token counts the API reported, or null. Errors also go to standard error, so keep the two streams apart when you parse the JSON.

Exit codes

Code Meaning
0 Every image succeeded
1 Interrupted (Ctrl-C), or a broken pipe
2 The command line was wrong: an unknown option, a missing file, -o or --mask with several images, -o with --output-dir, an output that is also an input or the mask, or two images that would write the same output
3 The tool refused an image or an output before or after the API call: it cannot be read, is animated, is wider than 3:1, its mask does not match, or the output exists or cannot be written
4 The OpenAI call failed or returned an unusable image, or OPENAI_API_KEY is not set

With several images the command carries on after a failure. If any image failed, it exits with 4 when at least one failure was an API failure, and 3 otherwise.

Timeouts and retries

The OpenAI client waits up to 300 seconds on each network operation and retries twice after a rate limit, a server error, a dropped connection or a timeout, pausing between attempts as the server asks. There is no overall deadline, so a slow image can take many minutes. A retried request can be billed more than once, because the server may have finished the first attempt.

Python library

from pathlib import Path

from remove_background_ai import RemovalOptions, remove_background

cutout = remove_background(
    Path("photo.jpg"),
    options=RemovalOptions(keep="the red backpack", quality="medium"),
)
Path("photo-no-bg.png").write_bytes(cutout.png)
print(cutout.model_size, cutout.request_id)

remove_background validates its arguments with Pydantic and raises pydantic.ValidationError for the wrong types. It takes a Path (not a str) as its only positional argument; options, mask and editor are keyword-only. RemovalOptions takes model (default gpt-image-2.5-sunburst-2026-09-08), quality (low, medium, high, xhigh, max or auto; default high), mode (original or generated), keep and remove.

It returns a Cutout holding the PNG bytes and their metadata; cutout.model_dump(mode="json") gives the metadata shown under JSON output, without the image. It raises InvalidInputError when it refuses an image and EditError when the API call fails; both are RemoveBackgroundErrors.

To change the timeout or retries, pass your own client:

from pathlib import Path

from openai import OpenAI

from remove_background_ai import OpenAIImageEditor, remove_background

editor = OpenAIImageEditor(OpenAI(timeout=600, max_retries=0))
cutout = remove_background(Path("photo.jpg"), editor=editor)

Any object with an edit(EditRequest) -> EditResponse method can stand in for OpenAIImageEditor, which is how the tests run without the API.

CLI reference

Usage: remove-background-ai [OPTIONS] IMAGES...

  Send each image to GPT Image 2.5 and write a transparent PNG. By default, the result
  keeps the original pixels and size and takes only transparency from the model. Set
  OPENAI_API_KEY before running this command.

  Examples:

      remove-background-ai photo.jpg
      remove-background-ai photo.jpg -o portrait.png
      remove-background-ai photo.jpg other.png -d cutouts --json
      remove-background-ai photo.jpg --keep "the red backpack, including both straps"

Options:
  -o, --output FILE               Write the PNG to FILE.
  -d, --output-dir DIRECTORY      Write PNGs to DIRECTORY.
  --force                         Replace output files that already exist.
  --keep TEXT                     What to keep, for example the red backpack and its
                                  straps.
  --remove TEXT                   What to remove besides the background.
  --mask FILE                     Mask FILE: white keeps, black removes; same size as
                                  the image.
  --mode [original|generated]     Keep original pixels and size, or use the generated
                                  image.  [default: original]
  --model [gpt-image-2.5-sunburst-2026-09-08|gpt-image-2.5-sunburst|gpt-image-2.5-flare-2026-09-08|gpt-image-2.5-flare]
                                  GPT Image model to use.  [default: gpt-
                                  image-2.5-sunburst-2026-09-08]
  --quality [low|medium|high|xhigh|max|auto]
                                  Image edit quality.  [default: high]
  --json                          Write a JSON array to stdout.
  --version                       Show the version and exit.
  --help                          Show this message and exit.

  Exit codes: 0 success; 1 general failure; 2 usage error; 3 input or output refused; 4
  image edit failed.

Development

git clone https://github.com/nmpowell/remove-background-ai
cd remove-background-ai
uv sync --locked
uv run pytest
uv run mypy
uv run ruff check .
uv run ruff format --check .

The tests run without the API, except one live test that makes a real call and costs one image. It is skipped unless you ask for it:

RUN_LIVE_OPENAI_TESTS=1 OPENAI_API_KEY=sk-... uv run pytest -m live

After changing the command's options, regenerate the CLI reference above with uv run cog -r README.md. The test suite fails while the reference is out of date.

Licence

Apache-2.0. See LICENSE.

Metadata

Release files for remove-background-ai 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for remove-background-ai 0.1.0
File Size Uploaded Provenance
remove_background_ai-0.1.0.tar.gz 23.5 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for remove-background-ai 0.1.0
File Interpreter ABI Platform
remove_background_ai-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 45.2 kB

Release files / remove_background_ai-0.1.0.tar.gz

Download URL remove_background_ai-0.1.0.tar.gz
Size 23.5 kB
Tags Source
SHA-256 checksum
How to use checksums
b4b5de239e84d871c71ddca7289c4deffdb481e83ee9ebd3926509fab0c1a50a
BLAKE2b-256 checksum
How to use checksums
912751aee768a1572d833188896755e90b0fae76ad4bc3771ef77f49eb7c9dc0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.

Transparency log

Release files / remove_background_ai-0.1.0-py3-none-any.whl

Download URL remove_background_ai-0.1.0-py3-none-any.whl
Size 21.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
470d409f5eda67e701f791aa7e2a26e418ca07255b7c8c3885f869dfeb2e76fa
BLAKE2b-256 checksum
How to use checksums
41a4d42818f21741afbf0fa58af047b7840050f5f0e6a5c404d22ff5beda072a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.

Transparency log

Security for remove-background-ai 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for remove_background_ai-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page