Skip to content

Commit 124c2cc

Browse files
committed
ENH: add easyreg normmethod
1 parent 4670b4d commit 124c2cc

14 files changed

+162
-16
lines changed

classes/conda_utils/environments/EasyReg.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ dependencies:
1515
- pip:
1616
- surfa==0.3.7
1717
- voxelmorph==0.2
18+
- ermodels==0.0.3

ea_apply_normalization.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ function ea_apply_normalization(options)
66

77
json = loadjson(options.subj.norm.log.method);
88

9-
if contains(json.method, 'ANTs')
9+
if contains(json.method, {'ANTs','EasyReg'})
1010
ea_ants_apply_transforms(options);
1111
elseif contains(json.method, 'FNIRT')
1212
ea_fsl_apply_normalization(options);

ea_apply_normalization_tofile.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ function ea_apply_normalization_tofile(options,from,to,useinverse,interp,ref)
2323

2424
if ischar(interp)
2525
if strcmp(interp,'auto') % only works if one image supplied
26-
interp=detinterp(from,contains(json.method, 'ANTs'));
26+
interp=detinterp(from,contains(json.method, {'ANTs','EasyReg'}));
2727
end
2828
end
2929

30-
if contains(json.method, 'ANTs')
30+
if contains(json.method, {'ANTs','EasyReg'})
3131
ea_ants_apply_transforms(options, from, to, useinverse, ref, '', interp);
3232
elseif contains(json.method, 'FNIRT')
3333
if useinverse

ea_genvat_butenko.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@
166166
if ~isfile(nativeTensor) && isfile(templateTensor)
167167
% Warp tensor data only when ANTs was used for normalization
168168
json = loadjson(options.subj.norm.log.method);
169-
if contains(json.method, 'ANTs')
169+
if contains(json.method, {'ANTs','EasyReg'})
170170
fprintf('Warping tensor data into patient space...\n\n')
171171
ea_ants_apply_transforms(options,...
172172
[ea_space, tensorName],... % From

ea_map_coords.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@
282282
json = loadjson(options.subj.norm.log.method);
283283
normMethod = upper(json.method);
284284

285-
if contains(normMethod, 'ANTS')
285+
if contains(normMethod, {'ANTS', 'EASYREG'})
286286
if endsWith(transform, 'inverseTransform')
287287
useinverse = 1;
288288
else
@@ -358,7 +358,7 @@
358358

359359
switch normMethod
360360

361-
case {'ANTS'} % ANTs used
361+
case {'ANTS', 'EASYREG'} % ANTs used
362362
if nargin >= 6
363363
useinverse = varargin{6};
364364
else

ea_normalize.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ case lower({'SPM12 Segment (Ashburner 2005)', 'SPMSegment', 'Segment'})
3030
ea_normalize_spmnewseg(options);
3131
case lower({'SPM12 SHOOT (Ashburner 2011)', 'SPMSHOOT', 'SHOOT'})
3232
ea_normalize_spmshoot(options);
33+
case lower({'EasyReg (Iglesias 2023)', 'EasyReg'})
34+
ea_normalize_easyreg(options);
3335
otherwise
3436
warning('Normalization method not recognized...');
3537
if options.prefs.diary

ea_normalize_easyreg.m

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
function varargout=ea_normalize_easyreg(options)
2+
3+
if ischar(options) % return name of method.
4+
varargout{1}='EasyReg (Iglesias 2023)';
5+
varargout{2}=1; % dummy output
6+
varargout{3}=1; % hassettings.
7+
varargout{4}=0; % is multispectral
8+
return
9+
end
10+
11+
% FSL FNIRT nonlinear registration
12+
[fwd_field, inv_field] = ea_easyreg([ea_space, options.primarytemplate, '.nii'], options.subj.coreg.anat.preop.(options.subj.AnchorModality));
13+
14+
% Move transformation file
15+
movefile(fwd_field, [options.subj.norm.transform.forwardBaseName, 'ants.nii.gz']);
16+
movefile(inv_field, [options.subj.norm.transform.inverseBaseName, 'ants.nii.gz']);
17+
18+
% Apply registration
19+
ea_apply_normalization(options)
20+
21+
%% add methods dump:
22+
[scit, lcit] = ea_getspacedefcit;
23+
cits = {'Iglesias, J. E. (2023). A ready-to-use machine learning tool for symmetric multi-modality registration of brain MRI. Scientific Reports, 13(1), Article 1. https://doi.org/10.1038/s41598-023-33781-0'};
24+
25+
if ~isempty(lcit)
26+
cits = [cits;{lcit}];
27+
end
28+
29+
ea_methods(options,['Pre- (and post-) operative acquisitions were spatially normalized into ',ea_getspace,' space ',scit,' based on the preoperative acquisition (',options.subj.AnchorModality,') using the'...
30+
' EasyReg approach as implemented in FreeSurfer (https://surfer.nmr.mgh.harvard.edu/fswiki/EasyReg).'],cits);

ea_normsettings_easyreg.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
function ea_normsettings_easyreg(varargin)
2+
3+
disp('EasyReg: Nothing to set up.')

ea_runwarpdrive.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
if isfield(options, 'overwriteapproved')
2929
keep_pts(i) = keep_pts(i) || options.overwriteapproved;
3030
end
31-
if ~contains(approved_load.method, 'ANTs')
31+
if ~contains(approved_load.method, {'ANTs', 'EasyReg'})
3232
keep_pts(i) = 0;
3333
disp([warpdrive_subs(i).subjId ' was normalized using ' approved_load.method '. Use ANTs in order to run warpdrive.']);
3434
end

ext_libs/EasyReg/ea_easyreg.m

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
function [itk_fwd_field, itk_inv_field] = ea_easyreg(target_image, source_image)
2+
% Wrapper to run EasyReg and get ANTs-like transforms
3+
4+
%
5+
% EasyReg
6+
%
7+
8+
target_seg = [target_image(1:end-4) '_synthseg.nii'];
9+
source_seg = [source_image(1:end-4) '_synthseg.nii'];
10+
fs_fwd_field = [source_image(1:end-4) '_fs_fwd_field.nii'];
11+
12+
% Check Conda installation
13+
if ~ea_conda.is_installed
14+
ea_conda.install;
15+
end
16+
17+
% Check Conda environment
18+
condaenv = ea_conda_env('easyreg');
19+
if ~condaenv.is_created
20+
ea_cprintf('CmdWinWarnings', 'Initializing easyreg environment...\n')
21+
condaenv.create;
22+
ea_cprintf('CmdWinWarnings', 'easyreg conda environment initialized.\n')
23+
end
24+
25+
% Run EasyReg
26+
easyreg_exe = fullfile(ea_getearoot, 'ext_libs', 'EasyReg', 'mri_easyreg');
27+
easyreg_cmd = {'python', easyreg_exe, '--ref', target_image, '--ref_seg', target_seg, '--flo', source_image, '--flo_seg', source_seg, '--fwd_field', fs_fwd_field};
28+
condaenv.system(strjoin(easyreg_cmd, ' '));
29+
30+
%
31+
% Convert transform
32+
%
33+
34+
% Freesurfer to ITK transform
35+
itk_fwd_field = [source_image(1:end-4) '_itk_fwd_field.h5'];
36+
freesurfer_nii_to_itk_h5(fs_fwd_field, itk_fwd_field);
37+
38+
% Set-up Custom Slicer
39+
s4l = ea_slicer_for_lead;
40+
if ~s4l.is_installed_and_up_to_date()
41+
s4l.install();
42+
end
43+
44+
% Invert transform
45+
itk_inv_field = strrep(itk_fwd_field, '_fwd_', '_inv_');
46+
python_script = fullfile(ea_getearoot, 'ext_libs', 'EasyReg', 'invert_transform.py');
47+
slicer_cmd = {'--no-splash', '--no-main-window', '--ignore-slicerrc', '--python-script', python_script, itk_fwd_field, source_image, itk_inv_field};
48+
s4l.run(strjoin(slicer_cmd, ' '));
49+
50+
% .h5 to .nii.gz
51+
ea_conv_antswarps(itk_fwd_field, target_image, 1);
52+
ea_conv_antswarps(itk_inv_field, source_image, 1);
53+
54+
itk_fwd_field = strrep(itk_fwd_field, '.h5', '.nii.gz');
55+
itk_inv_field = strrep(itk_inv_field, '.h5', '.nii.gz');
56+
57+
ea_delete({source_seg, fs_fwd_field});
58+
59+
end
60+
61+
62+
function [] = freesurfer_nii_to_itk_h5(warp_file_in, warp_file_out)
63+
64+
% substract mm coordinates for each voxel
65+
66+
n = load_nii(warp_file_in);
67+
s = n.hdr.dime.dim(2:4);
68+
index = 1:prod(s);
69+
[v1,v2,v3] = ind2sub(s,index);
70+
mm = ea_vox2mm([v1',v2',v3'], get_mat);
71+
mm = reshape(mm, [s,3]);
72+
out = n.img - mm;
73+
74+
% reshape output
75+
76+
out_rows = [-reshape(out(:,:,:,1),1,[]); -reshape(out(:,:,:,2),1,[]); reshape(out(:,:,:,3),1,[])];
77+
out_column = reshape(out_rows,[],1);
78+
79+
% save
80+
81+
copyfile(fullfile(ea_getearoot, 'ext_libs', 'EasyReg', 'itk_h5_template.h5'), warp_file_out);
82+
h5create(warp_file_out,"/TransformGroup/0/TransformParameters", numel(out_column));
83+
h5write(warp_file_out,"/TransformGroup/0/TransformParameters", out_column);
84+
85+
end
86+
87+
function mat = get_mat()
88+
89+
mat = [ 0.5 0 0 -98.5;...
90+
0 0.5 0 -134.5;...
91+
0 0 0.5 -72.5;...
92+
0 0 0 1];
93+
94+
end

0 commit comments

Comments
 (0)