Spaces:
Sleeping
Sleeping
| import numpy as np | |
| def box_denormalize(boxes: np.ndarray, img_w: int, img_h: int) -> np.ndarray: | |
| """ | |
| Denormalizes boxes from [0, 1] to [0, img_w] and [0, img_h]. | |
| Args: | |
| boxes (Tensor[N, 4]): boxes which will be denormalized. | |
| img_w (int): Width of image. | |
| img_h (int): Height of image. | |
| Returns: | |
| Tensor[N, 4]: Denormalized boxes. | |
| """ | |
| if boxes.size == 0: | |
| return boxes | |
| # check if boxes are normalized | |
| if np.any(boxes > 1.0): | |
| return boxes | |
| boxes[:, 0::2] *= img_w | |
| boxes[:, 1::2] *= img_h | |
| return boxes | |
| def box_convert(boxes: np.ndarray, in_fmt: str, out_fmt: str) -> np.ndarray: | |
| """ | |
| Converts boxes from given in_fmt to out_fmt. | |
| Supported in_fmt and out_fmt are: | |
| 'xyxy': boxes are represented via corners, x1, y1 being top left and x2, y2 being bottom right. | |
| This is the format that torchvision utilities expect. | |
| 'xywh' : boxes are represented via corner, width and height, x1, y2 being top left, w, h being width and height. | |
| 'cxcywh' : boxes are represented via centre, width and height, cx, cy being center of box, w, h | |
| being width and height. | |
| Args: | |
| boxes (Tensor[N, 4]): boxes which will be converted. | |
| in_fmt (str): Input format of given boxes. Supported formats are ['xyxy', 'xywh', 'cxcywh']. | |
| out_fmt (str): Output format of given boxes. Supported formats are ['xyxy', 'xywh', 'cxcywh'] | |
| Returns: | |
| Tensor[N, 4]: Boxes into converted format. | |
| """ | |
| if boxes.size == 0: | |
| return boxes | |
| allowed_fmts = ("xyxy", "xywh", "cxcywh") | |
| if in_fmt not in allowed_fmts or out_fmt not in allowed_fmts: | |
| raise ValueError( | |
| "Unsupported Bounding Box Conversions for given in_fmt and out_fmt") | |
| if in_fmt == out_fmt: | |
| return boxes.copy() | |
| if in_fmt != "xyxy" and out_fmt != "xyxy": | |
| # convert to xyxy and change in_fmt xyxy | |
| if in_fmt == "xywh": | |
| boxes = _box_xywh_to_xyxy(boxes) | |
| elif in_fmt == "cxcywh": | |
| boxes = _box_cxcywh_to_xyxy(boxes) | |
| in_fmt = "xyxy" | |
| if in_fmt == "xyxy": | |
| if out_fmt == "xywh": | |
| boxes = _box_xyxy_to_xywh(boxes) | |
| elif out_fmt == "cxcywh": | |
| boxes = _box_xyxy_to_cxcywh(boxes) | |
| elif out_fmt == "xyxy": | |
| if in_fmt == "xywh": | |
| boxes = _box_xywh_to_xyxy(boxes) | |
| elif in_fmt == "cxcywh": | |
| boxes = _box_cxcywh_to_xyxy(boxes) | |
| return boxes | |
| def _box_xywh_to_xyxy(boxes): | |
| """ | |
| Converts bounding boxes from (x, y, w, h) format to (x1, y1, x2, y2) format. | |
| (x, y) refers to top left of bounding box. | |
| (w, h) refers to width and height of box. | |
| Args: | |
| boxes (ndarray[N, 4]): boxes in (x, y, w, h) which will be converted. | |
| Returns: | |
| boxes (ndarray[N, 4]): boxes in (x1, y1, x2, y2) format. | |
| """ | |
| x, y, w, h = np.split(boxes, 4, axis=-1) | |
| x1 = x | |
| y1 = y | |
| x2 = x + w | |
| y2 = y + h | |
| converted_boxes = np.concatenate([x1, y1, x2, y2], axis=-1) | |
| return converted_boxes | |
| def _box_cxcywh_to_xyxy(boxes): | |
| """ | |
| Converts bounding boxes from (cx, cy, w, h) format to (x1, y1, x2, y2) format. | |
| (cx, cy) refers to center of bounding box | |
| (w, h) are width and height of bounding box | |
| Args: | |
| boxes (ndarray[N, 4]): boxes in (cx, cy, w, h) format which will be converted. | |
| Returns: | |
| boxes (ndarray[N, 4]): boxes in (x1, y1, x2, y2) format. | |
| """ | |
| cx, cy, w, h = np.split(boxes, 4, axis=-1) | |
| x1 = cx - 0.5 * w | |
| y1 = cy - 0.5 * h | |
| x2 = cx + 0.5 * w | |
| y2 = cy + 0.5 * h | |
| converted_boxes = np.concatenate([x1, y1, x2, y2], axis=-1) | |
| return converted_boxes | |
| def _box_xyxy_to_xywh(boxes): | |
| """ | |
| Converts bounding boxes from (x1, y1, x2, y2) format to (x, y, w, h) format. | |
| (x1, y1) refer to top left of bounding box | |
| (x2, y2) refer to bottom right of bounding box | |
| Args: | |
| boxes (ndarray[N, 4]): boxes in (x1, y1, x2, y2) which will be converted. | |
| Returns: | |
| boxes (ndarray[N, 4]): boxes in (x, y, w, h) format. | |
| """ | |
| x1, y1, x2, y2 = np.split(boxes, 4, axis=-1) | |
| w = x2 - x1 | |
| h = y2 - y1 | |
| converted_boxes = np.concatenate([x1, y1, w, h], axis=-1) | |
| return converted_boxes | |
| def _box_xyxy_to_cxcywh(boxes): | |
| """ | |
| Converts bounding boxes from (x1, y1, x2, y2) format to (cx, cy, w, h) format. | |
| (x1, y1) refer to top left of bounding box | |
| (x2, y2) refer to bottom right of bounding box | |
| Args: | |
| boxes (ndarray[N, 4]): boxes in (x1, y1, x2, y2) format which will be converted. | |
| Returns: | |
| boxes (ndarray[N, 4]): boxes in (cx, cy, w, h) format. | |
| """ | |
| x1, y1, x2, y2 = np.split(boxes, 4, axis=-1) | |
| cx = (x1 + x2) / 2 | |
| cy = (y1 + y2) / 2 | |
| w = x2 - x1 | |
| h = y2 - y1 | |
| converted_boxes = np.concatenate([cx, cy, w, h], axis=-1) | |
| return converted_boxes | |
| def _fix_empty_arrays(boxes: np.ndarray) -> np.ndarray: | |
| """Empty tensors can cause problems, this methods corrects them.""" | |
| if boxes.size == 0 and boxes.ndim == 1: | |
| return np.expand_dims(boxes, axis=0) | |
| return boxes | |
| def _input_validator(preds, targets, iou_type="bbox"): | |
| """Ensure the correct input format of `preds` and `targets`.""" | |
| if iou_type == "bbox": | |
| item_val_name = "boxes" | |
| elif iou_type == "segm": | |
| item_val_name = "masks" | |
| else: | |
| raise Exception(f"IOU type {iou_type} is not supported") | |
| if not isinstance(preds, (list, tuple)): | |
| raise ValueError( | |
| f"Expected argument `preds` to be of type list or tuple, but got {type(preds)}") | |
| if not isinstance(targets, (list, tuple)): | |
| raise ValueError( | |
| f"Expected argument `targets` to be of type list or tuple, but got {type(targets)}") | |
| if len(preds) != len(targets): | |
| raise ValueError( | |
| f"Expected argument `preds` and `targets` to have the same length, but got {len(preds)} and {len(targets)}" | |
| ) | |
| for k in [item_val_name, "scores", "labels"]: | |
| if any(k not in p for p in preds): | |
| raise ValueError( | |
| f"Expected all dicts in `preds` to contain the `{k}` key") | |
| for k in [item_val_name, "labels"]: | |
| if any(k not in p for p in targets): | |
| raise ValueError( | |
| f"Expected all dicts in `targets` to contain the `{k}` key") | |
| if any(type(pred[item_val_name]) is not np.ndarray for pred in preds): | |
| raise ValueError( | |
| f"Expected all {item_val_name} in `preds` to be of type ndarray") | |
| if any(type(pred["scores"]) is not np.ndarray for pred in preds): | |
| raise ValueError( | |
| "Expected all scores in `preds` to be of type ndarray") | |
| if any(type(pred["labels"]) is not np.ndarray for pred in preds): | |
| raise ValueError( | |
| "Expected all labels in `preds` to be of type ndarray") | |
| if any(type(target[item_val_name]) is not np.ndarray for target in targets): | |
| raise ValueError( | |
| f"Expected all {item_val_name} in `targets` to be of type ndarray") | |
| if any(type(target["labels"]) is not np.ndarray for target in targets): | |
| raise ValueError( | |
| "Expected all labels in `targets` to be of type ndarray") | |
| for i, item in enumerate(targets): | |
| if item[item_val_name].shape[0] != item["labels"].shape[0]: | |
| raise ValueError( | |
| f"Input {item_val_name} and labels of sample {i} in targets have a" | |
| f" different length (expected {item[item_val_name].shape[0]} labels, got {item['labels'].shape[0]})" | |
| ) | |
| for i, item in enumerate(preds): | |
| if not (item[item_val_name].shape[0] == item["labels"].shape[0] == item["scores"].shape[0]): | |
| raise ValueError( | |
| f"Input {item_val_name}, labels and scores of sample {i} in predictions have a" | |
| f" different length (expected {item[item_val_name].shape[0]} labels and scores," | |
| f" got {item['labels'].shape[0]} labels and {item['scores'].shape[0]})" | |
| ) |