90 lines
3.2 KiB
Python
90 lines
3.2 KiB
Python
"""
|
|
Helper functions used internally for object detection tasks.
|
|
"""
|
|
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
|
|
import numpy as np
|
|
|
|
from cleanlab.internal.numerics import softmax
|
|
|
|
|
|
def bbox_xyxy_to_xywh(bbox: List[float]) -> Optional[List[float]]:
|
|
"""Converts bounding box coodrinate types from x1y1,x2y2 to x,y,w,h"""
|
|
if len(bbox) == 4:
|
|
x1, y1, x2, y2 = bbox
|
|
w = x2 - x1
|
|
h = y2 - y1
|
|
return [x1, y1, w, h]
|
|
else:
|
|
print("Wrong bbox shape", len(bbox))
|
|
return None
|
|
|
|
|
|
def softmin1d(scores: np.ndarray, temperature: float = 0.99, axis: int = 0) -> float:
|
|
"""Returns softmin of passed in scores."""
|
|
scores = np.array(scores)
|
|
softmax_scores = softmax(x=-1 * scores, temperature=temperature, axis=axis, shift=True)
|
|
return np.dot(softmax_scores, scores)
|
|
|
|
|
|
def calculate_bounding_box_areas(rectangle_coordinates):
|
|
"""Calculate areas of bounding boxes represented by numpy array with x1, y1, x2, y2 format"""
|
|
widths = rectangle_coordinates[:, 2] - rectangle_coordinates[:, 0]
|
|
heights = rectangle_coordinates[:, 3] - rectangle_coordinates[:, 1]
|
|
return widths * heights
|
|
|
|
|
|
def assert_valid_aggregation_weights(aggregation_weights: Dict[str, Any]) -> None:
|
|
"""assert aggregation weights are in the proper format"""
|
|
weights = np.array(list(aggregation_weights.values()))
|
|
if (not np.isclose(np.sum(weights), 1.0)) or (np.min(weights) < 0.0):
|
|
raise ValueError(
|
|
f"""Aggregation weights should be non-negative and must sum to 1.0
|
|
"""
|
|
)
|
|
|
|
|
|
def assert_valid_inputs(
|
|
labels: List[Dict[str, Any]],
|
|
predictions,
|
|
method: Optional[str] = None,
|
|
threshold: Optional[float] = None,
|
|
):
|
|
"""Asserts proper input format."""
|
|
if len(labels) != len(predictions):
|
|
raise ValueError(
|
|
f"labels and predictions length needs to match. len(labels) == {len(labels)} while len(predictions) == {len(predictions)}."
|
|
)
|
|
# Typecheck labels and predictions
|
|
if not isinstance(labels[0], dict):
|
|
raise ValueError(
|
|
f"Labels has to be a list of dicts. Instead it is list of {type(labels[0])}."
|
|
)
|
|
# check last column of predictions is probabilities ( < 1.)?
|
|
if not isinstance(predictions[0], (list, np.ndarray)):
|
|
raise ValueError(
|
|
f"Prediction has to be a list or np.ndarray. Instead it is type {type(predictions[0])}."
|
|
)
|
|
if not predictions[0][0].shape[1] == 5:
|
|
raise ValueError(
|
|
f"Prediction values have to be of format [x1,y1,x2,y2,pred_prob]. Please refer to the documentation for predicted probabilities under object_detection.rank.get_label_quality_scores for details"
|
|
)
|
|
|
|
valid_methods = ["objectlab"]
|
|
if method is not None and method not in valid_methods:
|
|
raise ValueError(
|
|
f"""
|
|
{method} is not a valid object detection scoring method!
|
|
Please choose a valid scoring_method: {valid_methods}
|
|
"""
|
|
)
|
|
|
|
if threshold is not None and threshold > 1.0:
|
|
raise ValueError(
|
|
f"""
|
|
Threshold is a cutoff of predicted probabilities and therefore should be <= 1.
|
|
"""
|
|
)
|