Slicer3 Q&A 2008-11-18

From NAMIC
Jump to: navigation, search
Home < Slicer3 Q&A 2008-11-18

Logistics

Note changed time: 2:30-4:00 at the 2nd floor demo room at 1249 Boylston.

Attendees

Anyone is welcome, please sign up if you plan to attend:

Steve Pieper, Haytham Elhawary, Jan Gumprecht, Andriy Fedorov, Jayender Jagadeesan, Daniel Haehn, Madeleine Seeland

Questions

The name in parentheses defines the person who asks the question, and therefore is responsible for documenting the response.

Debugging

  • Best debugging practices in Slicer (hints for debugging on Linux/Windows, debugging GUI event handling) (Fedorov)

In Linux, you can attach the debugger to Slicer as it is running. To do this, first find the process id (pid) of Slicer3-real, then start gdb and attach to pid. Tell gdb to continue, and once you have a crash, you can identify the faulting code line with gdb command 'where'. Here's an example:

[andrey@beat ~] ps -ef |grep Slicer3-real
andrey     486   443  0 13:21 pts/6    00:00:00 grep Slicer3-real
andrey   31341 31340 88 13:20 pts/2    00:00:59 /home/andrey/local/src/Slicer/Sl
icer3-build/bin/Slicer3-real
[andrey@beat ~] gdb
GNU gdb 6.8
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-suse-linux".
(gdb) attach 31341
Attaching to process 31341
Reading symbols from /home/andrey/local/src/Slicer/Slicer3-build/bin/Slicer3-real...done.
...
(gdb) c
Continuing.
[New Thread 0x437cb950 (LWP 493)]
[Thread 0x437cb950 (LWP 493) exited]
...
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7f77be4de790 (LWP 31341)]
0x00007f77a93cd396 in __dynamic_cast () from /usr/lib64/libstdc++.so.6
(gdb) where
#0  0x00007f77a93cd396 in __dynamic_cast () from /usr/lib64/libstdc++.so.6
#1  0x000000000042e320 in Slicer3_main (argc=1, argv=0x7fffc6637d08)
    at /home/andrey/local/src/Slicer/Slicer3/Applications/GUI/Slicer3.cxx:1986
#2  0x000000000042f5c5 in main (argc=1, argv=0x7fffc6637d08)
    at /home/andrey/local/src/Slicer/Slicer3/Applications/GUI/Slicer3.cxx:2135
(gdb) q
The program is running.  Quit anyway (and detach it)? (y or n) y
Detaching from program: /home/andrey/local/src/Slicer/Slicer3-build/bin/Slicer3-real, process 31341

The key for debugging is to set up the correct shared library paths before launching the debugger. You can attach to an existing process, as shown above, or create a new shell with the right paths. One simple thing for unix is:

./Slicer3 --launch xterm

in the newly launched xterm, you can then run:

gdb bin/Slicer3-real

Or you may wish to use ddd for a more graphical debugging experience.

If you want to use ddd, set up the environment, launch ddd, attach to Slicer3-real, and "continue" as you do with gdb. To investigate a specific part of code, you need to go to menu "File->Open source", hit "Load shared library object symbols", and select the source file of your interest. Follow ddd instructions to insert breakpoints etc.

This approach also works for windows; for example, see these examples for visual studio. Once you have a debugger in the right shell, you can single step through the startup procedure or debug command line modules.

On Windows, it is useful to install rxvt package in Cygwin -- it is much more convenient to use (window resizing, better mouse support).

Note, that if you update CMakeLists.txt, add new files, and such, on Windows, you need to re-run cmake before compiling your project in VC. Exit VC before you do this.

Message output should be done with vtkDebugMacro(), vtkErrorMacro() and vtkWarningMacro(). The output from these macros will go to the Slicer error console (open it by clicking red button in the bottom-right corner.

Example Code

  • What existing modules in Slicer can serve as a good examples to follow (examples of good programming style, GUI, architecture, etc.)? (GradientAnisotropicDiffusion is one?) (Fedorov)

Yes, the "GAD" example is our prototype module that shows the basics of an interactive module. There is a C++ and a Python version. There is also ScriptedModuleExample showing how to write an interactive module in Tcl.

TractographyFiducialSeeding is a good example of more complex module.

  • What are the prerequisites of what a novice Slicer developer should know/learn to program in Slicer? (C/C++, CMake, ITK, VTK, Tcl/Tk, KWWidgets (?)) (Fedorov/Haytham)

It depends on how deep you want to go (need to go) to accomplish your research goals. For algorithm developers we focus primarily on ITK && C++ going through the execution model since that is the lowest barrier -- but it limits you to 'batch mode' interactions. For something interactive, like an IGT application, perhaps the minimum is (Tcl || Python || C++) && VTK && KWWidgets. For the developer who wants to be able to 'do it all' you need to be familiar with all the components of the NA-MIC Kit.

Tcl Coding

  • Advantages and disadvantages of writing parts of the modules in Tcl (example advantage: no recompilation is needed to make changes) (Fedorov)

Advantages of Tcl:

  • Tcl is Mature, Stable, Well-Engineered, Widely Used, Actively Developed... (see [1])
  • Interactive programming
    • no need to recompile source code (can source in directly with tkcon)
    • programmatic debugging - can access all classes and methods to confirm correct values and behavior, even create new renderers on-the-fly)
  • expressive syntax (code is much shorter than equivalent C++)
  • powerful standard library (elegant cross platform abstractions)
  • already widely used in slicer (KWWidgets, testing, launcher, build process...)

Disadvantages of Tcl:

  • Inefficient for numerics, image processing, or rendering (write an ITK or VTK class for these or use numpy for numerics)
  • Some people prefer to use only one language for consistency everywhere (for this, use C++)
  • Unfamiliar syntax
  • Cannot use C++ debugger
  • Cannot define new VTK or ITK classes
  • Some VTK class methods are not available from wrapped code


Tcl Interactor (tkcon)

  • Howto for Slicer Tcl interactor (Fedorov -- I would appreciate if someone help me documenting replies to this and other questions)

This is one of the most powerful tools in slicer. See the tkcon documentation for general capabilities. The tkcon has been enhanced in slicer to support method name completion for vtk classes (shift-tab) and wrapping statements in square brackets (control-]). See this (partly out-of-date) slicer2 documentation of what you can do with tkcon.

Some useful shortcuts: Ctrl+] will wrap the code in brackets -- this can be handy with multiple nesting levels common in Tcl. Shift+Tab does function auto-completion.

$::slicer3 -- namespace for all Slicer3 variables and methods. Explore MRMLScene, ListMethods can be called to list methods. MRMLWatcher includes all nodes in the MRML scene.

Volume Visualization

  • High-level architecture/diagram of Slicer volume visualization: relationship between vtkMRMLScalarVolumeNode/vtkMRMLScalarVolumeDisplayNode/vtkMRMLScene, howto for volume rendering, ... (Fedorov)

There are three kinds of MRML nodes: data, display and storage nodes. In the context of the scalar images, data nodes keep information pertinent to the image contents (spacing, orientation, IJKtoRAS matrix, origin, etc.). Display nodes are used to render the image data. Storage nodes specify details on saving information stored in data nodes (e.g., see storage node specifically for NRRD image format). Refer to MRML Node hierarchy slide in Slicer3 data model. For the specific illustration of how nodes are added and display views are attached see Modules/Volumes::Logic implementation.

Volume rendering is currently not at the stage when you can do the render by adding MRML nodes and specifying properties. What is currently implemented in, for example, ChangeTracker module (ChangeTracker/Wizard/vtkChangeTrackerStep.cxx::CreateRender()) is the ok way to do it. In the future, volume rendering should be possible to do through the interaction with MRML scene (Alex is working on this). Also, the attendees have been referred to the M.S. thesis of Andreas Freudling (U. of Heidelberg), who developed Slicer3 VolumeRendering module (thesis to be found and linked here). Also, see volume rendering tutorial materials

ITK Filters

  • Guidelines on the use of ITK filters from Slicer and what to expect. In case analogous functionality is available both in ITK and VTK, what should be used? (Fedorov)

In general, ITK code has been designed for correctness, while VTK code was designed as examples for a textbook (paraphrasing Bill Lorensen).

The current 'best practice' for simple filters, per Steve Pieper and Jim Miller, is to encapsulate the ITK code inside a VTK class as done in Libs/vtkITK/vtkITKWandImageFilter.h and Libs/vtkITK/vtkITKWandImageFilter.cxx

With some filters, one needs to manually to the transformation between RAS and IJK. To me, it is currently unclear when this is necessary, and how exactly this should be done. For now, it's important to know that there's this issue, and there may be a need to study it more if it becomes necessary.

  • Is there a framework for creating a workflow of command line modules programmatically? (Fedorov)

No, not something well-established. See Module chaining work from Marco Ruiz (Java), and a shell script from Steve on that same page, but there's not much more than that.

Memory Management and Leaks

  • Memory management: how to avoid memory leaks, differences in memory management between different components. Deallocation of image volumes created in a module. (Fedorov)
  • How to track down memory leaks of a particular loadable module -- is it possible to get per-module leak report? (Fedorov)


This can be very tricky so it's best to watch for leaks as the code is being developed. First you should try to start with a non-leaking version to start with.

You can check with:

./Slicer3 --exec exit

which will bring up the interface and then exit.

You can also use the --ignore-module <module name> command line argument to suppress a particular module to see if it is the source of the leak. See this leak test script for an example of how this can be used systematically to find a leaking module (note this script is still in development).

Rule of thumb: if something is set with vtkSet...() macro, the pointer can (should!) be deleted. Delete() will only decrement the reference count.

Event Management

  • Overview of different classes of events in Slicer, and what action should be done in what observer (GUI events, MRML events, Logic events, Scene events, anything else?...) (Fedorov/Haytham)

GUI responds to MRML changes by observing MRML events. GUI is also watching GUI events and updates MRML. This can become tricky when an update triggers another update, and care should be taken not to create event handling loops. This can be done with guard variables (e.g., no MRML event processing while handling GUI events). Logic events are rarely necessary, and currently are only used in slice rendering in the main GUI. Try to stay away from Logic events so that another layer of complexity is not introduced. According to Steve, debugging events is the most challenging task, fixing memory leaks is simple compared to this.

Good examples of event handling and coding: Transform Editor, Tractography module.

  • How do the Logic Methods keep track of the MRML node events? Which Logic Methods are involved? Are Macros used, and if so, where are they defined? (Haytham/Fedorov)

Logic can register to observe MRML events with, for example, SetAndObserveMRMLSceneEvents(), vtkSetAndObserveMRMLNodeMacro(). If this is done, ProcessMRMLEvents() defined by the class will be called with the caller and type of event.

Debugging VTK Pipelines

  • What is the best way to debug vtkPipelines? (e.g. a Pipeline viewer etc.) (Jan)

The best approach here is to write a small test program that confirms how you think the pipeline *should* work. I write these in tcl, but C++ or python work too. Ideally if you can factor out the parts which depend on slicer-specific data structures you can quickly narrow down how to use the VTK classes in a pipeline. Sometimes there are bugs in VTK that need to get fixed. Having the standalone test case is crucial for demonstrating these bugs and getting them fixed.

Documenting your contribution

Use Wink!