Question about manual rigid registration with Transform module

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Question about manual rigid registration with Transform module

Jean-David Jutras
Hello, I am new to 3D Slicer. I have been using the Transform module to do simple 3D rigid registration of a MRI phantom dataset to a CT dataset. I loaded dicom files created in Matlab after some post-processing for both the MRI and CT in order to match the geometry and resolution, and clean up bad information that was causing the datasets to be too far apart. I noticed that the units of translations appear to be in pixel values, rather than mm, and the units of rotation are in degrees. Now the thing I don't like is that 3D slicer does not allow me to make shifts to sub-pixel accuracy. Moreover, it allows rotation increments to the nearest 1 degree, but nothing in between. I have tried to work around this problem by up-sampling my image matrices to 512x512x400 slices, with resolution of 0.469x0.469x0.5 mm. Now I can already get a good registration using translations only, however, the rotation increments are still in steps of 1 degree. I was wondering if there is a way to achieve sub-pixel translations and sub-degree rotations. I noticed that this appears to be possible when looking at a 3D Slicer tutorial on the Transform Module. Perhaps I need to specify something else when writing dicom files in Matlab to enable this feature? Does anyone know what I should try?

Regards,
Jean-David Jutras

_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject
Reply | Threaded
Open this post in threaded view
|

Re: Question about manual rigid registration with Transform module

Sharp, Gregory C.
Dear Jean-David,
 
I tried the transform module with image of 1 cm voxel size. 
For me, shifting by 1 unit means 1 mm instead of 1 voxel.
Can you give more information about why you think it is 1 voxel
instead of 1 mm?
 
To get sub-mm shift, you need to type in the numbers in the field to the right
of the sliders.  However, as you state, this is quite inconvenient for precise alignment. 
There seems to be no way to configure these sliders.   I recommend file a feature
request in the bug tracker. 
 
 
Greg
 
 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Jean-David Jutras
Sent: Tuesday, March 12, 2013 1:23 PM
To: [hidden email]
Subject: [slicer-users] Question about manual rigid registration with Transform module

Hello, I am new to 3D Slicer. I have been using the Transform module to do simple 3D rigid registration of a MRI phantom dataset to a CT dataset. I loaded dicom files created in Matlab after some post-processing for both the MRI and CT in order to match the geometry and resolution, and clean up bad information that was causing the datasets to be too far apart. I noticed that the units of translations appear to be in pixel values, rather than mm, and the units of rotation are in degrees. Now the thing I don't like is that 3D slicer does not allow me to make shifts to sub-pixel accuracy. Moreover, it allows rotation increments to the nearest 1 degree, but nothing in between. I have tried to work around this problem by up-sampling my image matrices to 512x512x400 slices, with resolution of 0.469x0.469x0.5 mm. Now I can already get a good registration using translations only, however, the rotation increments are still in steps of 1 degree. I was wondering if there is a way to achieve sub-pixel translations and sub-degree rotations. I noticed that this appears to be possible when looking at a 3D Slicer tutorial on the Transform Module. Perhaps I need to specify something else when writing dicom files in Matlab to enable this feature? Does anyone know what I should try?

Regards,
Jean-David Jutras

_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject
Reply | Threaded
Open this post in threaded view
|

Re: Question about manual rigid registration with Transform module

Dominik Meier
In reply to this post by Jean-David Jutras
If your images have enough coverage and similarity in the content you could try an automated intensity based registration starting from your manual alignment and see if you get a lock.
Alternatively you can try a fiducial-based alignment; placement of fiducials might be easier than operating rotational controls.

-- Dominik

On Mar 12, 2013, at 1:23 PM, Jean-David Jutras <[hidden email]> wrote:

> Hello, I am new to 3D Slicer. I have been using the Transform module to do simple 3D rigid registration of a MRI phantom dataset to a CT dataset. I loaded dicom files created in Matlab after some post-processing for both the MRI and CT in order to match the geometry and resolution, and clean up bad information that was causing the datasets to be too far apart. I noticed that the units of translations appear to be in pixel values, rather than mm, and the units of rotation are in degrees. Now the thing I don't like is that 3D slicer does not allow me to make shifts to sub-pixel accuracy. Moreover, it allows rotation increments to the nearest 1 degree, but nothing in between. I have tried to work around this problem by up-sampling my image matrices to 512x512x400 slices, with resolution of 0.469x0.469x0.5 mm. Now I can already get a good registration using translations only, however, the rotation increments are still in steps of 1 degree. I was wondering if there is a way to !
 achieve sub-pixel translations and sub-degree rotations. I noticed that this appears to be possible when looking at a 3D Slicer tutorial on the Transform Module. Perhaps I need to specify something else when writing dicom files in Matlab to enable this feature? Does anyone know what I should try?
>
> Regards,
> Jean-David Jutras
> _______________________________________________
> slicer-users mailing list
> [hidden email]
> http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
> To unsubscribe: send email to [hidden email] with unsubscribe as the subject

_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject
Reply | Threaded
Open this post in threaded view
|

Fwd: Question about manual rigid registration with Transform module

Sudden Imphead
In reply to this post by Jean-David Jutras

On Tue, Mar 12, 2013 at 1:23 PM, Jean-David Jutras <[hidden email]> wrote:
 I noticed that the units of translations appear to be in pixel values, rather than mm,

No, I don't think that's true. It's mm all over (or rather: the same unit, whatever you *choose* it to be, normally the mm unit stems from DICOM convention).
 
and the units of rotation are in degrees. Now the thing I don't like is that 3D slicer does not allow me to make shifts to sub-pixel accuracy.
Moreover, it allows rotation increments to the nearest 1 degree, but nothing in between.

The sliders in Transforms module will allow numeric entry of tenths and hundreths, but their stepping is still 1mm (or whatever base unit you choose) and 1 degree. You could multiply all numbers by 10 just using a transform matrix that contains an upper left  submatrix 

   = 10 x (3x3 diagonal identity matrix) 

and then harden into your volume. Then you shouldn't have to resample I'd think. That doesn't solve your degree problem, however.

I'd very much like to change this stepping value as well for customizing user interfaces. I almost succeeded: I could retrieve the widget:

 wr=slicer.modules.transforms.widgetRepresentation()

We should be able to access the innards from there (?) I got lost in the Qt and XML metaprogramming of TranslationSliders in the C++ code and some of the fields are non-public.  

Can anybody reveal the last couple of steps? So close but no cigar...

For extremely accurate transforms (the matrix element fields in 3D Slicer allow only 2 decimals!)  I make a text file with a little Python snippet as below where I define a 4x4 matrix trans13 like:

try:
  trans13
except NameError:
    trans13 = slicer.vtkMRMLLinearTransformNode()
    trans13.SetName('trans13')
    slicer.mrmlScene.AddNode(trans13)

matrix13 = vtk.vtkMatrix4x4()
angle = math.pi / 180.0 * 13.0 # 13 degress
matrix13.DeepCopy([ -1, 0, 0, 0,
                     0, -1, -math.sin(angle), 0,
                     0, 0, math.cos(angle), 0,
                     0, 0, 0, 1])

trans13.SetAndObserveMatrixTransformToParent(matrix13)

That's much easier than trying to fiddle with the tmf file format which uses inverted and transposed matrices. If you're a programmer, you could probably make your own little Python scripting module with your own buttons for tweaking matrices via the vtkMRMLLinearTransformNode.

Sudden

PS: Also, see bug http://na-mic.org/Mantis/view.php?id=2579 by sbillin, who simply patched the source code for own use.

_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Question about manual rigid registration with Transform module

Steve Pieper
Hi - 

If you want to do a hack to change the sensitivity of the sliders, enter the transforms module and then paste the following code into the python console.

for s in findChildren(findChildren(text='LR')[0].parent().parent().parent(),className='qMRMLLinearTransformSlider'): s.singleStep = 0.0001; s.decimals = 5; s.pageStep = 0.001

-Steve


On Tue, Mar 12, 2013 at 5:38 PM, Sudden Imphead <[hidden email]> wrote:

On Tue, Mar 12, 2013 at 1:23 PM, Jean-David Jutras <[hidden email]> wrote:
 I noticed that the units of translations appear to be in pixel values, rather than mm,

No, I don't think that's true. It's mm all over (or rather: the same unit, whatever you *choose* it to be, normally the mm unit stems from DICOM convention).
 
and the units of rotation are in degrees. Now the thing I don't like is that 3D slicer does not allow me to make shifts to sub-pixel accuracy.
Moreover, it allows rotation increments to the nearest 1 degree, but nothing in between.

The sliders in Transforms module will allow numeric entry of tenths and hundreths, but their stepping is still 1mm (or whatever base unit you choose) and 1 degree. You could multiply all numbers by 10 just using a transform matrix that contains an upper left  submatrix 

   = 10 x (3x3 diagonal identity matrix) 

and then harden into your volume. Then you shouldn't have to resample I'd think. That doesn't solve your degree problem, however.

I'd very much like to change this stepping value as well for customizing user interfaces. I almost succeeded: I could retrieve the widget:

 wr=slicer.modules.transforms.widgetRepresentation()

We should be able to access the innards from there (?) I got lost in the Qt and XML metaprogramming of TranslationSliders in the C++ code and some of the fields are non-public.  

Can anybody reveal the last couple of steps? So close but no cigar...

For extremely accurate transforms (the matrix element fields in 3D Slicer allow only 2 decimals!)  I make a text file with a little Python snippet as below where I define a 4x4 matrix trans13 like:

try:
  trans13
except NameError:
    trans13 = slicer.vtkMRMLLinearTransformNode()
    trans13.SetName('trans13')
    slicer.mrmlScene.AddNode(trans13)

matrix13 = vtk.vtkMatrix4x4()
angle = math.pi / 180.0 * 13.0 # 13 degress
matrix13.DeepCopy([ -1, 0, 0, 0,
                     0, -1, -math.sin(angle), 0,
                     0, 0, math.cos(angle), 0,
                     0, 0, 0, 1])

trans13.SetAndObserveMatrixTransformToParent(matrix13)

That's much easier than trying to fiddle with the tmf file format which uses inverted and transposed matrices. If you're a programmer, you could probably make your own little Python scripting module with your own buttons for tweaking matrices via the vtkMRMLLinearTransformNode.

Sudden

PS: Also, see bug http://na-mic.org/Mantis/view.php?id=2579 by sbillin, who simply patched the source code for own use.

_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject


_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject
Reply | Threaded
Open this post in threaded view
|

Fwd: Fwd: Question about manual rigid registration with Transform module

Sudden Imphead
Thanks Steve, wow, this helps me tremendously! (And others too I'm sure,) 

It's really neat that in one fell stroke you specify both the meaning of the page up/down and the up/down arrow keys. 

I'd be interested in your comments for a couple of really basic questions!

Why didn't you use the simpler one-liner:

   for s in findChildren(className='qMRMLLinearTransformSlider'): s.singleStep = 0.0001; s.decimals = 5; s.pageStep = 0.001

??

In your one-liner you seem to look for the text property node with <string>LR</string> in the XML file qMRMLTransformSlider.ui (Slicer source code) and then going up three widgets (ctkCollapsibleGroupBox -> qMRMLTransformSliders -> ctkCollapsibleButton) which brings you to a master widget (?) of sorts of type ctkCollapsibleButton (that I couldn't find, but I'm just a beginner). Is this approach more robust?

Also, I think I learned from your example that slicer.util is an unnecessary prefix in the console (although the very first example in the http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Developers/Python_scripting uses it). (slicer.util.loadVolume is loadVolume evaluates to true.) Maybe update the Wiki?

I also learned that findChildren is a Qt misnomer for "find descendants" -- that's laid out in http://qt-project.org/doc/qt-4.8/qobject.html#findChildren -- that confused me as I started reading the code, not Slicer folks fault of course.  I hope more tidbits like this can be gathered in the Wiki to help others who are new to the amazing possibilities that Qt-based Slicer offers for customizing. I'd recommend the tutorial http://www.slicer.org/slicerWiki/index.php/4.0/Training#Slicer4_Programming_Tutorial BTW for anyone who found Steve's one-liner interesting.

Getting back to Jean-David's question, something like the forced one-liner: 

for s in [ s for s in findChildren(className='qMRMLLinearTransformSlider') if s.parent().parent().Title == u'Rotation' ]: s.singleStep = 0.1; s.decimals = 5; s.pageStep = 1

would set the rotational steps alone.

S


On Tue, Mar 12, 2013 at 6:18 PM, Steve Pieper <[hidden email]> wrote:
Hi - 

If you want to do a hack to change the sensitivity of the sliders, enter the transforms module and then paste the following code into the python console.

for s in findChildren(findChildren(text='LR')[0].parent().parent().parent(),className='qMRMLLinearTransformSlider'): s.singleStep = 0.0001; s.decimals = 5; s.pageStep = 0.001

-Steve


On Tue, Mar 12, 2013 at 5:38 PM, Sudden Imphead <[hidden email]> wrote:

On Tue, Mar 12, 2013 at 1:23 PM, Jean-David Jutras <[hidden email]> wrote:
 I noticed that the units of translations appear to be in pixel values, rather than mm,

No, I don't think that's true. It's mm all over (or rather: the same unit, whatever you *choose* it to be, normally the mm unit stems from DICOM convention).
 
and the units of rotation are in degrees. Now the thing I don't like is that 3D slicer does not allow me to make shifts to sub-pixel accuracy.
Moreover, it allows rotation increments to the nearest 1 degree, but nothing in between.

The sliders in Transforms module will allow numeric entry of tenths and hundreths, but their stepping is still 1mm (or whatever base unit you choose) and 1 degree. You could multiply all numbers by 10 just using a transform matrix that contains an upper left  submatrix 

   = 10 x (3x3 diagonal identity matrix) 

and then harden into your volume. Then you shouldn't have to resample I'd think. That doesn't solve your degree problem, however.

I'd very much like to change this stepping value as well for customizing user interfaces. I almost succeeded: I could retrieve the widget:

 wr=slicer.modules.transforms.widgetRepresentation()

We should be able to access the innards from there (?) I got lost in the Qt and XML metaprogramming of TranslationSliders in the C++ code and some of the fields are non-public.  

Can anybody reveal the last couple of steps? So close but no cigar...

For extremely accurate transforms (the matrix element fields in 3D Slicer allow only 2 decimals!)  I make a text file with a little Python snippet as below where I define a 4x4 matrix trans13 like:

try:
  trans13
except NameError:
    trans13 = slicer.vtkMRMLLinearTransformNode()
    trans13.SetName('trans13')
    slicer.mrmlScene.AddNode(trans13)

matrix13 = vtk.vtkMatrix4x4()
angle = math.pi / 180.0 * 13.0 # 13 degress
matrix13.DeepCopy([ -1, 0, 0, 0,
                     0, -1, -math.sin(angle), 0,
                     0, 0, math.cos(angle), 0,
                     0, 0, 0, 1])

trans13.SetAndObserveMatrixTransformToParent(matrix13)

That's much easier than trying to fiddle with the tmf file format which uses inverted and transposed matrices. If you're a programmer, you could probably make your own little Python scripting module with your own buttons for tweaking matrices via the vtkMRMLLinearTransformNode.

Sudden

PS: Also, see bug http://na-mic.org/Mantis/view.php?id=2579 by sbillin, who simply patched the source code for own use.

_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject




_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Fwd: Question about manual rigid registration with Transform module

Jean-David Jutras
Ok, thank you for your help. Indeed, sub-millimeter increments do work if I type in the values rather than use the scroll bars. I guess it is just a little bit buggy.

Jean-David 

On Tue, Mar 12, 2013 at 7:50 PM, Sudden Imphead <[hidden email]> wrote:
Thanks Steve, wow, this helps me tremendously! (And others too I'm sure,) 

It's really neat that in one fell stroke you specify both the meaning of the page up/down and the up/down arrow keys. 

I'd be interested in your comments for a couple of really basic questions!

Why didn't you use the simpler one-liner:

   for s in findChildren(className='qMRMLLinearTransformSlider'): s.singleStep = 0.0001; s.decimals = 5; s.pageStep = 0.001

??

In your one-liner you seem to look for the text property node with <string>LR</string> in the XML file qMRMLTransformSlider.ui (Slicer source code) and then going up three widgets (ctkCollapsibleGroupBox -> qMRMLTransformSliders -> ctkCollapsibleButton) which brings you to a master widget (?) of sorts of type ctkCollapsibleButton (that I couldn't find, but I'm just a beginner). Is this approach more robust?

Also, I think I learned from your example that slicer.util is an unnecessary prefix in the console (although the very first example in the http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Developers/Python_scripting uses it). (slicer.util.loadVolume is loadVolume evaluates to true.) Maybe update the Wiki?

I also learned that findChildren is a Qt misnomer for "find descendants" -- that's laid out in http://qt-project.org/doc/qt-4.8/qobject.html#findChildren -- that confused me as I started reading the code, not Slicer folks fault of course.  I hope more tidbits like this can be gathered in the Wiki to help others who are new to the amazing possibilities that Qt-based Slicer offers for customizing. I'd recommend the tutorial http://www.slicer.org/slicerWiki/index.php/4.0/Training#Slicer4_Programming_Tutorial BTW for anyone who found Steve's one-liner interesting.

Getting back to Jean-David's question, something like the forced one-liner: 

for s in [ s for s in findChildren(className='qMRMLLinearTransformSlider') if s.parent().parent().Title == u'Rotation' ]: s.singleStep = 0.1; s.decimals = 5; s.pageStep = 1

would set the rotational steps alone.

S


On Tue, Mar 12, 2013 at 6:18 PM, Steve Pieper <[hidden email]> wrote:
Hi - 

If you want to do a hack to change the sensitivity of the sliders, enter the transforms module and then paste the following code into the python console.

for s in findChildren(findChildren(text='LR')[0].parent().parent().parent(),className='qMRMLLinearTransformSlider'): s.singleStep = 0.0001; s.decimals = 5; s.pageStep = 0.001

-Steve


On Tue, Mar 12, 2013 at 5:38 PM, Sudden Imphead <[hidden email]> wrote:

On Tue, Mar 12, 2013 at 1:23 PM, Jean-David Jutras <[hidden email]> wrote:
 I noticed that the units of translations appear to be in pixel values, rather than mm,

No, I don't think that's true. It's mm all over (or rather: the same unit, whatever you *choose* it to be, normally the mm unit stems from DICOM convention).
 
and the units of rotation are in degrees. Now the thing I don't like is that 3D slicer does not allow me to make shifts to sub-pixel accuracy.
Moreover, it allows rotation increments to the nearest 1 degree, but nothing in between.

The sliders in Transforms module will allow numeric entry of tenths and hundreths, but their stepping is still 1mm (or whatever base unit you choose) and 1 degree. You could multiply all numbers by 10 just using a transform matrix that contains an upper left  submatrix 

   = 10 x (3x3 diagonal identity matrix) 

and then harden into your volume. Then you shouldn't have to resample I'd think. That doesn't solve your degree problem, however.

I'd very much like to change this stepping value as well for customizing user interfaces. I almost succeeded: I could retrieve the widget:

 wr=slicer.modules.transforms.widgetRepresentation()

We should be able to access the innards from there (?) I got lost in the Qt and XML metaprogramming of TranslationSliders in the C++ code and some of the fields are non-public.  

Can anybody reveal the last couple of steps? So close but no cigar...

For extremely accurate transforms (the matrix element fields in 3D Slicer allow only 2 decimals!)  I make a text file with a little Python snippet as below where I define a 4x4 matrix trans13 like:

try:
  trans13
except NameError:
    trans13 = slicer.vtkMRMLLinearTransformNode()
    trans13.SetName('trans13')
    slicer.mrmlScene.AddNode(trans13)

matrix13 = vtk.vtkMatrix4x4()
angle = math.pi / 180.0 * 13.0 # 13 degress
matrix13.DeepCopy([ -1, 0, 0, 0,
                     0, -1, -math.sin(angle), 0,
                     0, 0, math.cos(angle), 0,
                     0, 0, 0, 1])

trans13.SetAndObserveMatrixTransformToParent(matrix13)

That's much easier than trying to fiddle with the tmf file format which uses inverted and transposed matrices. If you're a programmer, you could probably make your own little Python scripting module with your own buttons for tweaking matrices via the vtkMRMLLinearTransformNode.

Sudden

PS: Also, see bug http://na-mic.org/Mantis/view.php?id=2579 by sbillin, who simply patched the source code for own use.

_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject




_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject


_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Fwd: Question about manual rigid registration with Transform module

Steve Pieper
In reply to this post by Sudden Imphead
Hi S - 

I like your improved one-liners - even if you are 'just a beginner' as you say, you've certainly gotten into the good stuff quickly!

Regarding robustness of these approaches, well, that's why I used the term 'hack' in my email, since a small change in the slicer layout or the displayed name of a widget can cause this one-liner to break.  Not for a given release, but maybe the next release will have a new transform module with different widgets.  Of course, when you need to get something done, like tweak the registration parameters and it's just one line of code I think it's a reasonable approach - but beware, it could be a slippery slope.  The 'right thing' would be for the module to provide a settings dialog to allow users to configure the sliders directly, but that's a bigger job.

Regarding putting more examples on the wiki: yes!  We need to flesh this out, and organize things better.  If you want to make edits, contributions would be very gratefully accepted.  Here's the right page for new material that works with the current nightly build [1].  Also, for scripts Jc has been using gists which is a great way to store medium sized snippets [2].

As for slicer.util.findChildren vs findChildren - either is fine as long as they actually refer to the same method (slicer.util.findChildren is different than QObject::findChildren).  I typically prefer the fully qualified version in code but use the shorter version at the prompt. 



Thanks for your interest and enthusiasm,
-Steve

On Tue, Mar 12, 2013 at 9:50 PM, Sudden Imphead <[hidden email]> wrote:
Thanks Steve, wow, this helps me tremendously! (And others too I'm sure,) 

It's really neat that in one fell stroke you specify both the meaning of the page up/down and the up/down arrow keys. 

I'd be interested in your comments for a couple of really basic questions!

Why didn't you use the simpler one-liner:

   for s in findChildren(className='qMRMLLinearTransformSlider'): s.singleStep = 0.0001; s.decimals = 5; s.pageStep = 0.001

??

In your one-liner you seem to look for the text property node with <string>LR</string> in the XML file qMRMLTransformSlider.ui (Slicer source code) and then going up three widgets (ctkCollapsibleGroupBox -> qMRMLTransformSliders -> ctkCollapsibleButton) which brings you to a master widget (?) of sorts of type ctkCollapsibleButton (that I couldn't find, but I'm just a beginner). Is this approach more robust?

Also, I think I learned from your example that slicer.util is an unnecessary prefix in the console (although the very first example in the http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Developers/Python_scripting uses it). (slicer.util.loadVolume is loadVolume evaluates to true.) Maybe update the Wiki?

I also learned that findChildren is a Qt misnomer for "find descendants" -- that's laid out in http://qt-project.org/doc/qt-4.8/qobject.html#findChildren -- that confused me as I started reading the code, not Slicer folks fault of course.  I hope more tidbits like this can be gathered in the Wiki to help others who are new to the amazing possibilities that Qt-based Slicer offers for customizing. I'd recommend the tutorial http://www.slicer.org/slicerWiki/index.php/4.0/Training#Slicer4_Programming_Tutorial BTW for anyone who found Steve's one-liner interesting.

Getting back to Jean-David's question, something like the forced one-liner: 

for s in [ s for s in findChildren(className='qMRMLLinearTransformSlider') if s.parent().parent().Title == u'Rotation' ]: s.singleStep = 0.1; s.decimals = 5; s.pageStep = 1

would set the rotational steps alone.

S


On Tue, Mar 12, 2013 at 6:18 PM, Steve Pieper <[hidden email]> wrote:
Hi - 

If you want to do a hack to change the sensitivity of the sliders, enter the transforms module and then paste the following code into the python console.

for s in findChildren(findChildren(text='LR')[0].parent().parent().parent(),className='qMRMLLinearTransformSlider'): s.singleStep = 0.0001; s.decimals = 5; s.pageStep = 0.001

-Steve


On Tue, Mar 12, 2013 at 5:38 PM, Sudden Imphead <[hidden email]> wrote:

On Tue, Mar 12, 2013 at 1:23 PM, Jean-David Jutras <[hidden email]> wrote:
 I noticed that the units of translations appear to be in pixel values, rather than mm,

No, I don't think that's true. It's mm all over (or rather: the same unit, whatever you *choose* it to be, normally the mm unit stems from DICOM convention).
 
and the units of rotation are in degrees. Now the thing I don't like is that 3D slicer does not allow me to make shifts to sub-pixel accuracy.
Moreover, it allows rotation increments to the nearest 1 degree, but nothing in between.

The sliders in Transforms module will allow numeric entry of tenths and hundreths, but their stepping is still 1mm (or whatever base unit you choose) and 1 degree. You could multiply all numbers by 10 just using a transform matrix that contains an upper left  submatrix 

   = 10 x (3x3 diagonal identity matrix) 

and then harden into your volume. Then you shouldn't have to resample I'd think. That doesn't solve your degree problem, however.

I'd very much like to change this stepping value as well for customizing user interfaces. I almost succeeded: I could retrieve the widget:

 wr=slicer.modules.transforms.widgetRepresentation()

We should be able to access the innards from there (?) I got lost in the Qt and XML metaprogramming of TranslationSliders in the C++ code and some of the fields are non-public.  

Can anybody reveal the last couple of steps? So close but no cigar...

For extremely accurate transforms (the matrix element fields in 3D Slicer allow only 2 decimals!)  I make a text file with a little Python snippet as below where I define a 4x4 matrix trans13 like:

try:
  trans13
except NameError:
    trans13 = slicer.vtkMRMLLinearTransformNode()
    trans13.SetName('trans13')
    slicer.mrmlScene.AddNode(trans13)

matrix13 = vtk.vtkMatrix4x4()
angle = math.pi / 180.0 * 13.0 # 13 degress
matrix13.DeepCopy([ -1, 0, 0, 0,
                     0, -1, -math.sin(angle), 0,
                     0, 0, math.cos(angle), 0,
                     0, 0, 0, 1])

trans13.SetAndObserveMatrixTransformToParent(matrix13)

That's much easier than trying to fiddle with the tmf file format which uses inverted and transposed matrices. If you're a programmer, you could probably make your own little Python scripting module with your own buttons for tweaking matrices via the vtkMRMLLinearTransformNode.

Sudden

PS: Also, see bug http://na-mic.org/Mantis/view.php?id=2579 by sbillin, who simply patched the source code for own use.

_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject




_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject


_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Fwd: Question about manual rigid registration with Transform module

Sudden Imphead
Great pointers Steve! I'll try whether I can help with Wiki -- a lot of what's flying by on the mailing list would belong there as well I just realize.
S


On Wed, Mar 13, 2013 at 9:35 AM, Steve Pieper <[hidden email]> wrote:
Hi S - 

I like your improved one-liners - even if you are 'just a beginner' as you say, you've certainly gotten into the good stuff quickly!

Regarding robustness of these approaches, well, that's why I used the term 'hack' in my email, since a small change in the slicer layout or the displayed name of a widget can cause this one-liner to break.  Not for a given release, but maybe the next release will have a new transform module with different widgets.  Of course, when you need to get something done, like tweak the registration parameters and it's just one line of code I think it's a reasonable approach - but beware, it could be a slippery slope.  The 'right thing' would be for the module to provide a settings dialog to allow users to configure the sliders directly, but that's a bigger job.

Regarding putting more examples on the wiki: yes!  We need to flesh this out, and organize things better.  If you want to make edits, contributions would be very gratefully accepted.  Here's the right page for new material that works with the current nightly build [1].  Also, for scripts Jc has been using gists which is a great way to store medium sized snippets [2].

As for slicer.util.findChildren vs findChildren - either is fine as long as they actually refer to the same method (slicer.util.findChildren is different than QObject::findChildren).  I typically prefer the fully qualified version in code but use the shorter version at the prompt. 



Thanks for your interest and enthusiasm,
-Steve


On Tue, Mar 12, 2013 at 9:50 PM, Sudden Imphead <[hidden email]> wrote:
Thanks Steve, wow, this helps me tremendously! (And others too I'm sure,) 

It's really neat that in one fell stroke you specify both the meaning of the page up/down and the up/down arrow keys. 

I'd be interested in your comments for a couple of really basic questions!

Why didn't you use the simpler one-liner:

   for s in findChildren(className='qMRMLLinearTransformSlider'): s.singleStep = 0.0001; s.decimals = 5; s.pageStep = 0.001

??

In your one-liner you seem to look for the text property node with <string>LR</string> in the XML file qMRMLTransformSlider.ui (Slicer source code) and then going up three widgets (ctkCollapsibleGroupBox -> qMRMLTransformSliders -> ctkCollapsibleButton) which brings you to a master widget (?) of sorts of type ctkCollapsibleButton (that I couldn't find, but I'm just a beginner). Is this approach more robust?

Also, I think I learned from your example that slicer.util is an unnecessary prefix in the console (although the very first example in the http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Developers/Python_scripting uses it). (slicer.util.loadVolume is loadVolume evaluates to true.) Maybe update the Wiki?

I also learned that findChildren is a Qt misnomer for "find descendants" -- that's laid out in http://qt-project.org/doc/qt-4.8/qobject.html#findChildren -- that confused me as I started reading the code, not Slicer folks fault of course.  I hope more tidbits like this can be gathered in the Wiki to help others who are new to the amazing possibilities that Qt-based Slicer offers for customizing. I'd recommend the tutorial http://www.slicer.org/slicerWiki/index.php/4.0/Training#Slicer4_Programming_Tutorial BTW for anyone who found Steve's one-liner interesting.

Getting back to Jean-David's question, something like the forced one-liner: 

for s in [ s for s in findChildren(className='qMRMLLinearTransformSlider') if s.parent().parent().Title == u'Rotation' ]: s.singleStep = 0.1; s.decimals = 5; s.pageStep = 1

would set the rotational steps alone.

S


On Tue, Mar 12, 2013 at 6:18 PM, Steve Pieper <[hidden email]> wrote:
Hi - 

If you want to do a hack to change the sensitivity of the sliders, enter the transforms module and then paste the following code into the python console.

for s in findChildren(findChildren(text='LR')[0].parent().parent().parent(),className='qMRMLLinearTransformSlider'): s.singleStep = 0.0001; s.decimals = 5; s.pageStep = 0.001

-Steve


On Tue, Mar 12, 2013 at 5:38 PM, Sudden Imphead <[hidden email]> wrote:

On Tue, Mar 12, 2013 at 1:23 PM, Jean-David Jutras <[hidden email]> wrote:
 I noticed that the units of translations appear to be in pixel values, rather than mm,

No, I don't think that's true. It's mm all over (or rather: the same unit, whatever you *choose* it to be, normally the mm unit stems from DICOM convention).
 
and the units of rotation are in degrees. Now the thing I don't like is that 3D slicer does not allow me to make shifts to sub-pixel accuracy.
Moreover, it allows rotation increments to the nearest 1 degree, but nothing in between.

The sliders in Transforms module will allow numeric entry of tenths and hundreths, but their stepping is still 1mm (or whatever base unit you choose) and 1 degree. You could multiply all numbers by 10 just using a transform matrix that contains an upper left  submatrix 

   = 10 x (3x3 diagonal identity matrix) 

and then harden into your volume. Then you shouldn't have to resample I'd think. That doesn't solve your degree problem, however.

I'd very much like to change this stepping value as well for customizing user interfaces. I almost succeeded: I could retrieve the widget:

 wr=slicer.modules.transforms.widgetRepresentation()

We should be able to access the innards from there (?) I got lost in the Qt and XML metaprogramming of TranslationSliders in the C++ code and some of the fields are non-public.  

Can anybody reveal the last couple of steps? So close but no cigar...

For extremely accurate transforms (the matrix element fields in 3D Slicer allow only 2 decimals!)  I make a text file with a little Python snippet as below where I define a 4x4 matrix trans13 like:

try:
  trans13
except NameError:
    trans13 = slicer.vtkMRMLLinearTransformNode()
    trans13.SetName('trans13')
    slicer.mrmlScene.AddNode(trans13)

matrix13 = vtk.vtkMatrix4x4()
angle = math.pi / 180.0 * 13.0 # 13 degress
matrix13.DeepCopy([ -1, 0, 0, 0,
                     0, -1, -math.sin(angle), 0,
                     0, 0, math.cos(angle), 0,
                     0, 0, 0, 1])

trans13.SetAndObserveMatrixTransformToParent(matrix13)

That's much easier than trying to fiddle with the tmf file format which uses inverted and transposed matrices. If you're a programmer, you could probably make your own little Python scripting module with your own buttons for tweaking matrices via the vtkMRMLLinearTransformNode.

Sudden

PS: Also, see bug http://na-mic.org/Mantis/view.php?id=2579 by sbillin, who simply patched the source code for own use.

_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject




_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject



_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Fwd: Question about manual rigid registration with Transform module

Jean-Christophe Fillion-Robin
Hi Sudden, 

This is great. Let us know if you have issue creating a wiki accound or if you have any question regarding the organization of the documentation.


Thanks
Jc


On Thu, Mar 14, 2013 at 2:14 PM, Sudden Imphead <[hidden email]> wrote:
Great pointers Steve! I'll try whether I can help with Wiki -- a lot of what's flying by on the mailing list would belong there as well I just realize.
S


On Wed, Mar 13, 2013 at 9:35 AM, Steve Pieper <[hidden email]> wrote:
Hi S - 

I like your improved one-liners - even if you are 'just a beginner' as you say, you've certainly gotten into the good stuff quickly!

Regarding robustness of these approaches, well, that's why I used the term 'hack' in my email, since a small change in the slicer layout or the displayed name of a widget can cause this one-liner to break.  Not for a given release, but maybe the next release will have a new transform module with different widgets.  Of course, when you need to get something done, like tweak the registration parameters and it's just one line of code I think it's a reasonable approach - but beware, it could be a slippery slope.  The 'right thing' would be for the module to provide a settings dialog to allow users to configure the sliders directly, but that's a bigger job.

Regarding putting more examples on the wiki: yes!  We need to flesh this out, and organize things better.  If you want to make edits, contributions would be very gratefully accepted.  Here's the right page for new material that works with the current nightly build [1].  Also, for scripts Jc has been using gists which is a great way to store medium sized snippets [2].

As for slicer.util.findChildren vs findChildren - either is fine as long as they actually refer to the same method (slicer.util.findChildren is different than QObject::findChildren).  I typically prefer the fully qualified version in code but use the shorter version at the prompt. 



Thanks for your interest and enthusiasm,
-Steve


On Tue, Mar 12, 2013 at 9:50 PM, Sudden Imphead <[hidden email]> wrote:
Thanks Steve, wow, this helps me tremendously! (And others too I'm sure,) 

It's really neat that in one fell stroke you specify both the meaning of the page up/down and the up/down arrow keys. 

I'd be interested in your comments for a couple of really basic questions!

Why didn't you use the simpler one-liner:

   for s in findChildren(className='qMRMLLinearTransformSlider'): s.singleStep = 0.0001; s.decimals = 5; s.pageStep = 0.001

??

In your one-liner you seem to look for the text property node with <string>LR</string> in the XML file qMRMLTransformSlider.ui (Slicer source code) and then going up three widgets (ctkCollapsibleGroupBox -> qMRMLTransformSliders -> ctkCollapsibleButton) which brings you to a master widget (?) of sorts of type ctkCollapsibleButton (that I couldn't find, but I'm just a beginner). Is this approach more robust?

Also, I think I learned from your example that slicer.util is an unnecessary prefix in the console (although the very first example in the http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Developers/Python_scripting uses it). (slicer.util.loadVolume is loadVolume evaluates to true.) Maybe update the Wiki?

I also learned that findChildren is a Qt misnomer for "find descendants" -- that's laid out in http://qt-project.org/doc/qt-4.8/qobject.html#findChildren -- that confused me as I started reading the code, not Slicer folks fault of course.  I hope more tidbits like this can be gathered in the Wiki to help others who are new to the amazing possibilities that Qt-based Slicer offers for customizing. I'd recommend the tutorial http://www.slicer.org/slicerWiki/index.php/4.0/Training#Slicer4_Programming_Tutorial BTW for anyone who found Steve's one-liner interesting.

Getting back to Jean-David's question, something like the forced one-liner: 

for s in [ s for s in findChildren(className='qMRMLLinearTransformSlider') if s.parent().parent().Title == u'Rotation' ]: s.singleStep = 0.1; s.decimals = 5; s.pageStep = 1

would set the rotational steps alone.

S


On Tue, Mar 12, 2013 at 6:18 PM, Steve Pieper <[hidden email]> wrote:
Hi - 

If you want to do a hack to change the sensitivity of the sliders, enter the transforms module and then paste the following code into the python console.

for s in findChildren(findChildren(text='LR')[0].parent().parent().parent(),className='qMRMLLinearTransformSlider'): s.singleStep = 0.0001; s.decimals = 5; s.pageStep = 0.001

-Steve


On Tue, Mar 12, 2013 at 5:38 PM, Sudden Imphead <[hidden email]> wrote:

On Tue, Mar 12, 2013 at 1:23 PM, Jean-David Jutras <[hidden email]> wrote:
 I noticed that the units of translations appear to be in pixel values, rather than mm,

No, I don't think that's true. It's mm all over (or rather: the same unit, whatever you *choose* it to be, normally the mm unit stems from DICOM convention).
 
and the units of rotation are in degrees. Now the thing I don't like is that 3D slicer does not allow me to make shifts to sub-pixel accuracy.
Moreover, it allows rotation increments to the nearest 1 degree, but nothing in between.

The sliders in Transforms module will allow numeric entry of tenths and hundreths, but their stepping is still 1mm (or whatever base unit you choose) and 1 degree. You could multiply all numbers by 10 just using a transform matrix that contains an upper left  submatrix 

   = 10 x (3x3 diagonal identity matrix) 

and then harden into your volume. Then you shouldn't have to resample I'd think. That doesn't solve your degree problem, however.

I'd very much like to change this stepping value as well for customizing user interfaces. I almost succeeded: I could retrieve the widget:

 wr=slicer.modules.transforms.widgetRepresentation()

We should be able to access the innards from there (?) I got lost in the Qt and XML metaprogramming of TranslationSliders in the C++ code and some of the fields are non-public.  

Can anybody reveal the last couple of steps? So close but no cigar...

For extremely accurate transforms (the matrix element fields in 3D Slicer allow only 2 decimals!)  I make a text file with a little Python snippet as below where I define a 4x4 matrix trans13 like:

try:
  trans13
except NameError:
    trans13 = slicer.vtkMRMLLinearTransformNode()
    trans13.SetName('trans13')
    slicer.mrmlScene.AddNode(trans13)

matrix13 = vtk.vtkMatrix4x4()
angle = math.pi / 180.0 * 13.0 # 13 degress
matrix13.DeepCopy([ -1, 0, 0, 0,
                     0, -1, -math.sin(angle), 0,
                     0, 0, math.cos(angle), 0,
                     0, 0, 0, 1])

trans13.SetAndObserveMatrixTransformToParent(matrix13)

That's much easier than trying to fiddle with the tmf file format which uses inverted and transposed matrices. If you're a programmer, you could probably make your own little Python scripting module with your own buttons for tweaking matrices via the vtkMRMLLinearTransformNode.

Sudden

PS: Also, see bug http://na-mic.org/Mantis/view.php?id=2579 by sbillin, who simply patched the source code for own use.

_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject




_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject



_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject



--
+1 919 869 8849

_______________________________________________
slicer-users mailing list
[hidden email]
http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users
To unsubscribe: send email to [hidden email] with unsubscribe as the subject