TensorFlow
object detection
bounding box
tutorial
API

Get the bounding box coordinates in the TensorFlow object detection API tutorial

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

When using the TensorFlow Object Detection API, the model returns predictions that include bounding box coordinates for each detected object. These coordinates are normalized values between 0 and 1, representing positions relative to the image dimensions. To draw boxes on the original image or use the detections in downstream logic, you need to convert these normalized values into actual pixel coordinates. This article walks through the entire process, from loading a model to extracting and converting bounding box coordinates, with complete code examples.

What Are Bounding Box Coordinates

A bounding box is a rectangle that surrounds a detected object in an image. The TensorFlow Object Detection API represents each box with four values: ymin, xmin, ymax, and xmax. These are normalized, meaning they fall between 0 and 1.

For example, a box with coordinates [0.1, 0.2, 0.5, 0.8] means:

  • The top edge is at 10% of the image height from the top
  • The left edge is at 20% of the image width from the left
  • The bottom edge is at 50% of the image height
  • The right edge is at 80% of the image width

To get pixel values, you multiply ymin and ymax by the image height, and xmin and xmax by the image width.

Loading the Model and Running Inference

First, load a pretrained model and run it on an input image:

python
1import tensorflow as tf
2import numpy as np
3from PIL import Image
4
5# Load the saved model
6model = tf.saved_model.load('ssd_mobilenet_v2/saved_model')
7detect_fn = model.signatures['serving_default']
8
9# Load and prepare the image
10image = Image.open('test_image.jpg')
11image_np = np.array(image)
12
13# The model expects a batch dimension
14input_tensor = tf.convert_to_tensor(image_np)
15input_tensor = input_tensor[tf.newaxis, ...]
16
17# Run inference
18detections = detect_fn(input_tensor)

The detections dictionary contains several keys. The ones relevant to bounding boxes are:

  • detection_boxes: A tensor of shape (1, N, 4) with normalized coordinates
  • detection_scores: Confidence scores for each detection
  • detection_classes: Class IDs for each detection
  • num_detections: How many valid detections were found

Extracting and Converting Coordinates

Here is how to extract the bounding boxes and convert them to pixel coordinates:

python
1# Get image dimensions
2height, width, _ = image_np.shape
3
4# Extract results (remove batch dimension)
5boxes = detections['detection_boxes'][0].numpy()
6scores = detections['detection_scores'][0].numpy()
7classes = detections['detection_classes'][0].numpy().astype(int)
8num_detections = int(detections['num_detections'][0].numpy())
9
10# Filter by confidence threshold
11threshold = 0.5
12
13for i in range(num_detections):
14    if scores[i] >= threshold:
15        ymin, xmin, ymax, xmax = boxes[i]
16        
17        # Convert normalized coordinates to pixel values
18        left = int(xmin * width)
19        top = int(ymin * height)
20        right = int(xmax * width)
21        bottom = int(ymax * height)
22        
23        print(f"Object {i}: class={classes[i]}, "
24              f"score={scores[i]:.2f}, "
25              f"box=({left}, {top}, {right}, {bottom})")

The threshold of 0.5 filters out low-confidence detections. You can adjust this value based on your application. A lower threshold catches more objects but includes more false positives. A higher threshold is more selective but may miss valid detections.

Drawing Bounding Boxes on the Image

Once you have pixel coordinates, you can draw the boxes on the image using PIL or OpenCV:

python
1from PIL import ImageDraw, ImageFont
2
3draw = ImageDraw.Draw(image)
4
5for i in range(num_detections):
6    if scores[i] >= threshold:
7        ymin, xmin, ymax, xmax = boxes[i]
8        left = int(xmin * width)
9        top = int(ymin * height)
10        right = int(xmax * width)
11        bottom = int(ymax * height)
12        
13        # Draw rectangle
14        draw.rectangle([left, top, right, bottom], 
15                       outline='red', width=3)
16        
17        # Add label
18        label = f"Class {classes[i]}: {scores[i]:.0%}"
19        draw.text((left, top - 15), label, fill='red')
20
21image.save('output_with_boxes.jpg')

For OpenCV, the equivalent code looks like this:

python
1import cv2
2
3image_cv = cv2.imread('test_image.jpg')
4height, width, _ = image_cv.shape
5
6for i in range(num_detections):
7    if scores[i] >= threshold:
8        ymin, xmin, ymax, xmax = boxes[i]
9        left = int(xmin * width)
10        top = int(ymin * height)
11        right = int(xmax * width)
12        bottom = int(ymax * height)
13        
14        cv2.rectangle(image_cv, (left, top), (right, bottom), 
15                      (0, 0, 255), 2)
16        cv2.putText(image_cv, f"{scores[i]:.2f}", 
17                    (left, top - 10), 
18                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
19
20cv2.imwrite('output_with_boxes.jpg', image_cv)

Extracting Cropped Objects

You can also crop each detected object from the original image for further processing:

python
1cropped_objects = []
2
3for i in range(num_detections):
4    if scores[i] >= threshold:
5        ymin, xmin, ymax, xmax = boxes[i]
6        top = int(ymin * height)
7        left = int(xmin * width)
8        bottom = int(ymax * height)
9        right = int(xmax * width)
10        
11        cropped = image_np[top:bottom, left:right]
12        cropped_objects.append(cropped)
13        
14        # Save individual crops
15        crop_image = Image.fromarray(cropped)
16        crop_image.save(f'crop_{i}.jpg')

This is useful for tasks like license plate reading, where you first detect the plate and then pass the cropped region to an OCR model.

Working with the Label Map

The detection_classes tensor contains integer IDs. To get human-readable class names, you need the label map file that came with the model:

python
1from object_detection.utils import label_map_util
2
3label_map_path = 'mscoco_label_map.pbtxt'
4category_index = label_map_util.create_category_index_from_labelmap(
5    label_map_path, use_display_name=True
6)
7
8for i in range(num_detections):
9    if scores[i] >= threshold:
10        class_id = classes[i]
11        class_name = category_index[class_id]['name']
12        print(f"Detected: {class_name} ({scores[i]:.0%})")

Common Pitfalls

Confusing the coordinate order. TensorFlow uses [ymin, xmin, ymax, xmax], not [xmin, ymin, xmax, ymax]. Swapping x and y will produce boxes that are rotated or positioned incorrectly. Always double-check the order.

Forgetting that coordinates are normalized. If you use the raw values (0 to 1) as pixel coordinates, your boxes will be clustered in the top-left corner of the image. Always multiply by the image dimensions.

Not filtering by score. The model returns a fixed number of detections (often 100), most of which have very low confidence scores. Without a threshold filter, you will draw dozens of incorrect boxes.

Using the wrong image dimensions. If you resize the image before inference but use the original dimensions for coordinate conversion, the boxes will be misaligned. Always use the dimensions of the original image for the conversion, since the normalized coordinates are relative to whatever size the model saw.

Summary

The TensorFlow Object Detection API returns bounding boxes as normalized coordinates in [ymin, xmin, ymax, xmax] order. To convert them to pixel coordinates, multiply ymin and ymax by the image height, and xmin and xmax by the image width. Filter detections by confidence score, use the label map for class names, and be mindful of the coordinate order. With these steps, you can extract, visualize, and crop detected objects from any image.


Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design