[PREVIEW] [Medical] Utility class for medical applications. More...
#include <Medical/helpers/MedicalHelper.h>
Public Types | |
enum | Axis { AXIAL = 2, TRANSVERSE = 2, CORONAL = 1, SAGITTAL = 0 } |
Public Member Functions | |
SbVec3f | getVoxelSize (const SoVolumeData *volume) const |
SbVec3f | getPhysicalSize (const SoVolumeData *volume) const |
SbVec3f | getDicomOrigin (const SoVolumeData *volume) const |
Static Public Member Functions | |
static SbBool | orientView (MedicalHelper::Axis axis, SoCamera *camera, const SoVolumeData *volume=NULL, float slack=1.01) |
static SbBool | dicomAdjustVolume (SoVolumeData *volume, SbBool useImagePosition=TRUE) |
static SbBool | dicomAdjustVolume (SoVolumeData *volume, SoMatrixTransform *imgToPatient) |
static SbBool | dicomAdjustDataRange (SoDataRange *rangeNode, const SoVolumeData *volume) |
static SbBool | dicomCheckMonochrome1 (SoTransferFunction *cmapNode, const SoVolumeData *volume, SbBool forceReverse=FALSE) |
static SbBool | dicomGetImagePosition (const SoVolumeData *volume, SbVec3f &imagePos) |
static SbBool | dicomGetWindowCenterWidth (const SoVolumeData *volume, SbVec2f &winCW) |
static SbVec2f | dicomGetWindowCenterWidth (const SoDataRange *dataRange) |
static SbBool | dicomSetWindowCenterWidth (SoDataRange *dataRange, const SbVec2f &winCW) |
static int | dicomFindFilesbySeries (const SbString &firstFile, std::vector< SbString > &files) |
static int | dicomFindFilesbySeries (const SbString &firstFile, SbStringList &files) |
static void | dollyZoom (float value, SoCamera *camera) |
static SbBool | setFilenameList (SoVRDicomFileReader &reader, const std::vector< SbString > &list) |
static SoMemoryDataAdapter * | getImageDataAdapter (const SoVolumeData *volume) |
static SoVolumeData * | getVolumeData (const SoImageDataAdapter *adapter) |
static SoSeparator * | buildSliceOrientationMarkers (const SoOrthoSlice *orthoSlice) |
static SoSeparator * | buildSliceScaleBars (const SoCamera *camera) |
static SoSeparator * | buildSliceAnnotation (const SoCamera *camera, const SoOrthoSlice *sliceNode, const SbString *dicomFilename) |
static const SbVec2s & | exampleWindowSize () |
static SoNode * | exampleLogoNode () |
static SoNode * | exampleDicomAnnotation (const SbString &filename) |
static Axis | MedicalAxisFromViewAxis (openinventor::inventor::Axis::Type viewAxis, const SoVolumeData *volData) |
static Axis | MedicalAxisFromViewAxis (openinventor::inventor::Axis::Type viewAxis, const SbMatrix &orientationMatrix) |
static openinventor::inventor::Axis::Type | ViewAxisFromMedicalAxis (Axis medicalAxis, const SoVolumeData *volData) |
static openinventor::inventor::Axis::Type | ViewAxisFromMedicalAxis (Axis medicalAxis, const SbMatrix &orientationMatrix) |
template<typename NodeType > | |
static NodeType * | find (SoNode *root, const SbString &nodeName=SbString(), const bool okIfNotFound=false) |
template<typename NodeType > | |
static std::vector< NodeType * > | findNodes (SoNode *scene) |
template<typename NodeType > | |
static NodeType * | find (SoTopLevelDialog *root, const SbString &auditorId=SbString(), bool exitIfNotFound=true) |
static SbBox3f | getBoundingBox (SoNode *node) |
static SoSeparator * | createCube (const SbBox3f &bbox) |
static SoSeparator * | createBoundingBox (const SbBox3f &bbox, SbColor *color=NULL) |
static SoSeparator * | readFile (const char *filename) |
template<typename WidgetType > | |
static WidgetType | buildInterface (WidgetType window, const char *filename, const char *viewerName, SoTopLevelDialog **topLevelDialog) |
Utility functions for medical visualization using Open Inventor.
Open Inventor includes a general purpose 3D graphics core library plus optimized extensions for specific data types and markets, including medical visualization. We recommend using these utility functions (and the Medical utility nodes) to get the best performance and productivity from Open Inventor for medical applications.
SUMMARY
// Data reader: Load all images in a series SoVRDicomFileReader* dicomReader = new SoVRDicomFileReader(); std::vector<SbString>& fileList; MedicalHelper::dicomFindFilesbySeries( firstFilename, fileList ); MedicalHelper::setFilenameList( *dicomRender, fileList ); // Data node SoVolumeData* volume = new SoVolumeData(); volData->setReader( *dicomReader ); MedicalHelper::dicomAdjustVolume( volData ); // Adjust position, extent, ... root->addChild(volData); // Data range (from data file by default) SoDataRange* dataRange = new SoDataRange(); MedicalHelper::dicomAdjustDataRange( dataRange, volData ); // Use window center/width if possible... root->addChild( dataRange );
// Start a filter pipeline from a VolumeViz data set SoMemoryDataAdapter* adapter = MedicalHelper::getImageDataAdapter( volume ); // Add a filter SoDeblurProcessing2d* filter = new SoDeblurProcessing2d(); filter->sharpeningFactor = 2; filter->inImage = adapter;
InventorMedical, DicomInfo, Gnomon, Magnifier, PlaneBoxIntersection, PlaneGeometryIntersection, Ruler, SliceOrientationMarkers, SliceScaleBar, TextBox, VolumeMarchingCubes
enum MedicalHelper::Axis |
static WidgetType MedicalHelper::buildInterface | ( | WidgetType | window, | |
const char * | filename, | |||
const char * | viewerName, | |||
SoTopLevelDialog ** | topLevelDialog | |||
) | [inline, static] |
Convenience function to read a .iv file defining a DialogViz user interface.
Not available for the Open Inventor Headless build.
SoDialogViz.h must be included before this file in order for this function to be available.
static SoSeparator* MedicalHelper::buildSliceAnnotation | ( | const SoCamera * | camera, | |
const SoOrthoSlice * | sliceNode, | |||
const SbString * | dicomFilename | |||
) | [static] |
Slice viewer annotations.
This is just a convenience method and helps keep the demo/example programs consistent. Applications can use SliceScaleBar (etc) directly.
Calls the buildSliceOrientationMarkers() and buildSliceScaleBars() methods and also creates some DicomInfo nodes using tag info from the optional image filename.
static SoSeparator* MedicalHelper::buildSliceOrientationMarkers | ( | const SoOrthoSlice * | orthoSlice | ) | [static] |
Build a scene graph to display slice orientation markers.
This is just a convenience method and helps keep the demo/example programs consistent. Applications can use SliceOrientationMarkers directly.
Creates a SliceOrientationMarkers node with a default color and background and connects its 'axis' field to the 'axis' field of the specified slice node.
static SoSeparator* MedicalHelper::buildSliceScaleBars | ( | const SoCamera * | camera | ) | [static] |
Build a scene graph to display dynamic scale bars for slice viewing.
This is just a convenience method and helps keep the demo/example programs consistent. Applications can use SliceScaleBar directly.
Note that a typical length, 10 cm, is assumed.
Creates horizontal and vertical SliceScaleBar nodes with a default color and line width and sets their 'trackedCamera' field to the specified camera node.
static SoSeparator* MedicalHelper::createBoundingBox | ( | const SbBox3f & | bbox, | |
SbColor * | color = NULL | |||
) | [static] |
Convenience function to draw a wireframe box representing the specified bounding box.
Default color is red (1,0,0).
static SoSeparator* MedicalHelper::createCube | ( | const SbBox3f & | bbox | ) | [static] |
Convenience function to draw a cube representing the specified bounding box.
Color is inherited.
static SbBool MedicalHelper::dicomAdjustDataRange | ( | SoDataRange * | rangeNode, | |
const SoVolumeData * | volume | |||
) | [static] |
Adjust data range based on values in the DICOM file, i.e.
the window center (0028,1050) and window width (0028,1051) values. Returns true if successful. Assigns default values if necessary. If there are multiple slices, values are taken from the first slice. Volume is needed to get DICOM attributes, but is not modified.
static SbBool MedicalHelper::dicomAdjustVolume | ( | SoVolumeData * | volume, | |
SoMatrixTransform * | imgToPatient | |||
) | [static] |
Similar to dicomAdjustVolume( SoVolumeData*, SbBool ) above but returns an SoMatrixTransform that can be used to properly locate VolumeData in patient space in case of non axis aligned acquisition:.
... SoMatrixTransform* matrixTransform = new SoMatrixTransfrom(); dicomAdjustVolume(volumeData, matrixTransfrom) root->addChild(matrixTransform); root->addChild(volumeData); ...
The computed matrix embeds the image position and image orientation as described here: https://dicom.innolitics.com/ciods/ct-image/image-plane/00200037 Scaling part is embedded in VolumeData extent.
If SoVolumeData is not a DICOM volume, matrixTransform will be set to identity.
Returns true if successful.
static SbBool MedicalHelper::dicomAdjustVolume | ( | SoVolumeData * | volume, | |
SbBool | useImagePosition = TRUE | |||
) | [static] |
Optimize volume data node for DICOM volumes.
Returns true if successful. The volume properties are modified (but not the data values). Do not call this method before setting the volume data node's fileName field or calling setReader.
Note that this method doesn't support non axis aligned acquisition. In such a case, prefer using the dicomAdjustVolume( SoVolumeData*, SoMatrixTransform* ) below.
static SbBool MedicalHelper::dicomCheckMonochrome1 | ( | SoTransferFunction * | cmapNode, | |
const SoVolumeData * | volume, | |||
SbBool | forceReverse = FALSE | |||
) | [static] |
Automatically adjusts the color map (transferFunction) if the specified volume is a DICOM data set (reader is SoVRDicomFileReader) and the the Photometric Interpretation (0028,0004) value is MONOCHROME1.
Specifically, if the above conditions are true, this method reverses the values in the current color map.
Typically used as a convenience call when rendering slices. For intensity based rendering of slices, set the transfer function to the predefined color map INTENSITY. This is an intensity ramp from black to white that is appropriate for Photometric Interpretation MONOCHROME2 (the most common case). When reversed it is appropriate for P.I. MONOCHROME1.
Returns true if change was needed and was successful. Volume is needed to get DICOM attributes, but is not modified. Transfer function is modified if necessary.
static int MedicalHelper::dicomFindFilesbySeries | ( | const SbString & | firstFile, | |
SbStringList & | files | |||
) | [static] |
Get files in DICOM series.
We recommend using the alternate version of this method. Note that SbStringList is a list of pointers to SbString objects, not a list of SbString objects.
static int MedicalHelper::dicomFindFilesbySeries | ( | const SbString & | firstFile, | |
std::vector< SbString > & | files | |||
) | [static] |
Get files in DICOM series.
Given the path to a DICOM file, returns a list containing all the files in the same directory that are part of the same DICOM series, based on the series UID (0x0020,0x000E). File name extensions are not considered.
Returns 0 if the specified file was not found or is not a valid DICOM file.
This allows the application user to select a DICOM series in a file selection dialog box by just selecting one file instead of having to select all the files explicitly.
To load the series in Open Inventor, create an SoVRDicomFileReader and call the setFilenameList() method with the file list. Then set this reader in the SoVolumeData node using the setReader() method. Note that SbStringList is a list of pointers to SbString objects, not a list of SbString objects.
The file names in the returned list are not in any particular order. It doesn't matter for loading the volume because the DICOM volume reader automatically sorts the images by their 'Slice Location' attribute (0x0020,0x1041).
See also: SbFileHelper::listFiles(). This method returns a list of files based on a specified pattern (regular expression) for the filenames.
static SbBool MedicalHelper::dicomGetImagePosition | ( | const SoVolumeData * | volume, | |
SbVec3f & | imagePos | |||
) | [static] |
Get the "Image Position (Patient)" attribute (0020,0032) from a DICOM volume.
DICOM calls this the upper left hand corner of the image, but more precisely it's the center of the first voxel, in millimeters (mm). For VolumeViz the upper left hand corner of the image is literally the corner of the voxel, one-half voxel different from Image Position. Returns true if the query is successful. If not successful, imagePos is 0,0,0. If there are multiple slices, value is taken from the first slice.
Note the SoVRDicomData getPosition() method does not return the value of the Image Position attribute. It returns a value computed from Image Position.
static SbVec2f MedicalHelper::dicomGetWindowCenterWidth | ( | const SoDataRange * | dataRange | ) | [static] |
Get the window center (level) and width values from an SoDataRange node.
Returns 0,0 on failure. Convenient for displaying data range in medical terms.
static SbBool MedicalHelper::dicomGetWindowCenterWidth | ( | const SoVolumeData * | volume, | |
SbVec2f & | winCW | |||
) | [static] |
Get the window center (level) and width values from a DICOM volume.
If the query fails, returns false and sets 'winCW' to 0,0.
Uses the Window Center (0028,1050) and Window Width (0028,1051) tags from the first image in the stack. If these tags do not exist in the volume, then window center and width are computed from the actual data min and max values. (Note that querying the actual min and max values may take some time because every voxel must be loaded.)
This method may be called with a non-DICOM volume. In that case the actual min and max data values are used.
static SbBool MedicalHelper::dicomSetWindowCenterWidth | ( | SoDataRange * | dataRange, | |
const SbVec2f & | winCW | |||
) | [static] |
Set an SoDataRange node from the window center (level) and width values.
Returns true if successful. Convenient for converting from medical user interface to data range.
static void MedicalHelper::dollyZoom | ( | float | value, | |
SoCamera * | camera | |||
) | [static] |
Make the scene appear larger or smaller.
Provided as a convenience to simplify application code. Effect is the same as creating an SoCameraInteractor and calling the dolly() method, but note that the value expected by that method is the inverse which is less intuitive. Using this method, values greater than 1 make the scene appear larger and values less than 1 make the scene appear smaller. For example a of 2 will make the scene approximately 2 times larger. The specific effect on the camera is a 'dolly' or a 'zoom' depending on the type of camera.
This is often useful after calling ViewAll(). That method sets the camera parameters based on a bounding sphere around the scene which often leaves the scene not "filling" the viewport.
Details:
Returns a collection of DicomInfo annotation nodes for Open Inventor medical examples.
This method is not important for customer appications, but the technique can be useful for adding annotation text to an application window.
static SoNode* MedicalHelper::exampleLogoNode | ( | ) | [static] |
Returns a logo image node for Open Inventor medical examples.
This method is not important for customer applications, but the technique can be useful for adding logo images to an application window. Returns an SoImageBackground node, but as an SoNode. The returned node has a ref count of zero.
static const SbVec2s& MedicalHelper::exampleWindowSize | ( | ) | [static] |
Returns standard window size for Open Inventor medical examples.
This method is not important for customer applications.
static NodeType* MedicalHelper::find | ( | SoTopLevelDialog * | root, | |
const SbString & | auditorId = SbString() , |
|||
bool | exitIfNotFound = true | |||
) | [inline, static] |
Convenience function to find first specified node in specified GUI graph.
SoDialogViz.h must be included before this file in order for this function to be available.
static NodeType* MedicalHelper::find | ( | SoNode * | root, | |
const SbString & | nodeName = SbString() , |
|||
const bool | okIfNotFound = false | |||
) | [inline, static] |
Convenience function to find first specified node in specified scene graph.
static std::vector<NodeType*> MedicalHelper::findNodes | ( | SoNode * | scene | ) | [inline, static] |
Convenience function to find all node of specified type in specified graph.
Convenience function to retrieve bounding box of specified node.
If node is a group that contains an SoVolumeData, uses SoVolumeData extent.
SbVec3f MedicalHelper::getDicomOrigin | ( | const SoVolumeData * | volume | ) | const |
Returns the DICOM volume origin in 3D space.
This is just a convenience. In DICOM terms the image/volume origin is the center of the first voxel, but in VolumeViz the minimum point of the 3D extent is the outer edge of the first voxel. The difference is 1/2 voxel.
Note: dicomGetImagePosition returns the actual value of the Image Position Patient attribute from the DICOM file (if possible).
static SoMemoryDataAdapter* MedicalHelper::getImageDataAdapter | ( | const SoVolumeData * | volume | ) | [static] |
Make a VolumeViz data set available in ImageViz.
Creates and returns an SoMemoryDataAdapter with the same dimensions, extent and data as the SoVolumeData. Returns NULL on failure, e.g. if volume is empty.
Note that this operation makes a copy of the data set. So it must be possible to allocate a contiguous block of memory large enough to hold the whole volume. It is not currently possible for ImageViz and VolumeViz to share a data set.
You can use SoVolumeReaderAdapter to get the same result but the performance is much slower because SoVolumeReaderAdapter loads data using the volume's associated volume reader class and re-reads the data from disk. This convenience method is much faster because it loads data using the LDMDataAccess interface which takes advantage of data that VolumeViz already has in memory.
Performance depends on the 'tile size' set for the source volume. It will be slow (but still faster than SoVolumeReaderAdapter) if you use the default tile size (64) with a 512^3 volume. We recommend setting the volume's tile size equal to the volume size (or calling the dicomAdjustVolume() method which does this automatically).
SbVec3f MedicalHelper::getPhysicalSize | ( | const SoVolumeData * | volume | ) | const |
Returns the volume's physical size in 3D space.
This is just a convenience. The physical size in 3D is simply the span of the volume extent.
static SoVolumeData* MedicalHelper::getVolumeData | ( | const SoImageDataAdapter * | adapter | ) | [static] |
Make an ImageViz data set available in VolumeViz.
Creates an SoVRImageDataReader to access the data and automatically sets the SoVolumeData's 'tile size' to an optimal value. Note that this operation makes a copy of the data set. It is not currently possible for ImageViz and VolumeViz to share a data set. Returns NULL on failure.
You can use SoVRImageDataReader directly, but the resulting volume may be slow to access if you do not set the tile size and the volume dimensions are larger than the default tile dimension (64). Setting the tile size allows VolumeViz to access the data as a single tile when the dimensions are <= 512 or at least to access the data using a larger tile size (which means a smaller number of tiles).
SbVec3f MedicalHelper::getVoxelSize | ( | const SoVolumeData * | volume | ) | const |
Returns the voxel size in 3D space.
This is just a convenience. The voxel size is simply the volume extent in 3D space divided by the number of voxels.
static Axis MedicalHelper::MedicalAxisFromViewAxis | ( | openinventor::inventor::Axis::Type | viewAxis, | |
const SbMatrix & | orientationMatrix | |||
) | [static] |
Returns the medical axis (AXIAL, CORONAL, SAGITTAL) corresponding to the specified view axis (X, Y, Z) based on the specified orientation matrix.
See MedicalAxisFromViewAxis(Axis, const SoVolumeData*) for details.
Normally this matrix is computed from the DICOM Image Orientation element. This version of the method allows the application to extract the orientation matrix and save it. The orientation matrix can be created from the DICOM Image Orientation vectors or conveniently queried using SoVRDicomData::getOrientation().
static Axis MedicalHelper::MedicalAxisFromViewAxis | ( | openinventor::inventor::Axis::Type | viewAxis, | |
const SoVolumeData * | volData | |||
) | [static] |
Returns the medical axis (AXIAL, CORONAL, SAGITTAL) corresponding to the specified view axis (X, Y, Z) based on the DICOM Image Orientation element (0x0020,0x0037).
Use this method when you know the camera will be aligned with one of the 3D world coordinate axes and you need to know which medical axis the view axis corresponds to. You need the medical axis in order to display the correct slice orientation letters. For example, if the Image Orientation is identity and the camera is aligned with the Z axis, then this is an Axial view.
The conversion may not be valid if the DICOM Image Orientation is not approximately axis aligned. The conversion uses the largest component of each direction cosine to detemine the associated axis.
volData parameter: This parameter is used to get the DICOM Image Orientation element. If the element is not available or the volume is not a DICOM data set (reader is not an SoVRDicomFileReader), then the method returns the value of the specified axis.
In many cases the medical axis and view axis are the same. However this depends on the DICOM Image Orientation element (0x0020,0x0037). If Image Orientation is missing or has the default value "1/0/0/0/1/0" (identity matrix), then the view and medical axes have the default DICOM relationship:
But, for example, if Image Orientation is "0/1/0/0/0/-1", then the view Z axis is actually the medical SAGITTAL (RL) axis.
Applications should use the view axis (e.g. Z) to set the camera direction and slice axis (see SoOrthoSlice), but use the medical axis (e.g. AXIAL) to select the slice orientation labels (see SliceOrientationMarkers).
Notes:
static SbBool MedicalHelper::orientView | ( | MedicalHelper::Axis | axis, | |
SoCamera * | camera, | |||
const SoVolumeData * | volume = NULL , |
|||
float | slack = 1.01 | |||
) | [static] |
Orient view.
The camera is rotated to give the conventional orientation for the specified axis, then if a volume data node was specified:
For a 3D volume rendering view, typically specify the Coronal axis.
The orientation calculation is based on the DICOM LPS (Left, Posterior, Superior) reference coordinate system for a bipedal patient, where:
This works correctly in many, but not all, cases. In particular it does not handle non-default values for the DICOM Image Orientation attribute.
Parameters:
Returns true if the operation succeeded.
static SoSeparator* MedicalHelper::readFile | ( | const char * | filename | ) | [static] |
Convenience function to read a .iv file and return pointer to the root of the created scenegraph.
static SbBool MedicalHelper::setFilenameList | ( | SoVRDicomFileReader & | reader, | |
const std::vector< SbString > & | list | |||
) | [static] |
Set filename list using a list of strings (file names).
This is a convenient alternative to calling SoVRDicomFileReader's method setFilenameList() directly. That method requires an SbStringList object which is a simple list of _pointers_, not a list of objects.
static openinventor::inventor::Axis::Type MedicalHelper::ViewAxisFromMedicalAxis | ( | Axis | medicalAxis, | |
const SbMatrix & | orientationMatrix | |||
) | [static] |
Returns the view axis (X, Y, Z) corresponding to the specified medical axis (AXIAL, CORONAL, SAGITTAL) based on the DICOM Image Orientation element (0x0020,0x0037).
See ViewAxisFromMedicalAxis(Axis, const SoVolumeData*) for details.
Normally this matrix is computed from the DICOM Image Orientation element. This version of the method allows the application to extract the orientation matrix and save it. The orientation matrix can be created from the DICOM Image Orientation vectors or conveniently queried using SoVRDicomData::getOrientation().
static openinventor::inventor::Axis::Type MedicalHelper::ViewAxisFromMedicalAxis | ( | Axis | medicalAxis, | |
const SoVolumeData * | volData | |||
) | [static] |
Returns the view axis (X, Y, Z) corresponding to the specified medical axis (AXIAL, CORONAL, SAGITTAL) based on the DICOM Image Orientation element (0x0020,0x0037).
Use this method when you know the medical axis that should be displayed and you need to know the view axis (X, Y, Z) that corresponds to that. For example, if the Image Orientation is identity and an Axial view should be displayed, then the camera and the SoOrthoSlice should be set to Z.