The YOLOv8 output format depends on the task being performed. Standard object detection returns bounding boxes, class IDs, confidence scores, and related image metadata. Segmentation adds masks, pose estimation adds keypoints, oriented bounding box models return rotated boxes, and tracking can add persistent object IDs. In the Ultralytics Python API, these outputs are organized inside a Results object returned for each image or video frame.
For normal detection, the most important output structure is:
result.boxes
which contains data such as:
bounding-box coordinates
confidence scores
class IDs
tracking IDs when available
Understanding the Results structure is essential when predictions need to be filtered, saved, converted to JSON or NumPy, sent to another application, or analyzed programmatically.
Introduction to YOLOv8 Output Format
YOLOv8 does not return only an annotated image after inference. The Ultralytics Python API produces structured prediction data that can be accessed directly.
A simple detection workflow is:
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
results = model("image.jpg")
For a normal image, results is a list containing one Results object for each processed image. When stream=True is used, Ultralytics instead yields Results objects through a generator.
Conceptually:
Input Image
↓
YOLOv8
↓
Results Object
↓
Task-Specific Output
For detection:
Results
└── boxes
For segmentation:
Results
├── boxes
└── masks
For pose:
Results
├── boxes
└── keypoints
For OBB:
Results
└── obb
The Results API provides a common interface regardless of which YOLO task is being used.
What Does YOLOv8 Output Contain?
The exact output depends on the model task, but standard YOLOv8 detection produces object-level information.
For every retained detection, you can usually access:
box coordinates
class ID
confidence score
class name through result.names
A standard detection row stored in result.boxes.data currently follows the structure:
[x1, y1, x2, y2, confidence, class_id]
and tracked detections can include an additional tracking ID.
Bounding Box Predictions
Bounding boxes identify where objects appear.
For example:
Detected object:
car
Bounding box:
x1 = 110
y1 = 140
x2 = 470
y2 = 520
In Python:
result = results[0]
print(result.boxes.xyxy)
The output may look conceptually like:
tensor([
[110, 140, 470, 520],
[520, 180, 740, 490]
])
Each row represents one detected object.
Class IDs and Class Names
The numeric class IDs are stored in:
result.boxes.cls
Example:
print(result.boxes.cls)
could produce:
tensor([0., 2., 7.])
These numbers correspond to the model’s class mapping.
The mapping is available through:
result.names
For example:
for box in result.boxes:
class_id = int(box.cls[0])
class_name = result.names[class_id]
print(class_name)
The Results object exposes names as a dictionary mapping class indices to human-readable class names.
Confidence Scores
Every detection also includes a confidence value:
result.boxes.conf
Example:
tensor([0.94, 0.87, 0.63])
Conceptually:
Detection 1 → confidence 0.94
Detection 2 → confidence 0.87
Detection 3 → confidence 0.63
Confidence scores can be used to rank or filter detections.
For example:
for box in result.boxes:
confidence = float(box.conf[0])
if confidence >= 0.70:
print(box.xyxy)
YOLOv8 Detection Output Format
YOLOv8 exposes multiple coordinate representations through the Boxes object.
The most common are:
xyxy
xywh
xyxyn
xywhn
The first two use pixel coordinates, while the normalized forms scale coordinates relative to the original image dimensions.
XYXY Bounding Box Format
The XYXY format is:
[x1, y1, x2, y2]
where:
x1 = left edge
y1 = top edge
x2 = right edge
y2 = bottom edge
Access it using:
boxes = result.boxes.xyxy
Example:
[100, 80, 400, 600]
means the box extends from:
top-left:
(100, 80)
to:
bottom-right:
(400, 600)
Current Ultralytics detection Results store raw box coordinates in XYXY form.
XYWH Bounding Box Format
The XYWH format uses:
[x_center, y_center, width, height]
Access:
print(result.boxes.xywh)
For example:
[250, 340, 300, 520]
means:
center x = 250
center y = 340
width = 300
height = 520
This format is useful when calculations depend on object center position or dimensions.
Normalized Coordinates
Normalized coordinates scale values according to image width and height.
Use:
result.boxes.xyxyn
for normalized XYXY coordinates.
Use:
result.boxes.xywhn
for normalized XYWH.
A normalized output might be:
0.52 0.46 0.21 0.34
Normalized coordinates are especially useful when exporting YOLO-style label information because the values are resolution-independent.
Understanding the YOLOv8 Results Object
Ultralytics wraps prediction data inside a Results object.
The Results object currently includes common attributes such as:
orig_img
orig_shape
boxes
masks
probs
keypoints
obb
speed
names
path
save_dir
Only the task-relevant fields are populated.
For example:
result = results[0]
print(result.orig_shape)
print(result.names)
print(result.boxes)
Results Boxes
For object detection:
result.boxes
contains the Boxes object.
Important properties include:
result.boxes.data
result.boxes.xyxy
result.boxes.xywh
result.boxes.xyxyn
result.boxes.xywhn
result.boxes.conf
result.boxes.cls
result.boxes.id
Standard raw box data currently has shape:
(N, 6)
or:
(N, 7)
when a track ID is included.
Original Image and Image Shape
The original image is available through:
result.orig_img
Ultralytics stores it as a NumPy array.
The original dimensions are:
result.orig_shape
which returns:
(height, width)
For example:
(1080, 1920)
These values are important when converting normalized coordinates or drawing custom boxes.
Model Class Names
Class names are available through:
result.names
For example:
print(result.names)
might conceptually return:
{
0: "person",
1: "bicycle",
2: "car"
}
You can then use:
class_id = int(box.cls[0])
class_name = result.names[class_id]
This avoids manually maintaining a separate class-name list.
YOLOv8 Output in Python
The Python API gives direct access to structured prediction output.
A basic workflow is:
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
results = model("image.jpg")
result = results[0]
From this point, the box coordinates, classes, and confidences can be extracted independently.
Access Bounding Box Coordinates
Get all boxes:
xyxy = result.boxes.xyxy
print(xyxy)
Loop through individual boxes:
for box in result.boxes:
coordinates = box.xyxy[0]
print(coordinates)
Convert them to a Python list:
coordinates = (
box.xyxy[0]
.cpu()
.tolist()
)
Extract Confidence Scores
Get all confidences:
confidence_scores = result.boxes.conf
print(confidence_scores)
Individual confidence:
for box in result.boxes:
confidence = float(box.conf[0])
print(confidence)
This is useful for application-specific filtering or ranking.
Extract Class IDs and Labels
Get IDs:
class_ids = result.boxes.cls
Convert each class ID to a name:
for box in result.boxes:
class_id = int(box.cls[0])
class_name = result.names[class_id]
print(
class_id,
class_name
)
You can combine everything:
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
)
Output Formats for Different YOLOv8 Tasks
The Results object changes depending on the model task.
Current Ultralytics uses separate task-specific fields including:
boxes
masks
keypoints
probs
obb
This keeps the API consistent while allowing each model family to return the information it needs.
Object Detection Output
A detection model primarily returns:
result.boxes
Important values are:
xyxy
confidence
class ID
optional track ID
The raw structure is:
[x1, y1, x2, y2, conf, cls]
with an optional tracking identifier in tracked results.
Segmentation Mask Output
Instance-segmentation models add:
result.masks
Current Ultralytics segmentation output includes:
result.masks.data
result.masks.xy
result.masks.xyn
masks.data contains binary instance masks with shape:
(N, H, W)
while xy provides mask polygons in pixel coordinates and xyn provides normalized polygon coordinates.
Segmentation also retains:
result.boxes
so each detected instance can have a mask, box, class, and confidence.
Pose Keypoint Output
Pose models populate:
result.keypoints
Useful properties include:
result.keypoints.data
result.keypoints.xy
result.keypoints.xyn
result.keypoints.conf
Current Ultralytics pose output stores keypoint data with shape:
(N, K, 2)
or:
(N, K, 3)
when a third confidence or visibility-related value is present.
Pose models also provide instance boxes through:
result.boxes
OBB Output
Oriented Bounding Box models use:
result.obb
instead of relying only on standard horizontal boxes.
Current Ultralytics OBB output provides:
result.obb.xywhr
result.obb.xyxyxyxy
result.obb.conf
result.obb.cls
xywhr has shape:
(N, 5)
and represents:
x_center
y_center
width
height
rotation
while xyxyxyxy returns four corner points with shape:
(N, 4, 2)
for each oriented box.
YOLOv8 Tracking Output Format
YOLOv8 Track mode extends the normal detection output with object identity information.
A tracked box can include:
coordinates
tracking ID
confidence
class ID
Current Ultralytics Boxes identifies whether tracking data is present with its is_track property, and boxes.id provides the tracking IDs when available.
Bounding Boxes with Track IDs
A normal detection row conceptually contains:
x1 y1 x2 y2 conf cls
Tracking adds an ID:
x1 y1 x2 y2 track_id conf cls
In Python:
results = model.track(
source="video.mp4",
stream=True,
persist=True
)
for result in results:
if result.boxes.id is not None:
print(result.boxes.id)
This allows the same object to be associated across frames.
Object Classes and Confidence Scores
Tracking does not remove the normal box properties.
You can still access:
result.boxes.xyxy
result.boxes.cls
result.boxes.conf
result.boxes.id
For example:
for box in result.boxes:
if box.id is None:
continue
track_id = int(box.id[0])
class_id = int(box.cls[0])
confidence = float(box.conf[0])
print(
track_id,
class_id,
confidence
)
Frame-by-Frame Tracking Results
In stream mode, each frame yields its own Results object.
Conceptually:
Frame 1
ID 4 → person
Frame 2
ID 4 → person
Frame 3
ID 4 → person
This structure can be used for:
object counting
trajectory analysis
dwell time
zone entry
zone exit
vehicle analytics
Tracking IDs are generated by the tracker and are not permanent identities across unrelated videos or arbitrary restarts.
Saving and Exporting YOLOv8 Output
Ultralytics provides built-in methods for saving visual results and converting structured predictions into formats suitable for other software.
Current Results methods include:
save()
save_txt()
summary()
to_df()
to_csv()
to_json()
cpu()
numpy()
This means you often do not need to manually construct export code unless a custom schema is required.
Save Annotated Images and Videos
Python prediction can save outputs with:
results = model.predict(
source="image.jpg",
save=True
)
For an individual result:
result.save(
filename="result.jpg"
)
The save() method creates an annotated result containing the detected boxes and other supported overlays.
CLI Predict mode also saves output by default in many normal CLI workflows, while the Python API defaults to not saving unless requested.
Save Results as Text Labels
You can request text output during prediction:
model.predict(
source="images/",
save_txt=True,
save_conf=True
)
Current Predict documentation describes text detections in the general form:
class x_center y_center width height confidence
when confidence saving is enabled.
The exact output can differ for tasks such as segmentation, pose, OBB, or tracking because those tasks contain additional task-specific information.
Convert Results to JSON or NumPy
Current Ultralytics Results objects provide:
result.to_json()
which returns JSON-formatted prediction data.
Example:
json_output = result.to_json()
print(json_output)
For NumPy:
numpy_result = result.numpy()
This returns a Results copy whose tensor-backed prediction structures have been converted to NumPy arrays.
You can also convert a specific field:
boxes = (
result.boxes.xyxy
.cpu()
.numpy()
)
Current Results also support:
result.to_csv()
and:
result.to_df()
for structured export workflows.
How to Filter YOLOv8 Output
Filtering can happen before inference output is finalized or after Results objects are returned.
Prediction-time filtering is useful when you want fewer detections from the model pipeline.
Post-processing filtering is useful when application rules are more specific.
Filter by Confidence Threshold
At prediction time:
results = model.predict(
source="image.jpg",
conf=0.50
)
After prediction:
for box in result.boxes:
confidence = float(box.conf[0])
if confidence >= 0.80:
print(box.xyxy)
You can also filter the whole Boxes object:
boxes = result.boxes
selected = boxes[
boxes.conf >= 0.80
]
Filter by Class
Suppose class 2 is the class you want.
You can use:
for box in result.boxes:
class_id = int(box.cls[0])
if class_id == 2:
print(box.xyxy)
Or use vectorized filtering:
selected = result.boxes[
result.boxes.cls == 2
]
This is helpful when one model detects many classes but your application only needs a subset.
Select Specific Detections
You can combine multiple conditions:
selected = []
for box in result.boxes:
class_id = int(box.cls[0])
confidence = float(box.conf[0])
if (
class_id == 2
and confidence >= 0.75
):
selected.append(
box.xyxy[0]
.cpu()
.tolist()
)
print(selected)
You can also filter by:
bounding-box size
image region
tracking ID
object center
class
confidence
depending on the application.
Common YOLOv8 Output Problems
Most YOLOv8 output problems come from misunderstanding task-specific fields, coordinate formats, tensor devices, or empty detections.
Inspecting the type, shape, and relevant Results field usually reveals the cause.
Empty Prediction Results
A valid Results object can contain zero detections.
For example:
results = model("image.jpg")
result = results[0]
print(len(result.boxes))
might return:
0
This means inference completed but no detection survived filtering.
Possible causes include:
no target objects
confidence threshold too high
poor model performance
very small objects
wrong model
Always distinguish:
empty result
from:
inference error
because they are different situations.
Incorrect Bounding Box Coordinates
A common mistake is confusing coordinate formats.
For example:
[100, 80, 400, 500]
means one thing in XYXY:
left = 100
top = 80
right = 400
bottom = 500
but something different in XYWH:
center x = 100
center y = 80
width = 400
height = 500
Always check whether you are reading:
boxes.xyxy
or:
boxes.xywh
Normalized variants should also not be confused with pixel values.
Unexpected Output Shape
The output shape depends on the task.
Detection:
boxes.data
→ (N, 6/7)
Segmentation:
masks.data
→ (N, H, W)
Pose:
keypoints.data
→ (N, K, 2/3)
OBB:
obb.xywhr
→ (N, 5)
and:
obb.xyxyxyxy
→ (N, 4, 2)
These task-specific shapes are documented by current Ultralytics Results interfaces.
Do not assume every YOLOv8 model returns the same tensor layout.
GPU Tensor Conversion Errors
If inference runs on CUDA, output tensors may remain on the GPU.
This can fail:
array = result.boxes.xyxy.numpy()
if the tensor is still CUDA-backed.
Use:
array = (
result.boxes.xyxy
.cpu()
.numpy()
)
or:
result_cpu = result.cpu()
result_numpy = result_cpu.numpy()
Current Ultralytics Results exposes both cpu() and numpy() conversion methods.
FAQs About YOLOv8 Output Format
What is the output format of YOLOv8?
The output depends on the task.
For detection, the primary output is:
result.boxes
with raw rows containing:
[x1, y1, x2, y2, confidence, class_id]
plus an optional tracking ID for tracked detections.
Segmentation uses result.masks, pose uses result.keypoints, and OBB models use result.obb.
What does YOLOv8 return after inference?
The normal Python prediction call returns one Results object per input image or frame.
For example:
results = model("image.jpg")
result = results[0]
The Results object can contain:
boxes
masks
keypoints
probs
obb
orig_img
orig_shape
names
path
speed
depending on the model task.
How do I get bounding box coordinates from YOLOv8?
Use:
result.boxes.xyxy
for:
[x1, y1, x2, y2]
or:
result.boxes.xywh
for:
[x_center, y_center, width, height]
Normalized forms are available through xyxyn and xywhn.
Does YOLOv8 output confidence scores?
Yes.
For detection:
result.boxes.conf
returns one confidence score per box.
For OBB:
result.obb.conf
provides confidence values for rotated detections.
How do I get class names from YOLOv8 output?
First get the class ID:
class_id = int(box.cls[0])
Then:
class_name = result.names[class_id]
result.names contains the model’s class-ID-to-name mapping.
Can YOLOv8 output segmentation masks and keypoints?
Yes.
Instance segmentation uses:
result.masks
including:
result.masks.data
result.masks.xy
result.masks.xyn
Pose uses:
result.keypoints
including:
result.keypoints.xy
result.keypoints.xyn
result.keypoints.conf
when confidence data is available.
How can I save YOLOv8 results in JSON format?
Current Ultralytics Results provides:
json_output = result.to_json()
You can write it to disk:
with open(
"results.json",
"w"
) as f:
f.write(
result.to_json()
)
The Results API also supports to_csv(), to_df(), summary(), and numpy() for other export and analysis workflows.
Conclusion
The YOLOv8 output format is built around the Ultralytics Results object, which provides a consistent interface for multiple computer vision tasks.
A standard detection workflow is:
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
results = model("image.jpg")
result = results[0]
The most important detection outputs are:
result.boxes.xyxy
result.boxes.xywh
result.boxes.xyxyn
result.boxes.xywhn
result.boxes.conf
result.boxes.cls
Standard detection box data follows:
x1
y1
x2
y2
confidence
class ID
and tracked outputs can additionally contain a track ID.
The overall Results structure can be summarized as:
YOLOv8 Inference
↓
Results Object
↓
┌───────────────┬──────────────────────┐
│ Detection │ result.boxes │
│ Segmentation │ result.masks │
│ Pose │ result.keypoints │
│ OBB │ result.obb │
│ Classification│ result.probs │
└───────────────┴──────────────────────┘
For segmentation, current Ultralytics returns instance masks through result.masks.data, polygon coordinates through masks.xy, and normalized polygons through masks.xyn.
For pose, keypoints are available through result.keypoints.xy, xyn, and optional confidence information.
For OBB models, rotated detections can be read in xywhr format or as four corner points through xyxyxyxy.
YOLOv8 results can also be converted or exported using:
result.cpu()
result.numpy()
result.to_json()
result.to_csv()
result.to_df()
result.summary()
result.save()
result.save_txt()
which makes the output suitable for NumPy analysis, APIs, databases, JSON files, CSV files, and custom computer vision applications.
A practical programmatic workflow is:
Run Inference
↓
Get Results Object
↓
Select Task Output
↓
Extract Coordinates
↓
Read Confidence
↓
Read Class IDs
↓
Filter Predictions
↓
Convert to CPU / NumPy
↓
Export JSON / CSV / Labels
Understanding this data structure is essential for moving beyond simple annotated images and building real YOLOv8 applications where detections need to be filtered, stored, tracked, analyzed, or passed to other software systems.
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.