AI: Computer Vision Project, Object Detection with YOLO

Text models are everywhere, but many of the most useful real-world problems are visual: counting people, reading signs, catching defects on an assembly line. YOLO object detection in Python is the fastest way to give your code eyes. YOLO (You Only Look Once) takes one look at the whole frame and hands back boxes and labels, quick enough for live video and light enough for a plain CPU.

Think of YOLO like a checkout scanner at a supermarket. The scanner does not study each item for a minute. It glances once, recognises the product, and moves on. YOLO works the same way: one quick look at the whole image, and out come the boxes and labels. That single glance is what makes it fast.

This post is a build project. By the end you will have a working object detection system that finds and labels objects in images and video. We will use the Ultralytics library with YOLO11, a current detection model at the time of writing that runs happily on a plain Central Processing Unit (CPU).

“YOLO changed the game by treating object detection as a single regression problem. One forward pass, all detections.”

Joseph Redmon, YOLO paper

Last Updated: July 2026 | Tested on: Python 3.14.6, ultralytics 8.4.72, PyTorch 2.12.1 (CPU), OpenCV 4.13.0 | Difficulty: Advanced | Reading Time: 15 minutes

📋 Prerequisites:

Object detection is the computer vision task of finding and labeling objects in images and video. Image classification only asks “what is this picture?” and gives back one label. Object detection asks a harder question: “what objects are in here, and where exactly is each one?” It hands you back a box around every object plus a label and a confidence score. YOLO is the most popular approach because it looks at the whole image in a single pass, which is what makes it quick enough for live video.

This post covers how YOLO is put together, how to set up the Ultralytics library, how to run detection on images and video, and how to train the model on your own objects. By the end you will have a working detection system that labels objects in real time.

Whether you are building a security camera, a shelf-stock counter for a shop, or a hobby self-driving car, the patterns in this post are your starting point.

What We’re Building

🖼️ Input Image640×640 pixels🔍 BackboneFeature extractionCSPDarknet / EfficientNet🔗 NeckFeature fusionFPN + PAN🎯 Detection HeadBounding boxesClass probabilities✂️ Non-Max SuppressionRemove duplicate boxesConfidence threshold📦 OutputBoxes + Labels + ScoresPerson 0.95, Car 0.87Python YOLO Object Detection: Image to Boxes Through Backbone, Neck, Head, and NMS

The diagram above is the journey a single image takes through YOLO. The image goes in at the top. The backbone pulls out features (edges, shapes, textures). The neck mixes features from different scales so small and large objects both get noticed. The head predicts the boxes and class scores. Non-max suppression (NMS) then throws away duplicate boxes that landed on the same object. What comes out the bottom is a clean list of boxes, labels, and confidence scores.

By the end of this post you will have a Python script that takes any image or webcam frame and draws those boxes for you, with labels and scores. The model recognises 80 everyday categories out of the box (people, cars, dogs, laptops, and so on), and later you will train it on your own custom objects.

The Quick Win: Detection in 5 Lines

No long setup, no config files. We point YOLO at an image and it tells us what is in it. The image below is the sample photo that ships with Ultralytics: a red bus with a few people standing in front of it. The very first time you run this, YOLO quietly downloads the model weights (about 5 MB) and the sample image, then it gets to work.

📄 detect_quick.py: object detection in a handful of lines

from ultralytics import YOLO

# Aditi runs a YOLO detection in just a few lines
model = YOLO("yolo11n.pt")              # Nano model: smallest and fastest
results = model("bus.jpg", verbose=False)  # Run detection on an image

# Print every detected object
for result in results:
    for box in result.boxes:
        cls_name = result.names[int(box.cls)]
        confidence = float(box.conf)
        x1, y1, x2, y2 = map(int, box.xyxy[0])
        print(f"  {cls_name:>12} ({confidence:.2%}) at [{x1},{y1}]-[{x2},{y2}]")

# Save the annotated image with boxes drawn on it
results[0].save(filename="bus_detected.jpg")
print("\nSaved annotated image to bus_detected.jpg")

▶ Output

           bus (94.02%) at [3,229]-[796,728]
        person (88.82%) at [671,394]-[809,878]
        person (87.83%) at [47,399]-[239,904]
        person (85.58%) at [223,408]-[344,860]
        person (62.19%) at [0,556]-[68,872]

Saved annotated image to bus_detected.jpg

What happened here: Three real lines of work (load, run, print) and YOLO found five objects: the bus and four people. Each line of output is one detection. The percentage is the model’s confidence, and the four numbers are the corner pixels of the box. Notice the last person sits at only 62 percent confidence: that is the figure half cut off at the edge of the photo, so YOLO is less sure.

The Nano model resizes the image to 640 pixels and runs in a fraction of a second on a plain CPU, faster still on a Graphics Processing Unit (GPU). Your own confidence numbers may shift by a fraction of a percent between library versions, but the objects and rough boxes will match. No training and no config, just load and detect.

YOLO Model Sizes: Speed vs Accuracy

YOLO11 comes in five sizes, from Nano to XLarge. They are the same model wearing different coats: bigger means more accurate but slower. Picking a size is like choosing a vehicle for a delivery. A scooter (Nano) is quick and cheap and perfect for short city hops. A truck (XLarge) carries more and is more thorough, but it is heavier and slower. Most teams land somewhere in the middle. The numbers below come straight from the official Ultralytics docs.

📄 model_comparison.py: choosing the right YOLO11 model

# Anvay compares YOLO11 model sizes (all numbers from the official Ultralytics docs)
models = {
    "yolo11n (Nano)":   {"params": "2.6M",  "mAP": "39.5", "cpu": "56ms",  "gpu": "1.5ms",  "use_case": "Mobile, edge, real-time video"},
    "yolo11s (Small)":  {"params": "9.4M",  "mAP": "47.0", "cpu": "90ms",  "gpu": "2.5ms",  "use_case": "Balanced speed and accuracy"},
    "yolo11m (Medium)": {"params": "20.1M", "mAP": "51.5", "cpu": "183ms", "gpu": "4.7ms",  "use_case": "General production use"},
    "yolo11l (Large)":  {"params": "25.3M", "mAP": "53.4", "cpu": "239ms", "gpu": "6.2ms",  "use_case": "High accuracy needed"},
    "yolo11x (XLarge)": {"params": "56.9M", "mAP": "54.7", "cpu": "463ms", "gpu": "11.3ms", "use_case": "Maximum accuracy, batch jobs"},
}

print(f"{'Model':<20} {'Params':>8} {'mAP50-95':>9} {'CPU ms':>8} {'GPU ms':>8}  {'Use Case':<35}")
print("=" * 92)
for name, info in models.items():
    print(f"{name:<20} {info['params']:>8} {info['mAP']:>9} {info['cpu']:>8} {info['gpu']:>8}  {info['use_case']:<35}")

print("\nRule of thumb: start with Nano (n) for prototyping. Move to Medium (m) for production.")
print("               Use XLarge (x) only when the extra accuracy is worth the slower inference.")

▶ Output

Model                  Params  mAP50-95   CPU ms   GPU ms  Use Case
============================================================================================
yolo11n (Nano)           2.6M      39.5     56ms    1.5ms  Mobile, edge, real-time video
yolo11s (Small)          9.4M      47.0     90ms    2.5ms  Balanced speed and accuracy
yolo11m (Medium)        20.1M      51.5    183ms    4.7ms  General production use
yolo11l (Large)         25.3M      53.4    239ms    6.2ms  High accuracy needed
yolo11x (XLarge)        56.9M      54.7    463ms   11.3ms  Maximum accuracy, batch jobs

Rule of thumb: start with Nano (n) for prototyping. Move to Medium (m) for production.
               Use XLarge (x) only when the extra accuracy is worth the slower inference.

What happened here: The mAP50-95 column (mAP stands for mean Average Precision) is the accuracy score on the COCO (Common Objects in Context) benchmark: higher is better. Notice how little accuracy you gain from Nano to XLarge (39.5 up to 54.7) compared to how much slower it gets (56 ms up to 463 ms on a CPU). The CPU times are Ultralytics’ own measurements on an Intel CPU using ONNX (Open Neural Network Exchange), and the GPU times are on an NVIDIA T4 with TensorRT, so treat them as a guide, not a promise for your exact machine.

For most projects Nano or Medium is the sweet spot. Reach for XLarge only when you have a GPU and accuracy matters more than speed, such as an offline batch job checking thousands of photos overnight.

Real-Time Video Detection

Think of a flipbook: each page is a single still drawing, but flick through them fast enough and your eye sees smooth motion. Video works the same way, so detection on video is just the single-image trick repeated many times per second. OpenCV grabs one frame from the webcam, YOLO runs on that frame, and we draw the boxes before grabbing the next one. Run this on your own laptop with a camera attached, because a webcam loop needs a live camera and a screen, which a server does not have.

📄 video_detection.py: live object detection from a webcam

from ultralytics import YOLO
import cv2

# Aviraj builds a real-time detection pipeline
model = YOLO("yolo11n.pt")
cap = cv2.VideoCapture(0)  # 0 = default webcam

print("Starting real-time detection... Press 'q' to quit.")

frame_count = 0
while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break

    # Run detection
    results = model(frame, verbose=False)
    annotated = results[0].plot()  # Draw boxes on frame

    # Count detections
    detections = len(results[0].boxes)
    cv2.putText(annotated, f"Objects: {detections}", (10, 30),
                cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

    cv2.imshow("YOLO Detection", annotated)
    frame_count += 1

    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

cap.release()
cv2.destroyAllWindows()
print(f"Processed {frame_count} frames")

▶ Output (illustrative: needs a live camera and a display)

Starting real-time detection... Press 'q' to quit.
[A live video window opens and draws boxes around detected objects in real time]
Processed 847 frames

What happened here: We built a real-time detection loop in about 20 lines. OpenCV grabs each webcam frame, YOLO detects the objects in it, and results[0].plot() draws the boxes onto the frame. We verified the heart of this loop separately (loading a frame, running model(frame), calling .plot(), counting results[0].boxes) and it works on Python 3.14.6. The two parts we cannot show on a server are the live camera feed and the popup window, so the frame count above is representative of a real session, not a captured run.

On a laptop with a GPU, YOLO11 Nano keeps up with 30 to 60 frames per second, which is plenty for a smooth live feed. This is the same pattern behind security cameras, self-driving prototypes, and shop-shelf analytics.

Training YOLO on Custom Data

The built-in model knows 80 everyday objects, but it has never seen a circuit board. To teach it your own objects, you fine-tune: you start from the pre-trained model (which already understands edges, shapes, and textures) and nudge it toward your new labels. This is much like hiring an experienced electrician and showing them your specific wiring, rather than training someone from zero. You need a labeled dataset, a one-line YAML file that points to it, and a single call to model.train().

📄 custom_training.py: train YOLO to detect your own objects

from ultralytics import YOLO

# Anvi trains YOLO to spot defects on circuit boards
# Step 1: describe the dataset in YOLO's simple YAML format
dataset_yaml = """
path: ./circuit-board-dataset
train: images/train
val: images/val
test: images/test

names:
  0: good_solder
  1: missing_component
  2: cold_solder
  3: bridge_defect
"""

# Save the dataset config to a file
with open("circuit_board.yaml", "w") as f:
    f.write(dataset_yaml)

# Step 2: train, starting from pre-trained weights (transfer learning)
model = YOLO("yolo11m.pt")  # Start from the pre-trained Medium model
results = model.train(
    data="circuit_board.yaml",
    epochs=50,
    imgsz=640,
    batch=16,
    patience=10,       # Stop early if it stops improving
    device=0,          # GPU index, or "cpu" if you have no GPU
    project="runs/defect_detection",
    name="v1",
)

print("Training complete!")
print(f"Best mAP50: {results.results_dict.get('metrics/mAP50(B)', 'N/A')}")

# Step 3: load the best weights and run on a new board
best_model = YOLO("runs/defect_detection/v1/weights/best.pt")
test_results = best_model("test_board.jpg")
for box in test_results[0].boxes:
    cls = test_results[0].names[int(box.cls)]
    conf = float(box.conf)
    print(f"  Detected: {cls} ({conf:.1%})")

▶ Output (illustrative: needs your labeled circuit-board dataset and a GPU)

Training complete!
Best mAP50: 0.923

  Detected: cold_solder (94.2%)
  Detected: missing_component (91.7%)
  Detected: good_solder (98.1%)
  Detected: good_solder (97.3%)

What happened here: The numbers above are representative of a finished defect-detection run, not a capture from this machine, because a real 50-epoch training needs your own labeled boards and ideally a GPU. The code itself is the genuine current Application Programming Interface (API), though. To prove that, we ran the exact same model.train() call against Ultralytics’ tiny built-in COCO8 dataset (eight images) for one epoch on a CPU with Python 3.14.6, and it trained, validated, saved best.pt, and returned a real results.results_dict whose keys include metrics/mAP50(B), which is the exact key this script reads.

On a proper dataset the same flow gives you a trained detector for your own objects. Two tips that decide success: use at least a few hundred labeled images per class, and set device="cpu" if you do not have a GPU (training will be slow but it will still work).

Common Mistakes

⚠️ Common Mistakes:
  • Too few training images: YOLO needs at least 100 images per class to learn anything useful. For production quality, aim for 1,000 or more per class with varied lighting, angles, and backgrounds.
  • Wrong image size: YOLO resizes every image to imgsz (640 by default). If your objects are tiny (a small defect on a big board), bump it up to imgsz=1280. For normal-sized objects, 640 is fine.
  • Not using pre-trained weights: Always start from the pre-trained .pt file. Training from scratch needs 10 to 100 times more data and time for a worse result.
  • Copying an old model name: Tutorials from a year ago load yolov8n.pt. Use a current model such as yolo11n.pt (or yolo26n.pt) so you get the latest accuracy and speed. The rest of the code stays the same.

Practice Exercises

  1. Exercise 1: Run YOLO11 on a photo of your own and print every detection with its confidence score.
  2. Exercise 2: Label 50 to 100 images of one custom object and fine-tune YOLO11 to detect it.
  3. Exercise 3: Build the full real-time loop: read video frames, run detection on each, and draw the boxes on screen.

More in this series:

Frequently Asked Questions

Do I need a GPU for yolo python detection?

No for running detection: YOLO11 Nano runs detection at 30 or more frames per second on a plain CPU, and a single image takes a fraction of a second. A GPU is strongly recommended for training your own model, where it cuts the job from days to hours. Google Colab gives you free GPU time that is enough for most YOLO training.

Can YOLO detect custom objects?

Yes. The pre-trained model already knows 80 everyday COCO classes. For your own objects you label a dataset (with a tool like Roboflow or LabelImg), write a short YAML config, and fine-tune from the pre-trained weights. With a few hundred labeled images per class you can reach 90 percent or higher mAP, which makes YOLO object detection practical even for niche domains like retail shelves or crop monitoring.

Which YOLO version should I use in 2026?

At the time of writing the Ultralytics docs recommend YOLO11 and the newer YOLO26 (released January 2026). YOLO11 is the safe default: it is well documented, fast, and accurate, and it runs on a plain CPU. YOLO26 adds NMS-free, end-to-end inference and faster edge deployment. Older models like YOLOv8 still work but are no longer the recommended choice. Models change fast, so check the Ultralytics docs for the latest before you start.

What’s Next?

You now know how YOLO is put together (backbone, neck, detection head, and NMS), how to run detection on an image in five lines, how to pick a model size for the speed versus accuracy trade-off, how to loop over webcam frames for real-time video, and how to fine-tune YOLO11 on your own custom objects. That is a complete, production-ready YOLO object detection skill set.

Next, in the multimodal AI tutorial, we go beyond detection to models that can see, hear, and read at the same time. You will send images to an LLM (Large Language Model), transcribe audio with Whisper, and build apps that understand several kinds of input at once.

Want the full picture of how this fits together? Browse every lesson from the basics to advanced AI in the Python + AI/ML tutorial series home.

Interview Questions on YOLO Object Detection

Scenario questions, not trivia: this is the form this topic takes in a real interview.

Q: What is the difference between object detection and image classification?

Image classification answers only “what is this picture?” and returns a single label for the whole image. Object detection answers a harder question: it finds every object, draws a bounding box around each one, and attaches a class label plus a confidence score. So detection gives you both the “what” and the “where,” which is why it can count people or locate defects, while classification cannot.

Q: Why is YOLO called a single-stage detector, and why does that make it fast?

YOLO stands for “You Only Look Once.” It treats detection as one regression problem: a single forward pass through the network predicts all boxes and class scores at once. Older two-stage detectors like Faster R-CNN first propose candidate regions and then classify each one, which is slower. Because YOLO looks at the whole image just once, it is quick enough for live video.

Q: What role does Non-Max Suppression (NMS) play in the pipeline?

The detection head often predicts several overlapping boxes for the same object. NMS cleans this up: it keeps the highest-confidence box, then removes any other box that overlaps it too much (measured by Intersection over Union). Without NMS you would see three or four duplicate boxes stacked on one person. Newer models like YOLO26 offer an NMS-free, end-to-end mode that folds this step into the network itself.

Q: What does the mAP50-95 metric measure, and why is it reported instead of plain accuracy?

mAP means mean Average Precision, averaged across all classes. The “50-95” part means it is averaged over ten IoU thresholds from 0.50 to 0.95, so the model is rewarded for boxes that are tightly aligned, not just roughly on the object. Plain accuracy does not work for detection because there is no single right answer per image: you have to score both whether an object was found and how well the box fits.

Q: Your YOLO model detects large objects well but keeps missing tiny defects on a large image. What do you check first?

Start with the input size. YOLO resizes every image to imgsz (640 by default), which shrinks small objects until they nearly vanish, so raise it to imgsz=1280. If that is not enough, tile the large image into overlapping crops and run detection on each tile, then merge the boxes. Also confirm your training set actually contains enough small-object examples, since the model can only learn what it has seen.

Q: Your real-time webcam loop runs at only 5 FPS on a CPU and feels laggy. How do you speed it up?

First switch to the Nano model (yolo11n.pt) if you were on a larger size, and lower imgsz (say to 480 or 320) to cut the work per frame. Export the model to ONNX or TensorRT for a faster runtime, and move inference to a GPU if one is available. If you still need headroom, process every second or third frame instead of every one, since a webcam feed rarely changes much between adjacent frames.

Go deeper: when you outgrow this post, the official Python documentation is the next stop.

Previous: DL: Transfer Learning with ResNet, VGG Pre-trained Models

Next: NLP: Word Embeddings (Word2Vec, GloVe, FastText)

Series Home: Python + AI/ML Tutorial Series

RahulAuthor posts

Avatar for Rahul

Rahul is a passionate IT professional who loves to sharing his knowledge with others and inspiring them to expand their technical knowledge. Rahul's current objective is to write informative and easy-to-understand articles to help people avoid day-to-day technical issues altogether. Follow Rahul's blog to stay informed on the latest trends in IT and gain insights into how to tackle complex technical issues. Whether you're a beginner or an expert in the field, Rahul's articles are sure to leave you feeling inspired and informed.

No comment

Leave a Reply

Your email address will not be published. Required fields are marked *