def draw_star(img_size, num_frames, bg_config, nb_branches=6):
    """ Draw a star and output the interest points
    Parameters:
      nb_branches: number of branches of the star
    """

    images = generate_background(img_size, num_frames=num_frames)
    background_color = int(np.mean(images))

    num_branches = random_state.randint(3, nb_branches)
    min_dim = min(img_size[0], img_size[1])
    thickness = random_state.randint(min_dim * 0.01, min_dim * 0.02)
    rad = max(random_state.rand() * min_dim / 2, min_dim / 5)
    x = random_state.randint(rad, img_size[1] -
                             rad)  # select the center of a circle
    y = random_state.randint(rad, img_size[0] - rad)
    # Sample num_branches points inside the circle
    slices = np.linspace(0, 2 * math.pi, num_branches + 1)
    angles = [
        slices[j] + random_state.rand() * (slices[j + 1] - slices[j])
        for j in range(num_branches)
    ]
    points = np.array([[
        int(x + max(random_state.rand(), 0.3) * rad * math.cos(a)),
        int(y + max(random_state.rand(), 0.3) * rad * math.sin(a))
    ] for a in angles])
    points = np.concatenate(([[x, y]], points), axis=0)
    color = get_random_color(background_color)
    rotation = get_random_rotation()
    speed = get_random_speed()

    pts_list = []
    img_list = []
    for i in range(num_frames):

        img = images[i]
        pts = np.empty((0, 2), dtype=np.int)

        center = (points[0][0], points[0][1])
        points = (np.matmul(points - center, rotation) + center +
                  speed).astype(int)
        for j in range(1, num_branches + 1):
            cv.line(img, (points[0][0], points[0][1]),
                    (points[j][0], points[j][1]), int(color[j]), thickness)

        # Keep only the points inside the image
        pts = keep_points_inside(points, img_size)

        if len(pts) == 0:
            draw_star(img_size, num_frames, bg_config, nb_branches)

        pts_list.append(pts)
        img_list.append(img)

    images = np.array(img_list)
    points = np.array(pts_list)

    event_sim = es.Event_simulator(images[0], 0)
    events = np.array([event_sim.simulate(img, 0) for img in images[1:]])
    return images, points, events
def draw_polygon(img_size, num_frames, bg_config, max_sides=8):
    """ Draw a polygon with a random number of corners
    and return the corner points
    Parameters:
      max_sides: maximal number of sides + 1
    """

    images = generate_background(img_size, num_frames=num_frames)
    background_color = int(np.mean(images))
    points = generate_polygons(img_size)
    num_lines = len(points)

    # Generate Speed and Rotation for animation
    rotation = get_random_rotation()
    speed = get_random_speed()
    color = get_random_color(background_color=background_color)

    # Generate animated scences
    frame_points = []
    for i, image in enumerate(images):
        center = np.average(points, axis=0)
        points = calculate_rigid_transformation(points, center, speed,
                                                rotation)

        corners = points.reshape((-1, 1, 2))
        cv.fillPoly(image, np.array([corners], dtype=np.int32), int(color))
        frame_points.append(points)

    points = np.array(frame_points)
    event_sim = es.Event_simulator(images[0], 0)
    events = np.array([event_sim.simulate(img, 0) for img in images[1:]])

    return images, points, events
def draw_lines(img_size, num_frames, bg_config, nb_lines=10):
    """ Draw random lines and output the positions of the endpoints
    Parameters:
      nb_lines: maximal number of lines
    """

    images = generate_background(img_size, num_frames=num_frames)
    background_color = int(np.mean(images))
    num_lines = random_state.randint(1, nb_lines)
    p1 = get_random_position(img_size, num_lines)
    p2 = p1 + get_random_length(num=num_lines)
    out_p1 = p1[np.newaxis, :, :]
    out_p2 = p2[np.newaxis, :, :]

    # Generate Speed and Rotation for animation
    thickness = get_random_thickness(num=num_lines)
    rotation = get_random_rotation(num=num_lines)
    speed = get_random_speed(num=num_lines)
    colors = get_random_color(num=num_lines, background_color=background_color)

    # Generate Frames and Remove collided lines
    for i in range(num_frames):

        center = (out_p1[i] + out_p2[i]) / 2
        p1 = calculate_rigid_transformation_batch_lines(
            out_p1[i], center, speed, rotation)
        p2 = calculate_rigid_transformation_batch_lines(
            out_p2[i], center, speed, rotation)

        valid_idx = [0]
        for j in range(1, num_lines):
            if not intersect(p1[valid_idx], p2[valid_idx], np.array([p1[j]]),
                             np.array([p2[j]])):
                valid_idx.append(j)

        out_p1 = np.vstack((out_p1[:, valid_idx, :], p1[np.newaxis,
                                                        valid_idx, :]))
        out_p2 = np.vstack((out_p2[:, valid_idx, :], p2[np.newaxis,
                                                        valid_idx, :]))
        speed = speed[valid_idx]
        rotation = rotation[valid_idx]
        num_lines = len(valid_idx)

    # Draw lines on background images
    for i in range(num_frames):
        for j in range(num_lines):
            cv.line(images[i], tuple(out_p1[i, j].astype(int)),
                    tuple(out_p2[i, j].astype(int)), int(colors[j]),
                    thickness[j])

    points = np.hstack((out_p1, out_p2))

    event_sim = es.Event_simulator(images[0], 0)
    events = np.array([event_sim.simulate(img, 0) for img in images[1:]])

    return images, points, events
def draw_cube(img_size,
              num_frames,
              bg_config,
              min_size_ratio=0.2,
              min_angle_rot=math.pi / 10,
              scale_interval=(0.4, 0.6),
              trans_interval=(0.5, 0.2)):
    """ Draw a 2D projection of a cube and output the corners that are visible
    Parameters:
      min_size_ratio: min(img.shape) * min_size_ratio is the smallest achievable
                      cube side size
      min_angle_rot: minimal angle of rotation
      scale_interval: the scale is between scale_interval[0] and
                      scale_interval[0]+scale_interval[1]
      trans_interval: the translation is between img.shape*trans_interval[0] and
                      img.shape*(trans_interval[0] + trans_interval[1])
    """
    # Generate a cube and apply to it an affine transformation
    # The order matters!
    # The indices of two adjacent vertices differ only of one bit (as in Gray codes)

    images = generate_background(img_size, num_frames=num_frames)
    background_color = int(np.mean(images))
    min_dim = min(img_size[:2])
    min_side = min_dim * min_size_ratio
    lx = min_side + random_state.rand(
    ) * 2 * min_dim / 3  # dimensions of the cube
    ly = min_side + random_state.rand() * 2 * min_dim / 3
    lz = min_side + random_state.rand() * 2 * min_dim / 3
    cube = np.array([[0, 0, 0], [lx, 0, 0], [0, ly, 0], [lx, ly, 0],
                     [0, 0, lz], [lx, 0, lz], [0, ly, lz], [lx, ly, lz]])
    rot_angles = random_state.rand(3) * 3 * math.pi / 10. + math.pi / 10.
    rotation = [
        random_state.uniform(0.01, 0.02) * random_state.choice([1, -1])
        for _ in range(3)
    ]

    scaling = np.array(
        [[scale_interval[0] + random_state.rand() * scale_interval[1], 0, 0],
         [0, scale_interval[0] + random_state.rand() * scale_interval[1], 0],
         [0, 0, scale_interval[0] + random_state.rand() * scale_interval[1]]])
    trans = np.array([
        img_size[1] * trans_interval[0] + random_state.randint(
            -img_size[1] * trans_interval[1], img_size[1] * trans_interval[1]),
        img_size[0] * trans_interval[0] + random_state.randint(
            -img_size[0] * trans_interval[1], img_size[0] * trans_interval[1]),
        0
    ])

    col_face = get_random_color(background_color=background_color)
    thickness = max(random_state.randint(min_dim * 0.003, min_dim * 0.015), 1)
    speed = get_random_speed()

    for i in [0, 1, 2]:
        for j in [0, 1, 2, 3]:
            col_edge = (col_face + 128
                        + random_state.randint(-64, 64))\
                        % 256

    img_list = []
    pts_list = []
    for t in range(num_frames):

        img = images[t]
        cube = np.array([[0, 0, 0], [lx, 0, 0], [0, ly, 0], [lx, ly, 0],
                         [0, 0, lz], [lx, 0, lz], [0, ly, lz], [lx, ly, lz]])

        rot_angles += rotation

        rotation_1 = np.array(
            [[math.cos(rot_angles[0]), -math.sin(rot_angles[0]), 0],
             [math.sin(rot_angles[0]),
              math.cos(rot_angles[0]), 0], [0, 0, 1]])
        rotation_2 = np.array(
            [[1, 0, 0], [0,
                         math.cos(rot_angles[1]), -math.sin(rot_angles[1])],
             [0, math.sin(rot_angles[1]),
              math.cos(rot_angles[1])]])
        rotation_3 = np.array(
            [[math.cos(rot_angles[2]), 0, -math.sin(rot_angles[2])], [0, 1, 0],
             [math.sin(rot_angles[2]), 0,
              math.cos(rot_angles[2])]])

        cube = trans + np.transpose(
            np.dot(
                scaling,
                np.dot(
                    rotation_1,
                    np.dot(rotation_2, np.dot(rotation_3,
                                              np.transpose(cube))))))

        # The hidden corner is 0 by construction
        # The front one is 7
        cube = cube[:, :2]  # project on the plane z=0
        cube = cube.astype(int)
        points = cube[1:, :]  # get rid of the hidden corner
        points += t * speed

        # Get the three visible faces
        faces = np.array([[7, 3, 1, 5], [7, 5, 4, 6], [7, 6, 2, 3]])

        # Fill the faces and draw the contours
        for i in [0, 1, 2]:
            cv.fillPoly(img, [cube[faces[i]].reshape((-1, 1, 2))],
                        int(col_face))

        for i in [0, 1, 2]:
            for j in [0, 1, 2, 3]:
                cv.line(img, (cube[faces[i][j], 0], cube[faces[i][j], 1]),
                        (cube[faces[i][(j + 1) % 4],
                              0], cube[faces[i][(j + 1) % 4], 1]),
                        int(col_edge), thickness)

        # Keep only the points inside the image
        points = keep_points_inside(points, img_size[:2])

        if len(points) == 0:
            return draw_cube(img_size, num_frames, bg_config, min_size_ratio,
                             min_angle_rot, scale_interval, trans_interval)

        pts_list.append(points)
        img_list.append(img)

    points = np.array(pts_list)
    images = np.array(img_list)

    event_sim = es.Event_simulator(images[0], 0)
    events = np.array([event_sim.simulate(img, 0) for img in images[1:]])

    return images, points, events
def draw_stripes(img_size,
                 num_frames,
                 bg_config,
                 max_nb_cols=13,
                 min_width_ratio=0.04,
                 transform_params=(0.05, 0.15)):
    """ Draw stripes in a distorted rectangle and output the interest points
    Parameters:
      max_nb_cols: maximal number of stripes to be drawn
      min_width_ratio: the minimal width of a stripe is
                       min_width_ratio * smallest dimension of the image
      transform_params: set the range of the parameters of the transformations
    """

    images = generate_background(img_size, num_frames=num_frames)
    background_color = int(np.mean(images))
    # Create the grid
    board_size = (int(img_size[0] * (1 + random_state.rand())),
                  int(img_size[1] * (1 + random_state.rand())))
    col = random_state.randint(5, max_nb_cols)  # number of cols
    cols = np.concatenate([
        board_size[1] * random_state.rand(col - 1),
        np.array([0, board_size[1] - 1])
    ],
                          axis=0)
    cols = np.unique(cols.astype(int))
    # Remove the indices that are too close
    min_dim = min(img_size)
    min_width = min_dim * min_width_ratio
    cols = cols[(np.concatenate(
        [cols[1:], np.array([board_size[1] + min_width])], axis=0) -
                 cols) >= min_width]
    col = cols.shape[0] - 1  # update the number of cols
    cols = np.reshape(cols, (col + 1, 1))
    cols1 = np.concatenate([cols, np.zeros((col + 1, 1), np.int32)], axis=1)
    cols2 = np.concatenate(
        [cols, (board_size[0] - 1) * np.ones((col + 1, 1), np.int32)], axis=1)
    points = np.concatenate([cols1, cols2], axis=0)

    # Warp the grid using an affine transformation and an homography
    # The parameters of the transformations are constrained
    # to get transformations not too far-fetched
    # Prepare the matrices
    alpha_affine = np.max(img_size) * (
        transform_params[0] + random_state.rand() * transform_params[1])
    center_square = np.float32(img_size) // 2
    square_size = min(img_size) // 3
    pts1 = np.float32([
        center_square + square_size,
        [center_square[0] + square_size, center_square[1] - square_size],
        center_square - square_size,
        [center_square[0] - square_size, center_square[1] + square_size]
    ])
    pts2 = pts1 + random_state.uniform(
        -alpha_affine, alpha_affine, size=pts1.shape).astype(np.float32)
    affine_transform = cv.getAffineTransform(pts1[:3], pts2[:3])
    pts2 = pts1 + random_state.uniform(-alpha_affine / 2,
                                       alpha_affine / 2,
                                       size=pts1.shape).astype(np.float32)
    perspective_transform = cv.getPerspectiveTransform(pts1, pts2)

    # Apply the affine transformation
    points = np.transpose(
        np.concatenate((points, np.ones((2 * (col + 1), 1))), axis=1))
    warped_points = np.transpose(np.dot(affine_transform, points))

    # Apply the homography
    warped_col0 = np.add(
        np.sum(np.multiply(warped_points, perspective_transform[0, :2]),
               axis=1), perspective_transform[0, 2])
    warped_col1 = np.add(
        np.sum(np.multiply(warped_points, perspective_transform[1, :2]),
               axis=1), perspective_transform[1, 2])
    warped_col2 = np.add(
        np.sum(np.multiply(warped_points, perspective_transform[2, :2]),
               axis=1), perspective_transform[2, 2])
    warped_col0 = np.divide(warped_col0, warped_col2)
    warped_col1 = np.divide(warped_col1, warped_col2)
    warped_points = np.concatenate(
        [warped_col0[:, None], warped_col1[:, None]], axis=1)
    warped_points = warped_points.astype(int)

    # Fill the rectangles
    colors = np.zeros(col + 1)
    colors[-1] = get_random_color(background_color=background_color)

    # Draw lines on the boundaries of the stripes at random
    nb_rows = random_state.randint(2, 5)
    nb_cols = random_state.randint(2, col + 2)

    thickness = random_state.randint(min_dim * 0.01, min_dim * 0.02)

    row_idx = [random_state.choice([0, col + 1]) for _ in range(nb_rows)]
    col_idx1 = [random_state.randint(col + 1) for _ in range(nb_rows)]
    col_idx2 = [random_state.randint(col + 1) for _ in range(nb_rows)]
    row_color = [
        get_random_color(background_color=background_color)
        for _ in range(nb_rows)
    ]

    col_idx = [random_state.randint(col + 1) for _ in range(nb_cols)]
    col_color = [
        get_random_color(background_color=background_color)
        for _ in range(nb_cols)
    ]

    for i in range(col):
        colors[i] = (colors[i - 1] + 128 + random_state.randint(-30, 30)) % 256

    # Translation and Rotation
    speed = get_random_speed()
    rotation = get_random_rotation()

    img_list = []
    pts_list = []
    for t in range(num_frames):

        img = images[t]
        center = np.average(warped_points, axis=0)
        warped_points = (np.matmul(warped_points - center, rotation) + center +
                         speed).astype(int)

        for i in range(col):
            cv.fillConvexPoly(
                img,
                np.array([(warped_points[i, 0], warped_points[i, 1]),
                          (warped_points[i + 1, 0], warped_points[i + 1, 1]),
                          (warped_points[i + col + 2,
                                         0], warped_points[i + col + 2, 1]),
                          (warped_points[i + col + 1,
                                         0], warped_points[i + col + 1, 1])]),
                colors[i])

        for i in range(nb_rows):
            cv.line(img, (warped_points[row_idx[i] + col_idx1[i], 0],
                          warped_points[row_idx[i] + col_idx1[i], 1]),
                    (warped_points[row_idx[i] + col_idx2[i], 0],
                     warped_points[row_idx[i] + col_idx2[i], 1]),
                    int(row_color[i]), thickness)

        for i in range(nb_cols):
            cv.line(
                img,
                (warped_points[col_idx[i], 0], warped_points[col_idx[i], 1]),
                (warped_points[col_idx[i] + col + 1,
                               0], warped_points[col_idx[i] + col + 1, 1]),
                int(col_color[i]), thickness)

        # Keep only the points inside the image
        points = keep_points_inside(warped_points, img.shape[:2])

        if len(points) == 0:
            return draw_stripes(img_size, num_frames, bg_config, max_nb_cols,
                                min_width_ratio, transform_params)

        pts_list.append(points)
        img_list.append(img)

    points = np.array(pts_list)
    images = np.array(img_list)

    event_sim = es.Event_simulator(images[0], 0)
    events = np.array([event_sim.simulate(img, 0) for img in images[1:]])

    return images, points, events
def draw_checkerboard(img_size,
                      num_frames,
                      bg_config,
                      max_rows=7,
                      max_cols=7,
                      transform_params=(0.05, 0.15)):
    """ Draw a checkerboard and output the interest points
    Parameters:
      max_rows: maximal number of rows + 1
      max_cols: maximal number of cols + 1
      transform_params: set the range of the parameters of the transformations"""

    images = generate_background(img_size, num_frames=num_frames)
    background_color = int(np.mean(images))

    # Create the grid
    rows = random_state.randint(3, max_rows)  # number of rows
    cols = random_state.randint(3, max_cols)  # number of cols
    s = min((img_size[1] - 1) // cols,
            (img_size[0] - 1) // rows)  # size of a cell
    x_coord = np.tile(range(cols + 1), rows + 1).reshape(
        ((rows + 1) * (cols + 1), 1))
    y_coord = np.repeat(range(rows + 1), cols + 1).reshape(
        ((rows + 1) * (cols + 1), 1))
    points = s * np.concatenate([x_coord, y_coord], axis=1)

    # Warp the grid using an affine transformation and an homography
    # The parameters of the transformations are constrained
    # to get transformations not too far-fetched
    alpha_affine = np.max(img_size) * (
        transform_params[0] + random_state.rand() * transform_params[1])
    center_square = np.float32(img_size) // 2
    min_dim = min(img_size)
    square_size = min_dim // 3
    pts1 = np.float32([
        center_square + square_size,
        [center_square[0] + square_size, center_square[1] - square_size],
        center_square - square_size,
        [center_square[0] - square_size, center_square[1] + square_size]
    ])
    pts2 = pts1 + random_state.uniform(
        -alpha_affine, alpha_affine, size=pts1.shape).astype(np.float32)
    affine_transform = cv.getAffineTransform(pts1[:3], pts2[:3])
    pts2 = pts1 + random_state.uniform(-alpha_affine / 2,
                                       alpha_affine / 2,
                                       size=pts1.shape).astype(np.float32)
    perspective_transform = cv.getPerspectiveTransform(pts1, pts2)

    # Apply the affine transformation
    points = np.transpose(
        np.concatenate((points, np.ones(((rows + 1) * (cols + 1), 1))),
                       axis=1))
    warped_points = np.transpose(np.dot(affine_transform, points))

    # Apply the homography
    warped_col0 = np.add(
        np.sum(np.multiply(warped_points, perspective_transform[0, :2]),
               axis=1), perspective_transform[0, 2])
    warped_col1 = np.add(
        np.sum(np.multiply(warped_points, perspective_transform[1, :2]),
               axis=1), perspective_transform[1, 2])
    warped_col2 = np.add(
        np.sum(np.multiply(warped_points, perspective_transform[2, :2]),
               axis=1), perspective_transform[2, 2])
    warped_col0 = np.divide(warped_col0, warped_col2)
    warped_col1 = np.divide(warped_col1, warped_col2)
    warped_points = np.concatenate(
        [warped_col0[:, None], warped_col1[:, None]], axis=1)
    warped_points = warped_points.astype(int)

    img = np.zeros((img_size[0], img_size[1], 3))

    # Fill the rectangles with colors
    colors = np.zeros((rows * cols, ), np.int32)
    for i in range(rows):
        for j in range(cols):
            # Get a color that contrast with the neighboring cells743
            if i == 0 and j == 0:
                col = get_random_color(background_color=background_color)
            else:
                neighboring_colors = []
                if i != 0:
                    neighboring_colors.append(colors[(i - 1) * cols + j])
                if j != 0:
                    neighboring_colors.append(colors[i * cols + j - 1])
                col = get_different_color(np.array(neighboring_colors))
            colors[i * cols + j] = col
            # Fill the cell

    # Random lines on the boundaries of the board
    nb_rows = random_state.randint(2, rows + 2)
    nb_cols = random_state.randint(2, cols + 2)
    thickness = random_state.randint(min_dim * 0.01, min_dim * 0.02)

    row_idx = [random_state.randint(rows + 1) for _ in range(nb_rows)]
    col_idx1 = [random_state.randint(cols + 1) for _ in range(nb_rows)]
    col_idx2 = [random_state.randint(cols + 1) for _ in range(nb_rows)]
    rows_colors = [
        get_random_color(background_color=background_color)
        for _ in range(nb_rows)
    ]

    col_idx = [random_state.randint(cols + 1) for _ in range(nb_cols)]
    row_idx1 = [random_state.randint(rows + 1) for _ in range(nb_cols)]
    row_idx2 = [random_state.randint(rows + 1) for _ in range(nb_cols)]
    cols_colors = [
        get_random_color(background_color=background_color)
        for _ in range(nb_cols)
    ]

    # Speed and Rotation
    speed = get_random_speed()
    rotation = get_random_rotation()

    img_list = []
    pts_list = []
    for t in range(num_frames):

        img = images[t]
        center = np.average(warped_points, axis=0)
        warped_points = (np.matmul(warped_points - center, rotation) + center +
                         speed).astype(int)

        # Draw Checkerboard
        for i in range(rows):
            for j in range(cols):
                cv.fillConvexPoly(
                    img,
                    np.array([(warped_points[i * (cols + 1) + j, 0],
                               warped_points[i * (cols + 1) + j, 1]),
                              (warped_points[i * (cols + 1) + j + 1, 0],
                               warped_points[i * (cols + 1) + j + 1, 1]),
                              (warped_points[(i + 1) * (cols + 1) + j + 1, 0],
                               warped_points[(i + 1) * (cols + 1) + j + 1, 1]),
                              (warped_points[(i + 1) * (cols + 1) + j, 0],
                               warped_points[(i + 1) * (cols + 1) + j, 1])]),
                    int(colors[i * cols + j]))

        # Draw lines on the boundaries of the board at random
        for i in range(nb_rows):
            cv.line(img,
                    (warped_points[row_idx[i] * (cols + 1) + col_idx1[i], 0],
                     warped_points[row_idx[i] * (cols + 1) + col_idx1[i], 1]),
                    (warped_points[row_idx[i] * (cols + 1) + col_idx2[i], 0],
                     warped_points[row_idx[i] * (cols + 1) + col_idx2[i], 1]),
                    int(rows_colors[i]), thickness)
        for i in range(nb_cols):
            cv.line(img,
                    (warped_points[row_idx1[i] * (cols + 1) + col_idx[i], 0],
                     warped_points[row_idx1[i] * (cols + 1) + col_idx[i], 1]),
                    (warped_points[row_idx2[i] * (cols + 1) + col_idx[i], 0],
                     warped_points[row_idx2[i] * (cols + 1) + col_idx[i], 1]),
                    int(cols_colors[i]), thickness)

        # Keep only the points inside the image
        points = keep_points_inside(warped_points, img.shape[:2])

        if (len(points)) == 0:
            draw_checkerboard(img_size, num_frames, bg_config, max_rows,
                              max_cols, transform_params)

        pts_list.append(points)
        img_list.append(img)

    points = np.array(pts_list)
    images = np.array(img_list)

    event_sim = es.Event_simulator(images[0], 0)
    events = np.array([event_sim.simulate(img, 0) for img in images[1:]])

    return images, points, events
def draw_ellipses(img_size, num_frames, bg_config, nb_ellipses=20):
    """ Draw several ellipses
    Parameters:
      nb_ellipses: maximal number of ellipses
    """

    images = generate_background(img_size, num_frames=num_frames)
    background_color = int(np.mean(images))

    centers = np.empty((0, 2), dtype=np.int)
    max_rads = np.empty((0, 1), dtype=np.int)
    rads = np.empty((0, 2), dtype=np.int)
    min_dim = min(img_size[0], img_size[1]) / 4

    for i in range(nb_ellipses):
        ax = int(max(random_state.rand() * min_dim, min_dim / 5))
        ay = int(max(random_state.rand() * min_dim, min_dim / 5))
        max_rad = max(ax, ay)
        x = random_state.randint(max_rad, img_size[1] - max_rad)  # center
        y = random_state.randint(max_rad, img_size[0] - max_rad)
        new_center = np.array([[x, y]])

        # Check that the ellipsis will not overlap with pre-existing shapes
        diff = centers - new_center
        if np.any(max_rad > (np.sqrt(np.sum(diff * diff, axis=1)) - max_rads)):
            continue
        centers = np.concatenate([centers, new_center], axis=0)
        max_rads = np.concatenate([max_rads, np.array([[max_rad]])], axis=0)
        rads = np.concatenate([rads, np.array([[ax, ay]])], axis=0)

    colors = [
        get_random_color(background_color=background_color)
        for _ in range(len(centers))
    ]
    angles = [random_state.rand() * 90 for _ in range(len(centers))]
    rotation = [random_state.rand() * 10 - 5 for _ in range(len(centers))]
    speed = np.array([get_random_speed() for _ in range(len(centers))])

    img_list = []
    for i, img in enumerate(images):

        for j, (center, rad, angle, R, S, color) in enumerate(
                zip(centers, rads, angles, rotation, speed, colors)):

            new_center = center + S
            angles[j] = angle + R

            # Check that the ellipsis will not overlap with pre-existing
            temp_max_rads = max_rads[np.arange(len(max_rads)) != j]
            temp_centers = centers[np.arange(len(centers)) != j]

            diff = temp_centers - new_center
            if not np.any(
                    max(rad) > (np.sqrt(np.sum(diff * diff, axis=1)) -
                                temp_max_rads)):
                centers[j] = new_center

            center = (center[0], center[1])
            axes = (rad[0], rad[1])

            cv.ellipse(img, center, axes, angle + R, 0, 360, int(color), -1)

        img_list.append(img)

        points = np.array(
            [np.empty((0, 2), dtype=np.int) for _ in range(num_frames)])
        images = np.array(img_list)

        event_sim = es.Event_simulator(images[0], 0)
        events = np.array([event_sim.simulate(img, 0) for img in images[1:]])
        # events = images[:,:,0:1]

    return images, points, events
def draw_multiple_polygons(img_size,
                           num_frames,
                           bg_config,
                           max_sides=8,
                           nb_polygons=15,
                           **extra):
    """ Draw multiple polygons with a random number of corners
    and return the corner points
    Parameters:
      max_sides: maximal number of sides + 1
      nb_polygons: maximal number of polygons
    """

    images = generate_background(img_size, num_frames=num_frames)
    background_color = int(np.mean(images))
    polygons = np.array([
        generate_polygons(img_size, max_rad_ratio=0.1)
        for _ in range(nb_polygons)
    ])

    # Generate Speed and Rotation for animation
    rotation = get_random_rotation(num=nb_polygons)
    speed = get_random_speed(num=nb_polygons)
    color = get_random_color(num=nb_polygons,
                             background_color=background_color)

    valid_idx = np.arange(nb_polygons)

    # Generate Frames and Remove collided lines
    polygon_shape = np.array([Polygon(poly) for poly in polygons])
    polygons_stack = np.array([polygon_shape])
    for i in range(num_frames):

        for j, poly in enumerate(polygon_shape):
            points = poly.exterior.coords
            center = np.average(points, axis=0)
            polygon_shape[j] = Polygon(
                calculate_rigid_transformation_batch(points, center, speed[j],
                                                     rotation[j]))

        valid_idx = [0]
        for j, poly in enumerate(polygon_shape[1:]):

            is_collision = False
            for idx in valid_idx:

                if poly.intersects(polygon_shape[idx]):
                    is_collision = True
                    break

            if not is_collision:
                valid_idx.append(j + 1)

        # print(polygon_shape.shape)
        polygon_shape = polygon_shape[valid_idx]
        polygons_stack = polygons_stack[:, valid_idx]

        # print(polygons.shape, polygons_stack.shape)
        polygons_stack = np.vstack((polygons_stack, polygon_shape))
        rotation = rotation[valid_idx]
        speed = speed[valid_idx]

    # Get Points, Images, Events
    frame_points_stack = []

    # print()
    # print(polygons_stack)
    for i, img in enumerate(images):

        polygons = polygons_stack[i]
        # print(polygons.shape)
        frame_points = np.empty((0, 2), dtype=np.int)
        for j, poly in enumerate(polygons):
            x, y = poly.exterior.coords.xy

            points = np.dstack((x, y)).squeeze()
            corners = points.reshape((-1, 1, 2)).astype(int)
            cv.fillPoly(img, [corners], int(color[j]))
            frame_points = np.concatenate((frame_points, corners.squeeze()))

        frame_points_stack.append(frame_points)

    points = np.array(frame_points_stack)
    event_sim = es.Event_simulator(images[0], 0)
    events = np.array([event_sim.simulate(img, 0) for img in images[1:]])

    # print(points)
    # raise
    return images, points, events