Skip to content

Commit

Permalink
[FIX] fix octave create roi (#130)
Browse files Browse the repository at this point in the history
* test with octave

* change name

* fix

* tweak

* fix several tests

* reset submod

* refactor set up

* update tests

* fix for matlab

* reuse set up
  • Loading branch information
Remi-Gau authored Jul 13, 2024
1 parent 4b4f7f2 commit ba2ba6d
Show file tree
Hide file tree
Showing 16 changed files with 186 additions and 147 deletions.
78 changes: 78 additions & 0 deletions .github/workflows/run_tests_octave.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
name: tests and coverage with octave

env:
OCTFLAGS: --no-gui --no-window-system --silent

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

on:
push:
branches:
- main
pull_request:
branches: ['*']
schedule:
- cron: 0 0 1 * *

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

jobs:
tests_octave:
runs-on: ubuntu-latest

steps:
- name: Install CPP_ROI
uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0

- name: Install SPM
run: |
git clone https://github.com/spm/spm12.git --depth 1
- name: Install Moxunit and MOcov
run: |
git clone https://github.com/MOxUnit/MOxUnit.git --depth 1
git clone https://github.com/MOcov/MOcov.git --depth 1
- name: Install octave
run: |
sudo apt-get -y -qq update
sudo apt-get -y install \
octave \
liboctave-dev\
octave-common \
octave-io \
octave-image \
octave-signal \
octave-statistics
make -C MOxUnit install
make -C MOcov install
- name: Compile SPM
run: |
make -C spm12/src PLATFORM=octave distclean
make -C spm12/src PLATFORM=octave
make -C spm12/src PLATFORM=octave install
octave $OCTFLAGS --eval "addpath(fullfile(pwd, 'spm12')); savepath();"
- name: Add bids-matlab
run: make install_dev

- name: Run tests
run: |
octave $OCTFLAGS --eval "addpath(fullfile(pwd, 'tests', 'utils')); savepath();"
octave $OCTFLAGS --eval "cd(fullfile(getenv('GITHUB_WORKSPACE'), '.github', 'workflows')); run tests_octave;"
- name: Code coverage
uses: codecov/codecov-action@v4
with:
file: coverage.xml
flags: octave
name: codecov-umbrella
fail_ci_if_error: false
22 changes: 22 additions & 0 deletions .github/workflows/tests_octave.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
function tests_octave()

%
% (C) Copyright 2024 CPP ROI developers

root_dir = getenv('GITHUB_WORKSPACE');

addpath(fullfile(root_dir, 'spm12'));
addpath(fullfile(root_dir, 'lib', 'bids-matlab'));
addpath(fullfile(root_dir, 'MOcov', 'MOcov'));

cd(fullfile(root_dir, 'MOxUnit', 'MOxUnit'));

moxunit_set_path();

cd(fullfile(root_dir));

initCppRoi();

run_tests();

end
5 changes: 0 additions & 5 deletions src/atlas/copyAtlasToSpmDir.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,6 @@ function copyAtlasToSpmDir(varargin)

% (C) Copyright 2022 CPP ROI developers

if bids.internal.is_octave
% the atlas in the spm dir are only useful in matlab with the GUI
return
end

args = inputParser;

addOptional(args, 'atlas', 'AAL', @ischar);
Expand Down
13 changes: 11 additions & 2 deletions src/atlas/extractRoiFromAtlas.m
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@
args = inputParser;

addRequired(args, 'outputDir', isChar);
addRequired(args, 'atlasName', @(x) isAKnownAtlas(x));
addRequired(args, 'atlasName');
addRequired(args, 'roiName', isChar);
addRequired(args, 'hemisphere', @(x) ismember(x, {'L', 'R'}));
addRequired(args, 'hemisphere');

parse(args, varargin{:});

Expand All @@ -50,6 +50,15 @@
roiName = args.Results.roiName;
hemisphere = args.Results.hemisphere;

if ~ismember(hemisphere, {'L', 'R'})
msg = sprintf('"hemisphere must be "L" or "R"": %s\nGot: "%s"', ...
hemisphere);
bids.internal.error_handling(mfilename(), ...
'invalidHemisphere', msg, false);
end

isAKnownAtlas(atlasName);

[atlasFile, lut] = getAtlasAndLut(atlasName);

switch lower(atlasName)
Expand Down
12 changes: 9 additions & 3 deletions src/atlas/unzipAtlas.m
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,13 @@ function gunzipAtlasIfNecessary(file)
end

function gunzipWithOctave(file)
copyfile(file, [file '.bak']);
gunzip(file);
copyfile([file '.bak'], file);
if iscellstr(file)
for i = 1:numel(file)
gunzipWithOctave(file{i});
end
else
copyfile(file, [file '.bak']);
gunzip(file);
copyfile([file '.bak'], file);
end
end
6 changes: 5 additions & 1 deletion src/roi/thresholdToMask.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

% add peakThreshold and clusterSizeInfo to desc
if ~isfield(bf.entities, 'desc')
bf.entities.desc = '';
bf.entities(1).desc = '';
end
descSuffix = sprintf('p%05.2f', peakThreshold);
if clusterSize > 0
Expand All @@ -57,6 +57,10 @@
descSuffix = strrep(descSuffix, '.', 'pt');
bf.entities.desc = [bf.entities.desc descSuffix];

if isempty(bf.extension)
bf.extension = '.nii';
end

bf = bf.update();

hdr = spm_vol(inputImage);
Expand Down
37 changes: 10 additions & 27 deletions tests/test_createRoi.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

function test_createRoi_sphere()

volumeDefiningImage = fullfile(demoDir(), 'TStatistic.nii');
inputDir = setUpDemoData();
volumeDefiningImage = fullfile(inputDir, 'inputs', 'TStatistic.nii');

sphere.location = [44 -67 0];
sphere.radius = 5;
Expand Down Expand Up @@ -91,38 +92,20 @@ function test_createRoi_intersection_mask_sphere()
value = fileparts(mfilename('fullpath'));
end

function value = demoDir()

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

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

end

function [roiFilename, volumeDefiningImage] = prepareRoiAndVolumeDefiningImage()

volumeDefiningImage = fullfile(demoDir(), 'TStatistic.nii');

roiFilename = fullfile(demoDir(), ...
'space-MNI_atlas-neurosynth_label-visualMotion_desc-p10pt00_mask.nii');

if exist(roiFilename, 'file') == 2
inputDir = setUpDemoData();

else
volumeDefiningImage = fullfile(inputDir, 'inputs', 'TStatistic.nii');

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

zMap = renameNeuroSynth(zMap);
zMap = resliceRoiImages(volumeDefiningImage, zMap);
zMap = renameNeuroSynth(zMap);
zMap = resliceRoiImages(volumeDefiningImage, zMap);

zMap = removePrefix(zMap, 'r');
zMap = removePrefix(zMap, 'r');

threshold = 10;
roiFilename = thresholdToMask(zMap, threshold);

end
threshold = 10;
roiFilename = thresholdToMask(zMap, threshold);

end
21 changes: 3 additions & 18 deletions tests/test_getPeakCoordinates.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@

function test_getPeakCoordinates_basic()

roiImage = extractRoiFromAtlas(pwd, 'wang', 'V1v', 'L');
inputDir = setUpDemoData();
dataImage = fullfile(inputDir, 'inputs', 'TStatistic.nii');

dataImage = fullfile(demoDir(), 'TStatistic.nii');
roiImage = extractRoiFromAtlas(pwd, 'wang', 'V1v', 'L');

reslicedImages = resliceRoiImages(dataImage, roiImage);

Expand All @@ -22,20 +23,4 @@ function test_getPeakCoordinates_basic()
assertEqual(voxelCoord, [28 8 24]);
assertElementsAlmostEqual(maxVal, 1.6212, 'absolute', 1e-3);

delete('*hemi-L_space-MNI_atlas-wang_label-V1v_mask.*');

end

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

function value = demoDir()

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

if exist(fullfile(value, 'TStatistic.nii'), 'file') == 0
gunzip(fullfile(value, '*.gz'));
end

end
42 changes: 6 additions & 36 deletions tests/test_isBinaryMask.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,50 +9,20 @@

function test_isBinaryMask_true()

roiFilename = prepareRoiAndVolumeDefiningImage();
[roiFilename, zMap] = prepareRoiAndVolumeDefiningImage();
isBinaryMask(roiFilename);

end

function test_isBinaryMask_false()

[~, zMap] = prepareRoiAndVolumeDefiningImage();
assertExceptionThrown(@()isBinaryMask(zMap), 'isBinaryMask:notBinaryImage');

end

function value = thisDir()
value = 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

function [roiFilename, zMap] = prepareRoiAndVolumeDefiningImage()

zMap = fullfile(demoDir(), 'space-MNI_atlas-neurosynth_label-visualMotion_probseg.nii');

roiFilename = fullfile(demoDir(), ...
'space-MNI_atlas-neurosynth_label-visualMotion_desc-p10pt00_mask.nii');

if exist(roiFilename, 'file') == 2
inputDir = setUpDemoData();

else
zMap = fullfile(inputDir, 'inputs', 'visual motion_association-test_z_FDR_0.01.nii');

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

zMap = renameNeuroSynth(zMap);

threshold = 10;
roiFilename = thresholdToMask(zMap, threshold);

end
zMap = renameNeuroSynth(zMap);
threshold = 10;
roiFilename = thresholdToMask(zMap, threshold);

end
8 changes: 1 addition & 7 deletions tests/test_keepHemisphere.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@

function test_keepHemisphere_basic()

inputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'demos', 'roi');

gunzip(fullfile(inputDir, 'inputs', '*.gz'));
inputDir = setUpDemoData();
zMap = fullfile(inputDir, 'inputs', 'visual motion_association-test_z_FDR_0.01.nii');

zMap = renameNeuroSynth(zMap);
Expand All @@ -32,8 +30,4 @@ function test_keepHemisphere_basic()
'file'), ...
2);

% TODO check the data content

delete(fullfile(inputDir, 'inputs', '*.nii'));

end
21 changes: 4 additions & 17 deletions tests/test_labelClusters.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

function test_labelClusters_basic

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

zMap = renameNeuroSynth(zMap);

Expand All @@ -19,28 +20,14 @@
labeledClusters = labelClusters(zMap, peakThreshold, extendThreshold);

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

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

roiName = extractRoiByLabel(labeledClusters, labelStruct);

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

end

function value = thisDir()
value = 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
assertEqual(exist(fullfile(inputDir, 'inputs', expected), 'file'), 2);

end
Loading

0 comments on commit ba2ba6d

Please sign in to comment.