diff --git a/toolbox/anatomy/mri_coregister.m b/toolbox/anatomy/mri_coregister.m index 291d1941b..cb6a72777 100644 --- a/toolbox/anatomy/mri_coregister.m +++ b/toolbox/anatomy/mri_coregister.m @@ -38,6 +38,7 @@ % =============================================================================@ % % Authors: Francois Tadel, 2016-2023 +% Chinmay Chinara, 2023 % ===== LOAD INPUTS ===== % Parse inputs @@ -233,7 +234,60 @@ end % Output file tag fileTag = '_mni'; + + % ===== CT2MRIREG ===== + case 'ct2mri' + % Check if ct2mrireg plugin is installed + [isInstalled, errMsg] = bst_plugin('Install', 'ct2mrireg'); + if ~isInstalled + if ~isProgress + bst_progress('stop'); + end + return; + end + + % Save files in tmp directory + bst_progress('text', 'Saving temporary files...'); + % Get temporary folder + TmpDir = bst_get('BrainstormTmpDir', 0, 'ct2mrireg'); + % Save source CT in .nii format + NiiSrcFile = bst_fullfile(TmpDir, 'ct2mri_src.nii'); + out_mri_nii(sMriSrc, NiiSrcFile); + % Save reference MRI in .nii format + NiiRefFile = bst_fullfile(TmpDir, 'ct2mri_ref.nii'); + out_mri_nii(sMriRef, NiiRefFile); + + % Save registered file in .nii.gz format + NiiRegFile = bst_fullfile(TmpDir, 'contrastmri2preMRI.nii.gz'); + bst_progress('text', 'Performing co-registration using ct2mrireg plugin...'); + NiiRegFile = ct2mrireg(NiiSrcFile, NiiRefFile, NiiRegFile); + + % Read output volume + sMriReg = in_mri(NiiRegFile, 'ALL', 0, 0); + + % Delete the temporary files + file_delete(TmpDir, 1, 1); + % Output file tag + fileTag = '_ct2mri'; + % === UPDATE FIDUCIALS === + if isReslice + % Use the reference SCS coordinates + if isfield(sMriRef, 'SCS') + sMriReg.SCS = sMriRef.SCS; + end + % Use the reference NCS coordinates + if isfield(sMriRef, 'NCS') + sMriReg.NCS = sMriRef.NCS; + end + + % Reslice the volume + [sMriReg, errMsg] = mri_reslice(sMriReg, sMriRef, 'scs', 'scs', isAtlas); + else + isUpdateScs = 1; + isUpdateNcs = 1; + end + % ===== VOX2RAS ===== case 'vox2ras' % Nothing to do, just reslice if needed diff --git a/toolbox/core/bst_plugin.m b/toolbox/core/bst_plugin.m index 6dc3de10a..6bc529367 100644 --- a/toolbox/core/bst_plugin.m +++ b/toolbox/core/bst_plugin.m @@ -105,7 +105,7 @@ % For more information type "brainstorm license" at command prompt. % =============================================================================@ % -% Authors: Francois Tadel 2021-2023 +% Authors: Francois Tadel, 2021-2023 eval(macro_method); end @@ -192,6 +192,20 @@ PlugDesc(end).UnloadPlugs = {'spm12', 'iso2mesh'}; PlugDesc(end).LoadFolders = {'lib/spm12', 'lib/iso2mesh', 'lib/cvx', 'lib/ncs2daprox', 'lib/NIFTI_20110921'}; + % === ANATOMY: CT2MRIREG === + % this plugin is used for performing CT to MRI co-registration + PlugDesc(end+1) = GetStruct('ct2mrireg'); + PlugDesc(end).Version = 'github-master'; + PlugDesc(end).Category = 'Anatomy'; + PlugDesc(end).AutoUpdate = 1; + PlugDesc(end).URLzip = 'https://github.com/ajoshiusc/USCCleveland/archive/master.zip'; + PlugDesc(end).URLinfo = 'https://github.com/ajoshiusc/USCCleveland/tree/master/ct2mrireg'; + PlugDesc(end).TestFile = 'ct2mrireg.m'; + PlugDesc(end).ReadmeFile = 'ct2mrireg/README.md'; + PlugDesc(end).CompiledStatus = 2; + PlugDesc(end).LoadFolders = {'ct2mrireg'}; + PlugDesc(end).DeleteFiles = {'fmri_analysis', 'for_clio', 'mixed_atlas', 'process_script', 'reg_prepost', 'visualize_channels', '.gitignore', 'README.md'}; + % === FORWARD: OPENMEEG === PlugDesc(end+1) = GetStruct('openmeeg'); PlugDesc(end).Version = '2.4.1'; diff --git a/toolbox/io/import_mri.m b/toolbox/io/import_mri.m index 26515ba0e..3825f8455 100644 --- a/toolbox/io/import_mri.m +++ b/toolbox/io/import_mri.m @@ -1,5 +1,5 @@ function [BstMriFile, sMri, Messages] = import_mri(iSubject, MriFile, FileFormat, isInteractive, isAutoAdjust, Comment, Labels) -% IMPORT_MRI: Import a MRI file in a subject of the Brainstorm database +% IMPORT_MRI: Import a volume file (MRI, Atlas, CT, etc) in a subject of the Brainstorm database % % USAGE: [BstMriFile, sMri, Messages] = import_mri(iSubject, MriFile, FileFormat='ALL', isInteractive=0, isAutoAdjust=1, Comment=[], Labels=[]) % BstMriFiles = import_mri(iSubject, MriFiles, ...) % Import multiple volumes at once @@ -38,6 +38,7 @@ % =============================================================================@ % % Authors: Francois Tadel, 2008-2023 +% Chinmay Chinara, 2023 %% ===== PARSE INPUTS ===== if (nargin < 3) || isempty(FileFormat) @@ -69,6 +70,15 @@ else sSubject = ProtocolSubjects.Subject(iSubject); end +% Volume type +volType = 'MRI'; +if ~isempty(strfind(Comment, 'CT')) + volType = 'CT'; +end +% Get node comment from filename +if ~isempty(strfind(Comment, 'Import')) + Comment = []; +end %% ===== SELECT MRI FILE ===== % If MRI file to load was not defined : open a dialog box to select it @@ -80,9 +90,10 @@ if isempty(DefaultFormats.MriIn) DefaultFormats.MriIn = 'ALL'; end - % Get MRI file + + % Get MRI/CT file [MriFile, FileFormat, FileFilter] = java_getfile( 'open', ... - 'Import MRI...', ... % Window title + ['Import ' volType '...'], ... % Window title LastUsedDirs.ImportAnat, ... % Default directory 'multiple', 'files_and_dirs', ... % Selection mode bst_get('FileFilters', 'mri'), ... @@ -140,7 +151,7 @@ %% ===== LOAD MRI FILE ===== isProgress = bst_progress('isVisible'); if ~isProgress - bst_progress('start', 'Import MRI', 'Loading MRI file...'); + bst_progress('start', ['Import ', volType], ['Loading ', volType, ' file...']); end % MNI / Atlas? isMni = ismember(FileFormat, {'ALL-MNI', 'ALL-MNI-ATLAS'}); @@ -215,7 +226,8 @@ else % If some transformation where made to the intial volume: apply them to the new one ? if isfield(sMriRef, 'InitTransf') && ~isempty(sMriRef.InitTransf) && any(ismember(sMriRef.InitTransf(:,1), {'permute', 'flipdim'})) - if ~isInteractive || java_dialog('confirm', ['A transformation was applied to the reference MRI.' 10 10 'Do you want to apply the same transformation to this new volume?' 10 10], 'Import MRI') + isApplyTransformation = java_dialog('confirm', ['A transformation was applied to the reference MRI.' 10 10 'Do you want to apply the same transformation to this new volume?' 10 10], ['Import ', volType]); + if ~isInteractive || isApplyTransformation % Apply step by step all the transformations that have been applied to the original MRI for it = 1:size(sMriRef.InitTransf,1) ttype = sMriRef.InitTransf{it,1}; @@ -253,11 +265,17 @@ % Register with the MNI transformation strOptions = [strOptions, '
- MNI:   Compute the MNI transformation for both volumes (inaccurate).']; cellOptions{end+1} = 'MNI'; + if strcmpi(volType, 'CT') + % Register with the ct2mrireg plugin + strOptions = [strOptions, '
- CT2MRI:   Coregister using USC ct2mrireg plugin.']; + cellOptions{end+1} = 'CT2MRI'; + end % Skip registration strOptions = [strOptions, '
- Ignore:   The two volumes are already registered.']; cellOptions{end+1} = 'Ignore'; % Ask user to make a choice - RegMethod = java_dialog('question', [strOptions '

'], 'Import MRI', [], cellOptions, 'Reg+reslice'); + RegMethod = java_dialog('question', [strOptions '

'], ['Import ', volType], [], cellOptions, 'Reg+reslice'); + % In non-interactive mode: ignore if possible, or use the first option available else RegMethod = 'Ignore'; @@ -283,9 +301,9 @@ % Ask to reslice isReslice = java_dialog('confirm', [... 'Reslice the volume?

' ... - 'This operation rewrites the new MRI to match the alignment,
size and resolution of the original volume.' ... + ['This operation rewrites the new ', volType, ' to match the alignment,
size and resolution of the original volume.'] ... strSizeWarn ... - '

'], 'Import MRI'); + '

'], ['Import ', volType]); % In non-interactive mode: never reslice else isReslice = 0; @@ -299,6 +317,9 @@ case 'SPM' % Register the new MRI on the existing one using SPM + RESLICE [sMri, errMsg, fileTag] = mri_coregister(sMri, sMriRef, 'spm', isReslice, isAtlas); + case 'CT2MRI' + % Register the CT to excisting MRI using USC's ct2mrireg plugin + [sMri, errMsg, fileTag] = mri_coregister(sMri, sMriRef, 'ct2mri', isReslice, isAtlas); case 'Ignore' if isReslice % Register the new MRI on the existing one using the transformation in the input files (files already registered) diff --git a/toolbox/tree/tree_callbacks.m b/toolbox/tree/tree_callbacks.m index 3da08d3ba..4e2dc75fd 100644 --- a/toolbox/tree/tree_callbacks.m +++ b/toolbox/tree/tree_callbacks.m @@ -562,6 +562,7 @@ gui_component('MenuItem', jPopup, [], 'Import anatomy folder', IconLoader.ICON_ANATOMY, [], @(h,ev)bst_call(@import_anatomy, iSubject, 0)); gui_component('MenuItem', jPopup, [], 'Import anatomy folder (auto)', IconLoader.ICON_ANATOMY, [], @(h,ev)bst_call(@import_anatomy, iSubject, 1)); gui_component('MenuItem', jPopup, [], 'Import MRI', IconLoader.ICON_ANATOMY, [], @(h,ev)bst_call(@import_mri, iSubject, [], [], 1)); + gui_component('MenuItem', jPopup, [], 'Import CT', IconLoader.ICON_ANATOMY, [], @(h,ev)bst_call(@import_mri, iSubject, [], [], 1, 1, 'Import CT')); gui_component('MenuItem', jPopup, [], 'Import surfaces', IconLoader.ICON_SURFACE, [], @(h,ev)bst_call(@import_surfaces, iSubject)); gui_component('MenuItem', jPopup, [], 'Import fibers', IconLoader.ICON_FIBERS, [], @(h,ev)bst_call(@import_fibers, iSubject)); gui_component('MenuItem', jPopup, [], 'Convert DWI to DTI', IconLoader.ICON_FIBERS, [], @(h,ev)bst_call(@process_dwi2dti, 'ComputeInteractive', iSubject));