# default_exp datasets.generators

Helpers for Dataset Generation

Display image

# export
def show_img(img):
    """
    Display a numpy array as a image
    """
    fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(3, 3))
    ax.imshow(img)
# export
def save_img(path, name, img):
    """
    Save a numpy array as a image
    """
    image = img.astype(np.uint8)
    filename = path / (name + ".jpg")

    imsave(filename, image, check_contrast=False)
# export
def save_img_annotations(path, annotations, name="annotations"):
    """
    Helper to save the annotations of a image into the desired file
    """
    filename = path / (name + ".json")

    with open(filename, "w") as file:
        json.dump(annotations, file)

Create images

from skimage.draw import (ellipse_perimeter)

# change from zeros to ones to have a white bg.
img = np.zeros((300, 500, 3), dtype=np.double)

fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(8, 8))

# draw ellipse with perimeter
rr_ellipse, cc_ellipse = ellipse(150, 100, 100, 50)
rr_ellipse_p, cc_ellipse_p = ellipse_perimeter(150, 100, 100, 50)
img[rr_ellipse, cc_ellipse, :] = (1, 0, 0)
img[rr_ellipse_p, cc_ellipse_p, :] = (0, 0, 0)

# draw square
rr_square, cc_square = rectangle(start=(100, 200), extent=(75, 75))
rr_square_p, cc_square_p = rectangle_perimeter(start=(100, 200), extent=(75, 75))
img[rr_square, cc_square, :] = (0, 0, 1)
img[rr_square_p, cc_square_p, :] = (1, 0, 0)

# draw line

rr_line, cc_line = line(70, 350, 200, 350)
img[rr_line, cc_line, :] = (1, 1, 0)

# display img
ax.imshow(img)
<matplotlib.image.AxesImage at 0x7f9c634f1430>
# export
def draw_grid(im=None, size=(100, 100), n_hlines=10, n_vlines=10, black=True):
    """
    Will draw the default background with a grid system.

    im  np.array:
        Existing image, if None will create one

    size  (int, int):
        Height and width, respectively

    n_hlines  int:
        Number of horizontal lines

    n_vlines  int:
        Number of vertial lines

    black  bool:
        If true, the background will be black

    """
    height, width = size
    img = im
    color = (0, 0, 0)
    line_color = (1, 1, 1)
    if not black:
        color = (1, 1, 1)
        line_color = (0, 0, 0)

    if im is None:
        img = np.full((height, width, 3), dtype=np.double, fill_value=color)

    for lines in range(n_hlines):
        y = height * lines * (1 / n_hlines)
        y = int(y)
        rr_line, cc_line = line(0, y, width - 1, y)
        img[rr_line, cc_line, :] = line_color

    for lines in range(n_vlines):
        x = width * lines * (1 / n_vlines)
        x = int(x)
        rr_line, cc_line = line(x, 0, x, height - 1)
        img[rr_line, cc_line, :] = line_color

    return img
img = draw_grid(size=(200, 200), n_hlines=4, n_vlines=4)
show_img(img)
# export

def draw_bbox(rect, rect_dimensions, im=None, black=True):
    """
    Draw a Bounding Box

    rect  (int, int):
        Begining point of the retangle

    rect_dimensions  (int, int):
        Width and Height of the retangle

    im  np.array:
        Image where bbox will be draw

    black  bool:
        If true, the bbox will be black

    """
    init_x, init_y = rect
    height, width = rect_dimensions
    img = im

    if im is None:
        img = np.ones((100, 200, 3), dtype=np.double)

    color = (0, 0, 0)
    if not black:
        color = (255, 255, 255)

    rr, cc = rectangle_perimeter(start=(init_x, init_y),
                                 extent=(height, width),
                                 shape=img.shape)
    img[rr, cc, :] = color

    ex_height = height + 10
    ex_width = width + 10
    if (ex_height > len(img)):
        ex_height = len(img)

    if (ex_width > len(im[0])):
        ex_width = len(img[0])

    rr, cc = rectangle_perimeter(start=(init_x - 5, init_y - 5),
                                 extent=(ex_height, ex_width),
                                 shape=img.shape)

    img[rr, cc, :] = color

    return img
#img = draw_grid(size=(3400, 400),n_hlines=2, n_vlines=10, black=False)
# draw_bbox((35, 50, 200, 250), im=img, black=False)
img = np.ones((300, 400, 3), dtype=np.double)
draw_bbox((215, 250), (15, 100), im=img, black=True)

show_img(img)

Overlap & Intersection over Union (IOU)

r1 = (10, 10)
r1_dimensions = (130, 130)
r2 = (50, 50)
r2_dimensions = (90, 90)
assert overlap(r1, r1_dimensions, r2, r2_dimensions) == 1
assert overlap(r2, r2_dimensions, r1, r1_dimensions) == 1
# export
def bb_intersection_over_union(boxA, boxA_dimensions, boxB, boxB_dimensions, verbose=False):
    interArea, boxAArea, boxBArea, _ = bbox_intersection(boxA, boxA_dimensions,
                                                         boxB, boxB_dimensions)

    iou = interArea / float(boxAArea + boxBArea - interArea)
    if verbose:
        print(f"iou: {iou: .2f}, interArea: {interArea: .2f}, "
              f"boxAArea {boxAArea: .2f}, box1Area {boxBArea: .2f}")
    return iou
r1 = (10, 10)
r2 = (80, 80)
r1_dimensions = (100, 100)
r2_dimensions = (100, 100)
img = np.zeros((300, 200, 3), dtype=np.double)
draw_bbox(r1, r1_dimensions, im=img, black=False)
draw_bbox(r2, r2_dimensions, im=img, black=False)


iou = bb_intersection_over_union(r1, r1_dimensions, r2, r2_dimensions, True)
# iou = bb_intersection_over_union(r1, r2, verbose=True)
_, _, _, union = bbox_intersection(r1, r1_dimensions, r2, r2_dimensions)

init_height, init_widht, final_height, final_widht = union
extent_height = final_height - init_height
extent_width = final_widht - init_widht

rr, cc = rectangle(start=(init_height, init_widht), extent=(final_height, final_widht))

img[rr, cc, :] = (1, 1, 1)

show_img(img)
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
iou:  0.05, interArea:  900.00, boxAArea  10000.00, box1Area  10000.00

Sample Random bbox

#export
def sample_bbox(bboxs=(), canvas_size=(100, 100), diag=(0.3, 0.3), ratio=(1, 1),
                max_iou=0.0, max_overlap=0.0,
                max_tries=1000, random_seed=None):
    """
    bboxs  [(x, y, x, y), ... ]:
        List of existing bboxs

    canvas_size  (int, int):
        Width and height on which to position the new bbox.

    max_iou  float [0, 1]:
        Maximum acceptable intersection over union between any two bboxs

    max_overlap  float [0, 1]:
        Maximum overlap between any two bboxs

    diag  (float, float) or float:
        Range of acceptable diagonal lenght relative to canvas diagonal

    ratio  (float, float) or float:
        Range of acceptable width / heigh ratios of the new bbox

    max_tries  int:
        Number of random tries to create a valid bbox
    """
#     for v in [diag, ratio]: assert min(v) >= 0 and max(v) <= 1, f"{v} is outside of (0, 1)"

    width, height = canvas_size
    canvas_diag = np.sqrt(width ** 2 + height**2)

    for i in range(max_tries):
        s_diag = np.random.uniform(*diag) * canvas_diag
        s_ratio = np.random.uniform(*ratio)

        # sample position fully inside canvas
        s_height = np.sqrt(s_diag ** 2 / (1. + s_ratio ** 2))
        s_width = s_ratio * s_height

        cx = np.random.randint(s_width / 2, width - s_width / 2)
        cy = np.random.randint(s_height / 2, height - s_height / 2)

        bbox_x = cx - s_width / 2
        bbox_y = cy - s_height / 2
        bbox_width = cx + s_width / 2 - bbox_x
        bbox_height = cy + s_height / 2 - bbox_y

        bbox = (bbox_x, bbox_y, bbox_width, bbox_height)
        bbox = tuple(int(v) for v in bbox)

        # check if valid iou then return
        if len(bboxs) == 0:
            return bbox
        violation = False
        for b in bboxs:
            b_x, b_y, b_width, b_heigh = b
            iou = bb_intersection_over_union((b_x, b_y), (b_width, b_heigh),
                                             (bbox_x, bbox_y), (bbox_width, bbox_height))
            b_overlap = overlap((b_x, b_y), (b_width, b_heigh),
                                (bbox_x, bbox_y), (bbox_width, bbox_height))
            if iou > max_iou or b_overlap > max_overlap:
                violation = True
        if not violation:
            return bbox

    return None
img = np.zeros((300, 300, 3), dtype=np.double)

bboxs: List[Tuple[int, int, int, int]] = []
for i in range(10):
    bbox: Tuple[int, int, int, int] = sample_bbox(
        bboxs=bboxs, canvas_size=(300, 300), diag=(0.1, 0.3), max_iou=0.3,
        max_overlap=0.5)

    init_x, init_y, width, heigh = bbox

    bboxs.append(bbox)
    draw_bbox((init_x, init_y), (width, heigh), im=img, black=False, )

show_img(img)
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).

Draw Objects inside bbox

#export
def draw_rectangle(im, start, dimensions, color):
    #draw = ImageDraw.Draw(im)
    #draw.rectangle(bbox, fill=color)
    rr, cc = rectangle(start=start, extent=dimensions)
    im[rr, cc, :] = color
    return im
#export
def draw_ellipse(im, start, dimensions, color):
    #draw = ImageDraw.Draw(im)
    #cx, cy = bbox[0] + bbox[2] / 2, bbox[1] + bbox[3]
    #draw.ellipse(bbox, fill=color)
    x, y = start
    v_radius, h_radius = dimensions

    rr, cc = ellipse(x, y, v_radius, h_radius)
    im[rr, cc, :] = color
    return im
img = np.zeros((200, 200, 3), dtype=np.double)

ractangle_init_point = (25, 25)
rectangle_dimensions = (75, 50)
img = draw_rectangle(img, ractangle_init_point, rectangle_dimensions, (0, 0, 1))
img = draw_bbox(im=img, rect=ractangle_init_point, black=False,
                rect_dimensions=rectangle_dimensions)

ellipse_init_point = (150, 65)
ellipse_dimensions = (20, 54)

ellipse_x, ellipse_y = ellipse_init_point
ellipse_v_radius, ellipse_h_radius = ellipse_dimensions
ellipse_bbox_start = (ellipse_x - ellipse_v_radius, ellipse_y - ellipse_h_radius)
ellipse_bbox_dimensions = (ellipse_v_radius * 2, ellipse_h_radius * 2)

img = draw_ellipse(img, ellipse_init_point, ellipse_dimensions, (1, 0, 0))
img = draw_bbox(im=img, rect=ellipse_bbox_start, black=False,
                rect_dimensions=ellipse_bbox_dimensions)
show_img(img)
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
image, shapes = random_shapes((500, 500), 50, multichannel=True)
rr_0, rr_1 = shapes[0][1][0]
cc_0, cc_1 = shapes[0][1][1]

middle_x = int((rr_0 + rr_1) / 2)
middle_y = int((cc_0 + cc_1) / 2)

# Picking up the middle value will guarantee we get the shape color
print(image[middle_x, middle_y])

show_img(image)
<ipython-input-30-63cfa24158e3>:1: FutureWarning: `multichannel` is a deprecated argument name for `random_shapes`. It will be removed in version 1.0. Please use `channel_axis` instead.
  image, shapes = random_shapes((500, 500), 50, multichannel=True)
[233 155   8]

Create Object Detection Dataset

Generic Dataset

Specific Tasks

#export
def create_color_classification(path, n_samples=10, size=(150, 150)):
    """
    Helper function to color classification
    """

    images, annotations = create_simple_object_detection_dataset(path=path, n_samples=n_samples,
                                                                 size=size)

    color_img = {}
    for img in annotations:
        color_arr = []

        for shape in annotations[img]['labels']:
            color_arr.append(shape[0])

        color_img[img] = {'label': color_arr}

    save_img_annotations(path, color_img)
    return (images, color_img)
#export
def create_shape_color_classification(path, n_samples=10, size=(150, 150)):
    """
    Helper function to shape classification
    """
    images, annotations = create_simple_object_detection_dataset(
        path, n_samples=n_samples, size=size)

    label_img = {}
    for img in annotations:
        label_arr = []

        for shape in annotations[img]['labels']:
            label_arr.append(shape)

        label_img[img] = {'label': label_arr}

    save_img_annotations(path, label_img)
    return (images, label_img)
#export
def create_object_detection(path, n_samples=10, n_objects=1, size=(150, 150), multilabel=False):
    """
    Helper function to object detection
    """
    images, annotations = create_simple_object_detection_dataset(path=path, size=size,
                                                                 n_samples=n_samples,
                                                                 n_objects_max=n_objects)

    coords_img = {}
    for img in annotations:
        coords_arr = []

        for coord in annotations[img]['bboxs']:
            coords_arr.append(coord)

        if not multilabel:
            coords_arr = coords_arr[0]

        coords_img[img] = {'label': coords_arr}

    save_img_annotations(path, coords_img)
    return (images, coords_img)