|
|
(22 intermediate revisions by 3 users not shown) |
Line 1: |
Line 1: |
− | = Goals and Functionality =
| + | <big>'''Note:''' We are migrating this content to the slicer.org domain - <font color="orange">The newer page is [https://www.slicer.org/wiki/Slicer3:Slicer_Daemon here]</font></big> |
− | | |
− | The Slicer Daemon refers to a network protocol that can be used to connect to a running instance of slicer to read and write data in the MRML scene and execute other commands. The name is based on the unix system convention of naming network services '[http://en.wikipedia.org/wiki/Daemon_%28computer_software%29 daemons]'.
| |
− | | |
− | = Server Implementation =
| |
− | | |
− | The file
| |
− | [http://www.na-mic.org/ViewVC/index.cgi/trunk/Modules/SlicerDaemon/Tcl/slicerd.tcl?view=log slicerd.tcl] implements the server side functionality.
| |
− | | |
− | By default it listens for connections on port 18943.
| |
− | | |
− | = Clients =
| |
− | | |
− | == Tcl ==
| |
− | | |
− | Two utilities are provided:
| |
− | | |
− | * [http://www.na-mic.org/ViewVC/index.cgi/trunk/Modules/SlicerDaemon/Tcl/slicerget.tcl?view=log slicerget.tcl] is used to read volumes out of slicer. The volume is written to the stdout of the slicerget command in nrrd format.
| |
− | | |
− | * [http://www.na-mic.org/ViewVC/index.cgi/trunk/Modules/SlicerDaemon/Tcl/slicerput.tcl?view=log slicerput.tcl] is used to write volumes into slicer. The volume is read in nrrd format from stdin of slicerput and loaded into the mrml scene.
| |
− | | |
− | Some sample commands (assumes your PATH is correctly set to include unu, slicerget and slicerput):
| |
− |
| |
− | # a noop -- just copy image onto itself
| |
− | slicerget.tcl 1 | slicerput.tcl noop
| |
− | | |
− | # put external data into slicer
| |
− | unu 1op abs -i d:/data/bunny-small.nrrd | slicerput.tcl
| |
− | | |
− | # run an external command and put the data back into slicer
| |
− | slicerget.tcl 1 | unu 1op abs -i - slicerput.tcl abs
| |
− | | |
− | == Python ==
| |
− | | |
− | A [http://www.na-mic.org/ViewVC/index.cgi/trunk/Modules/SlicerDaemon/Python/ Python based set of code] for interacting with the Slicer Daemon is provided.
| |
− | | |
− | For example, the [http://www.na-mic.org/ViewVC/index.cgi/trunk/Modules/SlicerDaemon/Python/mathExample.py?view=log following code] reads a volume and creates a new volume where each voxel is the square of the corresponding voxel of the input image. The new image is then sent back to slicer.
| |
− | | |
− | <pre> | |
− | import slicerd
| |
− | import numpy
| |
− | | |
− | s = slicerd.slicerd()
| |
− | | |
− | n = s.get(0)
| |
− | | |
− | im = n.getImage()
| |
− | n.setImage( im * im )
| |
− | | |
− | s.put(n, 'newImage')
| |
− | </pre>
| |
− | | |
− | For example, the [http://www.na-mic.org/ViewVC/index.cgi/trunk/Modules/SlicerDaemon/Python/sliceExample.py?view=log following code] reads a volume and extracts a slice of it for plotting using the matplotlib code (see [http://www.scipy.org the SciPy website] for more info on Python numerics and plotting).
| |
− | | |
− | <pre>
| |
− | import slicerd
| |
− | import pylab
| |
− | | |
− | s = slicerd.slicerd()
| |
− | | |
− | n = s.get(0)
| |
− | | |
− | slice = n.getImage()[16,:,:]
| |
− | pylab.imshow(slice)
| |
− | pylab.show()
| |
− | </pre>
| |
− | | |
− | == Matlab ==
| |
− | ''Note: this is initial documentation only.'' | |
− | | |
− | | |
− | | |
− | [http://www.na-mic.org/ViewVC/index.cgi/trunk/Modules/SlicerDaemon/Matlab/ Matlab based] versions of Slicer Daemon client code are available.
| |
− | | |
− | This [http://wiki.na-mic.org/Wiki/index.php/Projects/Slicer3/2007_Project_Week_Slicer_Matlab_Pipeline_for_scalars_and_tensors project ] has been worked on during the NAMIC project week 2007.
| |
− | | |
− | [[Image:SlicerMatlabPipeline.png|Slicer Matlab Pipeline Schema]]
| |
− | | |
− | | |
− | | |
− | The Matlab scripts getSlicerVolume.m and putSlicerVolume.m use Matlab extention [http://labrosa.ee.columbia.edu/matlab/popenrw.html popen] to connect to stdout(stdin respectively) of the tcl client slicerget.tcl (slicerput.tcl respectively). The tcl client establishes a channel to the SlicerDaemon socket and requests(sends) data. Thanks to Dan Ellis for letting us incorporate the popen matlab code into Slicer.
| |
− | | |
− | The SlicerDaemon in combination with matlab scripts provided here support the exchange of scalar and tensor volumes between Slicer and Matlab that are in orientation right-anterior-superior or left-posterior-superior. DWI volumes and other orientations are not supported yet.
| |
− | | |
− | === Basic Slicer-Matlab tutorial ===
| |
− | Here a step by step tutorial how to send a volume from Slicer to Matlab and then from back from Matlab to Slicer:
| |
− | | |
− | * Start Slicer3 with parameter "--daemon" and load the (scalar or tensor) volume you want to send to Matlab.
| |
− | * Start Matlab and for conveniance change into the "Matlab" subdirectory of the SlicerDaemon module in Slicer3 (something like ../Slicer3/Modules/SlicerDaemon/Matlab)
| |
− | * Initally, the popen C functions need to be compiled for your machine (this is not handled by cmake yet). This needs to be done only once in Matlab:
| |
− | mex popen/popenw.c
| |
− | mex popen/popenr.c
| |
− | * Typing the following command in Matlab, the Slicer volume named "wcase1.nhdr" will be piped into a Matlab structure called "slicer_volume":
| |
− | slicer_volume = getSlicerVolume('wcase1.nhdr')
| |
− | | |
− | All volumes that come out of Slicer are in 'right-anterior-superior' orientation, have 'raw' encoding, and 'little' endian. Even if the original file loaded into Slicer had other header parameters.
| |
− | | |
− | The resulting Matlab strucuture will looks like this (for a scalar volume):
| |
− | slicer_volume =
| |
− | content: 'wcase1.nhdr'
| |
− | type: 'short'
| |
− | dimension: 3
| |
− | space: 'right-anterior-superior'
| |
− | sizes: [256 256 124]
| |
− | endian: 'little'
| |
− | encoding: 'raw'
| |
− | spaceorigin: [119.5310 -92.2500 119.5310]
| |
− | spaceunits: {'mm' 'mm' 'mm'}
| |
− | kinds: {'space' 'space' 'space'}
| |
− | data: [256x256x124 int16]
| |
− | spacedirections: [3x3 double]
| |
− | or like that (for a tensor volume):
| |
− | slicer_volume =
| |
− | content: 'helix.nhdr'
| |
− | type: 'float'
| |
− | dimension: 4
| |
− | space: 'right-anterior-superior'
| |
− | sizes: [7 64 32 12]
| |
− | endian: 'little'
| |
− | encoding: 'raw'
| |
− | spaceorigin: [-6.9386 -28.7554 -8.7247]
| |
− | spaceunits: {'"mm"' '"mm"' '"mm"'}
| |
− | kinds: {'3D-masked-symmetric-matrix' 'space' 'space' 'space'}
| |
− | data: [4-D single]
| |
− | spacedirections: [3x3 double]
| |
− | measurementframe: [3x3 double]
| |
− | centerings: {'???' 'cell' 'cell' 'cell'}
| |
− | | |
− | Instead of typing the name the volume has in Slicer, you can choose the volume by its Slicer-id. The ids are given in the order volumes are loaded in Slicer. This command fetches the volume loaded first in Slicer:
| |
− | slicer_volume = getSlicerVolume(0)
| |
− | | |
− | | |
− | * Now the volume data can be processed in Matlab. Just for example, here the volume is thresholded:
| |
− | slicer_volume.data(slicer_volume.data > 100) = 0;
| |
− | | |
− | * By changing the field "content", the name of the volume node in Slicer will be changed:
| |
− | slicer_volume.content='Matlab_says_hi';
| |
− | | |
− | * This command sends the volume back to Slicer:
| |
− | putSlicerVolume(slicer_volume)
| |
− | | |
− | | |
− | === Slicer-Matlab interface and tensor data ===
| |
− | | |
− | [[Image:Coords-RAS.png|thumb|182px|right|NRRD fields for image orientation and measurement frame]]
| |
− | | |
− | When sending tensor data from Matlab to Slicer and vice versa, there are a couple of issues regarding tensor orientation that the user needs to be aware of.
| |
− | If the only thing you want to do is send a tensor volume from Slicer to Matlab, do some Matlab processing, and send the volume back to Slicer, tensor orientation should not be a problem.
| |
− | But in case you want to send tensor volumes from other sources but Slicer from Matlab to Slicer, the following needs to be considered:
| |
− | | |
− | | |
− | In the original file itself, the tensor data usually lives in "diffusion-sensitizing gradient space". When loading into Slicer3 though, the tensor data automatically gets transformed into so-called IJK-space, or "Index space". This is necessary for good computational performance in Slicer3, since most ITK based filters require the data to be in ijk space.
| |
− | When tensor data is piped into Slicer using the SlicerDaemon, it is assumed this data is in "Index space". Also, the SlicerDaemon expects tensor data to be in LPS orientation.
| |
− | The SlicerDaemon will not do any of these transformations. | |
− | How measurement frame, space directions and the different coordinate systems are related, is depicted in this figure by Gordon Kindlemann:
| |
− | | |
− | Some small and simple scripts that you might find useful to load nhdr files into Matlab and rotate tensor data into the space you want are provided:
| |
− | | |
− | ==== Load and save nrrd files in Matlab ====
| |
− | | |
− | * saveNrrdStructure.m and loadNrrdStructure.m read or write a nrrd file and create a Matlab structure according to the header information . The scripts call the "nrrdLoad" and "nrrdSave" functions of the [http://teem.sourceforge.net/ teem library]. The path to these functions need to be added to the Matlab path.
| |
− | tensor = loadNrrdStructure('/projects/schiz/guest/kquintus/data/testVolumes/tensor/helix.nhdr')
| |
− | | |
− | tensor =
| |
− | content: 'helix'
| |
− | type: 'float'
| |
− | dimension: 4
| |
− | space: 'right-anterior-superior'
| |
− | sizes: [7 64 32 12]
| |
− | endian: 'little'
| |
− | encoding: 'raw'
| |
− | spaceorigin: [-98.4375 -96.8750 -91.6667]
| |
− | kinds: {'3D-masked-symmetric-matrix' 'space' 'space' 'space'}
| |
− | data: [4-D single]
| |
− | spacedirections: [3x3 double]
| |
− | centerings: {'???' 'cell' 'cell' 'cell'}
| |
− | measurementframe: [3x3 double]
| |
− | | |
− | This is how to save a nrrd volume:
| |
− | saveNrrdStructure('/var/tmp/tensor.nhdr', tensor)
| |