<filename>src/main.py
"""A medical image analysis pipeline.

The pipeline is used for brain tissue segmentation using a decision forest classifier.
"""
import argparse
import datetime
import os
import logging
import random
from joblib import logger

import numpy as np
import sklearn.ensemble as sk_ensemble
import pymia.evaluation.writer as writer
import pymia.data.conversion as conversion

from constants import *
import mialab.data.structure as structure
from mialab.utilities.logger import CustomLogger
import mialab.utilities.better_pipelines as putil
import mialab.utilities.file_access_utilities as futil


random.seed(1721)
np.random.seed(1996)
logger = CustomLogger.get_instance()

def main(
    result_dir: str,  
    data_train_dir: str, 
    data_test_dir: str,
    force_preprocessing: bool):
    """Brain tissue segmentation using decision forests.

    The main routine executes the medical image analysis pipeline:

        - Image loading
        - Registration
        - Pre-processing
        - Feature extraction
        - Decision forest classifier model building
        - Segmentation using the decision forest classifier model on unseen images
        - Post-processing of the segmentation
        - Evaluation of the segmentation
    """
    
    logger.info("Training - Preporcessing")

    # crawl the training image directories
    train_data_crawler = futil.FileSystemDataCrawler(data_train_dir,
                                          LOADING_KEYS,
                                          futil.BrainImageFilePathGenerator(),
                                          futil.DataDirectoryFilter())


    # Crawler data into list
    train_data_images = [putil.pre_process(id_, path, **PRE_PROCESS_PARAM) for id_, path in train_data_crawler.data.items()]
  

    # generate feature matrix and label vector
    data_train = np.concatenate([img.feature_matrix[0] for img in train_data_images])
    labels_train = np.concatenate([img.feature_matrix[1] for img in train_data_images]).squeeze()

    logger.info("Training - Fitting")

    # Create forest tree
    forest = sk_ensemble.RandomForestClassifier(max_features=train_data_images[0].feature_matrix[0].shape[1],
                                                n_estimators=10,
                                                max_depth=40)
    forest.fit(data_train, labels_train)

    logger.info("Testing - Preprocessing")

    # initialize evaluator
    evaluator = putil.init_evaluator()

    # crawl the test image directories
    test_data_crawler = futil.FileSystemDataCrawler(
        data_test_dir,
        LOADING_KEYS,
        futil.BrainImageFilePathGenerator(),
        futil.DataDirectoryFilter())


    # Goes through the preprocessor only to be imported

    if force_preprocessing:
        PRE_PROCESS_PARAM['training'] = False
        test_data_list = [putil.pre_process(id_, path, **PRE_PROCESS_PARAM) for id_, path in test_data_crawler.data.items()]
    else:
        test_data_list = [putil.pre_process(id_, path, **PRE_PROCESS_PARAM_NOISE) for id_, path in test_data_crawler.data.items()]


    logger.info("Testing - Evaluation")
 
    for img in test_data_list:
        logger.debug("Predict - {}".format(img.id_))
 
        predictions = forest.predict(img.feature_matrix[0])

        # convert prediction and probabilities back to SimpleITK images
        img_prediction = conversion.NumpySimpleITKImageBridge.convert(predictions.astype(np.uint8), img.image_properties)

        # evaluate segmentation without post-processing
        evaluator.evaluate(img_prediction, img.images[structure.BrainImageTypes.GroundTruth], img.id_)



    # create a result directory with timestamp
    t = datetime.datetime.now().strftime('%Y-%m-%d_%H.%M.%S')
    result_dir = os.path.join(result_dir, os.path.basename(data_test_dir) + "_" + t)

    # use two writers to report the results
    os.makedirs(result_dir, exist_ok=True)  # generate result directory, if it does not exists
    result_file = os.path.join(result_dir, 'results.csv')
    writer.CSVWriter(result_file).write(evaluator.results)

    logger.info("Subject-wise results...")
    writer.ConsoleWriter().write(evaluator.results)

    # report also mean and standard deviation among all subjects
    result_summary_file = os.path.join(result_dir, 'results_summary.csv')
    functions = {'MEAN': np.mean, 'STD': np.std}
    writer.CSVStatisticsWriter(result_summary_file, functions=functions).write(evaluator.results)
    logger.info("Aggregated statistic results...")
    writer.ConsoleStatisticsWriter(functions=functions).write(evaluator.results)

    # clear results such that the evaluator is ready for the next evaluation
    evaluator.clear()


if __name__ == "__main__":
    """The program's entry point."""


    parser = argparse.ArgumentParser(description='Medical image analysis pipeline for brain tissue segmentation')

    parser.add_argument(
        '--result_dir',
        type=str,
        default=OUTPUT_PATH,
        help='Directory for results.'
    )

    parser.add_argument(
        '--data_train_dir',
        type=str,
        default=os.path.join(DATA_PATH, 'train'),
        help='Directory with training data.'
    )

    parser.add_argument(
        '--data_test_dir',
        type=str,
        default=os.path.join(DATA_PATH, 'test'),
        help='Directory with testing data.'
    )

    parser.add_argument(
        '--force_preprocessing',
        type=bool,
        default=False,
        help='Force the preprocessing for the test data',
        action=argparse.BooleanOptionalAction
    )

    args = parser.parse_args()
    main(
        args.result_dir, 
        args.data_train_dir, 
        args.data_test_dir,
        args.force_preprocessing)

<filename>src/main.py
"""A medical image analysis pipeline.

The pipeline is used for brain tissue segmentation using a decision forest classifier.
"""
import argparse
import datetime
import os
import logging
import random
from joblib import logger

import numpy as np
import sklearn.ensemble as sk_ensemble
import pymia.evaluation.writer as writer
import pymia.data.conversion as conversion

from constants import *
import mialab.data.structure as structure
from mialab.utilities.logger import CustomLogger
import mialab.utilities.better_pipelines as putil
import mialab.utilities.file_access_utilities as futil


random.seed(1721)
np.random.seed(1996)
logger = CustomLogger.get_instance()

def main(
    result_dir: str,  
    data_train_dir: str, 
    data_test_dir: str,
    force_preprocessing: bool):
    """Brain tissue segmentation using decision forests.

    The main routine executes the medical image analysis pipeline:

        - Image loading
        - Registration
        - Pre-processing
        - Feature extraction
        - Decision forest classifier model building
        - Segmentation using the decision forest classifier model on unseen images
        - Post-processing of the segmentation
        - Evaluation of the segmentation
    """
    
    logger.info("Training - Preporcessing")

    # crawl the training image directories
    train_data_crawler = futil.FileSystemDataCrawler(data_train_dir,
                                          LOADING_KEYS,
                                          futil.BrainImageFilePathGenerator(),
                                          futil.DataDirectoryFilter())


    # Crawler data into list
    train_data_images = [putil.pre_process(id_, path, **PRE_PROCESS_PARAM) for id_, path in train_data_crawler.data.items()]
  

    # generate feature matrix and label vector
    data_train = np.concatenate([img.feature_matrix[0] for img in train_data_images])
    labels_train = np.concatenate([img.feature_matrix[1] for img in train_data_images]).squeeze()

    logger.info("Training - Fitting")

    # Create forest tree
    forest = sk_ensemble.RandomForestClassifier(max_features=train_data_images[0].feature_matrix[0].shape[1],
                                                n_estimators=10,
                                                max_depth=40)
    forest.fit(data_train, labels_train)

    logger.info("Testing - Preprocessing")

    # initialize evaluator
    evaluator = putil.init_evaluator()

    # crawl the test image directories
    test_data_crawler = futil.FileSystemDataCrawler(
        data_test_dir,
        LOADING_KEYS,
        futil.BrainImageFilePathGenerator(),
        futil.DataDirectoryFilter())


    # Goes through the preprocessor only to be imported

    if force_preprocessing:
        PRE_PROCESS_PARAM['training'] = False
        test_data_list = [putil.pre_process(id_, path, **PRE_PROCESS_PARAM) for id_, path in test_data_crawler.data.items()]
    else:
        test_data_list = [putil.pre_process(id_, path, **PRE_PROCESS_PARAM_NOISE) for id_, path in test_data_crawler.data.items()]


    logger.info("Testing - Evaluation")
 
    for img in test_data_list:
        logger.debug("Predict - {}".format(img.id_))
 
        predictions = forest.predict(img.feature_matrix[0])

        # convert prediction and probabilities back to SimpleITK images
        img_prediction = conversion.NumpySimpleITKImageBridge.convert(predictions.astype(np.uint8), img.image_properties)

        # evaluate segmentation without post-processing
        evaluator.evaluate(img_prediction, img.images[structure.BrainImageTypes.GroundTruth], img.id_)



    # create a result directory with timestamp
    t = datetime.datetime.now().strftime('%Y-%m-%d_%H.%M.%S')
    result_dir = os.path.join(result_dir, os.path.basename(data_test_dir) + "_" + t)

    # use two writers to report the results
    os.makedirs(result_dir, exist_ok=True)  # generate result directory, if it does not exists
    result_file = os.path.join(result_dir, 'results.csv')
    writer.CSVWriter(result_file).write(evaluator.results)

    logger.info("Subject-wise results...")
    writer.ConsoleWriter().write(evaluator.results)

    # report also mean and standard deviation among all subjects
    result_summary_file = os.path.join(result_dir, 'results_summary.csv')
    functions = {'MEAN': np.mean, 'STD': np.std}
    writer.CSVStatisticsWriter(result_summary_file, functions=functions).write(evaluator.results)
    logger.info("Aggregated statistic results...")
    writer.ConsoleStatisticsWriter(functions=functions).write(evaluator.results)

    # clear results such that the evaluator is ready for the next evaluation
    evaluator.clear()


if __name__ == "__main__":
    """The program's entry point."""


    parser = argparse.ArgumentParser(description='Medical image analysis pipeline for brain tissue segmentation')

    parser.add_argument(
        '--result_dir',
        type=str,
        default=OUTPUT_PATH,
        help='Directory for results.'
    )

    parser.add_argument(
        '--data_train_dir',
        type=str,
        default=os.path.join(DATA_PATH, 'train'),
        help='Directory with training data.'
    )

    parser.add_argument(
        '--data_test_dir',
        type=str,
        default=os.path.join(DATA_PATH, 'test'),
        help='Directory with testing data.'
    )

    parser.add_argument(
        '--force_preprocessing',
        type=bool,
        default=False,
        help='Force the preprocessing for the test data',
        action=argparse.BooleanOptionalAction
    )

    args = parser.parse_args()
    main(
        args.result_dir, 
        args.data_train_dir, 
        args.data_test_dir,
        args.force_preprocessing)

A medical image analysis pipeline.
 
 The pipeline is used for brain tissue segmentation using a decision forest classifier. Brain tissue segmentation using decision forests.
 
     The main routine executes the medical image analysis pipeline:
 
         - Image loading
         - Registration
         - Pre-processing
         - Feature extraction
         - Decision forest classifier model building
         - Segmentation using the decision forest classifier model on unseen images
         - Post-processing of the segmentation
         - Evaluation of the segmentation # crawl the training image directories # Crawler data into list # generate feature matrix and label vector # Create forest tree # initialize evaluator # crawl the test image directories # Goes through the preprocessor only to be imported # convert prediction and probabilities back to SimpleITK images # evaluate segmentation without post-processing # create a result directory with timestamp # use two writers to report the results # generate result directory, if it does not exists # report also mean and standard deviation among all subjects # clear results such that the evaluator is ready for the next evaluation The program's entry point.