Skip to content

Commit 211f93e

Browse files
committed
Merge branch 'main' into config
2 parents 87e9f6c + e893baa commit 211f93e

File tree

19 files changed

+171
-62
lines changed

19 files changed

+171
-62
lines changed

.github/workflows/code_quality.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
with:
3333
python-version: 3.9
3434

35-
- uses: actions/cache@v3
35+
- uses: actions/cache@v4
3636
with:
3737
path: ~/.cache/pip
3838
key: ${{ runner.os }}-pip-${{ hashFiles('setup.py') }}

.github/workflows/pipeline_status.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
with:
3838
python-version: 3.9
3939

40-
- uses: actions/cache@v3
40+
- uses: actions/cache@v4
4141
with:
4242
path: ~/.cache/pip
4343
key: ${{ runner.os }}-pip-${{ hashFiles('setup.py') }}

docs/core.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ This module contains a set of functions dedicated to computations on images.
124124
# Get dimensions of voxels along x, y, and z in mm (returns e.g.: [1.0, 1.0, 1.0]).
125125
get_voxel_dimensions('/path/to/the/image.nii.gz')
126126
```
127+
128+
* `get_image_timepoint` : extracts the 3D volume in a given time point range from a 4D Nifti image
129+
130+
```python
131+
# Create a nifti 3D file containing time point 5 of the input image (returns a path to the generated 3D image)
132+
get_image_timepoints('/path/to/the/image.nii.gz', 5, 5):
133+
134+
# Create a nifti 3D file containing time points 5 to 10 of the input image (returns a path to the generated 3D image)
135+
get_image_timepoints('/path/to/the/image.nii.gz', 5, 10):
136+
```
137+
127138
## narps_open.core.interfaces
128139

129140
This module contains a set of interface creators inheriting form the `narps_open.core.interfaces.InterfaceCreator` abstract class.

narps_open/core/image.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,32 @@ def get_voxel_dimensions(image: str) -> list:
2323
float(voxel_dimensions[1]),
2424
float(voxel_dimensions[2])
2525
]
26+
27+
def get_image_timepoints(in_file: str, start_time_point: int, end_time_point: int) -> str:
28+
"""
29+
Extract the 3D volume at a given time point from a 4D Nifti image.
30+
Create a Nifti file containing the 3D volume.
31+
Return the filename of the created 3D output file.
32+
33+
Arguments:
34+
in_file: str, string that represent an absolute path to a Nifti 4D image.
35+
start_time_point: int, zero-based index of the first volume to extract from the 4D image.
36+
end_time_point: int, zero-based index of the last volume to extract from the 4D image.
37+
38+
Returns:
39+
str, path to the created file
40+
"""
41+
# These imports must stay inside the function, as required by Nipype
42+
from os import extsep
43+
from os.path import abspath, basename
44+
import nibabel as nib
45+
46+
# The output filename is based on the base filename of the input file.
47+
# Note that we use abspath to write the file in the base_directory of a nipype Node.
48+
out_file = abspath(
49+
basename(in_file).split(extsep)[0]+f'_timepoint-{start_time_point}-{end_time_point}.nii')
50+
51+
# Perform timepoints extraction
52+
nib.save(nib.load(in_file).slicer[..., start_time_point:end_time_point+1], out_file)
53+
54+
return out_file

narps_open/data/results/team_2T6S.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77

88
from shutil import copyfile
99

10-
from nibabel import load
11-
from nilearn.image import math_img
10+
from nibabel import load, save, Nifti1Image
1211

1312
from narps_open.data.results import ResultsCollection
1413

@@ -44,5 +43,4 @@ def rectify(self):
4443

4544
# Change the signs of values inside the input image
4645
input_image = load(input_file)
47-
output_image = math_img('img*-1', img = input_image)
48-
output_image.to_filename(rectified_file)
46+
save(Nifti1Image(input_image.get_fdata()*-1, input_image.affine), rectified_file)

narps_open/pipelines/team_0H5E.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,14 @@
1717
EstimateModel, EstimateContrast, Threshold
1818
)
1919
from nipype.interfaces.spm.base import Info as SPMInfo
20-
from nipype.interfaces.fsl import (
21-
ExtractROI
22-
)
2320

2421
from narps_open.pipelines import Pipeline
2522
from narps_open.data.task import TaskInformation
2623
from narps_open.data.participants import get_group
2724
from narps_open.core.common import (
2825
remove_parent_directory, list_intersection, elements_in_string, clean_list
2926
)
27+
from narps_open.core.image import get_image_timepoints
3028
from narps_open.utils.configuration import Configuration
3129

3230
class PipelineTeam0H5E(Pipeline):
@@ -93,10 +91,13 @@ def get_preprocessing(self):
9391

9492
# EXTRACTROI - remove first image of func
9593
# > Removal of "dummy" scans (deleting the first four volumes from each run)
96-
remove_first_image = Node(ExtractROI(), name = 'remove_first_image')
97-
remove_first_image.inputs.t_min = 4
98-
remove_first_image.inputs.t_size = 449 # number of time points - 4
99-
remove_first_image.inputs.output_type='NIFTI'
94+
remove_first_image = Node(Function(
95+
function = get_image_timepoints,
96+
input_names = ['in_file', 'start_time_point', 'end_time_point'],
97+
output_names = ['roi_file']
98+
), name = 'remove_first_image')
99+
remove_first_image.inputs.start_time_point = 4
100+
remove_first_image.inputs.end_time_point = 453 # last image
100101
preprocessing.connect(gunzip_func, 'out_file', remove_first_image, 'in_file')
101102

102103
# REALIGN - motion correction

narps_open/pipelines/team_98BT.py

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
DARTELNorm2MNI, FieldMap, Threshold
1717
)
1818
from nipype.interfaces.spm.base import Info as SPMInfo
19-
from nipype.interfaces.fsl import ExtractROI
2019
from nipype.algorithms.modelgen import SpecifySPMModel
2120
from niflow.nipype1.workflows.fmri.spm import create_DARTEL_template
2221

@@ -26,6 +25,7 @@
2625
from narps_open.core.common import (
2726
remove_parent_directory, list_intersection, elements_in_string, clean_list
2827
)
28+
from narps_open.core.image import get_image_timepoints
2929
from narps_open.utils.configuration import Configuration
3030

3131
class PipelineTeam98BT(Pipeline):
@@ -264,10 +264,13 @@ def get_preprocessing_sub_workflow(self):
264264
preprocessing.connect(slice_timing, 'timecorrected_files', motion_correction, 'in_files')
265265

266266
# Intrasubject coregistration
267-
extract_first = Node(ExtractROI(), name = 'extract_first')
268-
extract_first.inputs.t_min = 1
269-
extract_first.inputs.t_size = 1
270-
extract_first.inputs.output_type = 'NIFTI'
267+
extract_first = Node(Function(
268+
function = get_image_timepoints,
269+
input_names = ['in_file', 'start_time_point', 'end_time_point'],
270+
output_names = ['roi_file']
271+
), name = 'extract_first')
272+
extract_first.inputs.start_time_point = 1
273+
extract_first.inputs.end_time_point = 1
271274
preprocessing.connect(
272275
motion_correction, 'realigned_unwarped_files', extract_first, 'in_file')
273276

@@ -421,9 +424,9 @@ def get_parameters_file(
421424
from os import makedirs
422425
from os.path import join
423426
from nibabel import load
427+
from nibabel.processing import resample_from_to
424428
from numpy import mean
425-
from pandas import read_table
426-
from nilearn.image import iter_img, resample_to_img
429+
from pandas import read_csv
427430

428431
# Ignore all future warnings
429432
from warnings import simplefilter
@@ -432,22 +435,23 @@ def get_parameters_file(
432435
simplefilter(action = 'ignore', category = RuntimeWarning)
433436

434437
# Load wc2 file and create a mask out of it
435-
wc2 = load(wc2_file)
436-
wc2_mask = wc2.get_fdata() > 0.6
437-
wc2_mask = wc2_mask.astype(int)
438+
wm_class_image = load(wc2_file)
439+
wm_mask_data = wm_class_image.get_fdata() > 0.6
440+
wm_mask_data = wm_mask_data.astype(int)
438441

439442
# Compute the mean signal in white matter, for each slice of the functional data
440443
mean_wm = []
441-
for current_slice in iter_img(load(func_file)):
442-
slice_data = resample_to_img(
443-
current_slice, wc2, interpolation = 'nearest', clip = True).get_fdata()
444+
func_image = load(func_file)
445+
for index in range(func_image.header.get_data_shape()[3]):
446+
resampled_func = resample_from_to(
447+
func_image.slicer[..., index], wm_class_image, order = 0, mode = 'nearest')
448+
444449
# Append mean value of masked data
445-
mean_wm.append(mean(slice_data * wc2_mask))
450+
mean_wm.append(mean(resampled_func.get_fdata() * wm_mask_data))
446451

447452
# Create new parameters file
448-
data_frame = read_table(parameters_file, sep = ' ', header = None)
453+
data_frame = read_csv(parameters_file, sep = '\t', dtype = str)
449454
data_frame['Mean_WM'] = mean_wm
450-
451455
new_parameters_file = join(working_dir, 'parameters_files',
452456
f'parameters_file_sub-{subject_id}_run-{run_id}.tsv')
453457

narps_open/pipelines/team_UK24.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,23 +68,21 @@ def get_average_values(
6868
"""
6969
from os import makedirs
7070
from os.path import join, abspath
71-
72-
from nilearn.image import load_img, math_img, index_img, get_data
71+
from nibabel import load
72+
from numpy import mean
7373

7474
# Load input images
75-
mask_img = load_img(mask)
76-
in_file_img = load_img(in_file)
75+
mask_image = load(mask)
76+
in_file_image = load(in_file)
77+
78+
# Create mask
79+
mask_data = mask_image.get_fdata() > 0.0
80+
mask_data = mask_data.astype(int)
7781

7882
# Loop through time points
7983
average_values = []
80-
for frame_index in range(in_file_img.shape[3]):
81-
average_values.append(
82-
get_data(math_img(
83-
'np.mean(image * (mask > 0.0))',
84-
image = index_img(in_file_img, frame_index),
85-
mask = mask_img
86-
))
87-
)
84+
for index in range(in_file_image.shape[3]):
85+
average_values.append(mean(in_file_image.slicer[..., index].get_fdata() * mask_data))
8886

8987
# Write confounds to a file
9088
out_file_name = abspath(f'sub-{subject_id}_run-{run_id}_' + out_file_suffix)

narps_open/pipelines/team_V55J.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
Coregister, Smooth, OneSampleTTestDesign, EstimateModel, EstimateContrast,
1515
Level1Design, TwoSampleTTestDesign, RealignUnwarp,
1616
Normalize12, NewSegment, FieldMap, Threshold)
17-
from nipype.interfaces.fsl import ExtractROI
1817
from nipype.algorithms.modelgen import SpecifySPMModel
1918
from nipype.interfaces.spm.base import Info as SPMInfo
2019

@@ -24,6 +23,7 @@
2423
from narps_open.core.common import (
2524
remove_parent_directory, list_intersection, elements_in_string, clean_list
2625
)
26+
from narps_open.core.image import get_image_timepoints
2727
from narps_open.utils.configuration import Configuration
2828

2929
class PipelineTeamV55J(Pipeline):
@@ -100,10 +100,13 @@ def get_preprocessing(self):
100100

101101
# EXTRACTROI - get the image 10 in func file
102102
# "For each run, we selected image 10 to distortion correct and asked to match the VDM file"
103-
extract_tenth_image = Node(ExtractROI(), name = 'extract_tenth_image')
104-
extract_tenth_image.inputs.t_min = 10
105-
extract_tenth_image.inputs.t_size = 1
106-
extract_tenth_image.inputs.output_type='NIFTI'
103+
extract_tenth_image = Node(Function(
104+
function = get_image_timepoints,
105+
input_names = ['in_file', 'start_time_point', 'end_time_point'],
106+
output_names = ['roi_file']
107+
), name = 'extract_tenth_image')
108+
extract_tenth_image.inputs.start_time_point = 9 # 0-based 10th image
109+
extract_tenth_image.inputs.end_time_point = 9
107110
preprocessing.connect(gunzip_func, 'out_file', extract_tenth_image, 'in_file')
108111

109112
# FIELDMAP - Calculate VDM routine of the FieldMap tool in SPM12

setup.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
'importlib_resources>=5.10.2,<5.11',
1818
'tomli>=2.0.1,<2.1',
1919
'networkx>=2.0,<3.0', # a workaround to nipype's bug (issue 3530)
20-
'nilearn>=0.10.0,<0.11',
2120
'nipype>=1.8.6,<1.9',
2221
'pandas>=1.5.2,<1.6',
2322
'niflow-nipype1-workflows>=0.0.5,<0.1.0'

0 commit comments

Comments
 (0)