Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MRG: Add subject warping #3613

Merged
merged 13 commits into from
Oct 18, 2016
Merged

MRG: Add subject warping #3613

merged 13 commits into from
Oct 18, 2016

Conversation

larsoner
Copy link
Member

@larsoner larsoner commented Sep 22, 2016

This adds support for warping between subjects using spherical harmonics. The 0th order case is fitting spheres for two sets of points and using translation plus radius-scaling to transform; order 1 uses something like an oblate spheroid, etc.

This can create stuff like this (the stuff of Matti-related nightmares), for order 4 trying to fit a true surface using just dig points (orig surface is gray, dig in dark gray, spherical transformation/deformation in purple, resulting surface in green; [code in a gist](updated 9/29)(https://gist.github.com/Eric89GXL/75f4ee8ee930f5e5bc47cff9d7f0e8e3))

I still need to cross-check with other packages that the transformation is correct. But at least order=0 should be okay, and gives us a way to tackle #2995 and eventually #3527. cc @kambysese these is some progress at least :)

Closes #3611.
Closes #3527.

@codecov-io
Copy link

codecov-io commented Sep 22, 2016

Current coverage is 87.40% (diff: 97.92%)

Merging #3613 into master will increase coverage by 0.03%

@@             master      #3613   diff @@
==========================================
  Files           343        343          
  Lines         60754      60890   +136   
  Methods           0          0          
  Messages          0          0          
  Branches       9302       9308     +6   
==========================================
+ Hits          53084      53222   +138   
+ Misses         4913       4912     -1   
+ Partials       2757       2756     -1   

Sunburst

Powered by Codecov. Last update 468b0ab...42fd65a

@larsoner larsoner force-pushed the warp branch 2 times, most recently from a2d833f to f28f09d Compare September 29, 2016 13:40
@larsoner larsoner changed the title WIP: Add spherical harmonic transformations WIP: Add subject warping Oct 8, 2016
@larsoner
Copy link
Member Author

larsoner commented Oct 8, 2016

Okay @agramfort I think I have this working. Do you want me to clean up the code and improve tests, or actually implement something like DipoleFixed.morph() (morph from subject head space to fsaverage MRI space, which IIRC is MNI talairach...?) so we can see it in action? Or do you have some other example in mind? My slight preference would be to make it two PRs to reduce review burden, but right now there is no example added to the repo.

@larsoner
Copy link
Member Author

larsoner commented Oct 8, 2016

...if you want to review this as-is, I could at least make some hopefully helpful/explanatory image.

@agramfort
Copy link
Member

agramfort commented Oct 9, 2016 via email

@larsoner
Copy link
Member Author

@agramfort should I add fsaverage-head.fif, fsaverage-inner_skull-bem.fif, fsaverage-fiducials.fif, and fsaverage-trans.fif (~1MB total) to the mne/data directory? We probably want to have a template available for plotting, and I don't think those come with FreeSurfer / sample data.

@agramfort
Copy link
Member

fine with me.

On Wed, Oct 12, 2016 at 6:51 PM, Eric Larson [email protected]
wrote:

@agramfort https://github.com/agramfort should I add fsaverage-head.fif,
fsaverage-inner_skull-bem.fif, fsaverage-fiducials.fif, and
fsaverage-trans.fif (~1MB total) to the mne/data directory? We probably
want to have a template available for plotting, and I don't think those
come with FreeSurfer / sample data.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#3613 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAJ1HFJEMEzYqF2lxDzZqpKIBGnvvaTgks5qzRAKgaJpZM4KESK9
.

@ktavabi
Copy link
Contributor

ktavabi commented Oct 12, 2016

This looks great Eric, off course I am hitting some cockameme QT import error on my OSX machine while running the example. Here is the trace:

Traceback (most recent call last):
File "/Users/ktavabi/Projects/mne-python/examples/visualization/plot_warp_surfaces.py", line 59, in
from mayavi import mlab # noqa
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/mayavi/mlab.py", line 27, in
from mayavi.tools.camera import view, roll, yaw, pitch, move
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/mayavi/tools/camera.py", line 25, in
from engine_manager import get_engine
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/mayavi/tools/engine_manager.py", line 12, in
from mayavi.preferences.api import preference_manager
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/mayavi/preferences/api.py", line 4, in
from preference_manager import preference_manager
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/mayavi/preferences/preference_manager.py", line 29, in
from traitsui.api import View, Group, Item
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/traitsui/api.py", line 35, in
from .editors.api import (ArrayEditor, BooleanEditor, ButtonEditor,
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/traitsui/editors/init.py", line 22, in
from .api import (toolkit, ArrayEditor, BooleanEditor, ButtonEditor,
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/traitsui/editors/api.py", line 10, in
from .code_editor import CodeEditor
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/traitsui/editors/code_editor.py", line 36, in
class ToolkitEditorFactory ( EditorFactory ):
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/traitsui/editors/code_editor.py", line 48, in ToolkitEditorFactory
mark_color = Color( 0xECE9D8 )
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/traits/traits.py", line 487, in call
return self.maker_function( _args, *_metadata )
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/traits/traits.py", line 1191, in Color
return ColorTrait( _args, *_metadata )
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/traitsui/toolkit_traits.py", line 7, in ColorTrait
return toolkit().color_trait( _args, *_traits )
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/traitsui/toolkit.py", line 109, in toolkit
_toolkit = _import_toolkit(ETSConfig.toolkit)
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/traitsui/toolkit.py", line 51, in _import_toolkit
return import( name, globals=globals(), level=1 ).toolkit
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/traitsui/qt4/init.py", line 24, in
import toolkit
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/traitsui/qt4/toolkit.py", line 24, in
from pyface.qt import QtCore, QtGui, qt_api
File "/Users/ktavabi/anaconda2/lib/python2.7/site-packages/pyface/qt/QtGui.py", line 4, in
from PyQt4.Qt import QKeySequence, QTextCursor
ImportError: cannot import name QKeySequence

@ktavabi
Copy link
Contributor

ktavabi commented Oct 12, 2016

@Eric89GXL the import error from above seems to be restricted to my OSX machine. Example works on my linux box. I just need to figure out what is going on now.

@larsoner larsoner changed the title WIP: Add subject warping MRG: Add subject warping Oct 13, 2016
@larsoner
Copy link
Member Author

Ready for review/merge from my end. Tests added. Class doc here and example here -- it's not perfect, but should be better than affine.

After this is in, we can think about functions to morph dipole fits, BEM surfaces + source spaces, etc.

:toctree: generated/
:template: class.rst

SphericalHarmonicTPSWarp
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to avoid acronyms in name.

How about:

SphereSplineWarp
SphericalSplineWarp

?

@@ -17,6 +17,8 @@ Changelog

- Add filter plotting functions :func:`mne.viz.plot_filter` and :func:`mne.viz.plot_ideal_filter` as well as filter creation function :func:`mne.filter.create_filter` by `Eric Larson`_

- Add TPS warping with spherical harmonic surface approximations in :class:`mne.transforms.SphericalHarmonicTPSWarp` by `Eric Larson`_
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make acronym clear

fsaverage_trans = mne.read_trans(op.join(fsaverage_path,
'fsaverage-trans.fif'))
for surf in fsaverage_surfs:
mne.surface.transform_surface_to(surf, 'head', fsaverage_trans)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's weird that these functions work inplace no?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah it is abnormal. Worth the deprecation cycle to get to copy=True default or do you want to live with copy=False default (which I will add)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs copy=false ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oof, yes

for surf in sample_surfs:
surf['rr'] = warp.transform(surf['rr'])
# recompute our normals (only used for viz here)
mne.surface.complete_surface_info(surf)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same remark about inplace changes. we should avoid this for public functions. wdyt?

Kind of digitization points to use in the fitting. These can be any
combination of ('cardinal', 'hpi', 'eeg', 'extra'). Can also
be 'auto' (default), which will use only the 'extra' points if
enough are available, and if not, uses 'extra' and 'eeg' points.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you explicit what enough means here?

@@ -112,6 +112,7 @@
op.join('data', 'FreeSurferColorLUT.txt'),
op.join('data', 'image', '*gif'),
op.join('data', 'image', '*lout'),
op.join('data', 'fsaverage', '*.fif'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new files are pushed to pipy?

no need to update manifest.in ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a change in manifest.in, it's the first line of changes in the comparison...?

@larsoner
Copy link
Member Author

Thanks for the review, comments addressed @agramfort. Only remaining issue is if we should deprecate the implicit copy=False in transform_surface_to, since it was already public

@agramfort
Copy link
Member

agramfort commented Oct 16, 2016 via email

@larsoner
Copy link
Member Author

larsoner commented Oct 16, 2016 via email

@agramfort
Copy link
Member

I would go for 
SphericalSurfaceWarpThoughts anyone?

On Sun, Oct 16, 2016 at 3:16 PM +0200, "Eric Larson" [email protected] wrote:

The problem with that is that the TPS warp itself is a spline warp (and

there is a class for that pure operation), what this does is an

approximation/smoothing followed by spline warp. So maybe SmoothSplineWarp?

Actually I think having TPS in the name like SmoothTPSWarp might be okay

because the papers talk about TPS, but it does involve another TLA.

We could also go less specific with something like SmoothedSurfaceWarp or

SphericalSurfaceWarp (because it does rely on the surfaces being low-order

sphere-like).


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

@@ -926,7 +928,7 @@ def _col_norm_pinv(x):


def _sq(x):
"""Helper to square"""
"""Square quickly."""
return x * x
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is weird. Is this used somewhere?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about import numpy.square as _sq?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is actually a little bit slower:

>>> timeit.timeit('_sq(x)', setup='import numpy as np; x = np.random.RandomState(0).rand(1000); _sq = lambda x: x * x')
1.4139869213104248
>>> timeit.timeit('np.square(x)', setup='import numpy as np; x = np.random.RandomState(0).rand(1000); _sq = lambda x: x * x')
1.6284921169281006

@larsoner
Copy link
Member Author

larsoner commented Oct 17, 2016 via email

@agramfort
Copy link
Member

+1 for merge when CIs are happy.

thx @Eric89GXL

@larsoner
Copy link
Member Author

CIs are happy

@larsoner
Copy link
Member Author

Fixed

@agramfort agramfort merged commit c44781d into mne-tools:master Oct 18, 2016
@agramfort
Copy link
Member

thanks @Eric89GXL !

@larsoner
Copy link
Member Author

larsoner commented Oct 18, 2016 via email

jona-sassenhagen added a commit that referenced this pull request Oct 24, 2016
#3613 breaks .elp reading by doing a transpose at the wrong time. This fixes it.
This was referenced Oct 24, 2016
@larsoner larsoner deleted the warp branch November 28, 2016 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants