Skip to content

Commit

Permalink
Handle .txt and add test
Browse files Browse the repository at this point in the history
  • Loading branch information
jennydaman committed Nov 14, 2023
1 parent 6eccdb2 commit cbf4c3f
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 48 deletions.
36 changes: 32 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,41 @@ jobs:
tags: ${{ steps.info.outputs.local_tag }}
load: true
cache-from: type=gha
# 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: examples/download.sh
- name: Run examples
id: run_examples
run: |
echo TODO
mkdir /tmp/outgoing
docker run --rm -u "$(id -u):$(id -g)" \
-v "${{ github.workspace }}/examples/incoming:/incoming:ro" \
-v "/tmp/outgoing"/outgoing:rw" \
${{ steps.info.outputs.local_tag }}
mni2common /incoming /outgoing
- name: Assert example outputs are found
run: |
expected_outputs=(
outgoing/colin27_t1_tal_lin.mnc2nii.log
outgoing/colin27_t1_tal_lin.nii
outgoing/colin27_t1_tal_lin_headmask.mnc2nii.log
outgoing/colin27_t1_tal_lin_headmask.nii
outgoing/colin27_t1_tal_lin_mask.mnc2nii.log
outgoing/colin27_t1_tal_lin_mask.nii
outgoing/colin_white_mc_left.mz3
outgoing/colin_white_mc_mask_left.mz3
outgoing/colin_white_mc_mask_right.mz3
outgoing/colin_white_mc_right.mz3
)
for expected_output in "${expected_outputs[@]}"; do
if ! [ -f "$1" ]; then
echo "expected $1 to be a file, but it does not."
parent_dir="$(dirname "$1")"
set -ex
ls -lh "$parent_dir"
exit 1
fi
done
- name: Login to DockerHub
if: (github.event_name == 'push' || github.event_name == 'release') && contains(steps.info.outputs.tags_csv, 'docker.io')
Expand Down
29 changes: 15 additions & 14 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
FROM docker.io/fnndsc/pl-mni2common:base-1
FROM docker.io/fnndsc/pl-mni2common:base-2 AS base

LABEL org.opencontainers.image.authors="FNNDSC <[email protected]>" \
org.opencontainers.image.title="pl-mnc2common" \
org.opencontainers.image.description="A ChRIS plugin to convert MINC volume and MNI .obj surface file formats to NIFTI and Wavefront OBJ respectively."
FROM base AS mni2mz3-installer

RUN apt-get update \
&& apt-get install -y curl

# use micromamba to install binary python dependencies for multiarch build
RUN \
--mount=type=cache,sharing=private,target=/home/mambauser/.mamba/pkgs,uid=57439,gid=57439 \
--mount=type=cache,sharing=private,target=/opt/conda/pkgs,uid=57439,gid=57439 \
micromamba install -y -n base -c conda-forge python=3.11.5 numpy=1.26.0
RUN curl --proto '=https' --tlsv1.2 -LsSf 'https://github.com/FNNDSC/mni2mz3/releases/download/v1.0.0-rc.5/installer.sh' | bash

FROM base

LABEL org.opencontainers.image.authors="Jennings.Zhang <[email protected]>" \
org.opencontainers.image.title="pl-mnc2common" \
org.opencontainers.image.description="A ChRIS plugin to convert MINC volume, .txt surface data, and MNI .obj surface file formats to NIFTI and MZ3."

ARG SRCDIR=/usr/local/src/pl-mni2common
WORKDIR ${SRCDIR}

COPY --chown=57439:57439 requirements.txt .
RUN --mount=type=cache,sharing=private,target=/home/mambauser/.cache/pip,uid=57439,gid=57439 \
pip install -r requirements.txt

COPY --chown=mambauser:mambauser . .
COPY . .
ARG extras_require=none
RUN pip install ".[${extras_require}]" \
&& cd / && rm -rf ${SRCDIR}/*
WORKDIR /

COPY --from=mni2mz3-installer /usr/local/bin/mni2mz3 /usr/local/bin/mni2mz3

CMD ["mni2common"]
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
[![ci](https://github.com/FNNDSC/pl-mni2common/actions/workflows/ci.yml/badge.svg)](https://github.com/FNNDSC/pl-mni2common/actions/workflows/ci.yml)

`pl-mni2common` is a [_ChRIS_](https://chrisproject.org/)
_ds_ plugin which takes in ... as input files and
creates ... as output files.

## Abstract

...
_ds_ plugin wrapper around the programs
[mnc2nii](https://bic-mni.github.io/man-pages/man/mnc2nii.html)
and [mni2mz3](https://github.com/FNNDSC/mni2mz3).
It converts MINC volumes to NIFTI, surfaces to MZ3, and surface data to MZ3.
The output file formats NIFTI and MZ3 are convenient for visualization by [niivue](https://github.com/niivue/niivue).

## Installation

Expand Down
4 changes: 2 additions & 2 deletions base/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ FROM docker.io/fnndsc/microminc-builder:latest as builder

RUN microminc.sh mnc2nii /microminc

FROM ghcr.io/mamba-org/micromamba:1.5.1-bookworm-slim
FROM python:3.12.0-slim-bullseye
COPY --from=builder /microminc /opt/microminc
ENV PATH=/opt/conda/bin:/opt/microminc/bin:$PATH \
ENV PATH=/opt/microminc/bin:$PATH \
LD_LIBRARY_PATH=/opt/microminc/lib:$LD_LIBRARY_PATH \
MINC_FORCE_V2=1 MINC_COMPRESS=4 VOLUME_CACHE_THRESHOLD=-1 \
MNI_DATAPATH=/opt/microminc/share
2 changes: 1 addition & 1 deletion base/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

exec docker buildx build --push \
--platform linux/amd64,linux/arm64,linux/ppc64le \
-t docker.io/fnndsc/pl-mni2common:base-1 .
-t docker.io/fnndsc/pl-mni2common:base-2 .
2 changes: 2 additions & 0 deletions examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/incoming
/outgoing
22 changes: 22 additions & 0 deletions examples/download.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/bash

HERE="$(dirname "$(readlink -f "$0")")"

urls=(
https://github.com/aces/CIVET/raw/9818b3cbe8308249e7c373ef1a2a53956512143e/models/colin/colin_white_mc_mask_left.txt
https://github.com/aces/CIVET/raw/9818b3cbe8308249e7c373ef1a2a53956512143e/models/colin/colin_white_mc_mask_right.txt
https://github.com/aces/CIVET/raw/9818b3cbe8308249e7c373ef1a2a53956512143e/models/colin/colin_white_mc_left.obj
https://github.com/aces/CIVET/raw/9818b3cbe8308249e7c373ef1a2a53956512143e/models/colin/colin_white_mc_right.obj
https://github.com/aces/mni-models_colin27-lin/raw/60787485e2ed4e012bda4da8fc2b163384fc3431/colin27_t1_tal_lin.mnc.gz
https://github.com/aces/mni-models_colin27-lin/raw/60787485e2ed4e012bda4da8fc2b163384fc3431/colin27_t1_tal_lin_headmask.mnc.gz
https://github.com/aces/mni-models_colin27-lin/raw/60787485e2ed4e012bda4da8fc2b163384fc3431/colin27_t1_tal_lin_mask.mnc.gz
)

set -ex

cd "$HERE"
mkdir -v incoming
cd incoming

parallel wget -q ::: ${urls[@]}
find -type f -name '*.gz' | parallel gzip -d
39 changes: 22 additions & 17 deletions mni2common.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from argparse import ArgumentParser, Namespace, ArgumentDefaultsHelpFormatter
from tqdm.contrib.concurrent import thread_map
from tqdm.contrib.logging import logging_redirect_tqdm
from bicpl import PolygonObj, WavefrontObj

from chris_plugin import chris_plugin, PathMapper

Expand All @@ -27,7 +26,7 @@
"""


parser = ArgumentParser(description='Convert MINC and .obj to NIFTI and Wavefront respectively',
parser = ArgumentParser(description='Convert MINC and .obj to NIFTI and MZ3 respectively',
formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('-p', '--pattern', default='**/*', type=str,
help='Path filter')
Expand Down Expand Up @@ -60,12 +59,15 @@ def main(options: Namespace, inputdir: Path, outputdir: Path):

def convert_file(file_pair: tuple[Path, Path]) -> bool:
input_file, output_file = file_pair
if input_file.suffix == '.mnc':
return convert_minc(input_file, output_file.with_suffix('.nii'))
elif input_file.suffix == '.obj':
return convert_obj(input_file, output_file.with_suffix('.wf.obj'))
shutil.copy2(input_file, output_file)
return True
match input_file.suffix:
case '.mnc':
return convert_minc(input_file, output_file.with_suffix('.nii'))
case '.obj' | '.txt':
return mni2mz3(input_file, output_file.with_suffix('.mz3'))
case _:
if os.path.realpath(input_file) != os.path.realpath(output_file):
shutil.copy2(input_file, output_file)
return True


def convert_minc(mnc, nii) -> bool:
Expand All @@ -79,16 +81,19 @@ def convert_minc(mnc, nii) -> bool:
return False


def convert_obj(mniobj_path, wavefront_path) -> bool:
try:
obj = PolygonObj.from_file(mniobj_path)
wf = WavefrontObj.from_mni(obj)
with wavefront_path.open('w') as f:
wf.write_to(f)
def mni2mz3(input_path, output_path) -> bool:
cmd = ('mni2mz3', str(input_path), str(output_path))
proc = sp.run(cmd, stderr=sp.PIPE, stdout=sp.DEVNULL)
if proc.returncode == 0:
return True
# is a .txt file, but not a vertex-wise surface data file
if input_path.suffix == '.txt' and b'Could not parse 0th value as float' in proc.stderr:
output_txt = output_path.with_suffix(input_path.suffix)
if os.path.realpath(input_path) != os.path.realpath(output_txt):
shutil.copy2(input_path, output_txt)
return True
except Exception as e:
LOG.error(str(e))
return False
LOG.error(f'Command failed: {shlex.join(cmd)}')
return False


if __name__ == '__main__':
Expand Down
2 changes: 0 additions & 2 deletions requirements.txt

This file was deleted.

4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ def get_version(rel_path: str) -> str:
setup(
name='mni2common',
version=get_version('mni2common.py'),
description='A ChRIS plugin to convert MINC volume and MNI .obj surface file formats to NIFTI and Wavefront OBJ respectively.',
description='A ChRIS plugin to convert MINC volume and MNI .obj surface file formats to NIFTI and MZ3 OBJ respectively.',
author='FNNDSC',
author_email='[email protected]',
url='https://github.com/FNNDSC/pl-mni2common',
py_modules=['mni2common'],
install_requires=['chris_plugin', 'pybicpl', 'tqdm'],
install_requires=['chris_plugin==0.3.1', 'tqdm~=4.66'],
license='MIT',
entry_points={
'console_scripts': [
Expand Down

0 comments on commit cbf4c3f

Please sign in to comment.