def nifti2dcm_conversion_pipeline(self, **name_maps): pipeline = self.new_pipeline( name='conversion_to_dicom', desc=("Conversing aligned umap from nifti to dicom format - " "parallel implementation"), citations=(), name_maps=name_maps) list_niftis = pipeline.add( 'list_niftis', ListDir(), inputs={'directory': ('umaps_align2ref', directory_format)}) reorient_niftis = pipeline.add('reorient_niftis', ReorientUmap(), inputs={ 'niftis': (list_niftis, 'files'), 'umap': ('umap', dicom_format) }, requirements=[mrtrix_req.v('3.0rc3')]) list_dicoms = pipeline.add( 'list_dicoms', ListDir(sort_key=dicom_fname_sort_key), inputs={'directory': ('umap', dicom_format)}) nii2dicom = pipeline.add( 'nii2dicom', Nii2Dicom( # extension='Frame', # nii2dicom parameter ), inputs={'reference_dicom': (list_dicoms, 'files')}, outputs={'in_file': (reorient_niftis, 'reoriented_umaps')}, iterfield=['in_file'], wall_time=20) pipeline.add( 'copy2dir', CopyToDir(extension='Frame'), inputs={'in_files': (nii2dicom, 'out_file')}, outputs={'umap_aligned_dicoms': ('out_dir', directory_format)}) return pipeline
def qsm_pipeline(self, **name_maps): """ Process dual echo data for QSM (TE=[7.38, 22.14]) NB: Default values come from the STI-Suite """ pipeline = self.new_pipeline( name='qsm_pipeline', name_maps=name_maps, desc="Resolve QSM from t2star coils", citations=[sti_cites, fsl_cite, matlab_cite]) erosion = pipeline.add( 'mask_erosion', fsl.ErodeImage(kernel_shape='sphere', kernel_size=self.parameter('qsm_erosion_size'), output_type='NIFTI'), inputs={'in_file': ('brain_mask', nifti_gz_format)}, requirements=[fsl_req.v('5.0.8')], wall_time=15, mem_gb=12) # If we have multiple echoes we can combine the phase images from # each channel into a single image. Otherwise for single echo sequences # we need to perform QSM on each coil separately and then combine # afterwards. if self.branch('qsm_dual_echo'): # Combine channels to produce phase and magnitude images channel_combine = pipeline.add( 'channel_combine', HIPCombineChannels(), inputs={ 'magnitudes_dir': ('mag_channels', multi_nifti_gz_format), 'phases_dir': ('phase_channels', multi_nifti_gz_format) }) # Unwrap phase using Laplacian unwrapping unwrap = pipeline.add( 'unwrap', UnwrapPhase(padsize=self.parameter('qsm_padding')), inputs={ 'voxelsize': ('voxel_sizes', float), 'in_file': (channel_combine, 'phase') }, requirements=[matlab_req.v('r2017a'), sti_req.v(2.2)]) # Remove background noise vsharp = pipeline.add( "vsharp", VSharp(mask_manip="imerode({}>0, ball(5))"), inputs={ 'voxelsize': ('voxel_sizes', float), 'in_file': (unwrap, 'out_file'), 'mask': (erosion, 'out_file') }, requirements=[matlab_req.v('r2017a'), sti_req.v(2.2)]) # Run QSM iLSQR pipeline.add('qsmrecon', QSMiLSQR(mask_manip="{}>0", padsize=self.parameter('qsm_padding')), inputs={ 'voxelsize': ('voxel_sizes', float), 'te': ('echo_times', float), 'B0': ('main_field_strength', float), 'H': ('main_field_orient', float), 'in_file': (vsharp, 'out_file'), 'mask': (vsharp, 'new_mask') }, outputs={'qsm': ('qsm', nifti_format)}, requirements=[matlab_req.v('r2017a'), sti_req.v(2.2)]) else: # Dialate eroded mask dialate = pipeline.add( 'dialate', DialateMask(dialation=self.parameter('qsm_mask_dialation')), inputs={'in_file': (erosion, 'out_file')}, requirements=[matlab_req.v('r2017a')]) # List files for the phases of separate channel list_phases = pipeline.add( 'list_phases', ListDir(sort_key=coil_sort_key, filter=CoilEchoFilter(self.parameter('qsm_echo'))), inputs={ 'directory': ('phase_channels', multi_nifti_gz_format) }) # List files for the phases of separate channel list_mags = pipeline.add( 'list_mags', ListDir(sort_key=coil_sort_key, filter=CoilEchoFilter(self.parameter('qsm_echo'))), inputs={'directory': ('mag_channels', multi_nifti_gz_format)}) # Generate coil specific masks mask_coils = pipeline.add( 'mask_coils', MaskCoils(dialation=self.parameter('qsm_mask_dialation')), inputs={ 'masks': (list_mags, 'files'), 'whole_brain_mask': (dialate, 'out_file') }, requirements=[matlab_req.v('r2017a')]) # Unwrap phase unwrap = pipeline.add( 'unwrap', BatchUnwrapPhase(padsize=self.parameter('qsm_padding')), inputs={ 'voxelsize': ('voxel_sizes', float), 'in_file': (list_phases, 'files') }, requirements=[matlab_req.v('r2017a'), sti_req.v(2.2)]) # Background phase removal vsharp = pipeline.add( "vsharp", BatchVSharp(mask_manip='{}>0'), inputs={ 'voxelsize': ('voxel_sizes', float), 'mask': (mask_coils, 'out_files'), 'in_file': (unwrap, 'out_file') }, requirements=[matlab_req.v('r2017a'), sti_req.v(2.2)]) first_echo_time = pipeline.add( 'first_echo', Select(index=0), inputs={'inlist': ('echo_times', float)}) # Perform channel-wise QSM coil_qsm = pipeline.add( 'coil_qsmrecon', BatchQSMiLSQR(mask_manip="{}>0", padsize=self.parameter('qsm_padding')), inputs={ 'voxelsize': ('voxel_sizes', float), 'B0': ('main_field_strength', float), 'H': ('main_field_orient', float), 'in_file': (vsharp, 'out_file'), 'mask': (vsharp, 'new_mask'), 'te': (first_echo_time, 'out') }, requirements=[matlab_req.v('r2017a'), sti_req.v(2.2)], wall_time=45) # FIXME: Should be dependent on number of coils # Combine channel QSM by taking the median coil value pipeline.add('combine_qsm', MedianInMasks(), inputs={ 'channels': (coil_qsm, 'out_file'), 'channel_masks': (vsharp, 'new_mask'), 'whole_brain_mask': (dialate, 'out_file') }, outputs={'qsm': ('out_file', nifti_format)}, requirements=[matlab_req.v('r2017a')]) return pipeline
def preprocess_channels_pipeline(self, **name_maps): pipeline = self.new_pipeline( 'preprocess_channels', name_maps=name_maps, desc=("Convert channel signals in complex coords to polar coords " "and combine")) if (self.provided('header_image') or self.branch('reorient_to_std') or self.parameter('force_channel_flip') is not None): # Read channel files reorient them into standard space and then # write back to directory list_channels = pipeline.add( 'list_channels', ListDir(), inputs={ 'directory': ('channels', multi_nifti_gz_format)}) if self.parameter('force_channel_flip') is not None: force_flip = pipeline.add( 'flip_dims', fsl.SwapDimensions( new_dims=tuple(self.parameter('force_channel_flip'))), inputs={ 'in_file': (list_channels, 'files')}, iterfield=['in_file']) geom_dest_file = (force_flip, 'out_file') else: geom_dest_file = (list_channels, 'files') if self.provided('header_image'): # If header image is provided stomp its geometry over the # acquired channels copy_geom = pipeline.add( 'qsm_copy_geometry', fsl.CopyGeom( output_type='NIFTI_GZ'), inputs={ 'in_file': ('header_image', nifti_gz_format), 'dest_file': geom_dest_file}, iterfield=(['dest_file']), requirements=[fsl_req.v('5.0.8')]) reorient_in_file = (copy_geom, 'out_file') else: reorient_in_file = geom_dest_file if self.branch('reorient_to_std'): reorient = pipeline.add( 'reorient_channel', fsl.Reorient2Std( output_type='NIFTI_GZ'), inputs={ 'in_file': reorient_in_file}, iterfield=['in_file'], requirements=[fsl_req.v('5.0.8')]) copy_to_dir_in_files = (reorient, 'out_file') else: copy_to_dir_in_files = reorient_in_file copy_to_dir = pipeline.add( 'copy_to_dir', CopyToDir(), inputs={ 'in_files': copy_to_dir_in_files, 'file_names': (list_channels, 'files')}) to_polar_in_dir = (copy_to_dir, 'out_dir') else: to_polar_in_dir = ('channels', multi_nifti_gz_format) pipeline.add( 'to_polar', ToPolarCoords( in_fname_re=self.parameter('channel_fname_regex'), real_label=self.parameter('channel_real_label'), imaginary_label=self.parameter('channel_imag_label')), inputs={ 'in_dir': to_polar_in_dir}, outputs={ 'mag_channels': ('magnitudes_dir', multi_nifti_gz_format), 'phase_channels': ('phases_dir', multi_nifti_gz_format)}) return pipeline