MediumComputer Vision

Anchor Box Generation

Computer Vision

Medium

Problem

Object detectors like Faster R-CNN and SSD generate a dense set of predefined bounding boxes called anchors at every position on a feature grid. Each anchor serves as an initial guess that the network refines during training.

Given a square feature grid size, the original image size, a list of scales, and a list of aspect ratios, generate all anchor boxes in image coordinates.

Algorithm

  1. Compute the stride (spacing between grid cells in image space):

stride = \frac{image\_size}{feature\_size}

  1. For each grid cell (i, j), compute the center in image coordinates:

cx = (j + 0.5) \times stride \qquad cy = (i + 0.5) \times stride

  1. For each combination of scale s and aspect ratio r, compute the box width and height:

w = s \cdot \sqrt{r} \qquad h = \frac{s}{\sqrt{r}}

  1. The anchor box is [cx - w/2, cy - h/2, cx + w/2, cy + h/2].

Iterate over grid cells in row-major order (i then j), and for each cell iterate over scales then aspect ratios.

Theory

Anchor boxes (also called prior boxes or default boxes) are predefined bounding boxes used in object detection. Instead of predicting box coordinates from scratch, the network predicts adjustments to these anchors.

Key idea: scatter anchors densely across the image, then classify each anchor as containing an object or not, and refine the box coordinates.


Why Use Anchors?

Problem without anchors:

With anchors:

This is analogous to regression: predicting residuals from a baseline is easier than predicting raw values.


Anchor Parameters

Anchors are defined by:

Position (from feature map grid):

Scale:

Aspect ratio:

Each combination of (position, scale, aspect ratio) produces one anchor.


Grid to Image Coordinates

The feature map is smaller than the image (due to pooling/striding). To map grid positions to image coordinates:

\text{stride} = \frac{\text{image size}}{\text{feature size}}

For grid cell (i, j):

c_x = (j + 0.5) \times \text{stride}

c_y = (i + 0.5) \times \text{stride}

The +0.5 places the anchor at the cell center.


Computing Anchor Dimensions

Given scale s and aspect ratio r:

w = s \cdot \sqrt{r}

h = \frac{s}{\sqrt{r}}

This ensures the anchor area is approximately s^2 regardless of aspect ratio.

Example with scale=64, ratio=2 (wide):


Anchor Box Coordinates

The anchor box in (x1, y1, x2, y2) format:

x_1 = c_x - \frac{w}{2}, \quad y_1 = c_y - \frac{h}{2}

x_2 = c_x + \frac{w}{2}, \quad y_2 = c_y + \frac{h}{2}


Numerical Example

Parameters:

Stride: 8 / 2 = 4

Cell (0, 0) center: cx = 0.5 * 4 = 2, cy = 0.5 * 4 = 2

Anchors at (0, 0):

Scale 2, ratio 1.0:

Scale 2, ratio 2.0:

Scale 4, ratio 1.0:

Scale 4, ratio 2.0:

And so on for all 4 cells...


Total Number of Anchors

\text{Total anchors} = H_{feat} \times W_{feat} \times |\text{scales}| \times |\text{ratios}|

For a 50x50 feature map with 3 scales and 3 ratios:

This dense coverage ensures at least one anchor will overlap well with any object.


Anchor Matching

During training, each anchor is matched to ground truth:

Positive anchor:

Negative anchor:

Ignored:


Multi-Scale Anchors

Modern detectors use anchors at multiple feature map resolutions:

Small feature map (coarse):

Large feature map (fine):

This is the Feature Pyramid Network (FPN) approach used in many state-of-the-art detectors.


Architectures Using Anchors

Faster R-CNN:

SSD (Single Shot Detector):

RetinaNet:

YOLO v2+:


Anchor-Free Alternatives

Recent detectors avoid anchors entirely:

FCOS:

CenterNet:

Anchor-free methods are simpler but anchors remain competitive.

Examples

Example 1

Input
feature_size = 1, image_size = 8, scales = [4], aspect_ratios = [1.0]
Output
[[2.0, 2.0, 6.0, 6.0]]
Explanation
The only grid cell is centered at (4, 4), and its anchor has width and height 4.

Example 2

Input
feature_size = 2, image_size = 8, scales = [2], aspect_ratios = [1.0]
Output
[[1.0, 1.0, 3.0, 3.0], [5.0, 1.0, 7.0, 3.0], [1.0, 5.0, 3.0, 7.0], [5.0, 5.0, 7.0, 7.0]]

Hints

  1. Compute stride as image_size / feature_size and offset each grid coordinate by 0.5 before scaling.
  2. For scale s and ratio r, use width = s * sqrt(r) and height = s / sqrt(r).

Requirements

Constraints

Starter Code

def generate_anchors(feature_size: int, image_size: float, scales: list[float], aspect_ratios: list[float]) -> list[list[float]]:
    """
    Returns a list of [x1, y1, x2, y2] anchor boxes.
    """
    # Write code here
    pass

Test Cases

CaseMatches
Single cell, one anchorpublic
2x2 grid, single scale/ratiopublic