ClandininLab / brainsss2

refactor of the brainsss repo for 2-photon imaging analysis
MIT License
0 stars 0 forks source link

fix atlas_registration inverse transform from atlas to func #27

Closed poldrack closed 2 years ago

poldrack commented 2 years ago

the individual registrations from func->anat and anat->atlas seem to be working properly, but the composite inverse transform from atlas-> func is still failing. need to figure out why...

poldrack commented 2 years ago

@lukebrez interested to hear if you have thoughts on how to fix this...

bellabrez commented 2 years ago

ok so this could be an issue with the order of the transforms in the "transformlist" input to apply_transforms, or could be an issue with the inverse transform itself (or both).

Regarding the transformlist, the order of that list is pretty confusing and an important detail is hidden in the docs. apply_transforms has an input whichtoinvert, which says "(list of booleans (optional)) – Must be same length as transformlist. whichtoinvert[i] is True if transformlist[i] is a matrix, and the matrix should be inverted. If transformlist[i] is a warp field, whichtoinvert[i] must be False. If the transform list is a matrix followed by a warp field, whichtoinvert defaults to (True,False). Otherwise it defaults to [False]*len(transformlist))." So to be honest I can't even wrap my head around this, but @rueberger says this means if you do a SyN warp, which outputs a matrix and warp field, if you want to apply those transforms you need to provide the transform list as [warp field, matrix], which is the reverse of what I would have assumed. Furthermore, if you do an affine from func->anat, then SyN from anat->template, and then you want to apply those transforms, the list would be [aff['fwdtransforms'][0], syn['fwdtransforms'][0],syn['fwdtransforms'][1]] (sorry I forget if the first element of syn['fwdtransforms'] is a matrix or warp field).

Regarding the inverse transform, I think there may be a serious issue here of the inverse transforms actually being identical to the forward transforms, such that you may just want to re-run the registration in the other direction. @rueberger can set us straight here - is this true?

poldrack commented 2 years ago

thanks - I think I have figured it out. the problem is that the registration intermittently fails (on the same data) - but when it works I have it properly getting the same image from func to atlas space and back again. there is preliminarily work in tests/test_register.py - I'm doing more testing now, will update you.

On Wed, Jun 8, 2022 at 9:45 AM Luke Brezovec @.***> wrote:

ok so this could be an issue with the order of the transforms in the "transformlist" input to apply_transforms, or could be an issue with the inverse transform itself (or both).

Regarding the transformlist, the order of that list is pretty confusing and an important detail is hidden in the docs. apply_transforms has an input whichtoinvert, which says "(list of booleans (optional)) – Must be same length as transformlist. whichtoinvert[i] is True if transformlist[i] is a matrix, and the matrix should be inverted. If transformlist[i] is a warp field, whichtoinvert[i] must be False. If the transform list is a matrix followed by a warp field, whichtoinvert defaults to (True,False). Otherwise it defaults to [False]*len(transformlist))." So to be honest I can't even wrap my head around this, but @rueberger https://github.com/rueberger says this means if you do a SyN warp, which outputs a matrix and warp field, if you want to apply those transforms you need to provide the transform list as [warp field, matrix], which is the reverse of what I would have assumed. Furthermore, if you do an affine from func->anat, then SyN from anat->template, and then you want to apply those transforms, the list would be [aff['fwdtransforms'][0], syn['fwdtransforms'][0],syn['fwdtransforms'][1]] (sorry I forget if the first element of syn['fwdtransforms'] is a matrix or warp field).

Regarding the inverse transform, I think there may be a serious issue here of the inverse transforms actually being identical to the forward transforms, such that you may just want to re-run the registration in the other direction. @rueberger https://github.com/rueberger can set us straight here - is this true?

— Reply to this email directly, view it on GitHub https://github.com/ClandininLab/brainsss2/issues/27#issuecomment-1150152270, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAGUVEGTBT722CERJAG7NKTVODE2LANCNFSM5YDVUSMQ . You are receiving this because you authored the thread.Message ID: @.***>

-- Russell A. Poldrack Albert Ray Lang Professor of Psychology Associate Director, Stanford Data Science Director, SDS Center for Open and Reproducible Science Building 420 Stanford University Stanford, CA 94305

@. @.> http://www.poldracklab.org/

rueberger commented 2 years ago

Regarding the inverse transform, I think there may be a serious issue here of the inverse transforms actually being identical to the forward transforms, such that you may just want to re-run the registration in the other direction. @rueberger can set us straight here - is this true?

can't comment on what's happening in this library but for ants the story is that, for reasons beyond my understanding, the forward and inverse affines returned by a registration are identical.

ie:

aff = ants.registration(f, m, type_of_transform='Affine')
# passes
assert aff['fwdtransforms'][0] == aff['invtransforms'][0]

the forward and inverse warp fields for a SyN registration are actually forward and inverted though.

this leads to the insane default behavior of whichtoinvert

I did some experiments a couple weeks back to validate the order of the forward transform list, if it would be useful I can do the same for the inverse and we can put it in a wiki or something

poldrack commented 2 years ago

yeah, the whole approach is rather odd. tests/test_register.py is now passing, and it includes the full pathway including both forward and inverse transforms, so it can serve as an example. I don't want to check the testdata into the git repo since they are big but I am happy to put them somewhere to share if you ever want to run the tests.

rueberger commented 2 years ago

do you know about git lfs?

poldrack commented 2 years ago

know about it (as well as git-annex which is more popular in our neck of the woods as it's the basis for datalad). but have never actually gotten my head around how to use it in practice.

poldrack commented 2 years ago

fixed, see solution in tests/test_register.py