Spaces:
Build error
Build error
# Copyright (c) Meta Platforms, Inc. and affiliates. | |
# All rights reserved. | |
# | |
# This source code is licensed under the license found in the | |
# LICENSE file in the root directory of this source tree. | |
import warnings | |
from typing import Optional | |
import torch | |
from torch import Tensor | |
from ..utils import ext_loader | |
ext_module = ext_loader.load_ext('_ext', [ | |
'iou3d_boxes_overlap_bev_forward', 'iou3d_nms3d_forward', | |
'iou3d_nms3d_normal_forward' | |
]) | |
def boxes_overlap_bev(boxes_a: Tensor, boxes_b: Tensor) -> Tensor: | |
"""Calculate boxes BEV overlap. | |
Args: | |
boxes_a (torch.Tensor): Input boxes a with shape (M, 7). | |
boxes_b (torch.Tensor): Input boxes b with shape (N, 7). | |
Returns: | |
torch.Tensor: BEV overlap result with shape (M, N). | |
""" | |
ans_overlap = boxes_a.new_zeros( | |
torch.Size((boxes_a.shape[0], boxes_b.shape[0]))) | |
ext_module.iou3d_boxes_overlap_bev_forward(boxes_a.contiguous(), | |
boxes_b.contiguous(), | |
ans_overlap) | |
return ans_overlap | |
def boxes_iou3d(boxes_a: Tensor, boxes_b: Tensor) -> Tensor: | |
"""Calculate boxes 3D IoU. | |
Args: | |
boxes_a (torch.Tensor): Input boxes a with shape (M, 7). | |
boxes_b (torch.Tensor): Input boxes b with shape (N, 7). | |
Returns: | |
torch.Tensor: 3D IoU result with shape (M, N). | |
""" | |
assert boxes_a.shape[1] == boxes_b.shape[1] == 7,\ | |
'Input boxes shape should be (N, 7)' | |
boxes_a_height_max = (boxes_a[:, 2] + boxes_a[:, 5] / 2).view(-1, 1) | |
boxes_a_height_min = (boxes_a[:, 2] - boxes_a[:, 5] / 2).view(-1, 1) | |
boxes_b_height_max = (boxes_b[:, 2] + boxes_b[:, 5] / 2).view(1, -1) | |
boxes_b_height_min = (boxes_b[:, 2] - boxes_b[:, 5] / 2).view(1, -1) | |
overlaps_bev = boxes_a.new_zeros( | |
torch.Size((boxes_a.shape[0], boxes_b.shape[0]))) | |
ext_module.iou3d_boxes_overlap_bev_forward(boxes_a.contiguous(), | |
boxes_b.contiguous(), | |
overlaps_bev) | |
max_of_min = torch.max(boxes_a_height_min, boxes_b_height_min) | |
min_of_max = torch.min(boxes_a_height_max, boxes_b_height_max) | |
overlaps_h = torch.clamp(min_of_max - max_of_min, min=0) | |
overlaps_3d = overlaps_bev * overlaps_h | |
vol_a = (boxes_a[:, 3] * boxes_a[:, 4] * boxes_a[:, 5]).view(-1, 1) | |
vol_b = (boxes_b[:, 3] * boxes_b[:, 4] * boxes_b[:, 5]).view(1, -1) | |
iou3d = overlaps_3d / torch.clamp(vol_a + vol_b - overlaps_3d, min=1e-6) | |
return iou3d | |
def nms3d(boxes: Tensor, scores: Tensor, iou_threshold: float) -> Tensor: | |
"""3D NMS function GPU implementation (for BEV boxes). | |
Args: | |
boxes (torch.Tensor): Input boxes with the shape of (N, 7) | |
([x, y, z, dx, dy, dz, heading]). | |
scores (torch.Tensor): Scores of boxes with the shape of (N). | |
iou_threshold (float): Overlap threshold of NMS. | |
Returns: | |
torch.Tensor: Indexes after NMS. | |
""" | |
assert boxes.size(1) == 7, 'Input boxes shape should be (N, 7)' | |
order = scores.sort(0, descending=True)[1] | |
boxes = boxes[order].contiguous() | |
keep = boxes.new_zeros(boxes.size(0), dtype=torch.long) | |
num_out = boxes.new_zeros(size=(), dtype=torch.long) | |
ext_module.iou3d_nms3d_forward( | |
boxes, keep, num_out, nms_overlap_thresh=iou_threshold) | |
keep = order[keep[:num_out].to(boxes.device)].contiguous() | |
return keep | |
def nms3d_normal(boxes: Tensor, scores: Tensor, | |
iou_threshold: float) -> Tensor: | |
"""Normal 3D NMS function GPU implementation. The overlap of two boxes for | |
IoU calculation is defined as the exact overlapping area of the two boxes | |
WITH their yaw angle set to 0. | |
Args: | |
boxes (torch.Tensor): Input boxes with shape (N, 7). | |
([x, y, z, dx, dy, dz, heading]). | |
scores (torch.Tensor): Scores of predicted boxes with shape (N). | |
iou_threshold (float): Overlap threshold of NMS. | |
Returns: | |
torch.Tensor: Remaining indices with scores in descending order. | |
""" | |
assert boxes.shape[1] == 7, 'Input boxes shape should be (N, 7)' | |
order = scores.sort(0, descending=True)[1] | |
boxes = boxes[order].contiguous() | |
keep = boxes.new_zeros(boxes.size(0), dtype=torch.long) | |
num_out = boxes.new_zeros(size=(), dtype=torch.long) | |
ext_module.iou3d_nms3d_normal_forward( | |
boxes, keep, num_out, nms_overlap_thresh=iou_threshold) | |
return order[keep[:num_out].to(boxes.device)].contiguous() | |
def _xyxyr2xywhr(boxes: Tensor) -> Tensor: | |
"""Convert [x1, y1, x2, y2, heading] box to [x, y, dx, dy, heading] box. | |
Args: | |
box (torch.Tensor): Input boxes with shape (N, 5). | |
Returns: | |
torch.Tensor: Converted boxes with shape (N, 7). | |
""" | |
warnings.warn( | |
'This function is deprecated and will be removed in the future.', | |
DeprecationWarning) | |
return torch.stack( | |
((boxes[:, 0] + boxes[:, 2]) / 2, (boxes[:, 1] + boxes[:, 3]) / 2, | |
boxes[:, 2] - boxes[:, 0], boxes[:, 3] - boxes[:, 1], boxes[:, 4]), | |
dim=-1) | |
def boxes_iou_bev(boxes_a: Tensor, boxes_b: Tensor) -> Tensor: | |
"""Calculate boxes IoU in the Bird's Eye View. | |
Args: | |
boxes_a (torch.Tensor): Input boxes a with shape (M, 5) | |
([x1, y1, x2, y2, ry]). | |
boxes_b (torch.Tensor): Input boxes b with shape (N, 5) | |
([x1, y1, x2, y2, ry]). | |
Returns: | |
torch.Tensor: IoU result with shape (M, N). | |
""" | |
from .box_iou_rotated import box_iou_rotated | |
warnings.warn( | |
'`iou3d.boxes_iou_bev` is deprecated and will be removed in' | |
' the future. Please, use `box_iou_rotated.box_iou_rotated`.', | |
DeprecationWarning) | |
return box_iou_rotated(_xyxyr2xywhr(boxes_a), _xyxyr2xywhr(boxes_b)) | |
def nms_bev(boxes: Tensor, | |
scores: Tensor, | |
thresh: float, | |
pre_max_size: Optional[int] = None, | |
post_max_size: Optional[int] = None) -> Tensor: | |
"""NMS function GPU implementation (for BEV boxes). | |
The overlap of two boxes for IoU calculation is defined as the exact | |
overlapping area of the two boxes. In this function, one can also | |
set ``pre_max_size`` and ``post_max_size``. | |
Args: | |
boxes (torch.Tensor): Input boxes with the shape of (N, 5) | |
([x1, y1, x2, y2, ry]). | |
scores (torch.Tensor): Scores of boxes with the shape of (N,). | |
thresh (float): Overlap threshold of NMS. | |
pre_max_size (int, optional): Max size of boxes before NMS. | |
Default: None. | |
post_max_size (int, optional): Max size of boxes after NMS. | |
Default: None. | |
Returns: | |
torch.Tensor: Indexes after NMS. | |
""" | |
from .nms import nms_rotated | |
warnings.warn( | |
'`iou3d.nms_bev` is deprecated and will be removed in' | |
' the future. Please, use `nms.nms_rotated`.', DeprecationWarning) | |
assert boxes.size(1) == 5, 'Input boxes shape should be (N, 5)' | |
order = scores.sort(0, descending=True)[1] | |
if pre_max_size is not None: | |
order = order[:pre_max_size] | |
boxes = _xyxyr2xywhr(boxes)[order] | |
scores = scores[order] | |
keep = nms_rotated(boxes, scores, thresh)[1] | |
keep = order[keep] | |
if post_max_size is not None: | |
keep = keep[:post_max_size] | |
return keep | |
def nms_normal_bev(boxes: Tensor, scores: Tensor, thresh: float) -> Tensor: | |
"""Normal NMS function GPU implementation (for BEV boxes). | |
The overlap of two boxes for IoU calculation is defined as the exact | |
overlapping area of the two boxes WITH their yaw angle set to 0. | |
Args: | |
boxes (torch.Tensor): Input boxes with shape (N, 5) | |
([x1, y1, x2, y2, ry]). | |
scores (torch.Tensor): Scores of predicted boxes with shape (N,). | |
thresh (float): Overlap threshold of NMS. | |
Returns: | |
torch.Tensor: Remaining indices with scores in descending order. | |
""" | |
from .nms import nms | |
warnings.warn( | |
'`iou3d.nms_normal_bev` is deprecated and will be removed in' | |
' the future. Please, use `nms.nms`.', DeprecationWarning) | |
assert boxes.shape[1] == 5, 'Input boxes shape should be (N, 5)' | |
return nms(boxes[:, :-1], scores, thresh)[1] | |