DIPO / metrics /giou.py
xinjie.wang
init commit
c28dddb
import os, sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
import numpy as np
from metrics.iou import (
_sample_points_in_box3d,
_apply_backward_transformations,
_apply_forward_transformations,
_count_points_in_box3d,
)
def giou_aabb(bbox1_vertices, bbox2_verices):
"""
Compute the generalized IoU between two axis-aligned bounding boxes\n
- bbox1_vertices: the vertices of the first bounding box in the form: [[x0, y0, z0], [x1, y1, z1], ...]\n
- bbox2_vertices: the vertices of the second bounding box in the form: [[x0, y0, z0], [x1, y1, z1], ...]\n
Return:\n
- giou: the gIoU between the two bounding boxes
"""
volume1 = np.prod(np.max(bbox1_vertices, axis=0) - np.min(bbox1_vertices, axis=0))
volume2 = np.prod(np.max(bbox2_verices, axis=0) - np.min(bbox2_verices, axis=0))
# Compute the intersection and union of the two bounding boxes
min_bbox = np.maximum(np.min(bbox1_vertices, axis=0), np.min(bbox2_verices, axis=0))
max_bbox = np.minimum(np.max(bbox1_vertices, axis=0), np.max(bbox2_verices, axis=0))
intersection = np.prod(np.clip(max_bbox - min_bbox, a_min=0, a_max=None))
union = volume1 + volume2 - intersection
# Compute IoU
iou = intersection / union if union > 0 else 0
# Compute the smallest enclosing box
min_enclosing_bbox = np.minimum(np.min(bbox1_vertices, axis=0), np.min(bbox2_verices, axis=0))
max_enclosing_bbox = np.maximum(np.max(bbox1_vertices, axis=0), np.max(bbox2_verices, axis=0))
volume3 = np.prod(max_enclosing_bbox - min_enclosing_bbox)
# Compute gIoU
giou = iou - (volume3 - union) / volume3 if volume3 > 0 else iou
return giou
def sampling_giou(
bbox1_vertices,
bbox2_vertices,
bbox1_transformations,
bbox2_transformations,
num_samples=10000,
):
"""
Compute the IoU between two bounding boxes\n
- bbox1_vertices: the vertices of the first bounding box\n
- bbox2_vertices: the vertices of the second bounding box\n
- bbox1_transformations: list of transformations applied to the first bounding box\n
- bbox2_transformations: list of transformations applied to the second bounding box\n
- num_samples (optional): the number of samples to use per bounding box\n
Return:\n
- iou: the IoU between the two bounding boxes after applying the transformations
"""
# if no transformations are applied, use the axis-aligned bounding box IoU
if len(bbox1_transformations) == 0 and len(bbox2_transformations) == 0:
return giou_aabb(bbox1_vertices, bbox2_vertices)
# Volume of the two bounding boxes
bbox1_volume = np.prod(
np.max(bbox1_vertices, axis=0) - np.min(bbox1_vertices, axis=0)
)
bbox2_volume = np.prod(
np.max(bbox2_vertices, axis=0) - np.min(bbox2_vertices, axis=0)
)
# Volume of the smallest enclosing box
min_enclosing_bbox = np.minimum(np.min(bbox1_vertices, axis=0), np.min(bbox2_vertices, axis=0))
max_enclosing_bbox = np.maximum(np.max(bbox1_vertices, axis=0), np.max(bbox2_vertices, axis=0))
cbbox_volume = np.prod(max_enclosing_bbox - min_enclosing_bbox)
# Sample points in the two bounding boxes
bbox1_points = _sample_points_in_box3d(bbox1_vertices, num_samples)
bbox2_points = _sample_points_in_box3d(bbox2_vertices, num_samples)
# Transform the points
forward_bbox1_points = _apply_forward_transformations(
bbox1_points, bbox1_transformations
)
forward_bbox2_points = _apply_forward_transformations(
bbox2_points, bbox2_transformations
)
# Transform the forward points to the other box's rest pose frame
forward_bbox1_points_in_rest_bbox2_frame = _apply_backward_transformations(
forward_bbox1_points, bbox2_transformations
)
forward_bbox2_points_in_rest_bbox1_frame = _apply_backward_transformations(
forward_bbox2_points, bbox1_transformations
)
# Count the number of points in the other bounding box
num_bbox1_points_in_bbox2 = _count_points_in_box3d(
forward_bbox1_points_in_rest_bbox2_frame, bbox2_vertices
)
num_bbox2_points_in_bbox1 = _count_points_in_box3d(
forward_bbox2_points_in_rest_bbox1_frame, bbox1_vertices
)
# Compute the IoU
intersect = (
bbox1_volume * num_bbox1_points_in_bbox2
+ bbox2_volume * num_bbox2_points_in_bbox1
) / 2
union = bbox1_volume * num_samples + bbox2_volume * num_samples - intersect
iou = intersect / union
giou = iou - (cbbox_volume * num_samples - union) / (cbbox_volume * num_samples) if cbbox_volume > 0 else iou
return giou
def sampling_cDist(
part1,
part2,
bbox1_transformations,
bbox2_transformations,
):
'''
Compute the centroid distance between two bounding boxes\n
- bbox1_vertices: the vertices of the first bounding box\n
- bbox2_vertices: the vertices of the second bounding box\n
- bbox1_transformations: list of transformations applied to the first bounding box\n
- bbox2_transformations: list of transformations applied to the second bounding box\n
'''
bbox1_centroid = np.array(part1['aabb']['center'], dtype=np.float32).reshape(1, 3)
bbox2_centroid = np.array(part2['aabb']['center'], dtype=np.float32).reshape(1, 3)
# Transform the centroids
bbox1_transformed_centroids = _apply_forward_transformations(bbox1_centroid, bbox1_transformations)
bbox2_transformed_centroids = _apply_forward_transformations(bbox2_centroid, bbox2_transformations)
# Compute the centroid distance
cDist = np.linalg.norm(bbox1_transformed_centroids - bbox2_transformed_centroids)
return cDist