Ryan Chesler
commited on
Commit
·
356eefc
1
Parent(s):
12ea31e
removed redundant utils.py
Browse files
utils.py
DELETED
|
@@ -1,204 +0,0 @@
|
|
| 1 |
-
# SPDX-FileCopyrightText: Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 2 |
-
# SPDX-License-Identifier: Apache-2.0
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
import numpy as np
|
| 6 |
-
import pandas as pd
|
| 7 |
-
import numpy.typing as npt
|
| 8 |
-
import matplotlib.pyplot as plt
|
| 9 |
-
from matplotlib.patches import Rectangle
|
| 10 |
-
from typing import Dict, List, Tuple, Optional, Union
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
COLORS = [
|
| 14 |
-
"#003EFF",
|
| 15 |
-
"#FF8F00",
|
| 16 |
-
"#079700",
|
| 17 |
-
"#A123FF",
|
| 18 |
-
"#87CEEB",
|
| 19 |
-
"#FF5733",
|
| 20 |
-
"#C70039",
|
| 21 |
-
"#900C3F",
|
| 22 |
-
"#581845",
|
| 23 |
-
"#11998E",
|
| 24 |
-
]
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
def reformat_for_plotting(
|
| 28 |
-
boxes: npt.NDArray[np.float64],
|
| 29 |
-
labels: npt.NDArray[np.int_],
|
| 30 |
-
scores: npt.NDArray[np.float64],
|
| 31 |
-
shape: Tuple[int, int],
|
| 32 |
-
num_classes: int,
|
| 33 |
-
) -> Tuple[List[npt.NDArray[np.int_]], List[npt.NDArray[np.float64]]]:
|
| 34 |
-
"""
|
| 35 |
-
Reformat YOLOX predictions for plotting.
|
| 36 |
-
- Unnormalizes boxes to original image size.
|
| 37 |
-
- Reformats boxes to [xmin, ymin, width, height].
|
| 38 |
-
- Converts to list of boxes and scores per class.
|
| 39 |
-
|
| 40 |
-
Args:
|
| 41 |
-
boxes (np.ndarray [N, 4]): Array of bounding boxes in format [xmin, ymin, xmax, ymax].
|
| 42 |
-
labels (np.ndarray [N]): Array of labels.
|
| 43 |
-
scores (np.ndarray [N]): Array of confidence scores.
|
| 44 |
-
shape (tuple [2]): Shape of the image (height, width).
|
| 45 |
-
num_classes (int): Number of classes.
|
| 46 |
-
|
| 47 |
-
Returns:
|
| 48 |
-
list[np.ndarray[N]]: List of box bounding boxes per class.
|
| 49 |
-
list[np.ndarray[N]]: List of confidence scores per class.
|
| 50 |
-
"""
|
| 51 |
-
boxes_plot = boxes.copy()
|
| 52 |
-
boxes_plot[:, [0, 2]] *= shape[1]
|
| 53 |
-
boxes_plot[:, [1, 3]] *= shape[0]
|
| 54 |
-
boxes_plot = boxes_plot.astype(int)
|
| 55 |
-
boxes_plot[:, 2] -= boxes_plot[:, 0]
|
| 56 |
-
boxes_plot[:, 3] -= boxes_plot[:, 1]
|
| 57 |
-
boxes_plot = [boxes_plot[labels == c] for c in range(num_classes)]
|
| 58 |
-
confs = [scores[labels == c] for c in range(num_classes)]
|
| 59 |
-
return boxes_plot, confs
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
def plot_sample(
|
| 63 |
-
img: npt.NDArray[np.uint8],
|
| 64 |
-
boxes_list: List[npt.NDArray[np.int_]],
|
| 65 |
-
confs_list: List[npt.NDArray[np.float64]],
|
| 66 |
-
labels: List[str],
|
| 67 |
-
show_text: bool = True,
|
| 68 |
-
) -> None:
|
| 69 |
-
"""
|
| 70 |
-
Plots an image with bounding boxes.
|
| 71 |
-
Coordinates are expected in format [x_min, y_min, width, height].
|
| 72 |
-
|
| 73 |
-
Args:
|
| 74 |
-
img (numpy.ndarray): The input image to be plotted.
|
| 75 |
-
boxes_list (list[np.ndarray]): List of box bounding boxes per class.
|
| 76 |
-
confs_list (list[np.ndarray]): List of confidence scores per class.
|
| 77 |
-
labels (list): List of class labels.
|
| 78 |
-
show_text (bool, optional): Whether to show the text. Defaults to True.
|
| 79 |
-
"""
|
| 80 |
-
plt.imshow(img, cmap="gray")
|
| 81 |
-
plt.axis(False)
|
| 82 |
-
|
| 83 |
-
for boxes, confs, col, l in zip(boxes_list, confs_list, COLORS, labels):
|
| 84 |
-
for box_idx, box in enumerate(boxes):
|
| 85 |
-
# Better display around boundaries
|
| 86 |
-
h, w, _ = img.shape
|
| 87 |
-
box = np.copy(box)
|
| 88 |
-
box[:2] = np.clip(box[:2], 2, max(h, w))
|
| 89 |
-
box[2] = min(box[2], w - 2 - box[0])
|
| 90 |
-
box[3] = min(box[3], h - 2 - box[1])
|
| 91 |
-
|
| 92 |
-
rect = Rectangle(
|
| 93 |
-
(box[0], box[1]),
|
| 94 |
-
box[2],
|
| 95 |
-
box[3],
|
| 96 |
-
linewidth=2,
|
| 97 |
-
facecolor="none",
|
| 98 |
-
edgecolor=col,
|
| 99 |
-
)
|
| 100 |
-
plt.gca().add_patch(rect)
|
| 101 |
-
|
| 102 |
-
# Add class and index label with proper alignment
|
| 103 |
-
if show_text:
|
| 104 |
-
plt.text(
|
| 105 |
-
box[0], box[1],
|
| 106 |
-
f"{l}_{box_idx} conf={confs[box_idx]:.3f}",
|
| 107 |
-
color='white',
|
| 108 |
-
fontsize=8,
|
| 109 |
-
bbox=dict(facecolor=col, alpha=1, edgecolor=col, pad=0, linewidth=2),
|
| 110 |
-
verticalalignment='bottom',
|
| 111 |
-
horizontalalignment='left'
|
| 112 |
-
)
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
def reorder_boxes(
|
| 116 |
-
boxes: npt.NDArray[np.float64],
|
| 117 |
-
labels: npt.NDArray[np.int_],
|
| 118 |
-
classes: Optional[List[str]] = None,
|
| 119 |
-
scores: Optional[npt.NDArray[np.float64]] = None,
|
| 120 |
-
) -> Union[
|
| 121 |
-
Tuple[npt.NDArray[np.float64], npt.NDArray[np.int_]],
|
| 122 |
-
Tuple[npt.NDArray[np.float64], npt.NDArray[np.int_], npt.NDArray[np.float64]],
|
| 123 |
-
]:
|
| 124 |
-
"""
|
| 125 |
-
Reorder boxes, labels and scores by box coordinates.
|
| 126 |
-
Columns are sorted by x first, rows and cells are sorted by y first.
|
| 127 |
-
|
| 128 |
-
Args:
|
| 129 |
-
boxes (np.ndarray [N, 4]): Array of bounding boxes in format [xmin, ymin, xmax, ymax].
|
| 130 |
-
labels (np.ndarray [N]): Array of labels.
|
| 131 |
-
classes (list, optional): List of class labels. Defaults to None.
|
| 132 |
-
scores (np.ndarray [N], optional): Array of confidence scores. Defaults to None.
|
| 133 |
-
|
| 134 |
-
Returns:
|
| 135 |
-
np.ndarray [N, 4]: Ordered boxes in format [xmin, ymin, xmax, ymax].
|
| 136 |
-
np.ndarray [N]: Ordered labels.
|
| 137 |
-
np.ndarray [N]: Ordered scores if scores is not None.
|
| 138 |
-
"""
|
| 139 |
-
n_classes = labels.max() if classes is None else len(classes)
|
| 140 |
-
classes = labels.unique() if classes is None else classes
|
| 141 |
-
|
| 142 |
-
ordered_boxes, ordered_labels, ordered_scores = [], [], []
|
| 143 |
-
for c in range(n_classes):
|
| 144 |
-
boxes_class = boxes[labels == c]
|
| 145 |
-
if len(boxes_class):
|
| 146 |
-
# Reorder
|
| 147 |
-
sort = ["x0", "y0"] if classes[c] == "column" else ["y0", "x0"]
|
| 148 |
-
|
| 149 |
-
df_coords = pd.DataFrame({
|
| 150 |
-
"y0": np.round(boxes_class[:, 1] - boxes_class[:, 1].min(), 2),
|
| 151 |
-
"x0": np.round(boxes_class[:, 0] - boxes_class[:, 0].min(), 2),
|
| 152 |
-
})
|
| 153 |
-
|
| 154 |
-
idxs = df_coords.sort_values(sort).index
|
| 155 |
-
|
| 156 |
-
ordered_boxes.append(boxes_class[idxs])
|
| 157 |
-
ordered_labels.append(labels[labels == c][idxs])
|
| 158 |
-
|
| 159 |
-
if scores is not None:
|
| 160 |
-
ordered_scores.append(scores[labels == c][idxs])
|
| 161 |
-
|
| 162 |
-
ordered_boxes = np.concatenate(ordered_boxes)
|
| 163 |
-
ordered_labels = np.concatenate(ordered_labels)
|
| 164 |
-
if scores is not None:
|
| 165 |
-
ordered_scores = np.concatenate(ordered_scores)
|
| 166 |
-
return ordered_boxes, ordered_labels, ordered_scores
|
| 167 |
-
return ordered_boxes, ordered_labels
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
def postprocess_preds_table_structure(
|
| 171 |
-
preds: Dict[str, npt.NDArray],
|
| 172 |
-
threshold: float = 0.1,
|
| 173 |
-
class_labels: Optional[List[str]] = None,
|
| 174 |
-
reorder: bool = True,
|
| 175 |
-
) -> Tuple[npt.NDArray[np.float64], npt.NDArray[np.int_], npt.NDArray[np.float64]]:
|
| 176 |
-
"""
|
| 177 |
-
Post process predictions for table structure task.
|
| 178 |
-
- Applies thresholding
|
| 179 |
-
- Reorders boxes using the reading order
|
| 180 |
-
|
| 181 |
-
Args:
|
| 182 |
-
preds (dict): Predictions. Keys are "scores", "boxes", "labels".
|
| 183 |
-
threshold (float, optional): Threshold for the confidence scores. Defaults to 0.1.
|
| 184 |
-
class_labels (list, optional): List of class labels. Defaults to None.
|
| 185 |
-
reorder (bool, optional): Whether to apply reordering. Defaults to True.
|
| 186 |
-
|
| 187 |
-
Returns:
|
| 188 |
-
numpy.ndarray [N x 4]: Array of bounding boxes.
|
| 189 |
-
numpy.ndarray [N]: Array of labels.
|
| 190 |
-
numpy.ndarray [N]: Array of scores.
|
| 191 |
-
"""
|
| 192 |
-
boxes = preds["boxes"].cpu().numpy()
|
| 193 |
-
labels = preds["labels"].cpu().numpy()
|
| 194 |
-
scores = preds["scores"].cpu().numpy()
|
| 195 |
-
|
| 196 |
-
# Threshold
|
| 197 |
-
boxes = boxes[scores > threshold]
|
| 198 |
-
labels = labels[scores > threshold]
|
| 199 |
-
scores = scores[scores > threshold]
|
| 200 |
-
|
| 201 |
-
if len(boxes) > 0 and reorder:
|
| 202 |
-
boxes, labels, scores = reorder_boxes(boxes, labels, class_labels, scores)
|
| 203 |
-
|
| 204 |
-
return boxes, labels, scores
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|