# ============================================================================== # Binaries and/or source for the following packages or projects # are presented under one or more of the following open source licenses: # distance.py The OpenLane-V2 Dataset Authors Apache License, Version 2.0 # # Contact wanghuijie@pjlab.org.cn if you have any issue. # # Copyright (c) 2023 The OpenLane-v2 Dataset Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== import numpy as np from scipy.spatial.distance import cdist, euclidean from similaritymeasures import frechet_dist def pairwise(xs: list, ys: list, distance_function: callable, mask: np.ndarray = None, relax: bool = False) -> np.ndarray: r""" Calculate pairwise distance. Parameters ---------- xs : list List of data in shape (X, ). ys : list List of data in shape (Y, ). distance_function : callable Function that computes distance between two instance. mask : np.ndarray Boolean mask in shape (X, Y). relax : bool Relax the result based on distance to ego vehicle. Returns ------- np.ndarray Float in shape (X, Y), where array[i][j] denotes distance between instance xs[i] and ys[j]. """ result = np.ones((len(xs), len(ys)), dtype=np.float64) * 1024 for i, x in enumerate(xs): ego_distance = min([euclidean(p, np.zeros_like(p)) for p in x]) relaxation_factor = max(0.5, 1 - 5e-3 * ego_distance) if relax else 1.0 for j, y in enumerate(ys): if mask is None or mask[i][j]: result[i][j] = distance_function(x, y) * relaxation_factor return result def chamfer_distance(gt: np.ndarray, pred: np.ndarray) -> float: r""" Calculate Chamfer distance. Parameters ---------- gt : np.ndarray Curve of (G, N) shape, where G is the number of data points, and N is the number of dimmensions. pred : np.ndarray Curve of (P, N) shape, where P is the number of points, and N is the number of dimmensions. Returns ------- float Chamfer distance Notes ----- Adapted from https://github.com/Mrmoore98/VectorMapNet_code/blob/810ae463377f8e724c90a732361a675bcd7cf53b/plugin/datasets/evaluation/precision_recall/tgfg.py#L139. """ assert gt.ndim == pred.ndim == 2 and gt.shape[1] == pred.shape[1] dist_mat = cdist(pred, gt) dist_pred = dist_mat.min(-1).mean() dist_gt = dist_mat.min(0).mean() return (dist_pred + dist_gt) / 2 def frechet_distance(gt: np.ndarray, pred: np.ndarray) -> float: r""" Calculate discrete Frechet distance. Parameters ---------- gt : np.ndarray Curve of (G, N) shape, where G is the number of data points, and N is the number of dimmensions. pred : np.ndarray Curve of (P, N) shape, where P is the number of points, and N is the number of dimmensions. Returns ------- float discrete Frechet distance """ assert gt.ndim == pred.ndim == 2 and gt.shape[1] == pred.shape[1] return frechet_dist(pred, gt, p=2) def iou_distance(gt: np.ndarray, pred: np.ndarray) -> float: r""" Calculate IoU distance, which is 1 - IoU. Parameters ---------- gt : np.ndarray Bounding box in form [[x1, y1], [x2, y2]]. pred : np.ndarray Bounding box in form [[x1, y1], [x2, y2]]. Returns ------- float IoU distance """ assert pred.shape == gt.shape == (2, 2) bxmin = max(pred[0][0], gt[0][0]) bymin = max(pred[0][1], gt[0][1]) bxmax = min(pred[1][0], gt[1][0]) bymax = min(pred[1][1], gt[1][1]) inter = max((bxmax - bxmin), 0) * max((bymax - bymin), 0) union = (pred[1][0] - pred[0][0]) * (pred[1][1] - pred[0][1]) + (gt[1][0] - gt[0][0]) * (gt[1][1] - gt[0][1]) - inter return 1 - inter / union