In the previous lesson, you successfully set up a pretrained YOLOv8 model and ran it on your meal images to get initial detections. You saw how the model draws bounding boxes and labels on the image, and you worked with a script that printed these detection details to the console. Today, we will build directly on that foundation. Our goal is to move from simply viewing the results to systematically capturing them in a structured format that your program can use for further analysis.
This lesson focuses on a crucial step in any data-driven pipeline: processing raw model outputs into clean, usable data structures. You will write a Python script that takes an image, runs the YOLOv8 detector, and, instead of just printing what it finds, returns a structured list of all detected objects, including their names, confidence scores, and bounding box coordinates. This structured data will be the direct input for our next task: portion estimation.
From Raw Output to Structured Data
When you ran model.predict() in the last lesson, it returned a results object. As you saw, this object is rich with information. To build our pipeline, we need to extract the specific pieces we care about—the class label, the confidence, and the box coordinates—and organize them.
The official Ultralytics documentation provides a clear breakdown of the Results object and its components. It's a valuable reference to keep handy.
Model Prediction with Ultralytics YOLO
This official documentation from Ultralytics details the structure of the model's output. It's the "source of truth" for understanding what data is available.
First, briefly review the table under Working with Results. Note the boxes and names attributes, which are key for our task. Then, look at the table under the Boxes subsection. This table lists the properties of the Boxes object, such as xyxy, conf, and cls, which you've already started using.
The documentation confirms that for each detection, we can get:
- Bounding Box (
box.xyxy): The coordinates of the box,[x_min, y_min, x_max, y_max]. - Class ID (
box.cls): A number representing the object's class (e.g., 56 for 'chair'). - Confidence (
box.conf): The model's certainty in its prediction (a value between 0 and 1). - Class Names (
result.names): A dictionary mapping the class ID to a human-readable name (e.g.,{56: 'chair'}).
Our goal is to combine these pieces of information for every object detected in an image into a clean, reusable data structure. A list of dictionaries is an excellent choice for this, as it's easy to read, process, and even save to a file format like JSON. Here's what we're aiming for as an output for a single image:
[
{
"label": "bowl",
"confidence": 0.87,
"box": [150, 200, 450, 500]
},
{
"label": "carrot",
"confidence": 0.65,
"box": [200, 250, 300, 350]
}
]
Implementing the Extraction Script
Now, let's write the code to produce this structured output. The process involves iterating through the detections just as you did in the last lesson, but instead of printing the details in the loop, you will create a dictionary for each detection and add it to a list.
The following tutorial provides a clear, step-by-step guide to this exact process.
How to Detect Objects in Images Using the YOLOv8 Neural Network
This article from freeCodeCamp offers a practical walkthrough of processing YOLOv8 results. It clearly demonstrates the logic for extracting and interpreting detection data.
Focus on the part of the article that begins after the "cat_dog.jpg" image. Read the sections that explain how to access the result object, how to unpack the tensor values to get coordinates and confidence, and crucially, how to use the result.names dictionary to convert the numeric class ID to a meaningful label like "dog". Finally, review the code block that loops through all detected boxes and prints their information. This loop is the core logic we will adapt.
Building on the logic from the article and the script from our last lesson, we can create a reusable function. This is good software engineering practice and will make your main project script cleaner. The function will take an image path as input and return our desired list of detection dictionaries.
Here is the complete script. It defines a function extract_detection_data and then uses it to process an image and print the structured result.
from ultralytics import YOLO
import pprint # For nicely printing the output
# Initialize a pretrained YOLOv8 model
# The model will be downloaded automatically on first use
model = YOLO('yolov8n.pt')
def process_detections(image_path: str, confidence_threshold: float = 0.5) -> list:
"""
Runs YOLOv8 detection on an image and extracts structured data.
Args:
image_path (str): Path to the input image.
confidence_threshold (float): Minimum confidence score for a detection to be included.
Returns:
list: A list of dictionaries, where each dictionary represents a
detected object and contains its label, confidence, and bounding box.
"""
# Run prediction on the image
results = model.predict(image_path, verbose=False) # Set verbose=False to suppress console output
# We are processing a single image, so we access the first result object
result = results[0]
# Get the dictionary mapping class IDs to class names
class_names = result.names
detections = []
# Iterate over each detected object in the image
for box in result.boxes:
# Extract confidence score
confidence = box.conf.item()
# Filter out detections below the confidence threshold
if confidence < confidence_threshold:
continue
# Extract class ID and name
class_id = int(box.cls.item())
class_name = class_names[class_id]
# Extract bounding box coordinates [x_min, y_min, x_max, y_max]
# and convert them to integers
coords = box.xyxy.tolist()[0]
box_coords = [int(coord) for coord in coords]
# Create a dictionary for the current detection
detection_data = {
'label': class_name,
'confidence': round(confidence, 4),
'box': box_coords
}
# Add the dictionary to our list of detections
detections.append(detection_data)
return detections
# --- Main execution block ---
if __name__ == "__main__":
# Replace with a path to one of your meal images
image_to_process = 'path/to/your/meal_image.jpg'
print(f"Processing image: {image_to_process}")
# Call the function to get the structured detection data
detected_objects = process_detections(image_to_process, confidence_threshold=0.4)
print("\n--- Detected Objects (Structured Data) ---")
if detected_objects:
pprint.pprint(detected_objects)
else:
print("No objects detected with the given confidence threshold.")
Take a moment to analyze this script:
process_detectionsfunction: This function encapsulates all the logic. It takes an image path and an optionalconfidence_thresholdas input. This allows you to easily filter out low-confidence detections that are likely to be incorrect.model.predict(..., verbose=False): We've addedverbose=Falseto prevent theultralyticslibrary from printing its own summary for every prediction, keeping our output clean.- Iteration and Extraction: The loop is very similar to the one from our last lesson. The key difference is that instead of
print(), it populates a dictionarydetection_data. detections.append(...): Each dictionary is added to thedetectionslist.- Return Value: The function returns the complete
detectionslist. - Main Block (
if __name__ == "__main__":): This standard Python construct ensures the code inside it only runs when the script is executed directly. It demonstrates how to call your new function and usespprintto print the resulting list of dictionaries in a readable format.
Now, it's your turn. Save this code as a Python file (e.g., extract_features.py), replace 'path/to/your/meal_image.jpg' with an actual path to one of your meal photos, and run it from your terminal. You should see the structured data printed to your console. Try it on a few different images to see how the output changes.
Conclusion
In this lesson, you've taken a significant step from simply running a model to building a functional component of your data processing pipeline. You've learned how to methodically parse the raw output from YOLOv8 and transform it into a clean, structured, and highly usable format.
Here are the key takeaways:
- You know how to access the core attributes of the YOLOv8
ResultsandBoxesobjects, including coordinates (xyxy), confidence (conf), class ID (cls), and the class name mapping (names). - You have implemented a Python function that encapsulates the detection logic, making your code modular and reusable.
- You are now able to produce a structured list of dictionaries, which is the standard way to handle such data in a data science workflow.
The structured data you're now generating is the essential input for the next stage of your project. In our next lesson, you will use these extracted bounding box coordinates to estimate the portion size of food items, moving one step closer to a comprehensive meal quality analysis.