An object detector gives you more than a name. It estimates where objects are, assigns class labels and reports scores. The useful first project is to connect those predictions to a visible image, then change one setting and inspect the result.
In this example, YOLOv8n processes a synthetic 1024 × 1024 harbor image on a Windows CPU. With the same image and model, it returns 9 boxes at confidence 0.15 and 4 boxes at 0.70. Those are retained predictions, not independently verified counts of physical boats.
Watch the Python walkthrough
Watch the full tutorial on YouTube · Watch the confidence-threshold Short
What does object detection return?
Image classification answers a question about an image's category. Object detection adds estimated locations. In this run, every returned class label is boat, but each prediction has its own score and rectangle. The official detection documentation describes these outputs.
A bounding box does not trace an object's exact outline. It gives four edges around an estimated region. A confidence score helps filter predictions; it is not a certificate that a box is correct. Neither a convincing overlay nor a large number of boxes establishes model accuracy.

Prepare two local files and a small script
Use a local yolov8n.pt checkpoint and an image named harbor_scene.jpg, placed beside detect.py. The demonstrated input and checkpoint are included in lesson 28 of the course. For your own experiment, use an image you have permission to process and update the image path in the script. Your results will depend on that image; the numbers below belong to the demonstrated input.
The checkpoint in this run matches the official Ultralytics YOLOv8n release asset, SHA-256 f59b3d833e2ff32e194b5bb8e08d211dc7c5bdf144b90d2c8412c47ccfc83b36. Downloading the model is a separate setup step; the example deliberately stops if a local file is missing. Review the model license and Ultralytics licensing information before integrating it into another project.
For Windows with Python 3.13 installed, create an isolated environment and install the demonstrated Ultralytics version. Save the following script and put the two assets beside it before running the final command:
py -3.13 -m venv .venv
.venv\Scripts\python.exe -m pip install ultralytics==8.4.24
.venv\Scripts\python.exe detect.py
The measured run used Python 3.13.9, Ultralytics 8.4.24, PyTorch 2.10.0, NumPy 2.3.5 and OpenCV 4.13.0.92. The short installation command pins Ultralytics, not every transitive dependency. It is a starting setup, not a claim that a fresh installation on every machine reproduces the complete tested environment. Installing packages or obtaining assets may need internet access; prediction can run offline once they are present. No GPU or model training is required for this example.
Run the complete Python example
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright (c) 2026 ARTSCI - Author of the AI/ML/CV course materials.
"""Run detection on two local files; do not download missing assets."""
from pathlib import Path
from ultralytics import YOLO
ROOT = Path(__file__).resolve().parent
weights = ROOT / "yolov8n.pt"
image = ROOT / "harbor_scene.jpg"
for path in (weights, image):
if not path.is_file():
raise FileNotFoundError(f"Required local file: {path}")
model = YOLO(str(weights))
for confidence in (0.15, 0.70):
result = model.predict(
source=str(image), conf=confidence, iou=0.70,
imgsz=640, device="cpu", max_det=300,
classes=None, rect=True, half=False,
augment=False, agnostic_nms=False, verbose=False,
)[0]
print(f"conf={confidence:.2f}: {len(result.boxes)} detections")
for box in result.boxes:
label = result.names[int(box.cls.item())]
score = float(box.conf.item())
xyxy = [round(float(v), 1) for v in box.xyxy[0].tolist()]
print(f" {label}: score={score:.3f}, xyxy={xyxy}")
result.save(filename=str(ROOT / f"detections_{confidence:.2f}.jpg"))
Complete sample source above: copyright © 2026 ARTSCI — Author of the AI/ML/CV course materials. Licensed under GNU AGPL version 3, without warranty. Preserve applicable notices when sharing modified code. Ultralytics software and weights retain their own terms. This code notice does not automatically license independent images, narration or course videos.
Path(__file__).resolve().parent makes the asset paths relative to the saved script. Use it in a Python file; an interactive notebook needs paths appropriate to its working directory instead. The existence checks prevent an accidental missing-model download. YOLO(str(weights)) loads the local checkpoint, and model.predict(...)[0] selects the result for this single image.
The loop runs twice, changing only conf. It keeps IoU at 0.70, processing size at 640, the device on CPU and the other shown options fixed. For this YOLOv8 model, IoU controls overlap suppression. It is a different setting from confidence, so changing both at once would make this comparison harder to interpret. See the prediction argument documentation for their roles.
Read one prediction all the way back to the image
result.boxes contains the retained boxes. The class identifier indexes result.names to obtain a readable label. box.conf supplies the score. box.xyxy supplies left, top, right and bottom coordinates in the original input image's pixel coordinate system.
One prediction over the far-left red boat has label boat, score approximately 0.621 and coordinates [60.3, 517.6, 339.8, 852.8]. The rounded rectangle begins near x = 60 and y = 518, ending near x = 340 and y = 853. Resizing an illustration for display does not turn these into display-pixel coordinates; a custom overlay must apply the image's display transform once.

Here is an abbreviated excerpt from the printed output. The ellipses omit other rows; the script prints every returned row:
conf=0.15: 9 detections
...
boat: score=0.621, xyxy=[60.3, 517.6, 339.8, 852.8]
...
conf=0.70: 4 detections
Why does a visible boat lose its box?
The selected score, about 0.621, passes 0.15 but falls below 0.70. In the second run that prediction is absent. The underlying image has not changed, and the visible boat has not disappeared. The acceptance threshold has changed.

Keeping fewer predictions can remove weak duplicates or mistakes, but it can also remove useful detections. Keeping more can reveal weak candidates while introducing extra errors. We have not annotated every true object in this synthetic scene, so this is a controlled output comparison, not an accuracy benchmark. A score of 0.621 should not be read as a demonstrated 62.1% probability of correctness.
The two saved images make the result inspectable. For another experiment, retain the original input, record the model and versions, and change one parameter at a time. Test representative images and decide which missed or false detections matter for your application.
For the next step, see how detection becomes tracking and crossing events in Traffic Counter. The full notebooks, supporting files and complete applications are developed in my English course, Computer Vision: OpenCV, Machine Learning and YOLO.



