[IGSTK-Developers] Re: Tracker, slicer, etc
David Gobbi
dgobbi at atamai.com
Tue Jun 19 07:34:55 EDT 2007
Frank Lindseth wrote:
> Hi David,
>
> Tracker:
> I just went trough your "tracker interface changes" page: It looks
> very good, I will send our comments after speaking to the rest of the
> trondheim developers.
> But I was hoping that it would be possible to incorporate the
> "coordinate system changes" that we basically agrees on (both in terms
> of the necessity for doing so as well as how it should be done) at the
> same time:
> http://public.kitware.com/IGSTKWIKI/index.php/DesignChallenges#Coordinate_systems_.2F_Transforms_.2F_Registration
>
> http://public.kitware.com/IGSTKWIKI/index.php/Talk:DesignChallenges#Coordinate_systems_.2F_Transforms_.2F_Registration
> http://public.kitware.com/IGSTKWIKI/index.php/Minutes_052407#DesignChallenges
> I.e.
I can add a new section to the page entitled "Tracker, Spatial Object,
and Coordinate Systems" that will contain some information.
Note that we don't have a page up yet that describes the changes that
will be needed for the SpatialObject component. As far as the
coordinate system changes go, it is that component, rather than the
Tracker, that needs to be modified. No one has been assigned to make
the changes yet, though Julian's name has come up in the t-con.
> - The Tracker comp. supplies the (Image)SpatialObj with tool (tip)
> positions and orientations (i.e. calibration included) in tracker
> (reference frame) coordinates.
> - Each ImageSpatialObject is associated with A) a accumulated
> Image/VolumeTransform that tells where the volume is relative to the
> tracker ref. frame and B) a list of all the UpdateTransforms that a
> volume has gone trough (for a pre.op. volume the list of updateTransf.
> could be 1)DICOM transf. 2) MR-MR or CT-CT or CT-MR transf. 3) Patient
> reg. transf. (Tracker-Image transf.) 4) MR to US-01 update, 5) US-01
> to US-02 update, etc.).
> - Using the position of the tool tip in tracker coords.
> and accumulated Image/VolumeTransform the ImageSpatialObj
> can supply the ImageSliceRep. with the information needed to extract
> the right slices from the volume.
>
> Slicer:
> As pointed out by Patrick, it's time to start the practical work with
> the new Slicer comp.
> much have been said already:
> http://public.kitware.com/IGSTKWIKI/index.php/ImageSliceRepresentation
> http://public.kitware.com/IGSTKWIKI/index.php/Talk:ImageSliceRepresentation
> http://public.kitware.com/IGSTKWIKI/index.php/DesignChallenges#Slicing
> http://public.kitware.com/IGSTKWIKI/index.php/Talk:DesignChallenges#Slicing
>
> As you know, a slice can be displayed in both a "2D window" and (on a
> 2D plane) in a "3D scene".
> IGSTK needs both. You have previously told me that you will submit a
> C++ OrthoPlaneWidget class (based on the "atamai python classes") to VTK:
>>>>> Yes, we have an OrthoPlaneWidget C++ class that can be used for
>>>>> displaying
>>>>> three (or just two or one) slices in a 3D scene. This class will
>>>>> be committed
>>>>> to VTK cvs, probably around the middle of June.
>>>>>
> Do you think that it would be possible/wise to make IGSTK Slicer comp.
> based on such a Ortho/ObliquePlane/SliceWidget?
Unfortunately, I have had no time to do any work on VTK lately. This
SliceWidget class would be useful for doing 3D views, but is not useful
for 2D views.
> --------------
> Just to illustrate it's intended use of the slicer comp. I
> have included the miniasp.py atamai example below
> Of course, writing an application in C++ usually requires more lines
> of code than the equivalent application in python,
> but this is actually a "full blown viewer app." (easily extendable to
> a navigation/tracker app.), and it shows how "easy" it could
> be to put together an application with the right functionality using
> high-level components. I loved it during my PhD work several years ago,
> and I love it today... Wouldn't it be nice if it was just as easy to
> use IGSTK some time in the future, at the same time as it was safe. I
> believe this
> is possible if we focus functionality, anybody else???
It is interesting that you mention miniasp (below), of course I love the
way its high-level components fit together, too, and in fact we
developed a much larger framework called AtamaiViewer that is based on
it. I really do want to develop a similar collection of components
written in C++, and based on the new (and still in development) VTK
widgets. I have been able to spend some time on this over the past
year, but not nearly enough. I will keep you updated.
Back to IGSTK: It has been a goal of IGSTK from the very beginning that
it should be made of high-level components that are easy to hook
together to form an application. A very basic IGS application written
with IGSTK should ideally only be a hundred lines of source code.
Anything that we can do to the components that allows us to shrink the
application code (without making the code more difficult to understand)
should be considered a move in the right direction.
- David
> miniasp.py:
> ----
> #!/usr/local/bin/python
>
> # Basic image viewer example that doesn't rely on any GUI toolkits
> # outside of VTK
>
> # here are a few variables to change the behaviour:
>
> # initial size of the window
> windowWidth = 852
> windowHeight = 640
>
> # interpolation of images
> interpolation = 1
>
> # width of border around the frames
> borderwidth = 1
>
> # arrange the panes in a 1 + 3 griding
> viewports = [(0.00, 0.00, 0.67, 1.00),
> (0.67, 0.67, 1.00, 1.00),
> (0.67, 0.33, 1.00, 0.67),
> (0.67, 0.00, 1.00, 0.33)]
>
> # or arrange the planes in 2 * 2 gridding
> #viewports = [(0.00, 0.00, 0.50, 0.50),
> # (0.00, 0.50, 0.50, 1.00),
> # (0.50, 0.00, 1.00, 0.50),
> # (0.50, 0.50, 1.00, 1.00)]
>
> # check for correct usage
> import os, sys
>
> if not sys.argv[1:]:
> filename = "phantom.mnc"
> else:
> filename = sys.argv[1]
>
> # first, load a script that sets the paths for the modules we load
> import paths
>
> # then load all of the classes we use
> from PaneFrame import *
> from RenderPane import *
> from RenderPane2D import *
> from WindowLevelInteractionMode import *
>
> from OrthoPlanesFactory import *
> from AnatomicalLabelsFactory import *
> from OutlineFactory import *
> from CrossCursorFactory import *
>
> from ModePalette import *
>
> # load the 'vtk widget set'
> import Widgets
>
> # load the file reader
> from vtkMINCReader import *
>
> # put everything together
>
> # create the ortho-planes, to display 3 slices through data set
> planes = OrthoPlanesFactory()
> planes.SetSliceInterpolate(interpolation)
> planes.SetTextureInterpolate(interpolation)
> planes.ActivatePlaneGuides()
> # this reader can be replaced by a reader for other file types
> reader = vtkMINCReader()
> reader.SetFileName(filename)
>
> # get the data range for the lookup table,
> # also get the shift/scale to convert the data into intensity
> # values: intensity = data*scale + shift
> (minval,maxval) = reader.GetDataRange()
> intensityShift = reader.GetShift()
> intensityScale = reader.GetScale()
>
> # for convenience
> imageData = reader.GetOutput()
>
> # create a greyscale lookup table to use
> table = vtkLookupTable()
> table.SetTableRange(minval,maxval)
> table.SetSaturationRange(0,0)
> table.SetHueRange(0,0)
> table.SetValueRange(0,1)
> table.Build()
>
> # add these to the orthoplanes
> planes.SetInput(imageData)
> planes.SetLookupTable(table)
>
> # generate a frame around the volume
> frame = OutlineFactory()
> frame.SetInput(imageData)
> frame.SetColor(1.0000, 0.8431, 0.0000)
>
> # generate axes labels
> labels = AnatomicalLabelsFactory()
> labels.SetInput(imageData)
>
> # make a cursor to display in all the frames
> cursor = CrossCursorFactory()
>
> # create window/level interaction for the rendering pane, attach
> # the lookup table here too
> windowlevel = WindowLevelInteractionMode()
> windowlevel.SetLookupTable(table)
>
> # create the rendering panes, add the actors
> paneframe = PaneFrame(width=windowWidth, height=windowHeight)
> paneframe.SetTitle("Atamai MiniAsp ["+filename+"]")
>
> # the height of the control panel at the bottom,
> # and the width of the borders around the panes
> panelheight = 27
>
> # figure out what the offsets on the viewports will have to
> # be to make room for the control panel
> viewportOffsets = []
>
> for viewport in viewports:
> viewportOffsets.append(
> (0, int(panelheight*(1.0-viewport[1])),
> 0, int(panelheight*(1.0-viewport[3]))))
>
> # create the primary rendering pane with a nice border around it
> pane = RenderPane(paneframe)
> pane.SetViewport(viewports[0])
> pane.SetViewportOffsets(viewportOffsets[0])
> pane.SetBackground(1,1,1)
> pane.SetBorderWidth(borderwidth)
> pane.ConnectActorFactory(planes)
> pane.ConnectActorFactory(frame)
> pane.ConnectActorFactory(labels)
> pane.ConnectCursor(cursor)
> pane.BindModeToButton(windowlevel,3,"Shift")
>
> # set up another pane for the single image
> pane2 = RenderPane2D(paneframe)
> pane2.SetViewport(viewports[1])
> pane2.SetViewportOffsets(viewportOffsets[1])
> pane2.SetBackground(0.5,0.5,0.5)
> pane2.SetBorderWidth(borderwidth)
> pane2.ConnectPlane(planes.GetAxialPlane())
> pane2.ConnectCursor(cursor)
> pane2.BindModeToButton(windowlevel,3,"Shift")
>
> # set up another pane for the single image
> pane3 = RenderPane2D(paneframe)
> pane3.SetViewport(viewports[2])
> pane3.SetViewportOffsets(viewportOffsets[2])
> pane3.SetBackground(0.5,0.5,0.5)
> pane3.SetBorderWidth(borderwidth)
> pane3.ConnectPlane(planes.GetCoronalPlane())
> pane3.ConnectCursor(cursor)
> pane3.BindModeToButton(windowlevel,3,"Shift")
>
> # set up another pane for the single image
> pane4 = RenderPane2D(paneframe)
> pane4.SetViewport(viewports[3])
> pane4.SetViewportOffsets(viewportOffsets[3])
> pane4.SetBackground(0.5,0.5,0.5)
> pane4.SetBorderWidth(borderwidth)
> pane4.ConnectPlane(planes.GetSagittalPlane())
> pane4.ConnectCursor(cursor)
> pane4.BindModeToButton(windowlevel,3,"Shift")
>
> # set up a final pane just for the control panel
> pane5 = RenderPane2D(paneframe)
> pane5.SetViewport(0.0,0.0,1.0,0.0)
> pane5.SetViewportOffsets(0,0,0,panelheight)
> pane5.SetBackground(0.75,0.75,0.75)
>
> # create a label for cursor coordinate readout, set the text to black
> coordlabel = Widgets.CoordinateLabel(pane5,x=-280,y=0,
> foreground=(0.0,0.0,0.0))
> coordlabel.SetCursor(cursor)
>
> # create a label for intensity readout, set the text to red
> intensitylabel = Widgets.IntensityLabel(pane5,x=-380,y=0,
> foreground=(1.0,0.0,0.0))
> intensitylabel.SetInput(imageData)
> intensitylabel.SetCursor(cursor)
> intensitylabel.SetShift(intensityShift)
> intensitylabel.SetScale(intensityScale)
> intensitylabel.SetInterpolate(interpolation)
>
> # create a logo bitmap
> bitmapReader = vtkImageReader()
> bitmapReader.SetFileName(os.path.join(paths.prefix,"classes/Atamai.rgba"))
> bitmapReader.SetDataScalarTypeToUnsignedChar()
> bitmapReader.SetNumberOfScalarComponents(4)
> bitmapReader.SetDataExtent(0,199,0,57,0,0)
> logolabel = Widgets.Label(pane5,x=0,y=0,width=100,height=27,
> bitmap=bitmapReader.GetOutput())
>
> # create a palette of mouse mode interaction choices
> modePalette = ModePalette(pane5,x=105,y=0)
> modePalette.AddPane(pane)
> modePalette.AddPane(pane2)
> modePalette.AddPane(pane3)
> modePalette.AddPane(pane4)
> modePalette.SetLookupTable(table)
>
> paneframe.Render()
> pane.GetRenderer().GetActiveCamera().SetEyeAngle(5.0)
>
> # start 'er up
> paneframe.Start()
>
>
>
More information about the IGSTK-Developers
mailing list