How can you remove the background around one object without cutting it out by hand? In this Python tutorial, a pretrained YOLO segmentation model predicts a bus mask on a synthetic city image. We turn that mask into an alpha channel and save a PNG with a transparent background.
Our example selects one predicted bus on a 1024 × 1024 image and runs locally on a Windows CPU. In this run the model returned 12 predictions; those are model outputs, not a verified count of physical objects. A cyclist partly blocks the bus, and the predicted mask does not reconstruct the hidden part.
Watch the Python and YOLO tutorial
Watch the full tutorial or see the short demonstration.

Box versus mask versus alpha
A bounding box gives a rectangular region. It can contain background or another object, as the cyclist in this image illustrates. An instance segmentation mask marks pixels assigned to one predicted object. That boundary is an estimate; inspect it around occlusion, fine details and similar colors. See the Ultralytics instance segmentation documentation.
A PNG alpha channel controls transparency. In this binary example, an alpha value of 0 means transparent and 255 means opaque. A checkerboard is only a way to visualize transparent pixels: it is not the content of the alpha channel. This code keeps the image's full canvas size instead of cropping to the box.
What you need
The demonstrated run used Windows, Python 3.13.9, Ultralytics 8.4.24, PyTorch 2.10.0+cpu, OpenCV 4.13.0 and NumPy 2.3.5. Other versions or hardware can produce different results. Create a project folder and a virtual environment using Windows Command Prompt:
py -3.13 -m venv .venv
.venv\Scripts\python.exe -m pip install ultralytics==8.4.24
The command pins Ultralytics, not the full set of transitive dependencies; the exact fresh online installation has not been independently tested. Package installation and obtaining the checkpoint require an internet connection unless you already have suitable local files. Once the tested environment and inputs were present, the prediction and export were repeated with network access blocked.
Put an image and a segmentation checkpoint beside the script
Place a permitted color image as image.png and the official YOLOv8n-seg checkpoint as yolov8n-seg.pt alongside the Python file. This example image is included in lesson 37 of my Computer Vision course. For a different permitted input, predictions and output will differ.
background-demo/
├── remove_background.py
├── image.png
└── yolov8n-seg.pt
The tested checkpoint has SHA-256 a7cd8f929e1903d78a12a48efecab430209f18dc46cb96c3599a5980c63c423c. A hash identifies file bytes; it does not by itself grant usage rights. The model file is not hosted by this article.
Complete runnable example
Save the following as remove_background.py in the project folder. The script checks that the local files exist, selects the highest-scoring bus prediction and stops with an explicit message if there is no usable mask or no bus. The target class is an intentional choice for this image; change it deliberately for another object.
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright (c) 2026 ARTSCI - Author of the AI/ML/CV course materials.
"""Isolate the highest-scoring bus prediction as a transparent PNG."""
from pathlib import Path
import os
ROOT = Path(__file__).resolve().parent
config_dir = ROOT / 'config'
config_dir.mkdir(exist_ok=True)
os.environ['YOLO_CONFIG_DIR'] = str(config_dir)
os.environ['YOLO_OFFLINE'] = 'true'
import cv2
import numpy as np
import torch
from ultralytics import YOLO
def save_png(path, image):
if not cv2.imwrite(str(path), image):
raise OSError(f'Could not save {path}')
def main():
image_path = ROOT / 'image.png'
weights_path = ROOT / 'yolov8n-seg.pt'
for path in (image_path, weights_path):
if not path.is_file():
raise FileNotFoundError(f'Required local file: {path}')
image = cv2.imread(str(image_path), cv2.IMREAD_COLOR)
if image is None:
raise ValueError(f'Cannot decode image: {image_path}')
torch.set_num_threads(4)
model = YOLO(str(weights_path))
result = model.predict(
source=image, conf=0.25, iou=0.70, imgsz=640, device='cpu',
retina_masks=True, max_det=300, verbose=False,
)[0]
if result.masks is None or result.boxes is None:
raise ValueError('No segmentation masks were returned for this image.')
candidates = [i for i, box in enumerate(result.boxes)
if result.names[int(box.cls.item())] == 'bus']
if not candidates:
raise ValueError('No bus prediction passed the confidence threshold.')
selected = max(candidates, key=lambda i: float(result.boxes[i].conf.item()))
box = result.boxes[selected]
mask = result.masks.data[selected].cpu().numpy().astype(np.uint8)
if mask.shape != image.shape[:2]:
raise ValueError(f'Mask shape {mask.shape} differs from image {image.shape[:2]}.')
alpha = mask * 255
isolated = cv2.cvtColor(image, cv2.COLOR_BGR2BGRA)
isolated[:, :, 3] = alpha
isolated[mask == 0, :3] = 0 # Do not keep hidden background pixels.
output = ROOT / 'output'
output.mkdir(exist_ok=True)
save_png(output / 'isolated_bus.png', isolated)
save_png(output / 'mask.png', alpha)
highlighted = image.copy()
highlighted[mask == 1] = (
image[mask == 1].astype(np.float32) * 0.55
+ np.array([45, 190, 70], dtype=np.float32) * 0.45
).astype(np.uint8)
left, top, right, bottom = [round(float(v)) for v in box.xyxy[0].tolist()]
cv2.rectangle(highlighted, (left, top), (right, bottom), (40, 220, 255), 3)
save_png(output / 'selected_mask_and_box.png', highlighted)
print('Image width x height:', image.shape[1], 'x', image.shape[0])
print('Total returned predictions:', len(result.boxes))
print('Selected class:', result.names[int(box.cls.item())])
print('Selected confidence score:', round(float(box.conf.item()), 4))
print('Selected box xyxy:', [round(float(v), 1) for v in box.xyxy[0].tolist()])
print('Foreground pixels:', int(mask.sum()))
print('Background pixels:', int(mask.size - mask.sum()))
print('Saved:', output / 'isolated_bus.png')
if __name__ == '__main__':
main()
From the project directory, run:
.venv\Scripts\python.exe remove_background.py
The script writes output/isolated_bus.png with four BGRA channels, output/mask.png as the alpha mask and output/selected_mask_and_box.png for inspection. The rectangle and colored mask are diagnostic overlays; they are not drawn onto the transparent PNG.
Follow the image through the code
- Read and predict. OpenCV reads a color image, then the local segmentation model runs on the CPU. The example fixes
conf=0.25,iou=0.70andimgsz=640.retina_masks=Truerequests masks at the original image resolution; the explicit shape check rejects a mismatch instead of silently combining misaligned arrays. - Select one instance. The script filters predictions labelled
bus, then chooses the highest confidence among those candidates. It uses the same selected index for the box and mask. Confidence is a model score, not a calibrated guarantee that the label or every mask pixel is correct. - Make transparency. The returned mask in this run contains 0 and 1. Multiplying it by 255 creates the alpha plane. OpenCV adds an alpha channel to its BGR image to make BGRA; the code assigns the alpha values and clears hidden background color pixels. It then saves PNG, which preserves transparency.

Read and verify the result
The recorded run returned 12 predictions in total. The selected bus had score approximately 0.9458 and box [48.2, 412.2, 476.4, 716.6] in original-image coordinates. Its binary mask produced 98,828 opaque pixels and 949,748 transparent pixels on a 1024 × 1024 canvas. These are measurements of this output, not a pixel-accuracy evaluation against a ground-truth mask.
To check your saved file instead of relying on the checkerboard display, save this separate snippet as verify_alpha.py in the project folder. It reads the PNG with its alpha channel intact and reports its shape and distinct alpha values:
import cv2
import numpy as np
image = cv2.imread("output/isolated_bus.png", cv2.IMREAD_UNCHANGED)
if image is None or image.ndim != 3 or image.shape[2] != 4:
raise ValueError("Expected a readable image with four BGRA channels")
print("Shape:", image.shape)
print("Alpha values:", np.unique(image[:, :, 3]).tolist())
From the project folder, run .venv\Scripts\python.exe verify_alpha.py.
For the demonstrated output it reports a shape of (1024, 1024, 4) and alpha values [0, 255]. A different image or mask can produce different dimensions and counts. A viewer with a solid background may not make transparency obvious; verify the alpha channel or place the image on a contrasting background.
What this example does not do
Segmentation predicts the visible instance; it does not recover bus pixels hidden behind the cyclist. The binary alpha can also produce rough edges, and the model can include background or miss the object. If there is no suitable bus, inspect the input and class label; lowering the threshold may expose weaker candidates but does not guarantee a correct mask. Validate with representative images and an appropriate reference before relying on the output in a real application.
For another practical view of model outputs, see detecting objects from text labels with YOLO-World. The Ultralytics object-isolation guide discusses segmentation masks and transparent PNG export.
Code and component licenses
The complete example script on this page is © 2026 ARTSCI - Author of the AI/ML/CV course materials, licensed under GNU AGPL-3.0 only, without warranty. Preserve applicable notices and provide corresponding source when sharing covered modifications. This code notice does not automatically license the course image, narration or video.
Ultralytics software and model weights retain their own terms; review the Ultralytics assets license and licensing information for your use. Other dependencies have their own licenses. My full course covers more practical applications: Computer Vision: OpenCV, Machine Learning and YOLO.