<repo_name>patrickmlong/axondeepseg<file_sep>/AxonDeepSeg/integrity_test.py

# -*- coding: utf-8 -*-

# Basic integrity test to check is AxonDeepSeg is correctly installed
# Launches a segmentation in the data_test folder

try:

    import json
    import os
    from AxonDeepSeg.testing.segmentation_scoring import *
    from time import time

    from scipy.misc import imread, imsave

    # input parameters

    path_testing = "../AxonDeepSeg/data_test/"
    model_name = 'default_SEM_model_v1'
    path_model = '../AxonDeepSeg/models/' + model_name


    path_configfile = path_model + '/config_network.json'

    if not os.path.exists(path_model):
        os.makedirs(path_model)

    with open(path_configfile, 'r') as fd:
        config_network = json.loads(fd.read())


    from AxonDeepSeg.apply_model import axon_segmentation

    prediction = axon_segmentation([path_testing], ["image.png"], path_model, config_network,verbosity_level=0)


    mask = imread(path_testing + '/mask.png', flatten=True)
    pred = imread(path_testing + '/AxonDeepSeg.png', flatten=True)


    gt_axon = mask > 200
    gt_myelin = np.logical_and(mask >= 50, mask <= 200)

    pred_axon = pred > 200
    pred_myelin = np.logical_and(pred >= 50, pred <= 200)

    dice_axon = pw_dice(pred_axon, gt_axon)
    dice_myelin = pw_dice(pred_myelin, gt_myelin)

    print "* * * Integrity test passed. AxonDeepSeg is correctly installed. * * * "

except IOError:

    print "Integrity test failed... "
























































<file_sep>/AxonDeepSeg/testing/segmentation_scoring.py
from skimage import measure
from skimage.measure import regionprops
import numpy as np
import pandas as pd


def score_analysis(img, groundtruth, prediction, visualization=False, min_area=2):
    """
    Calculates segmentation score by keeping an only true centroids as TP.
    Excess of centroids detected for a unique object is counted by diffusion (Excess/TP+FN)
    Returns sensitivity (TP/P), precision (TP/TP+FN) and diffusion

    :param img: image to segment
    :param groundtruth: groundtruth of the image
    :param prediction: segmentation
    :param visualization: if True, FP and TP are displayed on the image
    :param min_area: minimal area of the predicted axon to count.
    :return: [sensitivity, precision, diffusion]
    """

    labels_pred = measure.label(prediction)
    regions_pred = regionprops(labels_pred)

    centroids = np.array([list(x.centroid) for x in regions_pred])
    centroids = centroids.astype(int)
    areas = np.array([x.area for x in regions_pred])
    centroids = centroids[areas > min_area]

    labels_true = measure.label(groundtruth)
    regions_true = regionprops(labels_true)

    centroid_candidates = set([tuple(row) for row in centroids])

    centroids_T = []
    notDetected = []
    n_extra = 0

    for axon in regions_true:
        axon_coords = [tuple(row) for row in axon.coords]
        axon_center = (np.array(axon.centroid)).astype(int)
        centroid_match = set(axon_coords) & centroid_candidates
        centroid_candidates = centroid_candidates.difference(centroid_match)
        centroid_match = list(centroid_match)
        if len(centroid_match) != 0:
            diff = np.sum((centroid_match - axon_center) ** 2, axis=1)
            ind = np.argmin(diff)
            center = centroid_match[ind]
            centroids_T.append(center)
            n_extra += len(centroid_match) - 1
        if len(centroid_match) == 0:
            notDetected.append(axon_center)

    centroids_F = list(centroid_candidates)
    P = len(regions_true)
    TP = len(centroids_T)

    FP = len(centroids_F)

    centroids_F = np.array(centroids_F)
    centroids_T = np.array(centroids_T)
    # not_detected = len(np.array(notDetected))

    sensitivity = round(float(TP) / P, 3)
    # errors = round(float(FP) / P, 3)
    diffusion = float(n_extra) / (TP + FP)
    precision = round(float(TP) / (TP + FP), 3)

    if visualization:
        plt.figure(1)
        plt.imshow(img, cmap=plt.get_cmap('gray'))
        plt.hold(True)
        plt.imshow(prediction, alpha=0.7)
        plt.hold(True)
        plt.scatter(centroids_T[:, 1], centroids_T[:, 0], color='g')
        plt.hold(True)
        plt.scatter(centroids_F[:, 1], centroids_F[:, 0], color='r')
        plt.hold(True)
        plt.scatter(notDetected[:, 1], notDetected[:, 0], color='y')
        plt.title('Prediction, Sensitivity : %s , Precision : %s ' % (sensitivity, precision))

        plt.figure(2)
        plt.imshow(img, cmap=plt.get_cmap('gray'))
        plt.hold(True)
        plt.imshow(groundtruth, alpha=0.7)
        plt.hold(True)
        plt.scatter(centroids_T[:, 1], centroids_T[:, 0], color='g')
        plt.hold(True)
        plt.scatter(centroids_F[:, 1], centroids_F[:, 0], color='r')
        plt.title('Ground Truth, Sensitivity : %s , Precision : %s ' % (sensitivity, precision))
        plt.show()

    return [sensitivity, precision, round(diffusion, 4)]


def dice(img, groundtruth, prediction, min_area=3):
    """
    :param img: image to segment
    :param groundtruth : True segmentation
    :param prediction : Segmentation predicted by the algorithm
    :param min_area: minimum area of the predicted object to measure dice
    :return dice_scores: pandas dataframe associating the axon predicted, its size and its dice score

    To get the global dice score of the prediction,
    """

    h, w = img.shape

    labels_true = measure.label(groundtruth)
    regions_true = regionprops(labels_true)

    labels_pred = measure.label(prediction)
    regions_pred = regionprops(labels_pred)
    features = ['coords', 'area', 'dice']
    df = pd.DataFrame(columns=features)

    i = 0
    for axon_predicted in regions_pred:
        centroid = (np.array(axon_predicted.centroid)).astype(int)
        if groundtruth[(centroid[0], centroid[1])] == 1:
            for axon_true in regions_true:

                if [centroid[0], centroid[1]] in axon_true.coords.tolist():
                    surface_pred = np.zeros((h, w))
                    surface_true = np.zeros((h, w))

                    surface_pred[axon_predicted.coords[:, 0], axon_predicted.coords[:, 1]] = 1
                    surface_true[axon_true.coords[:, 0], axon_true.coords[:, 1]] = 1
                    intersect = surface_pred * surface_true

                    Dice = 2 * float(sum(sum(intersect))) / (sum(sum(surface_pred)) + sum(sum(surface_true)))
                    df.loc[i] = [axon_predicted.coords, axon_predicted.area, Dice]
                    break
        i += 1
    dice_scores = df[df['area'] > min_area]
    return dice_scores

def pw_dice(img1, img2):
    """
    img1 and img2 are boolean masks ndarrays
    This functions compute the pixel-wise dice coefficient (not axon-wise but pixel wise)
    """

    img_sum = img1.sum() + img2.sum()
    if img_sum == 0:
        return 1

    intersection = np.logical_and(img1, img2)
    # Return the global dice coefficient
    return 2. * intersection.sum() / img_sum<file_sep>/AxonDeepSeg/invert_image.py




import sys





def invert_image(path_image):

    '''
    :param image: path of the image to invert
    :return: Nothing.
    '''


from PIL import Image
import PIL.ImageOps

image = Image.open(path_image) 
inverted_image = PIL.ImageOps.invert(image)
inverted_image.save(path_image)

if __name__ == "__main__":
    path_image = string(sys.argv[1])
    invert_image(path_image)



<file_sep>/AxonDeepSeg/segment.py
# Segmentation script
# -------------------
# This script lets the user segment automatically one or many images based on the default segmentation models: SEM or
# TEM.
#
# <NAME> - 2017-08-30

# Imports

from AxonDeepSeg.apply_model import axon_segmentation
import os, json
from tqdm import tqdm
import pkg_resources
import argparse

# Global variables
SEM_DEFAULT_MODEL_NAME = "default_SEM_model_v1"
TEM_DEFAULT_MODEL_NAME = "default_TEM_model_v1"

MODELS_PATH = pkg_resources.resource_filename('AxonDeepSeg', 'models')

# Definition of the functions

def segment_image(path_testing_image, path_model,
                    overlap_value, config, resolution_model, segmented_image_prefix,
                  acquired_resolution = 0.0, verbosity_level=0):

    '''
    Segment the image located at the path_testing_image location.
    :param path_testing_image: the path of the image to segment.
    :param path_model: where to access the model
    :param overlap_value: the number of pixels to be used for overlap when doing prediction. Higher value means less
    border effects but more time to perform the segmentation.
    :param config: dict containing the configuration of the network
    :param resolution_model: the resolution the model was trained on.
    :param segmented_image_prefix: the prefix to add before the segmented image.
    :param verbosity_level: Level of verbosity. The higher, the more information is given about the segmentation
    process.
    :return: Nothing.
    '''

    if os.path.exists(path_testing_image):

        # Extracting the image name and its folder path from the total path.
        tmp_path = path_testing_image.split('/')
        acquisition_name = tmp_path[-1]
        path_acquisition = '/'.join(tmp_path[:-1])

        # Performing the segmentation
        segmented_image_name = segmented_image_prefix + acquisition_name
        axon_segmentation(path_acquisitions_folders=path_acquisition, acquisitions_filenames=[acquisition_name],
                          path_model_folder=path_model, config_dict=config, ckpt_name='model',
                          inference_batch_size=1, overlap_value=overlap_value,
                          segmentations_filenames=segmented_image_name,
                          resampled_resolutions=resolution_model, verbosity_level=verbosity_level,
                          acquired_resolution=acquired_resolution,
                          prediction_proba_activate=False, write_mode=True)

        if verbosity_level >= 1:
            print "Image {0} segmented.".format(path_testing_image)

    else:

        print "The path {0} does not exist.".format(path_testing_image)



    return None

def segment_folders(path_testing_images_folder, path_model,
                    overlap_value, config, resolution_model, segmented_image_suffix,
                    acquired_resolution = 0.0,
                    verbosity_level=0):
    '''
    Segments the images contained in the image folders located in the path_testing_images_folder.
    :param path_testing_images_folder: the folder where all image folders are located (the images to segment are located
    in those image folders)
    :param path_model: where to access the model.
    :param overlap_value: the number of pixels to be used for overlap when doing prediction. Higher value means less
    border effects but more time to perform the segmentation.
    :param config: dict containing the configuration of the network
    :param resolution_model: the resolution the model was trained on.
    :param segmented_image_suffix: the prefix to add before the segmented image.
    :param verbosity_level: Level of verbosity. The higher, the more information is given about the segmentation
    process.
    :return: Nothing.
    '''

    # We loop over all image folders in the specified folded and we segment them one by one.

    # We loop through every file in the folder as we look for an image to segment
    for file_ in tqdm(os.listdir(path_testing_images_folder), desc="Segmentation..."):

        # We segment the image only if it's not already a segmentation.
        len_suffix = len(segmented_image_suffix)+4 # +4 for ".png"
        if (file_[-4:] == ".png") and (not (file_[-len_suffix:] == (segmented_image_suffix+'.png'))):

            # Performing the segmentation
            basename = file_.split('.')
            basename.pop() # We remove the extension.
            basename = ".".join(basename)
            segmented_image_name = basename + segmented_image_suffix + '.png'
            axon_segmentation(path_acquisitions_folders=path_testing_images_folder, acquisitions_filenames=[file_],
                              path_model_folder=path_model, config_dict=config, ckpt_name='model',
                              inference_batch_size=1, overlap_value=overlap_value,
                              segmentations_filenames=[segmented_image_name],
                              acquired_resolution=acquired_resolution,
                              verbosity_level=verbosity_level,
                              resampled_resolutions=resolution_model, prediction_proba_activate=False,
                              write_mode=True)

            if verbosity_level >= 1:
                print "Image {0} segmented.".format(os.path.join(path_testing_images_folder, file_))
    # The segmentation has been done for this image folder, we go to the next one.

    return None

def generate_default_parameters(type_acquisition, new_path):
    '''
    Generates the parameters used for segmentation for the default model corresponding to the type_model acquisition.
    :param type_model: String, the type of model to get the parameters from.
    :param new_path: Path to the model to use.
    :return: the config dictionary.
    '''
    # Building the path of the requested model if it exists and was supplied, else we load the default model.
    if type_acquisition == 'SEM':
        if (new_path is not None) and (os.path.exists(new_path)):
            path_model = new_path
        else:
            path_model = os.path.join(MODELS_PATH, SEM_DEFAULT_MODEL_NAME)
    elif type_acquisition == 'TEM':
        if (new_path is not None) and (os.path.exists(new_path)):
            path_model = new_path
        else:
            path_model = os.path.join(MODELS_PATH, TEM_DEFAULT_MODEL_NAME)

    path_config_file = os.path.join(path_model, 'config_network.json')
    config = generate_config_dict(path_config_file)

    return path_model, config

def generate_config_dict(path_to_config_file):
    '''
    Generates the dictionary version of the configuration file from the path where it is located.

    :param path_to_config: relative path where the file config_network.json is located.
    :return: dict containing the configuration of the network, or None if no configuration file was found at the
    mentioned path.
    '''

    try:
        with open(path_to_config_file, 'r') as fd:
            config_network = json.loads(fd.read())

    except ValueError:
        print "No configuration file available at this path."
        config_network = None

    return config_network

def generate_resolution(type_acquisition, model_input_size):
    '''
    Generates the resolution to use related to the trained modeL.
    :param type_acquisition: String, "SEM" or "TEM"
    :param model_input_size: String or Int, the size of the input.
    :return: Float, the resolution of the model.
    '''

    dict_size = {
        "SEM":{
            "512":0.1,
            "256":0.2
        },
        "TEM":{
            "512":0.01
        }
    }

    return dict_size[str(type_acquisition)][str(model_input_size)]

# Main loop

def main():
    '''
    Main loop.
    :return: None.
    '''
    ap = argparse.ArgumentParser()

    # Setting the arguments of the segmentation
    ap.add_argument("-t", "--type", required=True, help="Choose the type of acquisition you want to segment.") # type
    ap.add_argument("-i", "--imgpath", required=True, nargs='+', help="Folder where the images folders are located.")
    ap.add_argument("-m", "--model", required=False,
                    help="Folder where the model is located.", default=None)
    ap.add_argument("-s", "--sizepixel", required=False, help="Pixel size in micrometers to use for the segmentation.",
                    default=0.0)
    ap.add_argument("-v", "--verbose", required=False, help="Verbosity level.", default=0)
    ap.add_argument("-o", "--overlap", required=False, help="Overlap value when doing the segmentation. The higher the"
                                                            "value, the longer it will take to segment the whole image.",
                    default=25)

    # Processing the arguments
    args = vars(ap.parse_args())
    type_ = str(args["type"])
    verbosity_level = int(args["verbose"])
    overlap_value = int(args["overlap"])
    psm = float(args["sizepixel"])
    path_target_list = args["imgpath"]
    new_path = args["model"]

    # Preparing the arguments to axon_segmentation function
    path_model, config = generate_default_parameters(type_, new_path)
    resolution_model = generate_resolution(type_, config["trainingset_patchsize"])
    segmented_image_suffix = "_segmented"


    # Going through all paths passed into arguments
    for current_path_target in path_target_list:

        if (current_path_target[-4:] == '.png') and (not os.path.isdir(current_path_target)):

            # Performing the segmentation over the image
            segment_image(current_path_target, path_model, overlap_value, config,
                          resolution_model, segmented_image_suffix,
                          acquired_resolution=psm,
                          verbosity_level=verbosity_level)

        else:

            # Performing the segmentation over all folders in the specified folder containing acquisitions to segment.
            segment_folders(current_path_target, path_model, overlap_value, config,
                        resolution_model, segmented_image_suffix,
                            acquired_resolution=psm,
                            verbosity_level=verbosity_level)

    print "Segmentation finished."

# Calling the script
if __name__ == '__main__':
    main()






