Skip to content

[REF] add tests bids name and refactor #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions src/atlas/extractRoiByLabel.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,11 @@
outputVol = false(size(vol));
outputVol(vol == labelStruct.label) = true;

p = bids.internal.parse_filename(sourceImage);
p.entities.label = bids.internal.camel_case(labelStruct.ROI);
p.suffix = 'mask';
bf = bids.File(sourceImage);
bf.entities.label = bids.internal.camel_case(labelStruct.ROI);
bf.suffix = 'mask';

bidsFile = bids.File(p);

hdr.fname = spm_file(hdr.fname, 'filename', bidsFile.filename);
hdr.fname = spm_file(hdr.fname, 'filename', bf.filename);

spm_write_vol(hdr, outputVol);
outputImage = hdr.fname;
Expand Down
23 changes: 11 additions & 12 deletions src/atlas/labelClusters.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@
isFile = @(x) exist(x, 'file') == 2;
isPositive = @(x) isnumeric(x) && x >= 0;

p = inputParser;
args = inputParser;

addRequired(p, 'inputImage', isFile);
addRequired(p, 'peakThreshold', @isnumeric);
addOptional(p, 'clusterSize', default_clusterSize, isPositive);
addRequired(args, 'inputImage', isFile);
addRequired(args, 'peakThreshold', @isnumeric);
addOptional(args, 'clusterSize', default_clusterSize, isPositive);

parse(p, varargin{:});
parse(args, varargin{:});

inputImage = p.Results.inputImage;
peakThreshold = p.Results.peakThreshold;
clusterSize = p.Results.clusterSize;
inputImage = args.Results.inputImage;
peakThreshold = args.Results.peakThreshold;
clusterSize = args.Results.clusterSize;

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

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

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

hdr = spm_vol(inputImage);
bidsFile = bids.File(p);
hdr.fname = spm_file(hdr.fname, 'filename', bidsFile.filename);
hdr.fname = spm_file(hdr.fname, 'filename', bf.filename);

% Cluster labels as their size.
spm_write_vol(hdr, vol);
Expand Down
37 changes: 29 additions & 8 deletions src/roi/createRoiName.m
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
function roiName = createRoiName(mask, volumeDefiningImage)
function roiName = createRoiName(varargin)
%
% creates BIDS like filename for ROIs
%
% USAGE::
%
% roiName = createRoiName(mask, volumeDefiningImage)
%
% (C) Copyright 2022 CPP ROI developers

if strcmp(mask.def, 'sphere')
args = inputParser;

args.addRequired('mask', @isstruct);
args.addOptional('volumeDefiningImage', '', @ischar);

args.parse(varargin{:});

type = args.Results.mask.def;
label = args.Results.mask.label;
mask = args.Results.mask;
volumeDefiningImage = args.Results.volumeDefiningImage;

if strcmp(type, 'sphere')

bf = bids.File('');
bf.extension = '.nii';
Expand All @@ -20,28 +37,32 @@

end

label = '';
tmp = '';
if isfield(bf.entities, 'label')
label = bf.entities.label;
tmp = bf.entities.label;
end

entities.label = bids.internal.camel_case([label ' ' mask.label]);
entities.label = bids.internal.camel_case([tmp ' ' label]);

bf.entities = entities;

else

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

label = '';
bf.suffix = 'mask';

tmp = '';
if isfield(bf.entities, 'label')
label = bf.entities.label;
tmp = bf.entities.label;
end

bf.entities.label = bids.internal.camel_case([label ' ' mask.label]);
bf.entities.label = bids.internal.camel_case([tmp ' ' label]);

end

bf = bf.reorder_entities();
bf = bf.update;
roiName = bf.filename;

end
32 changes: 16 additions & 16 deletions src/roi/thresholdToMask.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,40 +26,40 @@
isFile = @(x) exist(x, 'file') == 2;
isPositive = @(x) isnumeric(x) && x >= 0;

p = inputParser;
args = inputParser;

addRequired(p, 'inputImage', isFile);
addRequired(p, 'peakThreshold', @isnumeric);
addOptional(p, 'clusterSize', default_clusterSize, isPositive);
addRequired(args, 'inputImage', isFile);
addRequired(args, 'peakThreshold', @isnumeric);
addOptional(args, 'clusterSize', default_clusterSize, isPositive);

parse(p, varargin{:});

inputImage = p.Results.inputImage;
peakThreshold = p.Results.peakThreshold;
clusterSize = p.Results.clusterSize;
parse(args, varargin{:});

inputImage = args.Results.inputImage;
peakThreshold = args.Results.peakThreshold;
clusterSize = args.Results.clusterSize;
[l2, num] = getClusters(inputImage, peakThreshold);
vol = sortAndThresholdClusters(l2, num, clusterSize);

% create output name
p = bids.internal.parse_filename(inputImage);
bf = bids.File(inputImage);

p.suffix = 'mask';
bf.suffix = 'mask';

% add peakThreshold and clusterSizeInfo to desc
if ~isfield(p.entities, 'desc')
p.entities.desc = '';
if ~isfield(bf.entities, 'desc')
bf.entities.desc = '';
end
descSuffix = sprintf('p%05.2f', peakThreshold);
if clusterSize > 0
descSuffix = [descSuffix, sprintf('k%03.0f', clusterSize)];
end
descSuffix = strrep(descSuffix, '.', 'pt');
p.entities.desc = [p.entities.desc descSuffix];
bf.entities.desc = [bf.entities.desc descSuffix];

bf = bf.update();

bidsFile = bids.File(p);
hdr = spm_vol(inputImage);
hdr.fname = spm_file(hdr.fname, 'filename', bidsFile.filename);
hdr.fname = spm_file(hdr.fname, 'filename', bf.filename);
outputImage = hdr.fname;

spm_write_vol(hdr, vol);
Expand Down
97 changes: 97 additions & 0 deletions tests/test_createRoiName.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
function test_suite = test_createRoiName %#ok<*STOUT>
% (C) Copyright 2022 CPP ROI developers
try % assignment of 'localfunctions' is necessary in Matlab >= 2016
test_functions = localfunctions(); %#ok<*NASGU>
catch % no problem; early Matlab versions can use initTestSuite fine
end
initTestSuite;
end

function test_createRoiName_non_sphere()

mask.def = 'expand';
mask.global.hdr.fname = 'suffixOnly.nii';

%%
mask.label = '';
roiName = createRoiName(mask);
assertEqual(roiName, 'mask.nii');

mask.label = 'foo';
roiName = createRoiName(mask);
assertEqual(roiName, 'label-foo_mask.nii');

%%
mask.global.hdr.fname = 'one-entity.nii';

mask.label = '';
roiName = createRoiName(mask);
assertEqual(roiName, 'one-entity_mask.nii');

% This will likely break when bids-matlab is updated and the order of entities
% is imposed by the schema
%
% label-foo_one-entity_mask.nii
%
mask.label = 'foo';
roiName = createRoiName(mask);
assertEqual(roiName, 'one-entity_label-foo_mask.nii');

end

function test_createRoiName_sphere()

mask.def = 'sphere';

%%
mask.label = '';
roiName = createRoiName(mask);
assertEqual(roiName, 'mask.nii');

mask.label = 'foo';
roiName = createRoiName(mask);
assertEqual(roiName, 'label-foo_mask.nii');

%%
volumeDefiningImage = fullfile(pwd, 'TStatistic.nii');

mask.label = '';
roiName = createRoiName(mask, volumeDefiningImage);
assertEqual(roiName, 'mask.nii');

mask.label = 'foo';
roiName = createRoiName(mask, volumeDefiningImage);
assertEqual(roiName, 'label-foo_mask.nii');

%%
volumeDefiningImage = fullfile(pwd, 'space-MNI_TStatistic.nii');

mask.label = '';
roiName = createRoiName(mask, volumeDefiningImage);
assertEqual(roiName, 'space-MNI_mask.nii');

mask.label = 'foo';
roiName = createRoiName(mask, volumeDefiningImage);
assertEqual(roiName, 'space-MNI_label-foo_mask.nii');

end

function test_createRoiName_sphere_spm()

% spm (ish) output

% https://github.com/cpp-lln-lab/CPP_ROI/issues/6
volumeDefiningImage = fullfile(pwd, 'task-auditory_p-0001_k-0_MC-none_label-001_spmT.nii');
mask.def = 'sphere';
mask.label = 'sphere5x44yMinus67z0';
roiName = createRoiName(mask, volumeDefiningImage);
assertEqual(roiName, 'label-sphere5x44yMinus67z0_mask.nii');

% https://github.com/cpp-lln-lab/CPP_ROI/issues/16
volumeDefiningImage = fullfile(pwd, 'con_0001.niii');
mask.def = 'sphere';
mask.label = 'sphere5x44yMinus67z0';
roiName = createRoiName(mask, volumeDefiningImage);
assertEqual(roiName, 'label-sphere5x44yMinus67z0_mask.nii');

end
46 changes: 46 additions & 0 deletions tests/test_labelClusters.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
function test_suite = test_labelClusters %#ok<*STOUT>
% (C) Copyright 2022 CPP ROI developers
try % assignment of 'localfunctions' is necessary in Matlab >= 2016
test_functions = localfunctions(); %#ok<*NASGU>
catch % no problem; early Matlab versions can use initTestSuite fine
end
initTestSuite;
end

function test_labelClusters_basic

zMap = fullfile(demoDir(), 'visual motion_association-test_z_FDR_0.01.nii');

zMap = renameNeuroSynth(zMap);

peakThreshold = 5;
extendThreshold = 50;

labeledClusters = labelClusters(zMap, peakThreshold, extendThreshold);

expected = 'space-MNI_atlas-neurosynth_label-visualMotion_dseg.nii';
assertEqual(exist(fullfile(demoDir(), expected), 'file'), 2);

labelStruct = struct('ROI', 'ns left MT', ...
'label', 1);

roiName = extractRoiByLabel(labeledClusters, labelStruct);

expected = 'space-MNI_atlas-neurosynth_label-nsLeftMT_mask.nii';
assertEqual(exist(fullfile(demoDir(), expected), 'file'), 2);

end

function value = thisDir()
value = fullfile(fileparts(mfilename('fullpath')));
end

function value = demoDir()

value = fullfile(thisDir(), '..', 'demos', 'roi', 'inputs');

if exist(fullfile(value, 'visual motion_association-test_z_FDR_0.01.nii'), 'file') == 0
gunzip(fullfile(value, '*.gz'));
end

end