Skip to content

Commit d9910b3

Browse files
authored
Merge pull request #37 from cpp-lln-lab/bids_name
[REF] add tests bids name and refactor
2 parents 15e21bf + 2c2c56a commit d9910b3

File tree

6 files changed

+203
-42
lines changed

6 files changed

+203
-42
lines changed

src/atlas/extractRoiByLabel.m

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,11 @@
2222
outputVol = false(size(vol));
2323
outputVol(vol == labelStruct.label) = true;
2424

25-
p = bids.internal.parse_filename(sourceImage);
26-
p.entities.label = bids.internal.camel_case(labelStruct.ROI);
27-
p.suffix = 'mask';
25+
bf = bids.File(sourceImage);
26+
bf.entities.label = bids.internal.camel_case(labelStruct.ROI);
27+
bf.suffix = 'mask';
2828

29-
bidsFile = bids.File(p);
30-
31-
hdr.fname = spm_file(hdr.fname, 'filename', bidsFile.filename);
29+
hdr.fname = spm_file(hdr.fname, 'filename', bf.filename);
3230

3331
spm_write_vol(hdr, outputVol);
3432
outputImage = hdr.fname;

src/atlas/labelClusters.m

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@
2828
isFile = @(x) exist(x, 'file') == 2;
2929
isPositive = @(x) isnumeric(x) && x >= 0;
3030

31-
p = inputParser;
31+
args = inputParser;
3232

33-
addRequired(p, 'inputImage', isFile);
34-
addRequired(p, 'peakThreshold', @isnumeric);
35-
addOptional(p, 'clusterSize', default_clusterSize, isPositive);
33+
addRequired(args, 'inputImage', isFile);
34+
addRequired(args, 'peakThreshold', @isnumeric);
35+
addOptional(args, 'clusterSize', default_clusterSize, isPositive);
3636

37-
parse(p, varargin{:});
37+
parse(args, varargin{:});
3838

39-
inputImage = p.Results.inputImage;
40-
peakThreshold = p.Results.peakThreshold;
41-
clusterSize = p.Results.clusterSize;
39+
inputImage = args.Results.inputImage;
40+
peakThreshold = args.Results.peakThreshold;
41+
clusterSize = args.Results.clusterSize;
4242

4343
[l2, num] = getClusters(inputImage, peakThreshold);
4444

@@ -50,12 +50,11 @@
5050
vol = sortAndLabelClusters(l2, num, clusterSize);
5151

5252
% Write new image with cluster laebelled with their voxel size
53-
p = bids.internal.parse_filename(inputImage);
54-
p.suffix = 'dseg'; % discrete segmentation
53+
bf = bids.File(inputImage);
54+
bf.suffix = 'dseg'; % discrete segmentation
5555

5656
hdr = spm_vol(inputImage);
57-
bidsFile = bids.File(p);
58-
hdr.fname = spm_file(hdr.fname, 'filename', bidsFile.filename);
57+
hdr.fname = spm_file(hdr.fname, 'filename', bf.filename);
5958

6059
% Cluster labels as their size.
6160
spm_write_vol(hdr, vol);

src/roi/createRoiName.m

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,26 @@
1-
function roiName = createRoiName(mask, volumeDefiningImage)
1+
function roiName = createRoiName(varargin)
22
%
3+
% creates BIDS like filename for ROIs
4+
%
5+
% USAGE::
6+
%
7+
% roiName = createRoiName(mask, volumeDefiningImage)
38
%
49
% (C) Copyright 2022 CPP ROI developers
510

6-
if strcmp(mask.def, 'sphere')
11+
args = inputParser;
12+
13+
args.addRequired('mask', @isstruct);
14+
args.addOptional('volumeDefiningImage', '', @ischar);
15+
16+
args.parse(varargin{:});
17+
18+
type = args.Results.mask.def;
19+
label = args.Results.mask.label;
20+
mask = args.Results.mask;
21+
volumeDefiningImage = args.Results.volumeDefiningImage;
22+
23+
if strcmp(type, 'sphere')
724

825
bf = bids.File('');
926
bf.extension = '.nii';
@@ -20,28 +37,32 @@
2037

2138
end
2239

23-
label = '';
40+
tmp = '';
2441
if isfield(bf.entities, 'label')
25-
label = bf.entities.label;
42+
tmp = bf.entities.label;
2643
end
2744

28-
entities.label = bids.internal.camel_case([label ' ' mask.label]);
45+
entities.label = bids.internal.camel_case([tmp ' ' label]);
2946

3047
bf.entities = entities;
3148

3249
else
3350

3451
bf = bids.File(mask.global.hdr.fname);
3552

36-
label = '';
53+
bf.suffix = 'mask';
54+
55+
tmp = '';
3756
if isfield(bf.entities, 'label')
38-
label = bf.entities.label;
57+
tmp = bf.entities.label;
3958
end
4059

41-
bf.entities.label = bids.internal.camel_case([label ' ' mask.label]);
60+
bf.entities.label = bids.internal.camel_case([tmp ' ' label]);
4261

4362
end
4463

64+
bf = bf.reorder_entities();
65+
bf = bf.update;
4566
roiName = bf.filename;
4667

4768
end

src/roi/thresholdToMask.m

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,40 +26,40 @@
2626
isFile = @(x) exist(x, 'file') == 2;
2727
isPositive = @(x) isnumeric(x) && x >= 0;
2828

29-
p = inputParser;
29+
args = inputParser;
3030

31-
addRequired(p, 'inputImage', isFile);
32-
addRequired(p, 'peakThreshold', @isnumeric);
33-
addOptional(p, 'clusterSize', default_clusterSize, isPositive);
31+
addRequired(args, 'inputImage', isFile);
32+
addRequired(args, 'peakThreshold', @isnumeric);
33+
addOptional(args, 'clusterSize', default_clusterSize, isPositive);
3434

35-
parse(p, varargin{:});
36-
37-
inputImage = p.Results.inputImage;
38-
peakThreshold = p.Results.peakThreshold;
39-
clusterSize = p.Results.clusterSize;
35+
parse(args, varargin{:});
4036

37+
inputImage = args.Results.inputImage;
38+
peakThreshold = args.Results.peakThreshold;
39+
clusterSize = args.Results.clusterSize;
4140
[l2, num] = getClusters(inputImage, peakThreshold);
4241
vol = sortAndThresholdClusters(l2, num, clusterSize);
4342

4443
% create output name
45-
p = bids.internal.parse_filename(inputImage);
44+
bf = bids.File(inputImage);
4645

47-
p.suffix = 'mask';
46+
bf.suffix = 'mask';
4847

4948
% add peakThreshold and clusterSizeInfo to desc
50-
if ~isfield(p.entities, 'desc')
51-
p.entities.desc = '';
49+
if ~isfield(bf.entities, 'desc')
50+
bf.entities.desc = '';
5251
end
5352
descSuffix = sprintf('p%05.2f', peakThreshold);
5453
if clusterSize > 0
5554
descSuffix = [descSuffix, sprintf('k%03.0f', clusterSize)];
5655
end
5756
descSuffix = strrep(descSuffix, '.', 'pt');
58-
p.entities.desc = [p.entities.desc descSuffix];
57+
bf.entities.desc = [bf.entities.desc descSuffix];
58+
59+
bf = bf.update();
5960

60-
bidsFile = bids.File(p);
6161
hdr = spm_vol(inputImage);
62-
hdr.fname = spm_file(hdr.fname, 'filename', bidsFile.filename);
62+
hdr.fname = spm_file(hdr.fname, 'filename', bf.filename);
6363
outputImage = hdr.fname;
6464

6565
spm_write_vol(hdr, vol);

tests/test_createRoiName.m

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
function test_suite = test_createRoiName %#ok<*STOUT>
2+
% (C) Copyright 2022 CPP ROI developers
3+
try % assignment of 'localfunctions' is necessary in Matlab >= 2016
4+
test_functions = localfunctions(); %#ok<*NASGU>
5+
catch % no problem; early Matlab versions can use initTestSuite fine
6+
end
7+
initTestSuite;
8+
end
9+
10+
function test_createRoiName_non_sphere()
11+
12+
mask.def = 'expand';
13+
mask.global.hdr.fname = 'suffixOnly.nii';
14+
15+
%%
16+
mask.label = '';
17+
roiName = createRoiName(mask);
18+
assertEqual(roiName, 'mask.nii');
19+
20+
mask.label = 'foo';
21+
roiName = createRoiName(mask);
22+
assertEqual(roiName, 'label-foo_mask.nii');
23+
24+
%%
25+
mask.global.hdr.fname = 'one-entity.nii';
26+
27+
mask.label = '';
28+
roiName = createRoiName(mask);
29+
assertEqual(roiName, 'one-entity_mask.nii');
30+
31+
% This will likely break when bids-matlab is updated and the order of entities
32+
% is imposed by the schema
33+
%
34+
% label-foo_one-entity_mask.nii
35+
%
36+
mask.label = 'foo';
37+
roiName = createRoiName(mask);
38+
assertEqual(roiName, 'one-entity_label-foo_mask.nii');
39+
40+
end
41+
42+
function test_createRoiName_sphere()
43+
44+
mask.def = 'sphere';
45+
46+
%%
47+
mask.label = '';
48+
roiName = createRoiName(mask);
49+
assertEqual(roiName, 'mask.nii');
50+
51+
mask.label = 'foo';
52+
roiName = createRoiName(mask);
53+
assertEqual(roiName, 'label-foo_mask.nii');
54+
55+
%%
56+
volumeDefiningImage = fullfile(pwd, 'TStatistic.nii');
57+
58+
mask.label = '';
59+
roiName = createRoiName(mask, volumeDefiningImage);
60+
assertEqual(roiName, 'mask.nii');
61+
62+
mask.label = 'foo';
63+
roiName = createRoiName(mask, volumeDefiningImage);
64+
assertEqual(roiName, 'label-foo_mask.nii');
65+
66+
%%
67+
volumeDefiningImage = fullfile(pwd, 'space-MNI_TStatistic.nii');
68+
69+
mask.label = '';
70+
roiName = createRoiName(mask, volumeDefiningImage);
71+
assertEqual(roiName, 'space-MNI_mask.nii');
72+
73+
mask.label = 'foo';
74+
roiName = createRoiName(mask, volumeDefiningImage);
75+
assertEqual(roiName, 'space-MNI_label-foo_mask.nii');
76+
77+
end
78+
79+
function test_createRoiName_sphere_spm()
80+
81+
% spm (ish) output
82+
83+
% https://github.com/cpp-lln-lab/CPP_ROI/issues/6
84+
volumeDefiningImage = fullfile(pwd, 'task-auditory_p-0001_k-0_MC-none_label-001_spmT.nii');
85+
mask.def = 'sphere';
86+
mask.label = 'sphere5x44yMinus67z0';
87+
roiName = createRoiName(mask, volumeDefiningImage);
88+
assertEqual(roiName, 'label-sphere5x44yMinus67z0_mask.nii');
89+
90+
% https://github.com/cpp-lln-lab/CPP_ROI/issues/16
91+
volumeDefiningImage = fullfile(pwd, 'con_0001.niii');
92+
mask.def = 'sphere';
93+
mask.label = 'sphere5x44yMinus67z0';
94+
roiName = createRoiName(mask, volumeDefiningImage);
95+
assertEqual(roiName, 'label-sphere5x44yMinus67z0_mask.nii');
96+
97+
end

tests/test_labelClusters.m

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
function test_suite = test_labelClusters %#ok<*STOUT>
2+
% (C) Copyright 2022 CPP ROI developers
3+
try % assignment of 'localfunctions' is necessary in Matlab >= 2016
4+
test_functions = localfunctions(); %#ok<*NASGU>
5+
catch % no problem; early Matlab versions can use initTestSuite fine
6+
end
7+
initTestSuite;
8+
end
9+
10+
function test_labelClusters_basic
11+
12+
zMap = fullfile(demoDir(), 'visual motion_association-test_z_FDR_0.01.nii');
13+
14+
zMap = renameNeuroSynth(zMap);
15+
16+
peakThreshold = 5;
17+
extendThreshold = 50;
18+
19+
labeledClusters = labelClusters(zMap, peakThreshold, extendThreshold);
20+
21+
expected = 'space-MNI_atlas-neurosynth_label-visualMotion_dseg.nii';
22+
assertEqual(exist(fullfile(demoDir(), expected), 'file'), 2);
23+
24+
labelStruct = struct('ROI', 'ns left MT', ...
25+
'label', 1);
26+
27+
roiName = extractRoiByLabel(labeledClusters, labelStruct);
28+
29+
expected = 'space-MNI_atlas-neurosynth_label-nsLeftMT_mask.nii';
30+
assertEqual(exist(fullfile(demoDir(), expected), 'file'), 2);
31+
32+
end
33+
34+
function value = thisDir()
35+
value = fullfile(fileparts(mfilename('fullpath')));
36+
end
37+
38+
function value = demoDir()
39+
40+
value = fullfile(thisDir(), '..', 'demos', 'roi', 'inputs');
41+
42+
if exist(fullfile(value, 'visual motion_association-test_z_FDR_0.01.nii'), 'file') == 0
43+
gunzip(fullfile(value, '*.gz'));
44+
end
45+
46+
end

0 commit comments

Comments
 (0)