Object Detection: YOLO, Bounding Boxes & Real-Time Computer Vision
Transition from holistic image-level classification to spatial localization and multi-object detection. Learn bounding box coordinate spaces, Intersection over Union (IoU) mechanics, Non-Maximum Suppression (NMS), the single-stage YOLO revolution, and train custom detectors using modern Ultralytics YOLO.
1 Introduction: From Image Classification to Object Detection
In the previous lessons, we mastered Convolutional Neural Networks (CNNs) and Transfer Learning to classify images. An image classifier inspects an input tensor and outputs a single probability distribution predicting what object is present in the scene.
However, real-world visual perception demands far more than global image classification. Consider an autonomous vehicle approaching a busy intersection. The onboard camera captures a scene containing three vehicles, four pedestrians, two traffic lights, and a cyclist. An image classifier would merely output the label "street" or "car". It cannot tell the vehicle's planner:
- How many distinct objects exist in the scene?
- Where is each object located in 2D image coordinates?
- What is the spatial boundary (bounding box) around each independent obstacle?
The Dual Mandate of Object Detection
Object detection simultaneously solves two fundamental computer vision tasks in a single unified inference pass:
Assigning a discrete semantic category label $c \in \{1, \dots, C\}$ with an associated confidence score $s \in [0, 1]$ to each identified visual instance.
Predicting continuous spatial bounding box coordinates $\mathbf{b} = [x_1, y_1, x_2, y_2]$ or $[x_c, y_c, w, h]$ tightly enclosing each respective object.
2 Learning Objectives
3 Classification vs. Localization vs. Object Detection
In computer vision literature, the boundaries between classification, single-object localization, and general object detection are formally defined by the cardinality and structure of their output tensors.
| Vision Paradigm | Output Formulation | Object Count | Loss Functions | Computational Bottleneck |
|---|---|---|---|---|
| Classification | $\hat{y} \in \mathbb{R}^C$ | None / Global (0 or 1) | Cross-Entropy Loss | Backbone feature extraction |
| Localization | $(\hat{y} \in \mathbb{R}^C, \mathbf{b} \in \mathbb{R}^4)$ | Exactly 1 prominent object | Cross-Entropy + Smooth L1 / MSE | Multi-task weight balancing |
| Object Detection | $\{(\hat{y}_i, \mathbf{b}_i, s_i)\}_{i=1}^K$ | Variable ($K \ge 0$) | Focal/BCE + CIoU + DFL | Combinatorial label assignment & NMS |
| Instance Segmentation | $\{(\hat{y}_i, \mathbf{b}_i, \mathbf{M}_i)\}_{i=1}^K$ | Variable ($K \ge 0$) | Detection Losses + Pixel Mask BCE | Pixel-level mask decoding |
4 Understanding Bounding Boxes & Coordinate Spaces
A bounding box represents the smallest axis-aligned rectangle (AABB) bounding an object. Different computer vision frameworks, annotation standards, and model architectures use different coordinate conventions. Mixing them up is the single most common cause of silent failures in vision pipelines.
1. Pascal VOC Format (XYXY)
Absolute PixelsRepresented by the top-left corner and bottom-right corner:
Used by: PyTorch Torchvision models, Faster R-CNN, OpenCV drawing routines.
2. COCO Format (XYWH Top-Left)
Absolute PixelsRepresented by top-left corner with box width and height:
Used by: MS COCO JSON annotations, Detectron2, Albumentations.
3. Center Format (XYWH Center)
Absolute PixelsRepresented by center coordinates with box width and height:
Used by: Anchor-based intermediate neural predictions, Kalman trackers.
4. YOLO Normalized Format
Relative [0, 1]Normalized relative to full image width $W$ and height $H$:
Used by: YOLO `.txt` labels, Darknet, Ultralytics YOLOv5/v8/11.
Step-by-Step Conversion Walkthrough ($W = 640\text{ px}, H = 480\text{ px}$)
Suppose an object in a $640 \times 480$ image has top-left corner $(50, 40)$ and bottom-right corner $(250, 180)$:
h = 180 - 40 = 140
[50, 40, 200, 140]
y_c = 40 + 140/2 = 110 → 110/480 = 0.2292
w^{\text{norm}} = 200/640 = 0.3125
h^{\text{norm}} = 140/480 = 0.2917
[0.2344, 0.2292, 0.3125, 0.2917]
Why normalize coordinates? Normalizing coordinates ensures that scale changes (such as resizing an image to $640 \times 640$ during training or multi-scale jittering) do not invalidate bounding box annotations. Furthermore, keeping target values in the range $[0, 1]$ prevents gradient instability.
5 Intersection over Union (IoU)
To evaluate how well a predicted bounding box $\mathbf{b}_{\text{pred}}$ matches a ground-truth bounding box $\mathbf{b}_{\text{gt}}$, we use the Jaccard similarity index, universally known in computer vision as Intersection over Union (IoU).
Given two boxes $A = [x_{1}^A, y_{1}^A, x_{2}^A, y_{2}^A]$ and $B = [x_{1}^B, y_{1}^B, x_{2}^B, y_{2}^B]$:
import torch
def calculate_iou(box1: torch.Tensor, box2: torch.Tensor) -> torch.Tensor:
# Computes IoU between two tensors of shape [N, 4] and [M, 4] in (x1, y1, x2, y2) format.
# Returns: [N, M] pairwise IoU matrix.
# Compute intersection corners
x1 = torch.max(box1[:, None, 0], box2[:, 0])
y1 = torch.max(box1[:, None, 1], box2[:, 1])
x2 = torch.min(box1[:, None, 2], box2[:, 2])
y2 = torch.min(box1[:, None, 3], box2[:, 3])
intersection = (x2 - x1).clamp(min=0) * (y2 - y1).clamp(min=0)
area1 = (box1[:, 2] - box1[:, 0]) * (box1[:, 3] - box1[:, 1])
area2 = (box2[:, 2] - box2[:, 0]) * (box2[:, 3] - box2[:, 1])
union = area1[:, None] + area2 - intersection
return intersection / (union + 1e-7)
6 How Does an Object Detector Work? (The 4-Pillar Pipeline)
Whether one-stage or two-stage, modern deep learning object detectors are modular architectures structured into four standardized stages:
Downsamples the input image through consecutive convolutional blocks, extracting rich visual representations. Modern backbones output a feature pyramid with strides $8\times$ ($P_3$), $16\times$ ($P_4$), and $32\times$ ($P_5$).
Examples: CSPDarknet53, ConvNeXt, EfficientNet, MobileNetV3.Fuses low-level spatial details from early layers (crucial for small objects) with high-level semantic abstractions from deep layers. Combines top-down and bottom-up information pathways.
Examples: FPN (Feature Pyramid Network), PANet, BiFPN.Operates on multi-scale feature maps to predict bounding box offsets, objectness/distribution probabilities, and class likelihoods. Modern architectures use decoupled heads to separate classification and localization.
Examples: Anchor-free decoupled heads (YOLOv8/11), RPN + RoIAlign.Filters raw dense predictions by confidence threshold ($\tau_{\text{conf}}$), rescales coordinates back to the original image dimensions, and applies Non-Maximum Suppression (NMS) to eliminate overlapping duplicates.
Examples: Greedy NMS, Soft-NMS, or end-to-end one-to-one matching.7 One-Stage vs. Two-Stage Object Detectors
Object detection architectures historically diverged into two philosophical paradigms: two-stage proposal-driven systems and one-stage dense single-shot predictors.
Two-Stage Detectors (e.g., Faster R-CNN)
High AccuracyMechanism: Stage 1 uses a Region Proposal Network (RPN) to scan feature maps and propose ~2,000 candidate bounding boxes (Regions of Interest). Stage 2 applies RoI Pooling / RoIAlign to crop features for each candidate and pass them through fully-connected classification and regression heads.
- • Pros: Superior localization precision on dense/crowded scenes.
- • Cons: High computational latency (50–150 ms per frame), unsuitable for high-FPS edge video streams.
One-Stage Detectors (e.g., YOLO, SSD)
Real-Time SpeedMechanism: Treats detection as a direct, single-pass regression problem. A single convolutional network evaluates the entire image at once, dividing it into spatial grids and directly predicting bounding boxes and class probabilities simultaneously across all feature pyramid levels.
- • Pros: Extremely fast inference (10–30 ms or 60–120+ FPS), lightweight memory footprint.
- • Cons: Historically struggled with extreme foreground-background class imbalance (solved by Focal Loss).
How RetinaNet & Focal Loss Leveled the Playing Field
Why did one-stage models initially lag behind two-stage models in accuracy? A standard image contains ~100,000 candidate grid cells, but only 5–10 contain actual objects. The massive deluge of trivial background negatives overwhelms the gradient during training. In 2017, Lin et al. introduced Focal Loss:
The modulating factor $(1 - p_t)^\gamma$ automatically down-weights easy examples ($p_t \to 1$), dynamically focusing gradient updates on hard, ambiguous false positives. This breakthrough enabled one-stage detectors like modern YOLO to match and surpass two-stage accuracy.
8 Understanding YOLO: Evolution, Architecture & Paradigm
Introduced by Joseph Redmon et al. in 2015, YOLO ("You Only Look Once") revolutionized computer vision. Instead of repurposing classifiers to evaluate thousands of candidate crops, YOLO processes the entire image in a single neural forward pass.
Generational Milestones of YOLO
Darknet Roots: Joseph Redmon introduced $S \times S$ grid regression (v1), anchor box priors via K-means clustering (v2), and multi-scale feature pyramids $P_3, P_4, P_5$ (v3).
Modern Engineering: Alexey Bochkovskiy and Glenn Jocher (Ultralytics) introduced CSPNet backbones, PANet necks, Mosaic augmentation, and seamless PyTorch integration.
Anchor-Free Decoupled Head: Eliminated rigid anchor boxes. Adopted Task-Aligned Assigner (TAL), decoupled classification/regression branches, and Distribution Focal Loss (DFL).
Next-Gen Efficiency: C3k2 building blocks, C2PSA (cross-stage partial with spatial attention), optimized for low-latency edge silicon and micro-NPU deployment.
Anchor-Based Detection (Legacy)
Predefines 3–9 bounding box priors (aspect ratios and scales) per grid cell. The model predicts bounding box offsets $(\Delta x, \Delta y, \Delta w, \Delta h)$ relative to these static templates.
× High hyperparameter sensitivity; struggle with unusual aspect ratios; complex anchor matching.Anchor-Free Detection (Modern YOLO)
Predicts object centers directly from grid cells, alongside 4 continuous distances $(l, t, r, b)$ from the center point to the left, top, right, and bottom object boundaries.
✓ Zero anchor tuning; faster NMS; better generalization across multi-scale objects.9 Non-Maximum Suppression (NMS) & Duplicate Removal
Because dense object detectors evaluate thousands of overlapping grid cells simultaneously, multiple nearby cells will detect the same object, resulting in a cloud of redundant candidate bounding boxes. Non-Maximum Suppression (NMS) is the algorithmic filter used to retain only the single best detection per physical object.
The Classic Greedy NMS Algorithm
- Confidence Filtering: Discard all candidate boxes where confidence score $s_i < \tau_{\text{conf}}$ (e.g., $0.25$).
- Sort Candidates: Sort the surviving candidates in descending order of confidence score: $\mathcal{B} = [b_1, b_2, \dots, b_N]$ where $s_1 \ge s_2 \ge \dots \ge s_N$.
- Greedy Selection: Pop the highest-scoring box $M = b_1$ and add it to the final output list $\mathcal{D}$.
- IoU Suppression: Calculate the pairwise IoU between $M$ and every remaining box $b_j \in \mathcal{B}$. If $\text{IoU}(M, b_j) > \tau_{\text{nms}}$ (e.g., $0.45$), permanently suppress and discard $b_j$.
- Iterate: Repeat steps 3 and 4 until $\mathcal{B}$ is empty.
Determines candidate admission. Higher values eliminate false positives; lower values maximize recall on dim/small objects.
Determines suppression aggressiveness. Higher values allow close side-by-side objects to survive; lower values purge duplicates strictly.
10 Evaluating Object Detection Models: Precision, Recall & mAP
In object detection, classification accuracy is meaningless because bounding box accuracy is continuous. We evaluate detection systems using mean Average Precision (mAP) based on IoU matching criteria.
Predicted box matches a ground-truth object with correct class label AND $\text{IoU} \ge \tau$ (e.g. $0.50$). Only the first matching prediction counts!
Predicted box has $\text{IoU} < \tau$ against all ground-truth objects, or is a redundant duplicate detection for an already-matched object.
A real ground-truth object that no predicted box successfully detected with $\text{IoU} \ge \tau$.
From Precision-Recall Curve to mAP@0.50:0.95
By sorting all predictions across the test dataset by confidence score and varying the cutoff threshold from $1.0$ down to $0.0$, we plot the Precision-Recall (PR) Curve. Average Precision (AP) is the area under this interpolated curve for a single class.
The mean of AP across all classes evaluated strictly at an IoU threshold of $\tau = 0.50$. Generous toward spatial imprecision.
Averaged across 10 IoU thresholds from $0.50$ to $0.95$ in increments of $0.05$ ($\tau \in \{0.50, 0.55, \dots, 0.95\}$). Penalizes sloppy bounding boxes.
11 Hands-on Object Detection with Ultralytics YOLO in Python
Let us implement object detection using the official ultralytics library. We will load a pretrained model, run inference, parse prediction tensors, and process video streams.
from ultralytics import YOLO
import cv2
# 1. Load pretrained nano model (downloaded automatically if not cached)
model = YOLO("yolo11n.pt") # or "yolov8n.pt"
# 2. Run inference on image with custom thresholds
results = model.predict(
source="street_scene.jpg",
conf=0.25, # Confidence threshold
iou=0.45, # NMS IoU threshold
imgsz=640, # Square inference resolution
device="cpu", # Use "0" or "cuda:0" for GPU
save=True # Save annotated image to runs/detect/predict/
)
# 3. Parse bounding box coordinates and metadata
for r in results:
boxes = r.boxes
for box in boxes:
# Bounding box in VOC absolute pixel format [x1, y1, x2, y2]
x1, y1, x2, y2 = box.xyxy[0].tolist()
# Confidence score and integer class ID
conf = float(box.conf[0].item())
cls_id = int(box.cls[0].item())
cls_name = model.names[cls_id]
print(f"[{cls_name.upper()}] Conf: {conf:.2f} | BBox: ({x1:.1f}, {y1:.1f}) -> ({x2:.1f}, {y2:.1f})")
# Process video or live camera (source=0) with memory-safe generator
results = model.predict(
source=0, # 0 for default webcam, or "traffic.mp4"
conf=0.30,
stream=True # Essential: returns generator, avoids RAM exhaustion
)
for frame_result in results:
# Render annotated frame with OpenCV
annotated_frame = frame_result.plot()
cv2.imshow("Real-Time YOLO Detection", annotated_frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
12 Preparing a Custom Object Detection Dataset
Custom enterprise vision applications—such as PPE compliance, factory safety, or crop disease identification—require custom datasets. YOLO follows a strictly standardized directory layout and annotation syntax.
Directory Hierarchy
dataset/
├── images/
│ ├── train/ (img001.jpg, img002.jpg)
│ ├── val/ (img101.jpg)
│ └── test/ (img201.jpg)
├── labels/
│ ├── train/ (img001.txt, img002.txt)
│ ├── val/ (img101.txt)
│ └── test/ (img201.txt)
└── data.yaml
data.yaml Specification
# Path relative to working directory or absolute
path: ./dataset
train: images/train
val: images/val
test: images/test
# Class ID mapping
names:
0: helmet
1: vest
2: person
Inside each .txt label file, each physical object occupies exactly one space-delimited row: <class_id> <x_center> <y_center> <width> <height>. All four coordinates must be normalized to $[0.0, 1.0]$. Images without objects must have an empty .txt file to serve as hard background negatives!
13 Training & Fine-Tuning YOLO on a Custom Dataset
Fine-tuning a pretrained model leverages existing low-level edge and texture filters while adapting upper detection heads to your domain-specific classes.
from ultralytics import YOLO
# 1. Initialize with pretrained weights (Transfer Learning)
model = YOLO("yolo11n.pt")
# 2. Train the detector
results = model.train(
data="dataset/data.yaml",
epochs=50,
imgsz=640,
batch=16,
patience=10, # Early stopping patience
project="runs/ppe_detect",
name="yolo11_ppe_v1",
save=True,
plots=True
)
# 3. Evaluate the best checkpoint on validation split
metrics = model.val(data="dataset/data.yaml", split="val")
print(f"Validation mAP@0.50: {metrics.box.map50:.4f}")
print(f"Validation mAP@0.50:0.95: {metrics.box.map:.4f}")
# 4. Export to ONNX / TensorRT for high-speed edge deployment
model.export(format="onnx", dynamic=False, simplify=True)
14 Real-Time Computer Vision & Edge AI
In embedded systems and edge devices (e.g., NVIDIA Jetson Orin, Raspberry Pi 5 with AI Hat, edge industrial PCs), raw model accuracy must be balanced against latency budgets.
The Real-Time Latency Equation
For standard 30 FPS video, $T_{\text{total}} \le 33.3\text{ ms}$. If $T_{\text{inference}}$ takes $28\text{ ms}$, you only have $5.3\text{ ms}$ for image decode, letterbox resizing, NMS, and visualization before frame drops occur.
15 Object Detection vs. Object Tracking
Object detection is stateless: it detects objects in isolation frame by frame. Object Tracking (MOT - Multi-Object Tracking) maintains a consistent identity ($\text{Track ID}$) for each object across consecutive frames as it moves, turns, or experiences temporary occlusion.
# Seamless Multi-Object Tracking with persistent IDs
results = model.track(
source="traffic_intersection.mp4",
tracker="bytetrack.yaml", # or "botsort.yaml" for camera motion compensation
conf=0.3,
stream=True
)
for r in results:
if r.boxes.id is not None:
track_ids = r.boxes.id.int().tolist()
print(f"Active Track IDs: {track_ids}")
ByteTrack Algorithm: Unlike older trackers that discard low-confidence detections, ByteTrack retains low-score boxes and matches them to active trajectories using motion Kalman filters, recovering heavily occluded objects without hallucinating false positives.
16 Top 10 Object Detection Pitfalls & Anti-Patterns Matrix
| # | Failure Mode / Anti-Pattern | Root Cause | Diagnostic Symptom | Production Remedy |
|---|---|---|---|---|
| 1 | Inverted / Mixed Coordinate Spaces | Passing COCO $[x, y, w, h]$ to a function expecting VOC $[x_1, y_1, x_2, y_2]$. | Distorted or negative-width bounding boxes; zero mAP. | Enforce assertions ($x_2 > x_1, y_2 > y_1$) and use dedicated converter utilities. |
| 2 | Unnormalized YOLO Labels | Writing absolute pixel coordinates instead of normalized $[0, 1]$ fractions in `.txt`. | Loss explodes to NaN on first training batch. |
Always divide: $x_c/W, y_c/H, w/W, h/H$. Verify range $[0, 1]$. |
| 3 | Video Frame Data Leakage | Splitting consecutive video frames randomly into train and validation sets. | Overly optimistic val mAP (99%), crashes on fresh test video. | Split by complete video sequences or camera locations, never by random frame shuffle. |
| 4 | Missing Background Images | Training only on images containing target objects with zero empty scenes. | High false positive rate when camera points to an empty background. | Include 5–10% empty background images with empty .txt label files. |
| 5 | Over-Aggressive NMS Threshold | Setting NMS IoU threshold too low ($\tau_{\text{iou}} < 0.20$). | Cannot detect people walking in pairs or overlapping vehicles. | Use standard $\tau_{\text{iou}} = 0.45 - 0.50$ or adopt Soft-NMS. |
| 6 | Small Object Disappearance | Objects smaller than $16 \times 16$ px downsampled away at stride 32 ($P_5$). | Near-zero recall on distant or tiny objects. | Train at higher resolution (`imgsz=1280`) or use a P2 small-object detection layer. |
| 7 | Distorted Aspect Ratio Resizing | Stretching rectangular images into square inputs without letterboxing. | Objects become artificially compressed, damaging aspect ratio learning. | Always use aspect-ratio preserving padding (Letterbox transformation). |
| 8 | Confidence Threshold Mismatch | Evaluating model at `conf=0.001` during mAP calculation but deploying at `conf=0.7`. | Mismatch between reported benchmark metric and user experience. | Tune operating confidence cutoff using the Precision-Recall F1-curve peak. |
| 9 | Loose / Inconsistent Annotations | Human annotators drawing oversized or inconsistent boxes across classes. | Bounding box regression loss plateaus; CIoU loss remains high. | Strict annotation protocol: boxes must touch object boundaries tightly. |
| 10 | Evaluating on Non-Stationary Video | Benchmarking latency on static images without accounting for camera decode/render. | System claims 60 FPS in benchmark, stutters at 18 FPS in production. | Profile end-to-end pipeline latency including V4L2/GStreamer capture and NMS. |
17 Practical Assignment: Build an End-to-End Object Detection System
Capstone Task: Train a Workplace Safety (PPE) Detector
Build, fine-tune, and evaluate an object detector with at least 2 distinct classes (e.g., Helmet vs. No-Helmet, or Car vs. Pedestrian).
18 Interactive Computer Vision Workbench
Explore bounding box coordinates, IoU overlap mathematics, Non-Maximum Suppression, and mAP precision-recall curves interactively.
Bounding Box & Coordinate Spaces Laboratory
Drag sliders to adjust box position and size. Watch real-time coordinate transformations across VOC, COCO, Center, and YOLO formats.
19 Key Takeaways
- Dual Task: Object detection solves classification ("what") and localization ("where") simultaneously for variable numbers of objects.
- Bounding Box Formats: Understand VOC $[x_1, y_1, x_2, y_2]$, COCO $[x, y, w, h]$, and YOLO normalized $[x_c/W, y_c/H, w/W, h/H]$ coordinates. Normalization ensures scale invariance.
- IoU Metric: Measures box overlap $\frac{\text{Area}(A \cap B)}{\text{Area}(A \cup B)}$. An IoU of $0.50$ is standard in PASCAL VOC, while COCO requires averaging across $0.50$ to $0.95$.
- One-Stage Paradigm: YOLO predicts dense bounding boxes directly across multi-scale feature pyramids without an RPN, achieving 60–120+ FPS for real-time edge processing.
- Non-Maximum Suppression: Eliminates duplicate overlapping detections by greedily retaining the highest-confidence box and suppressing overlapping candidates with $\text{IoU} > \tau_{\text{iou}}$.
- Evaluation with mAP: Area under the Precision-Recall curve averaged across evaluated classes. Never evaluate object detection with plain accuracy!
- Edge Real-Time AI: Requires end-to-end latency budgeting ($T_{\text{infer}} + T_{\text{NMS}} < 33.3\text{ ms}$ for 30 FPS) leveraging FP16 half precision and ONNX/TensorRT optimization.