Skip to content

Commit 1584b3b

Browse files
authored
Merge pull request #606 from MarcCote/enh_conversion_scripts
ENH: adding TRK <=> TCK streamlines conversion scripts
2 parents 4c2bca7 + de68635 commit 1584b3b

File tree

6 files changed

+225
-1
lines changed

6 files changed

+225
-1
lines changed

bin/nib-tck2trk

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!python
2+
# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*-
3+
# vi: set ft=python sts=4 ts=4 sw=4 et:
4+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
5+
#
6+
# See COPYING file distributed along with the NiBabel package for the
7+
# copyright and license terms.
8+
#
9+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
10+
"""
11+
Convert tractograms (TCK -> TRK).
12+
"""
13+
14+
from nibabel.cmdline.tck2trk import main
15+
16+
17+
if __name__ == '__main__':
18+
main()

bin/nib-trk2tck

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!python
2+
# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*-
3+
# vi: set ft=python sts=4 ts=4 sw=4 et:
4+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
5+
#
6+
# See COPYING file distributed along with the NiBabel package for the
7+
# copyright and license terms.
8+
#
9+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
10+
"""
11+
Convert tractograms (TRK -> TCK).
12+
"""
13+
14+
from nibabel.cmdline.trk2tck import main
15+
16+
17+
if __name__ == '__main__':
18+
main()

nibabel/cmdline/tck2trk.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""
2+
Convert tractograms (TCK -> TRK).
3+
"""
4+
import os
5+
import argparse
6+
7+
import nibabel as nib
8+
9+
from nibabel.streamlines import Field
10+
from nibabel.orientations import aff2axcodes
11+
12+
13+
def parse_args():
14+
DESCRIPTION = "Convert tractograms (TCK -> TRK)."
15+
parser = argparse.ArgumentParser(description=DESCRIPTION)
16+
parser.add_argument("anatomy",
17+
help="reference anatomical image (.nii|.nii.gz.")
18+
parser.add_argument("tractograms", metavar="tractogram", nargs="+",
19+
help="list of tractograms (.tck).")
20+
parser.add_argument("-f", "--force", action="store_true",
21+
help="overwrite existing output files.")
22+
23+
args = parser.parse_args()
24+
return args, parser
25+
26+
27+
def main():
28+
args, parser = parse_args()
29+
30+
try:
31+
nii = nib.load(args.anatomy)
32+
except Exception:
33+
parser.error("Expecting anatomical image as first agument.")
34+
35+
for tractogram in args.tractograms:
36+
tractogram_format = nib.streamlines.detect_format(tractogram)
37+
if tractogram_format is not nib.streamlines.TckFile:
38+
print("Skipping non TCK file: '{}'".format(tractogram))
39+
continue
40+
41+
filename, _ = os.path.splitext(tractogram)
42+
output_filename = filename + '.trk'
43+
if os.path.isfile(output_filename) and not args.force:
44+
msg = "Skipping existing file: '{}'. Use -f to overwrite."
45+
print(msg.format(output_filename))
46+
continue
47+
48+
# Build header using infos from the anatomical image.
49+
header = {}
50+
header[Field.VOXEL_TO_RASMM] = nii.affine.copy()
51+
header[Field.VOXEL_SIZES] = nii.header.get_zooms()[:3]
52+
header[Field.DIMENSIONS] = nii.shape[:3]
53+
header[Field.VOXEL_ORDER] = "".join(aff2axcodes(nii.affine))
54+
55+
tck = nib.streamlines.load(tractogram)
56+
nib.streamlines.save(tck.tractogram, output_filename, header=header)

nibabel/cmdline/trk2tck.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""
2+
Convert tractograms (TRK -> TCK).
3+
"""
4+
5+
import os
6+
import argparse
7+
8+
import nibabel as nib
9+
10+
11+
def parse_args():
12+
DESCRIPTION = "Convert tractograms (TRK -> TCK)."
13+
parser = argparse.ArgumentParser(description=DESCRIPTION)
14+
parser.add_argument("tractograms", metavar="tractogram", nargs="+",
15+
help="list of tractograms (.trk).")
16+
parser.add_argument("-f", "--force", action="store_true",
17+
help="overwrite existing output files.")
18+
19+
args = parser.parse_args()
20+
return args, parser
21+
22+
23+
def main():
24+
args, parser = parse_args()
25+
for tractogram in args.tractograms:
26+
tractogram_format = nib.streamlines.detect_format(tractogram)
27+
if tractogram_format is not nib.streamlines.TrkFile:
28+
print("Skipping non TRK file: '{}'".format(tractogram))
29+
continue
30+
31+
filename, _ = os.path.splitext(tractogram)
32+
output_filename = filename + '.tck'
33+
if os.path.isfile(output_filename) and not args.force:
34+
msg = "Skipping existing file: '{}'. Use -f to overwrite."
35+
print(msg.format(output_filename))
36+
continue
37+
38+
trk = nib.streamlines.load(tractogram)
39+
nib.streamlines.save(trk.tractogram, output_filename)

nibabel/tests/test_scripts.py

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,23 @@
88

99
import sys
1010
import os
11+
import shutil
1112
from os.path import (dirname, join as pjoin, abspath, splitext, basename,
1213
exists)
1314
import csv
1415
from glob import glob
1516

1617
import numpy as np
1718

19+
import nibabel as nib
1820
from ..tmpdirs import InTemporaryDirectory
1921
from ..loadsave import load
2022
from ..orientations import flip_axis, aff2axcodes, inv_ornt_aff
2123

2224
from nose.tools import assert_true, assert_false, assert_equal
2325
from nose import SkipTest
2426

25-
from numpy.testing import assert_almost_equal
27+
from numpy.testing import assert_almost_equal, assert_array_equal
2628

2729
from .scriptrunner import ScriptRunner
2830
from .nibabel_data import needs_nibabel_data
@@ -357,3 +359,92 @@ def test_parrec2nii_with_data():
357359
assert_equal(sorted(csv_keys), ['diffusion b value number',
358360
'gradient orientation number'])
359361
assert_equal(nlines, 8) # 8 volumes present in DTI.PAR
362+
363+
364+
@script_test
365+
def test_nib_trk2tck():
366+
simple_trk = pjoin(DATA_PATH, "simple.trk")
367+
standard_trk = pjoin(DATA_PATH, "standard.trk")
368+
369+
with InTemporaryDirectory() as tmpdir:
370+
# Copy input files to convert.
371+
shutil.copy(simple_trk, tmpdir)
372+
shutil.copy(standard_trk, tmpdir)
373+
simple_trk = pjoin(tmpdir, "simple.trk")
374+
standard_trk = pjoin(tmpdir, "standard.trk")
375+
simple_tck = pjoin(tmpdir, "simple.tck")
376+
standard_tck = pjoin(tmpdir, "standard.tck")
377+
378+
# Convert one file.
379+
cmd = ["nib-trk2tck", simple_trk]
380+
code, stdout, stderr = run_command(cmd)
381+
assert_equal(len(stdout), 0)
382+
assert_true(os.path.isfile(simple_tck))
383+
trk = nib.streamlines.load(simple_trk)
384+
tck = nib.streamlines.load(simple_tck)
385+
assert_array_equal(tck.streamlines.data, trk.streamlines.data)
386+
assert_true(isinstance(tck, nib.streamlines.TckFile))
387+
388+
# Skip non TRK files.
389+
cmd = ["nib-trk2tck", simple_tck]
390+
code, stdout, stderr = run_command(cmd)
391+
assert_true("Skipping non TRK file" in stdout)
392+
393+
# By default, refuse to overwrite existing output files.
394+
cmd = ["nib-trk2tck", simple_trk]
395+
code, stdout, stderr = run_command(cmd)
396+
assert_true("Skipping existing file" in stdout)
397+
398+
# Convert multiple files and with --force.
399+
cmd = ["nib-trk2tck", "--force", simple_trk, standard_trk]
400+
code, stdout, stderr = run_command(cmd)
401+
assert_equal(len(stdout), 0)
402+
trk = nib.streamlines.load(standard_trk)
403+
tck = nib.streamlines.load(standard_tck)
404+
assert_array_equal(tck.streamlines.data, trk.streamlines.data)
405+
406+
407+
@script_test
408+
def test_nib_tck2trk():
409+
anat = pjoin(DATA_PATH, "standard.nii.gz")
410+
standard_tck = pjoin(DATA_PATH, "standard.tck")
411+
412+
with InTemporaryDirectory() as tmpdir:
413+
# Copy input file to convert.
414+
shutil.copy(standard_tck, tmpdir)
415+
standard_trk = pjoin(tmpdir, "standard.trk")
416+
standard_tck = pjoin(tmpdir, "standard.tck")
417+
418+
# Anatomical image not found as first argument.
419+
cmd = ["nib-tck2trk", standard_tck, anat]
420+
code, stdout, stderr = run_command(cmd, check_code=False)
421+
assert_equal(code, 2) # Parser error.
422+
assert_true("Expecting anatomical image as first agument" in stderr)
423+
424+
# Convert one file.
425+
cmd = ["nib-tck2trk", anat, standard_tck]
426+
code, stdout, stderr = run_command(cmd)
427+
assert_equal(len(stdout), 0)
428+
assert_true(os.path.isfile(standard_trk))
429+
tck = nib.streamlines.load(standard_tck)
430+
trk = nib.streamlines.load(standard_trk)
431+
assert_array_equal(trk.streamlines.data, tck.streamlines.data)
432+
assert_true(isinstance(trk, nib.streamlines.TrkFile))
433+
434+
# Skip non TCK files.
435+
cmd = ["nib-tck2trk", anat, standard_trk]
436+
code, stdout, stderr = run_command(cmd)
437+
assert_true("Skipping non TCK file" in stdout)
438+
439+
# By default, refuse to overwrite existing output files.
440+
cmd = ["nib-tck2trk", anat, standard_tck]
441+
code, stdout, stderr = run_command(cmd)
442+
assert_true("Skipping existing file" in stdout)
443+
444+
# Convert multiple files and with --force.
445+
cmd = ["nib-tck2trk", "--force", anat, standard_tck, standard_tck]
446+
code, stdout, stderr = run_command(cmd)
447+
assert_equal(len(stdout), 0)
448+
tck = nib.streamlines.load(standard_tck)
449+
trk = nib.streamlines.load(standard_trk)
450+
assert_array_equal(tck.streamlines.data, trk.streamlines.data)

setup.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ def main(**extra_args):
117117
pjoin('bin', 'nib-ls'),
118118
pjoin('bin', 'nib-dicomfs'),
119119
pjoin('bin', 'nib-nifti-dx'),
120+
pjoin('bin', 'nib-tck2trk'),
121+
pjoin('bin', 'nib-trk2tck'),
120122
],
121123
cmdclass = cmdclass,
122124
**extra_args

0 commit comments

Comments
 (0)