Skip to content

anchor_generator

AnchorGenerator

Standard anchor generator for 2D anchor-based detectors.

Parameters:

Name Type Description Default
strides list[int]

Strides of anchors in multiple feture levels.

required
ratios list[float]

The list of ratios between the height and width of anchors in a single level.

required
scales list[int] | None

Anchor scales for anchors in a single level. It cannot be set at the same time if octave_base_scale and scales_per_octave are set.

required
base_sizes list[int] | None

The basic sizes of anchors in multiple levels. If None is given, strides will be used as base_sizes.

required
scale_major bool

Whether to multiply scales first when generating base anchors. If true, the anchors in the same row will have the same scales. By default it is True in V2.0

required
octave_base_scale int

The base scale of octave.

required
scales_per_octave int

Number of scales for each octave. octave_base_scale and scales_per_octave are usually used in retinanet and the scales should be None when they are set.

required
centers list[tuple[float, float]] | None

The centers of the anchor relative to the feature grid center in multiple feature levels. By default it is set to be None and not used. If a list of tuple of float is given, they will be used to shift the centers of anchors.

required
center_offset float

The offset of center in propotion to anchors' width and height. By default it is 0 in V2.0.

required

Examples:

>>> from mmdet.core import AnchorGenerator
>>> self = AnchorGenerator([16], [1.], [1.], [9])
>>> all_anchors = self.grid_anchors([(2, 2)], device='cpu')
>>> print(all_anchors)
[tensor([[-4.5000, -4.5000,  4.5000,  4.5000],
        [11.5000, -4.5000, 20.5000,  4.5000],
        [-4.5000, 11.5000,  4.5000, 20.5000],
        [11.5000, 11.5000, 20.5000, 20.5000]])]
>>> self = AnchorGenerator([16, 32], [1.], [1.], [9, 18])
>>> all_anchors = self.grid_anchors([(2, 2), (1, 1)], device='cpu')
>>> print(all_anchors)
[tensor([[-4.5000, -4.5000,  4.5000,  4.5000],
        [11.5000, -4.5000, 20.5000,  4.5000],
        [-4.5000, 11.5000,  4.5000, 20.5000],
        [11.5000, 11.5000, 20.5000, 20.5000]]),         tensor([[-9., -9., 9., 9.]])]

num_levels: int property readonly

Returns the number of levels.

Returns:

Type Description
int

Number of levels.

gen_base_anchors(self)

Computes the anchors.

Returns:

Type Description
List[numpy.ndarray]

List of arrays with the anchors.

Source code in pyodi/core/anchor_generator.py
def gen_base_anchors(self) -> List[ndarray]:
    """Computes the anchors.

    Returns:
        List of arrays with the anchors.
    """
    multi_level_base_anchors = []
    for i, base_size in enumerate(self.base_sizes):
        center = None
        if self.centers is not None:
            center = self.centers[i]
        multi_level_base_anchors.append(
            self.gen_single_level_base_anchors(
                base_size, scales=self.scales, ratios=self.ratios, center=center
            )
        )
    return multi_level_base_anchors

gen_single_level_base_anchors(self, base_size, scales, ratios, center=None)

Computes the anchors of a single level.

Parameters:

Name Type Description Default
base_size int

Basic size of the anchors in a single level.

required
scales ndarray

Anchor scales for anchors in a single level

required
ratios ndarray

Ratios between height and width of anchors in a single level.

required
center Optional[Tuple[float, float]]

Center of the anchor relative to the feature grid center in single level.

None

Returns:

Type Description
ndarray

Array with the anchors.

Source code in pyodi/core/anchor_generator.py
def gen_single_level_base_anchors(
    self,
    base_size: int,
    scales: ndarray,
    ratios: ndarray,
    center: Optional[Tuple[float, float]] = None,
) -> ndarray:
    """Computes the anchors of a single level.

    Args:
        base_size: Basic size of the anchors in a single level.
        scales: Anchor scales for anchors in a single level
        ratios: Ratios between height and width of anchors in a single level.
        center: Center of the anchor relative to the feature grid center in single
            level.

    Returns:
        Array with the anchors.

    """
    w = base_size
    h = base_size
    if center is None:
        x_center = self.center_offset * w
        y_center = self.center_offset * h
    else:
        x_center, y_center = center

    h_ratios = np.sqrt(ratios)
    w_ratios = 1 / h_ratios
    if self.scale_major:
        ws = (w * w_ratios[:, None] * scales[None, :]).flatten()
        hs = (h * h_ratios[:, None] * scales[None, :]).flatten()
    else:
        ws = (w * scales[:, None] * w_ratios[None, :]).flatten()
        hs = (h * scales[:, None] * h_ratios[None, :]).flatten()

    # use float anchor and the anchor's center is aligned with the
    # pixel center
    base_anchors = [
        x_center - 0.5 * ws,
        y_center - 0.5 * hs,
        x_center + 0.5 * ws,
        y_center + 0.5 * hs,
    ]
    base_anchors = np.stack(base_anchors, axis=-1)

    return base_anchors

grid_anchors(self, featmap_sizes)

Generate grid anchors in multiple feature levels.

Parameters:

Name Type Description Default
featmap_sizes List[Tuple[int, int]]

List of feature map sizes in multiple feature levels.

required

Returns:

Type Description
List[numpy.ndarray]

Anchors in multiple feature levels. The sizes of each tensor should be [N, 4], where N = width * height * num_base_anchors, width and height are the sizes of the corresponding feature level, num_base_anchors is the number of anchors for that level.

Source code in pyodi/core/anchor_generator.py
def grid_anchors(self, featmap_sizes: List[Tuple[int, int]]) -> List[ndarray]:
    """Generate grid anchors in multiple feature levels.

    Args:
        featmap_sizes: List of feature map sizes in multiple feature levels.

    Returns:
        Anchors in multiple feature levels. The sizes of each tensor should be
        [N, 4], where N = width * height * num_base_anchors, width and height are
        the sizes of the corresponding feature level, num_base_anchors is the
        number of anchors for that level.
    """
    assert self.num_levels == len(featmap_sizes)
    multi_level_anchors = []
    for i in range(self.num_levels):
        anchors = self.single_level_grid_anchors(
            self.base_anchors[i], featmap_sizes[i], self.strides[i],
        )
        multi_level_anchors.append(anchors)
    return multi_level_anchors

single_level_grid_anchors(self, base_anchors, featmap_size, stride=16)

Generate grid anchors in a single feature level.

Parameters:

Name Type Description Default
base_anchors ndarray

Anchors in a single level.

required
featmap_size Tuple[int, int]

Feature map size in a single level.

required
stride int

Number of stride. Defaults to 16.

16

Returns:

Type Description
ndarray

Grid of anchors in a single feature level.

Source code in pyodi/core/anchor_generator.py
def single_level_grid_anchors(
    self, base_anchors: ndarray, featmap_size: Tuple[int, int], stride: int = 16
) -> ndarray:
    """Generate grid anchors in a single feature level.

    Args:
        base_anchors: Anchors in a single level.
        featmap_size: Feature map size in a single level.
        stride: Number of stride. Defaults to 16.

    Returns:
          Grid of anchors in a single feature level.

    """
    feat_h, feat_w = featmap_size
    shift_x = np.arange(0, feat_w) * stride
    shift_y = np.arange(0, feat_h) * stride
    shift_xx, shift_yy = self._meshgrid(shift_x, shift_y)
    shifts = np.stack([shift_xx, shift_yy, shift_xx, shift_yy], axis=-1)
    shifts = shifts.astype(base_anchors.dtype)
    # first feat_w elements correspond to the first row of shifts
    # add A anchors (1, A, 4) to K shifts (K, 1, 4) to get
    # shifted anchors (K, A, 4), reshape to (K*A, 4)

    all_anchors = base_anchors[None, :, :] + shifts[:, None, :]
    all_anchors = np.reshape(all_anchors, [-1, 4])
    # first A rows correspond to A anchors of (0, 0) in feature map,
    # then (0, 1), (0, 2), ...
    return all_anchors

to_dict(self)

Transforms configuration into dictionary.

Returns:

Type Description
Dict[str, Any]

Dictionary with config.

Source code in pyodi/core/anchor_generator.py
def to_dict(self) -> Dict[str, Any]:
    """Transforms configuration into dictionary.

    Returns:
        Dictionary with config.
    """
    anchor_config = dict(
        type="'AnchorGenerator'",
        scales=sorted(list(self.scales.ravel())),
        ratios=sorted(list(self.ratios.ravel())),
        strides=list(self.strides),
        base_sizes=list(self.base_sizes),
    )

    return anchor_config

to_string(self)

Transforms configuration into string.

Returns:

Type Description
str

String with config.

Source code in pyodi/core/anchor_generator.py
def to_string(self) -> str:
    """Transforms configuration into string.

    Returns:
        String with config.

    """
    anchor_config = self.to_dict()

    string = "anchor_generator=dict(\n"
    for k, v in anchor_config.items():
        string += f"{' '* 4}{k}={v},\n"
    string += ")"

    return string