import itertools
import math
import more_itertools
import numpy as np
from kitcar_ml.utils.bounding_box import BoundingBox
[docs]def lcm(a, b):
"""Calculate the least common multiple of two numbers."""
return abs(a * b) // math.gcd(a, b)
[docs]def create_bounding_boxes(
accuracy=0.5, num_images=10, num_classes=1, max_boxes=1000, confidence=0.5
):
"""Create bounding boxes for detections and the groundtruth.
Args:
accuracy: The accuracy of the detections.
num_images: The number of images.
num_classes: The number of classes.
max_boxes: The maximal number of bounding boxes.
confidence: The confidence of inaccurate bounding boxes.
Returns:
The list of groundtruth and detection bounding boxes per image
and the resulting accuracy of the bounding boxes,
because it can happen that crocked accurcay get rounded a bit.
"""
if accuracy == 0:
num_boxes = num_images * 10
else:
num_boxes = lcm(lcm(math.ceil(1 / accuracy), num_classes), num_images) * num_images
num_boxes = min(max_boxes, num_boxes)
return create_bounding_boxes_by_amount(
accuracy=accuracy,
num_images=num_images,
num_classes=num_classes,
confidence=confidence,
)
[docs]def create_bounding_boxes_by_amount(
accuracy=0.5,
num_images=10,
num_classes=1,
num_boxes=100,
confidence=0.5,
):
"""Create bounding boxes for detections and the groundtruth.
Args:
accuracy: The accuracy of the detections.
num_images: The number of images.
num_classes: The number of classes.
num_boxes: The number of bounding boxes.
confidence: The confidence of inaccurate bounding boxes.
Returns:
The list of groundtruth and detection bounding boxes per image
and the resulting accuracy of the bounding boxes,
because it can happen that crocked accurcay get rounded a bit.
"""
# Assure should be divisible by the images
positives = num_boxes * accuracy
classes_iter = itertools.cycle(str(x) for x in range(num_classes))
accuracy_indices = [i < positives for i in range(num_boxes)]
permuted_accuracy_indices = [
np.random.permutation(indices)
for indices in more_itertools.chunked(accuracy_indices, num_boxes // num_images)
]
random_points = np.random.rand(num_boxes, 2) * 10
# Split random_points for all images
point1 = np.split(random_points, num_images)
# Endpoint of the box is just 10 pixel further.
point2 = np.add(point1, 10)
# Concatenate box endpoints to get the whole box.
bbs = np.concatenate((point1, point2), axis=2)
gts = [
[BoundingBox(*bb, cls) for bb, cls in zip(image_bbs, classes_iter)]
for image_bbs in bbs
]
dets = [
[
BoundingBox(*gt.coordinates, gt.class_label, 1)
if indices[i]
else BoundingBox(25, 25, 30, 30, gt.class_label, confidence=confidence)
for i, gt in enumerate(img_gts)
]
for img_gts, indices in zip(gts, permuted_accuracy_indices)
]
accuracy = int(math.ceil(positives)) / num_boxes
return gts, dets, accuracy