Skip to content

Commit

Permalink
completed the first version of dicom processing
Browse files Browse the repository at this point in the history
  • Loading branch information
Reza Eghbali committed Jun 24, 2024
1 parent e7d2eb2 commit b699e6e
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 57 deletions.
52 changes: 47 additions & 5 deletions pyalfe/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@

from dependency_injector import containers, providers

from pyalfe.data_structure import DefaultALFEDataDir, BIDSDataDir, Modality
from pyalfe.data_structure import (
DefaultALFEDataDir,
BIDSDataDir,
PatientDicomDataDir,
Modality
)
from pyalfe.image_processing import Convert3DProcessor, NilearnProcessor
from pyalfe.image_registration import GreedyRegistration, AntsRegistration
from pyalfe.inference import NNUnetV2
from pyalfe.models import MODELS_PATH
from pyalfe.pipeline import PyALFEPipelineRunner
from pyalfe.pipeline import PyALFEPipelineRunner, DicomProcessingPipelineRunner
from pyalfe.tasks.dicom_processing import DicomProcessing
from pyalfe.tasks.initialization import Initialization
from pyalfe.tasks.quantification import Quantification
from pyalfe.tasks.registration import (
Expand All @@ -26,12 +32,11 @@
from pyalfe.tasks.t1_preprocessing import T1Preprocessing


class Container(containers.DeclarativeContainer):
class PipelineContainer(containers.DeclarativeContainer):
"""
container objects for all the dependencies of the pipeline.
"""

logger = logging.getLogger('Container')
config = providers.Configuration()

pipeline_dir = providers.Selector(
Expand Down Expand Up @@ -212,7 +217,7 @@ class Container(containers.DeclarativeContainer):
dominant_tissue=config.options.dominant_tissue,
)

pipeline_runner = providers.Singleton(
pyalfe_pipeline_runner = providers.Singleton(
PyALFEPipelineRunner,
initialization=initialization,
skullstripping=skullstripping,
Expand All @@ -226,3 +231,40 @@ class Container(containers.DeclarativeContainer):
resampling=resampling,
quantification=quantification,
)


class DicomProcessingContianer(containers.DeclarativeContainer):
"""Contianer for dicom processing pipeline depedencies"""

config = providers.Configuration()

pipeline_dir = providers.Selector(
config.options.data_dir_structure,
alfe=providers.Singleton(
DefaultALFEDataDir,
output_dir=os.devnull,
input_dir=config.options.input_dir,
),
bids=providers.Singleton(
BIDSDataDir,
output_dir=os.devnull,
input_dir=config.options.input_dir,
),
)

dicom_dir = providers.Singleton(
PatientDicomDataDir,
dicom_dir=config.options.dicom_dir
)

dicom_processing = providers.Singleton(
DicomProcessing,
pipeline_dir=pipeline_dir,
dicom_dir=dicom_dir,
overwrite=config.options.overwrite_images
)

dicom_processing_pipeline_runner = providers.Singleton(
DicomProcessingPipelineRunner,
dicom_processing=dicom_processing
)
26 changes: 13 additions & 13 deletions pyalfe/data_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,17 +560,17 @@ def get_quantification_file(
return ret


class PatientDicomDir():
class PatientDicomDataDir():
"""This class is designe to work with directories containing raw dicom
files for a patient that are organized as:
patient_id
└─ accession (study_id)
└─ series_id
└─ accession (study_uid)
└─ series_uid
├─ instance_0.dcm
└─ instance_1.dcm
"""
def __init__(self, patient_dir) -> None:
self.patient_dir = patient_dir
def __init__(self, dicom_dir) -> None:
self.dicom_dir = dicom_dir

def is_dicom_file(self, file):
"""Function to check if file is a dicom file.
Expand Down Expand Up @@ -623,19 +623,19 @@ def get_all_dicom_series_instances(self, accession):
list of instances as values.
"""
ret = {}
accession_path = os.path.join(self.patient_dir, accession)
for path in glob.glob(accession_path, '*'):
accession_path = os.path.join(self.dicom_dir, accession)
for path in glob.glob(os.path.join(accession_path, '*')):
instances = []
for file in glob.glob(path, '*'):
for file in glob.glob(os.path.join(path, '*')):
if os.path.isfile(file) and self.is_dicom_file(file):
instances.append(file)
if len(instances) > 0:
series_id = os.path.basename(path)
ret[series_id] = instances
series_uid = os.path.basename(path)
ret[series_uid] = instances
return ret


def get_series(self, accession, series_id):
def get_series(self, accession, series_uid):
"""This method returns the path to a series.
Parameters
Expand All @@ -644,12 +644,12 @@ def get_series(self, accession, series_id):
The patient_id.
accession: str
The accession or study number.
series_id: str
series_uid: str
The series ID.
Returns
-------
str
The path to the series directory
"""
return os.path.join(self.patient_dir, accession, series_id)
return os.path.join(self.dicom_dir, accession, series_uid)
59 changes: 56 additions & 3 deletions pyalfe/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ def download(assets):
'--data-dir-structure',
type=click.Choice(['alfe', 'bids'], case_sensitive=False),
)
@click.option(
'-dcm',
'--dicom-dir',
type=click.Path(), default=None
)
def run(
accession: str,
config: str,
Expand Down Expand Up @@ -134,9 +139,9 @@ def run(
-------
None
"""
from pyalfe.containers import Container
from pyalfe.containers import PipelineContainer

container = Container()
container = PipelineContainer()
container.config.from_ini(config, required=True, envs_required=True)

options = container.config.options()
Expand All @@ -163,7 +168,7 @@ def run(
click.echo(options)

container.init_resources()
pipeline_runner = container.pipeline_runner()
pipeline_runner = container.pyalfe_pipeline_runner()

pipeline_runner.run(accession)

Expand Down Expand Up @@ -234,5 +239,53 @@ def configure():
config.write(conf)


@main.command()
@click.argument('accession')
@click.argument('dicom_dir')
@click.option(
'-c',
'--config',
default=DEFAULT_CFG,
)
@click.option('-nd', '--nifti-dir')
@click.option(
'-dds',
'--data-dir-structure',
type=click.Choice(['alfe', 'bids'], case_sensitive=False),
)
@click.option('-ow/-now', '--overwrite/--no-overwrite', default=True)
def process_dicom(
accession: str,
dicom_dir: str,
config: str,
nifti_dir: str,
data_dir_structure: str,
overwrite: bool,
):
from pyalfe.containers import DicomProcessingContianer

container = DicomProcessingContianer()
container.config.from_ini(config, required=True, envs_required=True)

options = container.config.options()

options['dicom_dir'] = dicom_dir

if nifti_dir:
options['nifti_dir'] = nifti_dir
else:
options['nifti_dir'] = options['input_dir']
if data_dir_structure:
options['data_dir_structure'] = data_dir_structure
options['overwrite_images'] = overwrite

container.init_resources()
pipeline_runner = container.dicom_processing_pipeline_runner()

pipeline_runner.run(accession)




if __name__ == '__main__':
main()
62 changes: 38 additions & 24 deletions pyalfe/pipeline.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from pyalfe.tasks.dicom_processing import DicomProcessing
from pyalfe.tasks.initialization import Initialization
from pyalfe.tasks.quantification import Quantification
from pyalfe.tasks.registration import (
Expand All @@ -14,7 +15,16 @@
from pyalfe.tasks.t1_preprocessing import T1Preprocessing


class PyALFEPipelineRunner:
class PipelineRunner:
def __init__(self, steps):
self.steps = steps

def run(self, accession: str) -> None:
for step in self.steps:
step.run(accession)


class PyALFEPipelineRunner(PipelineRunner):
"""The pyalfe pipeline runner.
Attributes
Expand Down Expand Up @@ -57,27 +67,31 @@ def __init__(
resampling: Resampling,
quantification: Quantification,
):
self.initialization = initialization
self.skullstripping = skullstripping
self.t1_preprocessing = t1_preprocessing
self.cross_modality_registration = cross_modality_registration
self.flair_segmentation = flair_segmentation
self.enhancement_segmentation = enhancement_segmentation
self.tissue_segmentation = tissue_segmentation
self.t1_postprocessing = t1_postprocessing
self.t1_registration = t1_registration
self.resampling = resampling
self.quantification = quantification
steps = [
initialization,
skullstripping,
t1_preprocessing,
cross_modality_registration,
flair_segmentation,
enhancement_segmentation,
t1_postprocessing,
t1_registration,
tissue_segmentation,
resampling,
quantification
]
super().__init__(steps)



def run(self, accession) -> None:
self.initialization.run(accession)
self.skullstripping.run(accession)
self.t1_preprocessing.run(accession)
self.cross_modality_registration.run(accession)
self.flair_segmentation.run(accession)
self.enhancement_segmentation.run(accession)
self.t1_postprocessing.run(accession)
self.t1_registration.run(accession)
self.tissue_segmentation.run(accession)
self.resampling.run(accession)
self.quantification.run(accession)
class DicomProcessingPipelineRunner(PipelineRunner):
"""The Dicom processing pipeline runner
Attributes
----------
dicom_processing: DicomProcessing
The dicom processing object.
"""
def __init__(self, dicom_processing: DicomProcessing):
steps = [dicom_processing]
super().__init__(steps)
Loading

0 comments on commit b699e6e

Please sign in to comment.