YOLOv8 Results Boxes are the structured bounding-box outputs returned after object detection. In the Ultralytics Python API, detection results are stored inside a Results object, and the bounding-box information is available through result.boxes. The current Boxes class provides direct access to coordinates, confidence scores, class IDs, normalized coordinates, and optional tracking IDs.
For standard object detection, the most commonly used properties are:
result.boxes.xyxy
result.boxes.xywh
result.boxes.xyxyn
result.boxes.xywhn
result.boxes.conf
result.boxes.cls
If the results come from tracking, result.boxes.id can also contain persistent tracking IDs. Understanding these properties makes it much easier to build custom detection pipelines, export predictions, filter objects, or connect YOLOv8 outputs to another application.
Introduction to YOLOv8 Results Boxes
When YOLOv8 processes an image, it does not only return an annotated picture. The Python API returns structured result objects containing the information generated by the model.
For a detection model, the workflow is:
Input Image
↓
YOLOv8 Inference
↓
Results Object
↓
Boxes Object
↓
Coordinates
Confidence
Class IDs
Tracking IDs if available
A simple prediction example is:
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
results = model("image.jpg")
result = results[0]
print(result.boxes)
The Boxes object is designed specifically for managing detection boxes and supports several coordinate representations as well as conversion between CPU, GPU, tensor, and NumPy forms.
This structured output is one of the main reasons the Python API is useful. Instead of manually parsing raw neural-network output, developers can work with properties such as xyxy, conf, and cls directly.
What Are Results Boxes in YOLOv8?
Results boxes are the detected object bounding boxes stored inside each YOLOv8 Results object.
For example:
results = model("image.jpg")
boxes = results[0].boxes
The current Ultralytics Boxes class can contain data in either six-column or seven-column form. Standard detections contain coordinates, confidence, and class ID, while tracked detections can additionally include a track ID.
Conceptually:
Standard detection:
x1 y1 x2 y2 confidence class_id
Tracking result:
x1 y1 x2 y2 track_id confidence class_id
This information is wrapped inside the Boxes class so you normally do not need to manually index raw columns.
Role of Bounding Boxes in Detection Results
Bounding boxes identify where detected objects appear inside the image.
For example:
Detected class:
person
Bounding box:
x1 = 120
y1 = 80
x2 = 360
y2 = 640
The coordinates define the rectangular region containing the detected object.
Bounding boxes are useful for:
drawing detections
cropping detected objects
tracking objects
counting objects
measuring position
zone monitoring
saving annotations
Without the box coordinates, you would know which classes were detected but not where they appeared.
How YOLOv8 Stores Detection Output
The current Boxes object stores raw detection information internally in:
boxes.data
and exposes easier properties on top of that data.
Important attributes include:
data
orig_shape
is_track
xyxy
xywh
xyxyn
xywhn
conf
cls
id
The orig_shape value stores the original image dimensions as:
(height, width)
and is used when normalized coordinate properties are calculated.
Understanding the YOLOv8 Boxes Object
The Boxes class acts as a convenient interface between the raw model output and your application.
A basic example is:
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
results = model("image.jpg")
boxes = results[0].boxes
print(boxes.xyxy)
print(boxes.conf)
print(boxes.cls)
The number of rows corresponds to the number of detections.
If five objects were detected:
boxes.xyxy shape
→ [5, 4]
boxes.conf shape
→ [5]
boxes.cls shape
→ [5]
The corresponding row positions refer to the same detection.
Bounding Box Coordinates
The most common box property is:
boxes.xyxy
It returns coordinates in:
[x1, y1, x2, y2]
format.
For example:
print(result.boxes.xyxy)
might produce values conceptually like:
[
[120, 80, 360, 640],
[500, 200, 720, 480]
]
Current Ultralytics documents xyxy as an (N, 4) tensor or NumPy array where N is the number of detected boxes.
Confidence Scores
Confidence values are available using:
boxes.conf
For example:
print(result.boxes.conf)
may return:
tensor([0.92, 0.81, 0.67])
Each confidence value corresponds to the detection at the same index.
For example:
Box 0 → confidence 0.92
Box 1 → confidence 0.81
Box 2 → confidence 0.67
The current Boxes.conf property returns one confidence score per detection.
Class IDs
Predicted class IDs are stored in:
boxes.cls
Example:
print(result.boxes.cls)
may return:
tensor([0., 2., 7.])
These values represent class indices.
You can convert them to names using:
names = result.names
for box in result.boxes:
class_id = int(box.cls[0])
class_name = names[class_id]
print(class_name)
The current cls property returns one class identifier for each detected box.
YOLOv8 Bounding Box Coordinate Formats
YOLOv8 exposes several box coordinate formats so developers do not need to manually convert them.
The main forms are:
xyxy
xywh
xyxyn
xywhn
The difference is whether coordinates represent corners or center dimensions and whether they are absolute pixels or normalized values.
XYXY Format
Access:
boxes.xyxy
Format:
[x1, y1, x2, y2]
where:
x1 = left edge
y1 = top edge
x2 = right edge
y2 = bottom edge
Example:
[100, 60, 400, 500]
means the box begins at pixel coordinate:
(100, 60)
and ends at:
(400, 500)
Ultralytics stores standard box coordinates internally in this form.
XYWH Format
Access:
boxes.xywh
Format:
[x_center, y_center, width, height]
For example:
[250, 280, 300, 440]
means:
center x = 250
center y = 280
width = 300
height = 440
Current Ultralytics converts xyxy boxes into center-based XYWH form automatically through the xywh property.
XYWH is useful for:
custom visualization
geometric calculations
YOLO-style annotation conversion
object-center analysis
Normalized Coordinates
Normalized coordinates scale values relative to the original image dimensions.
YOLOv8 provides:
boxes.xyxyn
and:
boxes.xywhn
xyxyn returns:
[x1, y1, x2, y2]
normalized approximately to:
0.0–1.0
relative to the original image dimensions.
xywhn returns normalized:
[x_center, y_center, width, height]
For example:
print(result.boxes.xywhn)
could produce:
0.50 0.42 0.20 0.31
Normalized coordinates are especially useful when saving YOLO-format labels because they do not depend directly on pixel resolution.
How to Access YOLOv8 Results Boxes in Python
Accessing box results requires only a few lines of Python.
Basic workflow:
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
results = model("image.jpg")
result = results[0]
boxes = result.boxes
Once the Boxes object is available, coordinates, classes, and confidence values can be extracted directly.
Access results.boxes
Example:
results = model("image.jpg")
result = results[0]
print(result.boxes)
If several images are processed:
results = model([
"image1.jpg",
"image2.jpg"
])
for result in results:
print(result.boxes)
Each Results object contains the boxes for its own image.
This means:
results[0].boxes
→ detections from image 1
results[1].boxes
→ detections from image 2
Extract Box Coordinates
To get all boxes:
boxes = result.boxes.xyxy
print(boxes)
To process each detected object separately:
for box in result.boxes:
xyxy = box.xyxy[0]
print(xyxy)
You can convert individual values:
for box in result.boxes:
x1, y1, x2, y2 = box.xyxy[0].tolist()
print(
x1,
y1,
x2,
y2
)
Extract Confidence and Class Values
Example:
for box in result.boxes:
confidence = float(box.conf[0])
class_id = int(box.cls[0])
print(
"Class:",
class_id,
"Confidence:",
confidence
)
You can also retrieve the class name:
for box in result.boxes:
class_id = int(box.cls[0])
class_name = result.names[class_id]
confidence = float(box.conf[0])
print(
class_name,
confidence
)
This gives a human-readable output such as:
person 0.93
car 0.87
dog 0.76
Working with Multiple Detection Boxes
Most real-world images contain more than one detection.
The Boxes object makes it easy to iterate through all predictions and maintain the relationship between coordinates, confidence, and class ID.
The important rule is that matching indices refer to the same detection.
For example:
boxes.xyxy[3]
boxes.conf[3]
boxes.cls[3]
all represent detection number 3.
Loop Through Detected Objects
A common loop is:
for box in result.boxes:
xyxy = box.xyxy[0].tolist()
confidence = float(box.conf[0])
class_id = int(box.cls[0])
print(
xyxy,
confidence,
class_id
)
This is useful when every object needs individual processing.
For example:
Detection 1
→ check class
→ store result
Detection 2
→ check class
→ store result
Match Boxes with Classes
Example:
for box in result.boxes:
class_id = int(box.cls[0])
class_name = result.names[class_id]
coordinates = box.xyxy[0].tolist()
print(
class_name,
coordinates
)
You might obtain:
person [100, 50, 280, 600]
car [350, 300, 700, 610]
This makes it easy to build class-specific logic.
Filter Specific Predictions
Suppose you only want persons.
If the person class ID is:
0
you can use:
for box in result.boxes:
class_id = int(box.cls[0])
if class_id != 0:
continue
print(box.xyxy)
You can also combine class and confidence filtering:
for box in result.boxes:
class_id = int(box.cls[0])
confidence = float(box.conf[0])
if class_id == 0 and confidence >= 0.70:
print(box.xyxy)
YOLOv8 Boxes for Object Tracking
When YOLOv8 Track mode is used, bounding boxes can include tracking IDs in addition to the normal coordinates, confidence, and class values.
Current Ultralytics stores standard detection boxes with six columns, while tracked boxes contain seven values because a tracking ID is included. The Boxes.is_track attribute indicates whether IDs are present.
Access Tracking IDs
Tracking example:
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
results = model.track(
source="video.mp4",
stream=True,
persist=True
)
for result in results:
if (
result.boxes is not None
and result.boxes.id is not None
):
print(result.boxes.id)
Current Boxes.id returns tracking IDs only when tracking information is available. Otherwise, it returns None.
You can convert them to integers:
track_ids = (
result.boxes.id
.int()
.cpu()
.tolist()
)
Match Boxes Across Video Frames
Tracking IDs make it possible to associate the same object across frames.
Example:
Frame 1
Person box → ID 4
Frame 2
Person box → ID 4
Frame 3
Person box → ID 4
A typical loop is:
for result in results:
if (
result.boxes is None
or result.boxes.id is None
):
continue
for box in result.boxes:
track_id = int(box.id[0])
class_id = int(box.cls[0])
coordinates = box.xyxy[0].tolist()
print(
track_id,
class_id,
coordinates
)
This can be used for counting, trajectories, dwell time, entry and exit detection, or object history.
Convert and Export YOLOv8 Box Results
YOLOv8 detection results often begin as PyTorch tensors, particularly when inference runs on a GPU.
For logging, JSON, CSV, NumPy processing, or database storage, you may need to move the data to CPU memory and convert it.
The Boxes class inherits convenience methods such as cpu(), numpy(), cuda(), and to().
Convert Boxes to NumPy
The cleanest approach is:
boxes_numpy = result.boxes.numpy()
The returned Boxes object contains NumPy-backed data.
You can then access:
print(boxes_numpy.xyxy)
print(boxes_numpy.conf)
print(boxes_numpy.cls)
If you only need one property:
xyxy = result.boxes.xyxy.cpu().numpy()
when the property is a PyTorch tensor.
Move Box Data from GPU to CPU
Use:
boxes_cpu = result.boxes.cpu()
Then:
print(boxes_cpu.xyxy)
This is important when inference runs on CUDA.
A common pattern is:
coordinates = (
result.boxes.xyxy
.cpu()
.numpy()
)
The cpu() method returns a copy of the Boxes object with tensor data moved to CPU memory.
Save Bounding Box Results
For custom export:
import csv
with open(
"detections.csv",
"w",
newline=""
) as f:
writer = csv.writer(f)
writer.writerow([
"class_id",
"confidence",
"x1",
"y1",
"x2",
"y2"
])
for box in result.boxes:
class_id = int(box.cls[0])
confidence = float(box.conf[0])
x1, y1, x2, y2 = (
box.xyxy[0]
.cpu()
.tolist()
)
writer.writerow([
class_id,
confidence,
x1,
y1,
x2,
y2
])
The same structure can be adapted for:
JSON
CSV
database rows
REST API payloads
analytics events
Current Ultralytics Results also contains summary functionality that produces structured dictionaries containing class name, class ID, confidence, box coordinates, and track ID when tracking is enabled.
Filtering YOLOv8 Results Boxes
Filtering can happen either during prediction or after the results are returned.
Prediction-level filtering reduces detections before you receive them.
Result-level filtering lets your application apply custom rules to the returned boxes.
Both approaches are useful depending on the workflow.
Filter by Confidence Score
During prediction:
results = model.predict(
source="image.jpg",
conf=0.50
)
After prediction:
for box in result.boxes:
confidence = float(box.conf[0])
if confidence >= 0.70:
print(box.xyxy)
Vector-style filtering is also possible:
boxes = result.boxes
mask = boxes.conf >= 0.70
high_conf_boxes = boxes[mask]
Because Boxes supports indexing, this can produce a filtered Boxes object.
Filter by Class ID
Suppose class ID 2 represents car.
You can filter:
for box in result.boxes:
if int(box.cls[0]) == 2:
print(box.xyxy)
Or:
boxes = result.boxes
car_boxes = boxes[
boxes.cls == 2
]
This is useful when one model detects many classes but the application only cares about specific categories.
Select Specific Bounding Boxes
You can combine conditions.
Example:
selected = []
for box in result.boxes:
cls_id = int(box.cls[0])
conf = float(box.conf[0])
if cls_id == 2 and conf >= 0.80:
selected.append(
box.xyxy[0].cpu().tolist()
)
print(selected)
This could represent:
only cars
with confidence >= 0.80
Additional filters can also use:
box width
box height
box center
screen region
tracking ID
depending on the application.
Common YOLOv8 Results Boxes Problems
Problems with results.boxes usually come from misunderstanding output shape, tensor devices, empty predictions, or coordinate formats.
Checking the object type and shape is often the fastest way to diagnose the issue.
No Boxes Returned
If:
print(result.boxes)
shows no detections, possible reasons include:
target object absent
confidence threshold too high
incorrect model
poor model performance
very small objects
unsupported input
Try inspecting:
print(len(result.boxes))
If the length is:
0
the prediction completed but no boxes survived detection filtering.
This is different from the inference itself failing.
Incorrect Coordinate Values
A common issue is confusing:
xyxy
with:
xywh
For example:
[100, 50, 300, 400]
in XYXY means:
left = 100
top = 50
right = 300
bottom = 400
but in XYWH it means:
center x = 100
center y = 50
width = 300
height = 400
The meanings are completely different.
Always check whether you are using:
boxes.xyxy
or:
boxes.xywh
before interpreting the numbers.
Empty Detection Results
A result object may exist even if no objects were detected.
For example:
results = model("empty_scene.jpg")
result = results[0]
may still be valid while:
len(result.boxes)
is zero.
Use:
if len(result.boxes) == 0:
print("No detections")
before attempting to loop through detections.
An empty Boxes collection is not necessarily an error.
CUDA Tensor Conversion Errors
A common PyTorch error occurs when trying to convert a GPU tensor directly to NumPy.
Incorrect:
array = result.boxes.xyxy.numpy()
when the tensor is still on CUDA.
Use:
array = (
result.boxes.xyxy
.cpu()
.numpy()
)
or convert the whole result structure:
boxes = result.boxes.cpu().numpy()
Current Ultralytics exposes both cpu() and numpy() methods on the Boxes object specifically for these conversions.
FAQs About YOLOv8 Results Boxes
What is results.boxes in YOLOv8?
results.boxes is the bounding-box container attached to an Ultralytics detection Results object.
It stores:
coordinates
confidence scores
class IDs
optional tracking IDs
and provides multiple coordinate formats such as xyxy, xywh, xyxyn, and xywhn.
How do I get bounding box coordinates from YOLOv8?
Example:
results = model("image.jpg")
boxes = results[0].boxes.xyxy
print(boxes)
To process individual detections:
for box in results[0].boxes:
print(box.xyxy[0])
The returned format is:
[x1, y1, x2, y2]
for xyxy.
What does boxes.xyxy mean in YOLOv8?
boxes.xyxy contains coordinates in:
[x1, y1, x2, y2]
format.
Where:
x1 = left
y1 = top
x2 = right
y2 = bottom
Current Ultralytics returns this as an (N, 4) tensor or array where N is the number of detections.
What is the difference between xyxy and xywh?
xyxy represents two opposite box corners:
x1 y1 x2 y2
xywh represents:
x_center
y_center
width
height
Ultralytics provides both directly through the Boxes object.
How do I get confidence scores from YOLOv8 boxes?
Use:
confidence = result.boxes.conf
or:
for box in result.boxes:
confidence = float(box.conf[0])
print(confidence)
The conf property returns one confidence value for every detection.
How do I get class IDs from YOLOv8 results?
Use:
class_ids = result.boxes.cls
For individual boxes:
for box in result.boxes:
class_id = int(box.cls[0])
print(class_id)
To obtain the name:
class_name = result.names[class_id]
The current cls property provides the category ID associated with every detection box.
Can YOLOv8 results boxes include tracking IDs?
Yes.
When Track mode returns tracked boxes, the Boxes structure can contain:
result.boxes.id
The current implementation identifies tracked box data using is_track=True, and the tracking ID is included as an additional value in the underlying box data.
For example:
if result.boxes.id is not None:
print(result.boxes.id)
Conclusion
YOLOv8 Results Boxes provide structured access to the detections returned by an Ultralytics object detection model.
A standard Python workflow is:
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
results = model("image.jpg")
result = results[0]
boxes = result.boxes
The most important properties are:
boxes.xyxy
→ [x1, y1, x2, y2]
boxes.xywh
→ [x_center, y_center, width, height]
boxes.xyxyn
→ normalized XYXY
boxes.xywhn
→ normalized XYWH
boxes.conf
→ confidence scores
boxes.cls
→ class IDs
boxes.id
→ tracking IDs when available
All of these properties are part of the current Ultralytics Boxes API.
A complete extraction example is:
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
results = model("image.jpg")
for result in results:
if result.boxes is None:
continue
for box in result.boxes:
x1, y1, x2, y2 = (
box.xyxy[0]
.cpu()
.tolist()
)
confidence = float(
box.conf[0]
)
class_id = int(
box.cls[0]
)
class_name = result.names[
class_id
]
print(
class_name,
confidence,
x1,
y1,
x2,
y2
)
The internal relationship can be summarized as:
YOLOv8 Prediction
↓
Results Object
↓
Boxes Object
↓
Coordinates
Confidence
Class
Tracking ID
For normal detection, the internal box data contains coordinates, confidence, and class information. Tracking adds an optional track ID. Current Ultralytics supports six-value standard detections and seven-value tracked detection rows internally.
Understanding the Boxes object is especially important when building custom applications because it allows YOLOv8 detections to be filtered, converted, exported, tracked, counted, stored, and connected directly to application logic without manually decoding raw neural-network outputs.
I’m Jane Austen, a skilled content writer with the ability to simplify any complex topic. I focus on delivering valuable tips and strategies throughout my articles.