[pymvpa] digging for "the hidden treasure" - the PyMVPA atlas module
Yaroslav Halchenko
debian at onerussian.com
Tue Mar 1 19:47:45 UTC 2011
Hi Susanne,
Sorry for the delay with the reply -- Monday happened to be too hectic to sit
down to compose a reply with necessary load of details ;-) And I had to fix
things up mvpa.atlas in pymvpa 0.6.rc*. Description of mvpa.atlases below
might be of interest of others - and I would be eager to hear your opinion on
either you see it useful and what features/interface should be optimal for the
usecases you have.
> space, or simply do not like NIFTI ... not nice. So the only way is to
> refer to some atlas in order to make sure you are referring to the very
> same brain part.
eh, I wish it was that simple... although knowing the nomenclature of brain
imaging would be of great help in orienting yourself in your own findings and
the descriptions of results by others, automagic labeling based on non
subject-derived atlases, should be done with caution and only as
preliminary step before eyeballing the results visually. For more on the topic
please see
Devlin, J. & Poldrack, R.A. (2007). In praise of tedious anatomy. Neuroimage, 37, 1033-41.
http://www.poldracklab.org/Publications/pdfs/Neuroimage%202007%20Devlin.pdf
> brain areas. Again an atlas has to be consulted to launch your MVPA
> analysis straight away on that area of interest.
that is, indeed, where I see a good use for those probabilistic atlases
from FSL -- to constrain feature space to the ballpark of areas of interest.
> '0.6.0~rc1' even seems to support using a standard FSL xml file for the
> atlas (filename) and a custom image file in your subject space
> (image_file).
yeap -- and that was done for 2 reasons:
* to overcome slowness of 'label_voxel|point' function calls which would
possibly apply subject -> MNI (or Talairach transformation) per each call
* to be able simply to spit out masks given a regular expression for the
areas of interest, e.g.:
>> fusiform_mask = atl.get_map(re.compile('Fusiform'), strategy='max')>40
which would gather all components for the Fusiform. And get_maps could be
used to get a set of the "interesting" maps at once.
> So is anybody of you already using the atlas module a lot and can give
> me a hand with the following example:
> - To label: searchlight results in subject space, lets call that
> dataset sl_map
At the moment it would require "manual" step, something like
>> labels = [atl_hoc.label_voxel(x) for x in ds.fa.voxel_indices]
and then cleaning up (selecting among multiple labels based on max
probability). I guess that could be indeed a reason for a helper function --
given at atlas and strategy (e.g. max probability) to resolve multiple hits to
assign some .fa .
Alternatively, there is also yet another utility which you might have not
discovered (yet): bin/atlaslabeler which, given a Nifti image file should
provide you with a summary table... from its limited documentation:
,---
| Usage: /usr/bin/atlaslabeler [OPTIONS] [input_file.nii.gz]
| Examples:
|
| /usr/bin/atlaslabeler -s -A talairach-dist -d 10 -R Closest\ Gray -l Structure,Brodmann\ area -cC mask.nii.gz
|
| produces a summary per each structure and brodmann area, for each voxel
| looking within 10mm radius for the closest gray matter voxel.
`---
unfortunately I have not used it much recently and just now adopted for nibabel
as the backend to access Nifti/Analyze files. More testing is necessary and
there are some outstanding issues with FSL:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=616006
to make it work flawlessly
> - Preferably using Talairach (not my choice) from FSL
Especially in the light of above reference, I would strongly discourage using
an atlas derived from a single 60-years old female with known atypical
properties. Although Talairach atlas has served as the basis for MNI
templates, brains in the two (Talairach vs MNI) do not align, that is why
additional transformation between two systems is necessary. And (surprise!)
there is no known ultimate transformation. The most known/used one is a
piece-wise linear from Matthew Brett. I have not checked but I think that is
the one which was used by FSL folks. there are few more available in
mvpa.atlases.
Moreover, probably realizing that Talairach atlas is anyways mediocre, they
(FSL guys) did not care much about providing adequate transformation from the
original Talairach space into MNI space they have their other atlases in. To
appreciate that, just open corresponding NIFTI file for the atlas and go
through the slices to see something like:
http://www.onerussian.com/tmp/gkrellShoot_03-01-11_084556.png
although they seems have done reasonable job compensating for its small
original size, so for any typical brain voxel you would get some areas.
At some point long ago, whenever Atlas module was conceived (before PyMVPA
existence) I also haven't liked the fact that FSL's atlas description labels by
unique combination of different levels (answer for your
> - what exactly does this levels option do?
i.e.:
<label index="19" x="28" y="58" z="14">Right Cerebrum.Limbic Lobe.Inferior Temporal Gyrus.Gray Matter.Brodmann area 20</label>
that is why I came up with my own version of a Talairach atlas specified
in Talairach space with all level separated. Having not received reply
from Dr.Lancaster whom I asked about copyright/license terms for the
original atlas from http://www.talairach.org/ not knowing that most
probably data such as this atlas is not copyrightable at least in the
states.
The Debian package of that atlas is available from
http://www.onerussian.com/tmp/python-rumba_0.0.10-1_all.deb
and that atlas specifies different "levels":
In [3]: atl_tl.levels
Out[3]:
{0: Labels Level: Laterality [0] ,
1: Labels Level: Lobe [1] ,
2: Labels Level: Structure [2] ,
3: Labels Level: Matter [3] ,
4: Labels Level: Brodmann area [4] ,
'Brodmann area': Labels Level: Brodmann area [4] ,
'Laterality': Labels Level: Laterality [0] ,
'Lobe': Labels Level: Lobe [1] ,
'Matter': Labels Level: Matter [3] ,
'Structure': Labels Level: Structure [2] }
Moreover, since I was interested in the 'Structure' level, but it is often
quite misaligned to the actual subject anatomy, I came up with talairach-dist
atlas, which provides capability to search for the nearest defined labeling at
a given level, e.g. if we query talairach coordinates:
In [6]: atl_tl.label_point([-22, -40, 8])
Out[6]:
{'coord_queried': [-22, -40, 8],
'labels': [{'id': 'Laterality',
'index': 0,
'label': Label(Left Cerebrum, abbr='L', coord=('-29', '-15', '17'), count=652194, index=4)},
{'id': 'Lobe',
'index': 1,
'label': Label(Sub-lobar, abbr='sl', coord=('2', '-9', '8'), count=165879, index=11)},
{'id': 'Structure',
'index': 2,
'label': Label(Lateral Ventricle, abbr='LV', coord=('-2', '-9', '14'), count=17061, index=23)},
{'id': 'Matter',
'index': 3,
'label': Label(Cerebro-Spinal Fluid, abbr='CSF', coord=('0', '-16', '5'), count=18431, index=1)},
{'id': 'Brodmann area',
'index': 4,
'label': Label(None, abbr='', coord=('0', '-17', '12'), count=2203089, index=0)}],
'voxel_atlas': [112, 86, 80],
'voxel_queried': [112, 86, 80]}
We hit CSF (cerebro-spinal fluid) and no broadman area, but if we use
talairach-dist atlas looking for the closest defined 'Brodmann' area, it would
hit corpus callosum (regardless of how fascinating that is) at 1mm distance:
In [9]: atl_tld = Atlas(name='talairach-dist', reference_level='Closest Brodmann', distance=10)
In [10]: atl_tld.label_point([-22, -40, 8])
Out[10]:
{'coord_queried': [-22, -40, 8],
'distance': 1.0,
'labels': [{'id': 'Laterality',
'index': 0,
'label': Label(Left Cerebrum, abbr='L', coord=('-29', '-15', '17'), count=652194, index=4)},
{'id': 'Lobe',
'index': 1,
'label': Label(Sub-lobar, abbr='sl', coord=('2', '-9', '8'), count=165879, index=11)},
{'id': 'Structure',
'index': 2,
'label': Label(Extra-Nuclear, abbr='EN', coord=('2', '-11', '10'), count=75981, index=13)},
{'id': 'Matter',
'index': 3,
'label': Label(White Matter, abbr='WM', coord=('1', '-15', '18'), count=727061, index=3)},
{'id': 'Brodmann area',
'index': 4,
'label': Label(Corpus Callosum, abbr='CC', coord=('0', '-8', '18'), count=18443, index=49)}],
'voxel_atlas': [112, 86, 80],
'voxel_queried': array([111, 86, 80], dtype=uint8),
'voxel_referenced': [112, 86, 80]}
So, that talairach-dist atlas might provide a bit more adequate labeling given
some reasonable distance specification.
> - the coordinate system of the atlas modul [26,26,26] would correspond
> to the sl_map.fa.voxel_indices!?
it should... although due to migration from zyx to xyz order change between
pynifti and nibabel it requires more adition before becoming reliable -- I
have just committed/pushed into our master branch some fixes and additional
tests -- but more remains TODO .
> - the other way round should be possible using the find option!? I
> tried searching for "Cortex", but as soon as there are multiple matches
> the option finishes in an error...
eh, indeed documentation could be greatly improved here:
In [19]: atl_hos.levels[0].find('Cortex', unique=False)
Out[19]:
[Label(Left Cerebral Cortex, coord=('70', '58', '40'), count=0, index=1),
Label(Right Cerebral Cortex, coord=('20', '60', '43'), count=0, index=12)]
> Those multiple sa options are just great. Super comfortable for our
> kind of experiments!
you are welcome ;-)
So, after the dump above -- do you still think we should pursue
mvpa.atlases module to make it easier to use? ;-)
--
=------------------------------------------------------------------=
Keep in touch www.onerussian.com
Yaroslav Halchenko www.ohloh.net/accounts/yarikoptic
More information about the Pkg-ExpPsy-PyMVPA
mailing list