Source code for StructFolderCheck

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
.. _CHECK_FOLDER:

The `CHECK_FOLDER` module verifies if the subfolders within a study folder are structured correctly for use with img2radiomics. Each subfolder should contain the required DICOM or NIfTI files organized in the structure expected by img2radiomics.

Folder Structure Requirements
-----------------------------

Subfolders within a study folder should follow the structure shown below:

.. image:: img/Struct_OK.jpg
   :alt: Correct folder structure for img2radiomics

Alternatively, subfolders can be organized in the following structure and then reorganized using the `REORGANIZE` module:

.. image:: img/Struct_Ready.jpg
	:width: 400
	:alt: Alternative folder structure for img2radiomics

Options
-------

The `CHECK_FOLDER` module can be configured with the following options:

- **verbose**: Enables or disables verbose output, providing more details during execution.
- **timer**: Enables or disables the timer, recording the module's execution time.
- **inputFolder**: Specifies the path to the main study folder containing subfolders with DICOM files.
- **with-segmentation**: Indicates if subfolders contain segmentation files. Set to `False` if only some subfolders contain segmentation files.
- **log**: Path to a log file for recording output details.
- **new_log_file**: Creates a new log file. If a log file with the same name already exists, it will be overwritten.

Example Usage
-------------

The example below demonstrates how to use the `CHECK_FOLDER` module to verify that each subfolder within a study folder is correctly structured:

.. code-block:: bash

    CHECK_FOLDER:  # Verify if subfolders within a study folder have the correct structure
    {
        inputFolder: /path/to/study_folder
        with-segmentation: False
        log: /path/to/logs/checkfolder.log
    }
"""

# Check if a folder has the correct structure to process the image analysis pipeline
#
# Usage: StructFolderCheck.py -i <inputfolder>
#        StructFolderCheck.py --log=<logfile> --new_log --verbose --no-segmentation
# Help: StructFolderCheck.py -h or --help
#
# This script verifies the structure of a specified folder for compatibility with img2radiomics.
# Options:
#   -h, --help               Show help and usage information.
#   -v, --verbose            Enable verbose output (False by default).
#   -i, --inputFolder        Specify the input folder containing DICOM images.
#       --no-segmentation    Specify if the input folder does not contain segmentation files.
#       --log                Redirect output to a log file.
#       --new_log            Overwrite previous log file if it exists.

import sys, getopt, os
from tqdm import tqdm
import glob
import re
from datetime import datetime
from utils import hprint_msg_box
from utils import hprint

[docs] def main(argv): inpath = '' verbose = False c = 1; log = '' new_log = False NoSegmentation = False try: opts, args = getopt.getopt(argv, "vhi:",["log=","new_log","verbose","help","inputFolder=","no-segmentation"]) except getopt.GetoptError: print('StructFolderCheck.py -i <inputfolder>',flush=True) sys.exit(2) for opt,arg in opts: if opt in ("-h", "--help"): print("NAME",flush=True) print("\tdStructFolderCheck.py\n",flush=True) print("SYNOPSIS",flush=True) print("\tStructFolderCheck.py [-h|--help][-v|--verbose][-i|--inputFolder <inputfolder>]\n",flush=True) print("DESRIPTION",flush=True) print("\tCheck if a folder has a correct structure to process the image analysis pipeline\n",flush=True) print("OPTIONS",flush=True) print("\t -h, --help: print this help page",flush=True) print("\t -v, --verbose: False by default",flush=True) print("\t -i, --inputFolder: input folder with Dicom images",flush=True) print("\t, --no-segmentation: input folder do not contain segmentations",flush=True) print("\t --log: stdout redirect to log file") print("\t --new_log: overwrite previous log file") sys.exit() elif opt in ("-i", "--inputFolder"): inpath = arg elif opt in ("-v", "--verbose"): verbose = True elif opt in ("--log"): log= arg elif opt in ("--new_log"): new_log= True elif opt in ("--no-segmentation"): NoSegmentation = True if log != '': if new_log: f = open(log,'w+') else: f = open(log,'a+') sys.stdout = f if verbose: msg = ( f"Cheking structure of: {inpath}\n" f"No segmentation: {str(NoSegmentation)}\n" f"Log: {log}\n" f"Overwrite previous log file: {str(new_log)}\n" f"Verbose: {verbose}\n" ) hprint_msg_box(msg=msg, indent=2, title=f"CHECK_FOLDER {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") for patient in tqdm(glob.glob(inpath+"/*"), ncols=100, desc="Checking folder:", bar_format="{l_bar}{bar} [time left: {remaining}, time spent: {elapsed}]", colour="yellow"): patientID=os.path.basename(patient) if verbose: hprint(f"Processing {patientID}", patient) c=checkPatientFolderStructure(patient,verbose,log, NoSegmentation) if c==0: break; if c==0 : print("\033[33mFolder is NOT correctly structured for the image processing pipeline\033[0m",flush=True) print("Checking if the folder can be restructured using the script reoganize.py",flush=True) c=1 for patient in tqdm(glob.glob(inpath+"/*"), ncols=100, desc="Checking folder:", bar_format="{l_bar}{bar} [time left: {remaining}, time spent: {elapsed}]", colour="yellow"): patientID=os.path.basename(patient) if verbose: hprint(f"Processing {patientID}", patient) c=checkPatientFolderStructure_Alternative(patient,verbose,log, NoSegmentation) if c==0: break; if c==0 : print("\033[31mFolder is NOT correctly structured to be restructed with reorganize.py\033[0m",flush=True) if log !='': sys.stdout = sys.__stdout__ print("\033[31mFolder is NOT correctly structured to be restructed with reorganize.py\033[0m",flush=True) sys.stdout = f sys.exit() else: print("Folder is correctly structured to be restructed with reorganize.py",flush=True) if log !='': sys.stdout = sys.__stdout__ print("Folder is correctly structured to be restructed with reorganize.py",flush=True) sys.stdout = f sys.exit() else: print("Folder is correctly structured for the image processing pipeline",flush=True) if log !='': sys.stdout = sys.__stdout__ print("Folder is correctly structured for the image processing pipeline",flush=True) sys.stdout = f
#return 1 if the folder has a valid structure
[docs] def checkPatientFolderStructure(patient,verbose,log,NoSegmentation): if log != '': f = open(log,'a+') sys.stdout = f Valid_structure=1 for patient_subdirectory in glob.glob(patient+"/*"): if os.path.isdir(patient_subdirectory): doc_list=os.listdir(patient_subdirectory) if not NoSegmentation: #Check for RTSTRUCT only if data are segmented if not "RTSTRUCT.dcm" in doc_list: #subfolder contain a file RTSTRUCT.dcm Valid_structure=0 if verbose: print("\033[31mINCORRECT STRUCTURE FOUND FOR",patient,"\033[0m",flush=True) return Valid_structure elif not os.path.isfile(os.path.join(patient_subdirectory,"RTSTRUCT.dcm")): #RTSTRUCT.dcm is a file not a folder Valid_structure=0 if verbose: print("\033[31mINCORRECT STRUCTURE FOUND FOR",patient,"\033[0m",flush=True) return Valid_structure if not "DCM" in doc_list: #RTSTRUCT Valid_structure=0 if verbose: print("\033[31mINCORRECT STRUCTURE FOUND FOR",patient,"\033[0m",flush=True) return Valid_structure elif not os.path.isdir(os.path.join(patient_subdirectory,"DCM")): Valid_structure=0 if verbose: print("\033[31mINCORRECT STRUCTURE FOUND FOR",patient,"\033[0m",flush=True) return Valid_structure if verbose: print(patient,"... OK",flush=True) return 1
[docs] def checkPatientFolderStructure_Alternative(patient,verbose,log,NoSegmentation): if log != '': f = open(log,'a+') sys.stdout = f Alternative_valid_structure=1 for patient_subdirectory in glob.glob(patient+"/*"): subdirectory=os.path.basename(patient_subdirectory) rtstruct_list=[f for f in os.listdir(patient) if os.path.isfile(os.path.join(patient,f))] #select index that match the name of the current subdirectory rtstruct_list_idx=[i for i, item in enumerate (rtstruct_list) if re.search(subdirectory,item, re.IGNORECASE)] if not NoSegmentation: #Check for RTSTRUCT only if data are segmented if len(rtstruct_list_idx) == 0: Alternative_valid_structure=0 if verbose: print("\033[31mINCORRECT STRUCTURE FOUND FOR",patient,"\033[0m",flush=True) return Alternative_valid_structure elif len(rtstruct_list_idx) > 1: Alternative_valid_structure=0 if verbose: print("\033[31mINCORRECT STRUCTURE FOUND FOR",patient,"\033[0m",flush=True) return Alternative_valid_structure if verbose: print(patient,"... OK",flush=True) return 1
if __name__ == "__main__": main(sys.argv[1:])