Skip to content

Commit

Permalink
🔮
Browse files Browse the repository at this point in the history
  • Loading branch information
jennydaman committed Jan 5, 2024
1 parent c925220 commit d3384fd
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 90 deletions.
56 changes: 16 additions & 40 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,6 @@ on:
branches: [ main ]

jobs:
test:
name: Unit tests
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- name: Build
uses: docker/build-push-action@v5
with:
build-args: extras_require=dev
context: .
load: true
push: false
tags: "localhost/local/app:dev"
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Run pytest
run: |
docker run -v "$GITHUB_WORKSPACE:/app:ro" -w /app localhost/local/app:dev \
pytest -o cache_dir=/tmp/pytest
build:
name: Build
if: github.event_name == 'push' || github.event_name == 'release'
Expand Down Expand Up @@ -106,34 +85,31 @@ jobs:
# If you have a directory called examples/incoming/ and examples/outgoing/, then
# run your ChRIS plugin with no parameters, and assert that it creates all the files
# which are expected. File contents are not compared.
- name: Download example data
run: cd examples && ./download.sh incoming
- name: Run examples
id: run_examples
run: |
if ! [ -d 'examples/incoming/' ] || ! [ -d 'examples/outgoing/' ]; then
echo "No examples."
exit 0
fi
dock_image=${{ steps.info.outputs.local_tag }}
output_dir=$(mktemp -d)
cmd=$(docker image inspect -f '{{ (index .Config.Cmd 0) }}' $dock_image)
docker run --rm -u "$(id -u):$(id -g)" \
-v "$PWD/examples/incoming:/incoming:ro" \
-v "$output_dir:/outgoing:rw" \
$dock_image $cmd /incoming /outgoing
$dock_image $cmd --thresholds template.nii.gz:37.0 /incoming /outgoing
for expected_file in $(find examples/outgoing -type f); do
fname="${expected_file##*/}"
out_path="$output_dir/$fname"
printf "Checking output %s exists..." "$out_path"
if [ -f "$out_path" ]; then
echo "ok"
else
echo "not found"
exit 1
fi
done
set +e
diff -q examples/incoming/age34/template.nii.gz $output_dir/age34/template.nii.gz
if [ "$?" = "0" ]; then
echo "age34/template.nii.gz should have been changed, but it was not."
exit 1
fi
diff -q examples/incoming/age34/mask.nii.gz $output_dir/age34/mask.nii.gz
if [ "$?" = "1" ]; then
echo "age34/template.nii.gz should have been copied, but it was changed."
exit 1
fi
echo "tests passed"
- name: Login to DockerHub
if: (github.event_name == 'push' || github.event_name == 'release') && contains(steps.info.outputs.tags_csv, 'docker.io')
uses: docker/login-action@v3
Expand All @@ -155,7 +131,7 @@ jobs:
file: ./Dockerfile
tags: ${{ steps.info.outputs.tags_csv }}
# if non-x86_84 architectures are supported, add them here
platforms: linux/amd64 #,linux/arm64,linux/ppc64le
platforms: linux/amd64,linux/arm64,linux/ppc64le
push: ${{ steps.info.outputs.push }}
cache-to: type=gha,mode=max

Expand Down
13 changes: 7 additions & 6 deletions examples/download.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@

mkdir "$1"
cd "$1"
mkdir age24 age34

wget -O template24.nii.gz https://fetalmri-hosting-of-medical-image-analysis-platform-dcb83b.apps.shift.nerc.mghpcc.org/api/v1/files/307/template.nii.gz
wget -O ventricles24.nii.gz https://fetalmri-hosting-of-medical-image-analysis-platform-dcb83b.apps.shift.nerc.mghpcc.org/api/v1/files/331/ventricles.nii.gz
wget -O mask24.nii.gz https://fetalmri-hosting-of-medical-image-analysis-platform-dcb83b.apps.shift.nerc.mghpcc.org/api/v1/files/330/mask.nii.gz
wget -O age24/template.nii.gz https://fetalmri-hosting-of-medical-image-analysis-platform-dcb83b.apps.shift.nerc.mghpcc.org/api/v1/files/307/template.nii.gz
wget -O age24/ventricles.nii.gz https://fetalmri-hosting-of-medical-image-analysis-platform-dcb83b.apps.shift.nerc.mghpcc.org/api/v1/files/331/ventricles.nii.gz
wget -O age24/mask.nii.gz https://fetalmri-hosting-of-medical-image-analysis-platform-dcb83b.apps.shift.nerc.mghpcc.org/api/v1/files/330/mask.nii.gz

wget -O template34.nii.gz https://fetalmri-hosting-of-medical-image-analysis-platform-dcb83b.apps.shift.nerc.mghpcc.org/api/v1/files/351/template.nii.gz
wget -O ventricles34.nii.gz https://fetalmri-hosting-of-medical-image-analysis-platform-dcb83b.apps.shift.nerc.mghpcc.org/api/v1/files/350/ventricles.nii.gz
wget -O mask34.nii.gz https://fetalmri-hosting-of-medical-image-analysis-platform-dcb83b.apps.shift.nerc.mghpcc.org/api/v1/files/310/mask.nii.gz
wget -O age34/template.nii.gz https://fetalmri-hosting-of-medical-image-analysis-platform-dcb83b.apps.shift.nerc.mghpcc.org/api/v1/files/351/template.nii.gz
wget -O age34/ventricles.nii.gz https://fetalmri-hosting-of-medical-image-analysis-platform-dcb83b.apps.shift.nerc.mghpcc.org/api/v1/files/350/ventricles.nii.gz
wget -O age34/mask.nii.gz https://fetalmri-hosting-of-medical-image-analysis-platform-dcb83b.apps.shift.nerc.mghpcc.org/api/v1/files/310/mask.nii.gz
8 changes: 1 addition & 7 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,5 @@ def get_version(rel_path: str) -> str:
'Topic :: Scientific/Engineering',
'Topic :: Scientific/Engineering :: Bio-Informatics',
'Topic :: Scientific/Engineering :: Medical Science Apps.'
],
extras_require={
'none': [],
'dev': [
'pytest~=7.1'
]
}
]
)
21 changes: 0 additions & 21 deletions tests/test_example.py

This file was deleted.

54 changes: 38 additions & 16 deletions zb.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
#!/usr/bin/env python

import os
import shutil
import sys
from pathlib import Path
from argparse import ArgumentParser, Namespace, ArgumentDefaultsHelpFormatter
from tqdm.contrib.concurrent import process_map
from typing import Callable

import numpy as np
import nibabel as nib

from chris_plugin import chris_plugin, PathMapper
from tqdm.contrib.concurrent import process_map, thread_map

from chris_plugin import chris_plugin, PathMapper, helpers

__version__ = '1.0.0'

Expand All @@ -22,8 +29,8 @@

parser = ArgumentParser(description='Set the background intensity of MRI volumes to zero.',
formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('-t', '--threshold', required=False, type=str,
default='.nii.gz:37',
parser.add_argument('-t', '--thresholds', required=False, type=str,
default='.nii.gz:37.0',
help='A filename glob and background intensity threshold. Multiple pairs should be comma-separated,'
' i.e. GLOB1:THRESHOLD1,GLOB2:THRESHOLD2,...')
parser.add_argument('-J', '--threads', type=int, default=0,
Expand All @@ -36,22 +43,37 @@
@chris_plugin(
parser=parser,
title='Zero MRI Background',
category='', # ref. https://chrisstore.co/plugins
min_memory_limit='1Gi', # supported units: Mi, Gi
min_cpu_limit='1000m', # millicores, e.g. "1000m" = 1 CPU core
category='MRI', # ref. https://chrisstore.co/plugins
min_memory_limit='4Gi', # supported units: Mi, Gi
min_cpu_limit='4000m', # millicores, e.g. "1000m" = 1 CPU core
min_gpu_limit=0 # set min_gpu_limit=1 to enable GPU
)
def main(options: Namespace, inputdir: Path, outputdir: Path):
print(DISPLAY_TITLE, flush=True)

mapper = PathMapper.file_mapper(inputdir, outputdir, glob=options.pattern, suffix='.count.txt')
for input_file, output_file in mapper:
# The code block below is a small and easy example of how to use a ``PathMapper``.
# It is recommended that you put your functionality in a helper function, so that
# it is more legible and can be unit tested.
data = input_file.read_text()
frequency = data.count(options.word)
output_file.write_text(str(frequency))
mapper = PathMapper.file_mapper(inputdir, outputdir)
nproc = options.threads if options.threads else len(os.sched_getaffinity(0))
threshold_map = {k: float(v) for k, v in helpers.parse_csv_as_dict(options.thresholds).items()}
results = thread_map(curry_zerobg(threshold_map), mapper, max_workers=nproc, total=mapper.count(), maxinterval=0.1)
if not all(results):
sys.exit(1)


def curry_zerobg(threshold_map: dict[str, float]) -> Callable[[tuple[Path, Path]], bool]:
return lambda t: zerobg(t[0], t[1], threshold_map)


def zerobg(input: Path, output: Path, threshold_map: dict[str, float]) -> bool:
threshold = next((v for k, v in threshold_map.items() if input.name.endswith(k)), None)
if threshold is None:
shutil.copy(input, output)
return True

vol = nib.load(input)
data = vol.get_fdata()
result = np.where(data <= threshold, 0, data)
output_vol = vol.__class__(result, vol.affine, header=vol.header)
nib.save(output_vol, output)


if __name__ == '__main__':
Expand Down

0 comments on commit d3384fd

Please sign in to comment.