def get_instance(rnd):
        U = rnd.uniform
        N = rnd.normal

        rr = rotation_range
        hs = height_shift_range
        ws = width_shift_range
        sr = shear_range
        agn = additive_gaussian_noise_range
        dp = distortion_prob
        mg = multiplication_gaussian
        tcp = transform_colorspace_param
        tcb = transform_colorspace_bounds

        return {
            'input_shape': input_shape,
            'theta': np.pi / 180 * U(-rr, rr) if rr else 0,
            'ty': U(-hs, hs) * input_shape[0] if hs else 0,
            'tx': U(-ws, ws) * input_shape[1] if ws else 0,
            'shear': U(-sr, sr) if shear_range else 0,
            'z': U(zoom_range[0], zoom_range[1]) if zoom_range != (1, 1) else 1,
            'h_flip': rnd.rand() < 0.5 if horizontal_flip else False,
            'add_noise': N(0, U(agn[0], agn[1]), input_shape) if agn is not None else None,
            'resize': U(*resize_range) if U(0, 1) < dp else None,
            'resize_smooth': U(0, 1) < 0.5,
            'mul': N(1, mg) if mg > 0 else None,
            'color_m': utils.crop_value(N(tcp[0], tcp[1], (3, 3)), tcb) if tcp is not None else None,
            'agn': agn
        }
def transform(v,
              t_matrix,
              h_flip=False,
              add_noise=None,
              resize=None,
              resize_smooth=None,
              mul=None,
              color_m=None):
    """
    Transform image with (inverted) transformation matrix

    :param v: Input image to be transformed
    :param t_matrix: Transformation matrix
    :param h_flip: Whether do horizontal flip
    :return: Transformed image
    """
    def apply_transform(x,
                        transform_matrix,
                        channel_index=0,
                        fill_mode='nearest',
                        cval=0.):
        x = np.rollaxis(x, channel_index, 0)
        final_affine_matrix = transform_matrix[:2, :2]
        final_offset = transform_matrix[:2, 2]
        channel_images = [
            ndimage.interpolation.affine_transform(x_channel,
                                                   final_affine_matrix,
                                                   final_offset,
                                                   order=2,
                                                   mode=fill_mode,
                                                   cval=cval)
            for x_channel in x
        ]
        x = np.stack(channel_images, axis=0)
        x = np.rollaxis(x, 0, channel_index + 1)

        return x

    def flip_axis(x, axis):
        x = np.asarray(x).swapaxes(axis, 0)
        x = x[::-1, ...]
        x = x.swapaxes(0, axis)
        return x

    v = apply_transform(v, t_matrix, 2)

    if h_flip:
        v = flip_axis(v, 1)

    if color_m is not None or mul is not None or add_noise is not None:
        v = v.astype(np.float32)
        shape = v.shape

        if mul is not None:
            v *= mul

        if color_m is not None:
            v = np.reshape(v, [-1, 3])
            v = np.matmul(v, color_m)
            v = np.reshape(v, shape)

        if add_noise is not None:
            v += add_noise

        if resize is not None:
            interpolation = 'bilinear' if resize_smooth else 'nearest'

            v = imresize(v, (resize * np.array(shape[:2])).astype(np.uint16),
                         interpolation)
            v = imresize(v, shape[:2], interpolation)

        v = utils.crop_value(v, [np.zeros(shape), np.ones(shape) * 255])

    return v.astype(np.uint8)
        if color_m is not None:
            v = np.reshape(v, [-1, 3])
            v = np.matmul(v, color_m)
            v = np.reshape(v, shape)

        if add_noise is not None:
            v += add_noise

        if resize is not None:
            interpolation = 'bilinear' if resize_smooth else 'nearest'

            v = imresize(v, (np.resize * np.array(shape[:2])).astype(np.uint16), interpolation)
            v = imresize(v, shape[:2], interpolation)

        v = utils.crop_value(v, [np.zeros(shape), np.ones(shape) * 255])

    return v.astype(np.uint8)


def crop_data(img, labels, new_img_size, new_label_size = None, crop_label = True):
    """
    Both images and labels will be cropped to match the given size

    :param img: Images to be cropped
    :param labels: Labels to be cropped
    :param new_img_size: New image size
    :param new_label_size: New labels size
    :return: Cropped image and labels
    """