Not as far as I know. But interestingly, I do know that Marc Côté is working on .tck
support for nibabel
- there’s an example there for conversion from .trk
to .tck
, so it looks like it should work.
You can also do this by wrapping the nipype interfaces. Take a look at nipype.interfaces.mrtrix.MRTrix2TrackVis. I did this a few years ago now, so there may be a better way now :-). (sorry, the indenting after the if statements was lost)
#! /usr/bin/env python
# Jan 2014
# Christopher J. Steele
# simple script to convert mrtrix .tck to trackvis .trk
# using nipype interface
import sys
if len(sys.argv) < 3:
print "Loads NiPy module to transform file"
print "Usage:",sys.argv[0], "<base_image> <input_file>"
print """base_image - file with resolution of template
input_file - MRTrix track file (.tck)"""
print "Output: TrackVis track vile (.trk)"
sys.exit(0)
import nipype.interfaces.mrtrix as mrt
mr=mrt.MRTrix2TrackVis()
mr.inputs.image_file=sys.argv[1]
mr.inputs.in_file=sys.argv[2]
mr.inputs.out_filename=sys.argv[2].split('.')[-2] + '.trk'
mr.run()
mr.inputs.print_traits()
Have you figured out a way to do this in reverse-- trk to tck, or is this a one way street?
A, sorry about that. I read it the wrong way the first time.
As @jdtournier pointed out above, this is an open issue that looks mostly solved but not yet integrated into nibabel. I think that the example that was referred to is here: https://gist.github.com/MarcCote/ea6842cc4c3950f7596fc3c8a0be0154
Dear all,
Thank you for this instructive post, which is helpful as I preprocess DSI data with DSI-studio, and am going to build the tract using MRtrix3. However, I came across the issue using trk2tck.py. The error message is shown in the following,
hsiang-yuanlin% python ~/Documents/PyScripts/trk2tck.py /Volumes/HY_SSD/DSI/ASD_FU_0502/ASD_5220-1/2.trk.gz
Traceback (most recent call last):
File “/Users/hsiang-yuanlin/Documents/PyScripts/trk2tck.py”, line 31, in
main()
File “/Users/hsiang-yuanlin/Documents/PyScripts/trk2tck.py”, line 28, in main
nib.streamlines.save(trk.tractogram, output_filename)
File “/usr/local/lib/python2.7/site-packages/nibabel/streamlines/init.py”, line 118, in save
raise ValueError(msg)
ValueError: Unknown tractogram file format: ‘/Volumes/HY_SSD/DSI/ASD_FU_0502/ASD_5220-1/2.tr.tck’
Does someone know how to deal with this issue?
Thank you very much!!!
Hsiang-Yuan
Looks like it is not available in the current pip version of nibabel (2.1.0). It was merged into the github repo last month, so you can likely clone and use from there if you need it immediately.
–> https://github.com/nipy/nibabel/tree/master/nibabel/streamlines
Hello all,
Just for the record on the Internet, I also have another (round about) approach which likely will be obsolete pretty soon but just in case some people might find this as an easier alternative.
The steps:
-
In a bash shell:
camino_to_trackvis -i streamlines.trk -o streamlines.Bfloat
(Camino to and fro trackvis utility)
vtkstreamlines < streamlines.Bfloat > streamlines.vtk
(Camino command) -
In Matlab:
SL = get_streamlines('streamlines.Bfloat', [1, 1, 1]);
WriteStreamlinesForMrtrix3(SL, 'streamlines');
-
In a bash shell:
tckconvert streamlines-[].txt streamlines.tck
The two Matlab functions (get_streamlines
and WriteStreamlinesForMrtrix3
) are pasted below. I could not attach them. Sorry the get_streamlines.m
is not as elegant. I had written it a while back.
Thanks.
Nagesh
====================
WriteStreamlinesForMrtrix3.m
function WriteStreamlinesForMrtrix3(SL, filePrefix)
idxCells = arrayfun(@(x){x-1}, 1:length(SL));
cellfun(@(s, idx) save(sprintf('%s-%.6d.txt', filePrefix, idx), 's', '-ascii'), SL, idxCells', 'UniformOutput', false);
return
====================
====================
get_streamlines.m
function SL = get_streamlines(filename,pixsize)
f = fopen(filename,'r', 'b');
fend = 0;
i = 1; %index
maxP = 0;
tic;
while (fend == 0)
%read streamline from input file
a = fread(f,1,'float');
if (isempty(a))
break;
end
fread(f,1,'float');
Npoints = floor(a);
if (Npoints>maxP)
maxP = Npoints;
end
fread(f,[3 Npoints], 'float');
i = i+1;
end
fclose(f);
%disp (['Total number of streamlines: ' num2str(i-1)]);
%disp (['Longest streamline: ' num2str(maxP) ' points']);
%Now actual reading.
f = fopen(filename,'r', 'b');
fend = 0;
SL=cell(i-1,1);
i=1;
while (fend == 0)
%read streamline from input file
a = fread(f,1,'float');
if (isempty(a))
break;
end
fread(f,1,'float');
Npoints = floor(a);
xyz = fread(f,[3 Npoints], 'float');
xyz(1, :) = xyz(1,:)/pixsize(1);
xyz(2, :) = xyz(2,:)/pixsize(2);
xyz(3, :) = xyz(3,:)/pixsize(3);
xyz = xyz';
SL{i} = xyz;
i = i+1;
end
fclose(f);
%fprintf('Read the file in %f sec.',toc);
return
====================
Hi Chris,
Thanks a lot, it works now!
For any others wondering the, nibabel conversion doesn’t work. It’s broke you can’t use any mrtrix functions with the converted tratograms. For instance, if you run tckmap to try and generate a TDI image all you get is black image of all 0’s.
nadluru do you know if your procedure works with tckmap and other mrtrix functions?
Revisiting this because i’ve recently had an issue with data conversion.
I’ve been running the same tck -> trk conversion for years, which uses nipype’s mrtrix interface ( essentially ) :
import nipype.interfaces.mrtrix as mrt
import shutil
tck2trk = mrt.MRTrix2TrackVis()
tck2trk.inputs.image_file = b0file
tck2trk.inputs.in_file = os.path.join(os.path.dirname(infile), '%s.tck' % tckname)
tck2trk.run()
shutil.move('converted.trk',os.path.join(os.path.dirname(infile), '%s.trk' % tckname))
Currently, the output data no longer lines up in trackvis ( L = trackvis, R = mrview )
I believe this started when i upgraded mrtrix3 from RC1 -> RC2. I’ve also tried it on RC3 with the same results. Any ideas whats going on? Has mrtrix3 changed the way it stores things in headers of the data that could attribute to this? Its nice to be able to use trackvis for easy filtering by lengths, ROIs, etc
That’s odd. Nothing has changed in the tck
format for a decade or so… And since vertices are stored relative to scanner coordinates, there’s very little that can go wrong. I don’t see how there could be an issue on that front.
However, I think TRK format is relative to the image grid…? In which case it’s presumably dependent on using the same image when converting the tracks as when displaying them – but I’ve no experience with this, so there’s a good chance I might be plain wrong…
i’m using the same nii.gz image to convert and display.
I was thinking maybe something in the headers of the nii.gz could’ve changed? The thing that struck me as a bit odd was the transform vs q-form/s-form and the RAS matrix from the trk file. Wasn’t sure if these should all be the same.
tesla:av cmp12$ mrinfo trace.nii.gz
************************************************
Image: "trace.nii.gz"
************************************************
Dimensions: 384 x 384 x 48
Voxel size: 0.599 x 0.599 x 0.6
Data strides: [ -1 -2 3 ]
Format: NIfTI-1.1 (GZip compressed)
Data type: 32 bit float (little endian)
Intensity scaling: offset = 0, multiplier = 1
Transform: 1 -0 0 -114.7
-0 1 0 -74.21
-0 -0 1 2.889
comments: untitled
mrtrix_version: 3.0_RC2-82-gbb77205e
The q-form / s-form from the trace.nii.gz data as produced from dwiextract via fslhd
qto_xyz:1 -0.599000 0.000000 0.000000 114.697006
qto_xyz:2 0.000000 -0.599000 0.000000 155.209015
qto_xyz:3 0.000000 0.000000 0.600000 2.889300
qto_xyz:4 0.000000 0.000000 0.000000 1.000000
The metadata from the converted trk file.
tesla:av cmp12$ /Applications/Diffusion\ Toolkit.app/Contents/MacOS/track_info converted.trk
ID string: TRACK
Version: 2
Dimension: 384 384 48
Voxel size: 0.599 0.599 0.6
Voxel order: LPS
Voxel order original: LPS
Voxel to RAS matrix:
-0.5990 0.0000 0.0000 114.6970
0.0000 -0.5990 0.0000 155.2090
0.0000 0.0000 0.6000 2.8893
0.0000 0.0000 0.0000 1.0000
Image Orientation: 1.0000/0.0000/0.0000/0.0000/1.0000/0.0000
Orientation patches: none
Number of scalars: 0
Number of properties: 0
Number of tracks: 1000000
The output of mrinfo
doesn’t report the information as stored in the NIfTI directly, but rather as MRtrix3 interprets it. In this instance, the fact that fslhd
and the TRK metadata match is all we need to know.
Incidentally, the only time the mrinfo output would be expected to match the sform
as stored in the NIfTI header is in the special case of close-to-axial orientations (i.e. strides: 1 2 3
) with unit voxel sizes. This is because the transform reported by mrinfo
is the pure rotation applied to the image axes, having modified them to be close to axial (see the documentation for details). In contrast, the sform
includes the voxel scaling, and does not try to account for the orientation of the axes in any way.
So the issue is elsewhere. I have no idea what could be causing this – as I mentioned earlier, there’s been no changes to the format or conventions assumed for the streamlines data. There have been a few changes to the NIfTI handling though, which may account for the discrepancy – but these were included into 3.0_RC3
, not RC2. We also had quite a bit of fun investigating fundamental instabilities in the qform
if you’re really interested – but these changes are on master
only, not even 3.0_RC3
. I can’t find any changes in the NIfTI handling between RC1 & RC2 – here’s the full diff for the relevant files:
$ git log -p 3.0_RC1..3.0_RC2 -- core/file/nifti* core/formats/nifti*
which basically gives copyright notice changes and not a lot else:
commit 3db1bb2b07b2cbeed35596a63c67bdd310a0492d
Author: Robert Smith <robert.smith@florey.edu.au>
Date: Sat May 20 01:08:36 2017 +1000
Remove #include <vector> usages
This header should no longer be included directly, since class MR::vector (defined in core/types.h) should always be used.
diff --git a/core/file/nifti_utils.h b/core/file/nifti_utils.h
index ba232f38f..b5b2d9398 100644
--- a/core/file/nifti_utils.h
+++ b/core/file/nifti_utils.h
@@ -15,8 +15,6 @@
#ifndef __file_nifti_utils_h__
#define __file_nifti_utils_h__
-#include <vector>
-
#include "types.h"
namespace MR
commit 729dd6cfc1a773f0f16592b8533c6e9d89d03ac3
Author: Thijs Dhollander <thijs.dhollander@gmail.com>
Date: Mon May 15 10:33:05 2017 +1000
copyright update and cleanup
diff --git a/core/file/nifti1_utils.cpp b/core/file/nifti1_utils.cpp
index ded0e761e..9b53dd81e 100644
--- a/core/file/nifti1_utils.cpp
+++ b/core/file/nifti1_utils.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017 the MRtrix3 contributors
+/* Copyright (c) 2008-2017 the MRtrix3 contributors.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
diff --git a/core/file/nifti1_utils.h b/core/file/nifti1_utils.h
index ecd412789..16b117eaa 100644
--- a/core/file/nifti1_utils.h
+++ b/core/file/nifti1_utils.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017 the MRtrix3 contributors
+/* Copyright (c) 2008-2017 the MRtrix3 contributors.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
diff --git a/core/file/nifti2.h b/core/file/nifti2.h
index d9e4de475..5643fa909 100644
--- a/core/file/nifti2.h
+++ b/core/file/nifti2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017 the MRtrix3 contributors
+/* Copyright (c) 2008-2017 the MRtrix3 contributors.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
diff --git a/core/file/nifti2_utils.cpp b/core/file/nifti2_utils.cpp
index 1d76659c1..d0fafa7ee 100644
--- a/core/file/nifti2_utils.cpp
+++ b/core/file/nifti2_utils.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017 the MRtrix3 contributors
+/* Copyright (c) 2008-2017 the MRtrix3 contributors.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
diff --git a/core/file/nifti2_utils.h b/core/file/nifti2_utils.h
index dcd629e9c..39f272b8f 100644
--- a/core/file/nifti2_utils.h
+++ b/core/file/nifti2_utils.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017 the MRtrix3 contributors
+/* Copyright (c) 2008-2017 the MRtrix3 contributors.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
diff --git a/core/file/nifti_utils.cpp b/core/file/nifti_utils.cpp
index 1d0d6e19c..2e909f671 100644
--- a/core/file/nifti_utils.cpp
+++ b/core/file/nifti_utils.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017 the MRtrix3 contributors
+/* Copyright (c) 2008-2017 the MRtrix3 contributors.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
diff --git a/core/file/nifti_utils.h b/core/file/nifti_utils.h
index 18e9d0bf0..ba232f38f 100644
--- a/core/file/nifti_utils.h
+++ b/core/file/nifti_utils.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017 the MRtrix3 contributors
+/* Copyright (c) 2008-2017 the MRtrix3 contributors.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
diff --git a/core/formats/nifti1.cpp b/core/formats/nifti1.cpp
index f188bb60c..06d4977df 100644
--- a/core/formats/nifti1.cpp
+++ b/core/formats/nifti1.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017 the MRtrix3 contributors
+/* Copyright (c) 2008-2017 the MRtrix3 contributors.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
diff --git a/core/formats/nifti1_gz.cpp b/core/formats/nifti1_gz.cpp
index 41938ff75..588f1a322 100644
--- a/core/formats/nifti1_gz.cpp
+++ b/core/formats/nifti1_gz.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017 the MRtrix3 contributors
+/* Copyright (c) 2008-2017 the MRtrix3 contributors.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
diff --git a/core/formats/nifti2.cpp b/core/formats/nifti2.cpp
index 0ccd4cde6..06c76faa1 100644
--- a/core/formats/nifti2.cpp
+++ b/core/formats/nifti2.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017 the MRtrix3 contributors
+/* Copyright (c) 2008-2017 the MRtrix3 contributors.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
diff --git a/core/formats/nifti2_gz.cpp b/core/formats/nifti2_gz.cpp
index c63e8e22b..b79a28145 100644
--- a/core/formats/nifti2_gz.cpp
+++ b/core/formats/nifti2_gz.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017 the MRtrix3 contributors
+/* Copyright (c) 2008-2017 the MRtrix3 contributors.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
In short, I can’t think of anything that would affect this… The only other option that might play a role here is if there’s a discrepancy between the sform
and the qform
in your reference image. We did introduce checks on that front in 3.0_RC3
(this commit), along with a config file option to set which of the two to use when they don’t match (this commit). I’m not sure what might have happened in the past, although I have a feeling it would have silently defaulted to the sform
. If that doesn’t match what nipype
is defaulting to in case of mismatch, that could introduce the kinds of errors you’re seeing… You should be able to check this with a quick look through fslhd
– and a 3.0_RC3
version of mrinfo
should also warn you if there is a mismatch…
Great. Thanks for the confirmation and looking into this. I reprocessed with RC3 and had the same result.
I then processed a scan off of our other scanner with the exact same procedures and everything lined up perfectly as before. Looks like i’ll be digging in deeper to the data coming off the new scanner.
Hey @Chris_Steele @jdtournier,
I have been trying to find the correct implementation of trk2tck for a month now, and have only been able to find that they have implemented it using nibabel.streamlines.load
and nibabel.streamlines.save
into .tck but when you use normal mrtrix functions into the same they do not work, and raise an error “invalid mrtrix tracks”.
Be it the streamlines_tck
or another implementation on brainslife.io, app-trk2tck, they have also used the nibabel save and load methods which do not convert .trk(s) to .tck(s).
Please let me know if there are any solution available now to convert between these file formats.
Regards,
Anoushkrit Goel
Hi @anoushkrit,
Not sure I can help a great deal here, but my first recommendation is to make sure you’re using the most up to date version of nibabel available – it might have been an issue with an earlier version. If that doesn’t solve the problem, can you send me a (small) example output from the conversion (just the tck
file should be enough) so I can look into what it is about it that is invalid. It might be a simple fix, and if so we might be able to feed that back to the nibabel team and get it fixed upstream.
Hi @jdtournier
Thank you!! for such a prompt reply, currently I am using nibabel==3.2.2
currently. I also tried cloning the latest nibabel version from git, but somehow that didn’t work and conflicted with other packages in the virtual env. However, I am attaching the converted .tck
file for your reference. This I created using nibabel.streamlines.load
and the save
method to .tck
which has been used in the above mentioned implementations, where tckinfo
doesn’t work. Please find attached the converted .tck
for your reference.
Regards,
Anoushkrit Goel
OK, the file you sent me has a .tck
extension, but clearly isn’t in our format. It starts with the characters TRACK
, which according to the TrackVis documentation, is what you’d expect for their trk
format. It looks like no conversion was performed at all…
Hi everyone,
just for information, I managed to convert between .tck
and .trk
using DIPY. It has a StatefulTractogram
class that can be used to conveniently convert between various track formats. It was really easy even for me, who is not a Python programmer.
tutorial on the topic DIPY : Docs 1.5.0 - Read/Write streamline files
Best regards
Samuel