def get_exp_image_generator():
    from numpy.random import randint, uniform, normal, choice
    from math import pi
    import deeptrack

    image_parameters_function = lambda: deeptrack.get_image_parameters(
        particle_center_x_list=lambda: normal(0, 5, 1),
        particle_center_y_list=lambda: normal(0, 5, 1),
        particle_radius_list=lambda: uniform(2, 5, 1),  #uniform(1.5, 3, 1)
        particle_bessel_orders_list=lambda: [
            [
                randint(1, 2),
            ],
        ],
        particle_intensities_list=lambda: [
            [
                -1 * uniform(.05, .4, 1),
            ],
        ],  #[[choice([-1, 1]) * uniform(.2, .6, 1), ], ],
        image_half_size=lambda: 25,
        image_background_level=lambda: uniform(.15, .8),  #uniform(.2, .8)
        signal_to_noise_ratio=lambda: uniform(20, 100),  #uniform(10, 100)
        gradient_intensity=lambda: uniform(0, 0.2),
        gradient_direction=lambda: uniform(-pi, pi),
        ellipsoidal_orientation=lambda: uniform(-pi, pi, 1),
        ellipticity=lambda: uniform(0.5, 1.5, 1))  # Changed from 1

    ### Define image generator
    image_generator = lambda: deeptrack.get_image_generator(
        image_parameters_function)
    return image_generator
def get_image_generator_movies():
    from numpy.random import randint, uniform, normal, choice
    from math import pi
    import deeptrack
    image_parameters_function = lambda: deeptrack.get_image_parameters(
        particle_center_x_list=lambda: [
            normal(0, 2, 1),
        ],
        particle_center_y_list=lambda: [
            normal(0, 2, 1),
        ],
        particle_radius_list=lambda: uniform(2, 3, 1),
        particle_bessel_orders_list=lambda: [
            [1, 2],
        ],
        particle_intensities_list=lambda: [
            [uniform(.7, .9, 1), -uniform(.2, .3, 1)],
        ],
        image_half_size=lambda: 25,
        image_background_level=lambda: uniform(.2, .5),
        signal_to_noise_ratio=lambda: uniform(5, 100),
        gradient_intensity=lambda: uniform(0, .8),
        gradient_direction=lambda: uniform(-pi, pi))

    ### Define image generator
    image_generator = lambda: deeptrack.get_image_generator(
        image_parameters_function)
    return image_generator
def predictions_on_noise_levels(
    network,
    SNT_levels,
    nbr_images_to_evaluate=1000,
    particle_center_x_list=lambda: normal(0, 1, 1),
    particle_center_y_list=lambda: normal(0, 1, 1),
    particle_radius_list=lambda: uniform(1.5, 3, 1),
    particle_bessel_orders_list=lambda: [
        [
            randint(1, 3),
        ],
    ],
    particle_intensities_list=lambda: [
        [
            choice([-1, 1]) * uniform(.2, .6, 1),
        ],
    ],
    image_half_size=lambda: 25,
    image_background_level=lambda: uniform(.2, .8),
    signal_to_noise_ratio=lambda: uniform(10, 100),
    gradient_intensity=lambda: uniform(0, 1),
    gradient_direction=lambda: uniform(-pi, pi)):
    """
    Function for making predictions on different noise levels
    Inputs: network to be evaluated, noise levels to evaluate on and parameters of the image generator(other than noise level)
        Number of images to evaluate on
    Outputs: predicted positions and target positions.
    """

    image_shape = network.get_layer(
        index=0).get_config()['batch_input_shape'][1:]

    all_predictions = []
    all_targets = []

    for SNT_level in SNT_levels:

        ### Create an image generator
        image_parameters_function = lambda: deeptrack.get_image_parameters(
            particle_center_x_list=particle_center_x_list,
            particle_center_y_list=particle_center_y_list,
            particle_radius_list=particle_radius_list,
            particle_bessel_orders_list=particle_bessel_orders_list,
            particle_intensities_list=particle_intensities_list,
            image_half_size=image_half_size,
            image_background_level=image_background_level,
            signal_to_noise_ratio=lambda: SNT_level,
            gradient_intensity=gradient_intensity,
            gradient_direction=gradient_direction)
        image_generator = lambda: deeptrack.get_image_generator(
            image_parameters_function)

        ### Genereate images for evaluation
        images, targets = deeptrack.get_images_and_targets(
            image_generator, nbr_images_to_evaluate, image_shape=image_shape)
        all_targets.append(targets)
        predictions = network.predict(images)
        all_predictions.append(predictions)

    return all_predictions, all_targets
def generate_images_and_targets_from_noise_levels(
    network,
    SNT_levels,
    nbr_images_to_evaluate=1000,
    translation_distance=1,
    particle_radius_list=lambda: uniform(1.5, 3, 1),
    particle_bessel_orders_list=lambda: [
        [
            randint(1, 3),
        ],
    ],
    particle_intensities_list=lambda: [
        [
            choice([-1, 1]) * uniform(.2, .6, 1),
        ],
    ],
    image_half_size=lambda: 25,
    image_background_level=lambda: uniform(.2, .8),
    signal_to_noise_ratio=lambda: uniform(10, 100),
    gradient_intensity=lambda: uniform(0, 1),
    gradient_direction=lambda: uniform(-pi, pi)):
    """
    Generates images of different noise levels and corresponding targets
    """
    translation_distance = 1
    particle_center_x_list = lambda: normal(0, translation_distance,
                                            translation_distance)
    particle_center_y_list = lambda: normal(0, translation_distance,
                                            translation_distance)
    image_shape = network.get_layer(
        index=0).get_config()['batch_input_shape'][1:]

    #all_predictions = []
    all_targets = []
    all_images = []

    for SNT_level in SNT_levels:

        ### Create an image generator
        image_parameters_function = lambda: deeptrack.get_image_parameters(
            particle_center_x_list=particle_center_x_list,
            particle_center_y_list=particle_center_y_list,
            particle_radius_list=particle_radius_list,
            particle_bessel_orders_list=particle_bessel_orders_list,
            particle_intensities_list=particle_intensities_list,
            image_half_size=image_half_size,
            image_background_level=image_background_level,
            signal_to_noise_ratio=lambda: SNT_level,
            gradient_intensity=gradient_intensity,
            gradient_direction=gradient_direction)
        image_generator = lambda: deeptrack.get_image_generator(
            image_parameters_function)

        ### Genereate images for evaluation
        images, targets = deeptrack.get_images_and_targets(
            image_generator, nbr_images_to_evaluate, image_shape=image_shape)
        all_targets.append(targets)
        all_images.append(images)

    return all_targets, all_images
def evaluate_noise_levels(
    network,
    SNT_levels,
    nbr_images_to_evaluate=1000,
    particle_center_x_list = lambda : normal(0, 1, 1),
    particle_center_y_list=lambda : normal(0, 1, 1),
    particle_radius_list=lambda : uniform(1.5, 3, 1),
    particle_bessel_orders_list=lambda : [[randint(1, 3),], ],
    particle_intensities_list=lambda : [[choice([-1, 1]) * uniform(.2, .6, 1), ], ],
    image_half_size=lambda : 25,
    image_background_level=lambda : uniform(.2, .8),
    signal_to_noise_ratio=lambda : uniform(10, 100),
    gradient_intensity=lambda : uniform(0, 1),
    gradient_direction=lambda : uniform(-pi, pi)):
    """
    Function for evaluating performance of network for different noise levels
    Inputs: network to be evaluated, noise levels to evaluate on and parameters of the image generator(other than noise level)
        Number of images to evaluate on
    Outputs: Loss,mae and mse for the various noise levels
    """

    image_shape = network.get_layer(index=0).get_config()['batch_input_shape'][1:]

    losses = []
    MSEs = []
    MAEs = []

    for SNT_level in SNT_levels:

        ### Create an image generator
        image_parameters_function = lambda : deeptrack.get_image_parameters(
           particle_center_x_list=particle_center_x_list,
           particle_center_y_list=particle_center_y_list,
           particle_radius_list=particle_radius_list,
           particle_bessel_orders_list=particle_bessel_orders_list,
           particle_intensities_list=particle_intensities_list,
           image_half_size=image_half_size,
           image_background_level=image_background_level,
           signal_to_noise_ratio= lambda: SNT_level,
           gradient_intensity=gradient_intensity,
           gradient_direction= gradient_direction)
        image_generator = lambda : deeptrack.get_image_generator(image_parameters_function)

        ### Genereate images for evaluation
        images, targets = deeptrack.get_images_and_targets(image_generator,nbr_images_to_evaluate,image_shape=image_shape)
        loss,mse,mae = network.evaluate(images,targets)

        ### Fix units and append to final results
        mse *= image_half_size()**2 #what happens if it is not a function? Silly error?
        mae *= image_half_size()
        losses.append(loss)
        MSEs.append(mse)
        MAEs.append(mae)
    return losses,MSEs,MAEs
def get_default_image_generator_deeptrack(translation_distance=5,
                                          SN_limits=[10, 100],
                                          radius_limits=[1.5, 3]):
    """
    Returns a default image genereator for deeptrack. Allows for some parameter tweaking.
    """
    import deeptrack
    from numpy.random import randint, uniform, normal, choice
    from math import pi

    image_parameters_function = lambda: deeptrack.get_image_parameters(
        particle_center_x_list=lambda: normal(0, translation_distance,
                                              translation_distance),
        particle_center_y_list=lambda: normal(0, translation_distance,
                                              translation_distance),
        particle_radius_list=lambda: uniform(radius_limits[0], radius_limits[
            1], 1),
        particle_bessel_orders_list=lambda: [
            [
                randint(1, 3),
            ],
        ],
        particle_intensities_list=lambda: [
            [
                choice([-1, 1]) * uniform(.2, .6, 1),
            ],
        ],
        image_half_size=lambda: 25,
        image_background_level=lambda: uniform(.2, .8),
        signal_to_noise_ratio=lambda: uniform(SN_limits[0], SN_limits[1]),
        gradient_intensity=lambda: uniform(0, 1),
        gradient_direction=lambda: uniform(-pi, pi),
        ellipsoidal_orientation=lambda: uniform(-pi, pi, 1),
        ellipticity=lambda: 1)
    ### Define image generator
    image_generator = lambda: deeptrack.get_image_generator(
        image_parameters_function)
    return image_generator
def get_vesicle_image_generator():
    # Used for vesicles
    import deeptrack
    image_generator = lambda: deeptrack.get_image_generator(
        get_image_parameters_optimized_vesicles())
    return image_generator
def get_multiparticle_genertator():
    # Used for multiparticle tracking
    import deeptrack
    image_generator = lambda: deeptrack.get_image_generator(
        get_image_parameters_multi_particle())
    return image_generator
    image_parameters['Image Half-Size'] = image_half_size
    image_parameters['Image Background Level'] = 0.2#uniform(.2, .4)
    image_parameters['Signal to Noise Ratio'] = 5#10#20#uniform(2, 8)
    image_parameters['Gradient Intensity'] = 0#uniform(0, 0.2)
    image_parameters['Gradient Direction'] = uniform(-pi, pi)
    image_parameters['Ellipsoid Orientation'] = uniform(-pi, pi, particle_number)
    image_parameters['Ellipticity'] = 1

    return image_parameters



image_parameters_function = lambda : get_image_parameters_optimized()

### Define image generator
image_generator = lambda : deeptrack.get_image_generator(image_parameters_function)

### Show some examples of generated images
#path = 'vesicle_models/LBL_vesicles_larger_r_rangerun_0_network_no' # WORKS!!!
path = 'vesicle_models/default_training_run_1_network_no' # ok, 8.7as threshold for large, run 0!?!?!
#path = 'vesicle_models/LBL_vesiclesrun_2_network_no'
#path = 'multi_particle/large_dist_vesicle_training_run0_network_no'
saved_network_file_name = path+'0.h5'#'vesicle_models/LBL_vesicles_larger_r_rangerun_0_network_no0.h5'
network_small = deeptrack.load(saved_network_file_name)
saved_network_file_name = path+'4.h5' # 4.h5
network_large = deeptrack.load(saved_network_file_name)

enhanced_thres = 7.1
small_thres_enhanced = 7.5 # use smaller for actual accurate predictionsmall_thres
small_thres = 7#7.3
large_thres = 6.7