basti
July 16, 2019, 3:05pm
1
Dear forum,
I’m trying to create a vtkPolyData out of a vtkOrientedImageData. Given a segmentation ‘Segmentation’ with a segment with id ‘Segment_1’, the output model is strangely transformed to the input oriented imagedata:
seg = slicer.util.getNode('Segmentation')
segID = 'Segment_1'
import vtkSegmentationCorePython
modelsLogic = slicer.modules.models.logic()
orImg = vtkSegmentationCorePython.vtkOrientedImageData()
slicer.vtkSlicerSegmentationsModuleLogic.GetSegmentBinaryLabelmapRepresentation(seg, segID, orImg)
inputDiscreteCubes = vtk.vtkDiscreteMarchingCubes()
inputDiscreteCubes.SetInputData(orImg)
inputDiscreteCubes.GenerateValues(1,0,0)
inputDiscreteCubes.Update()
modelNode = modelsLogic.AddModel(inputDiscreteCubes.GetOutput())
It is possible to solve this by first removing the ImageToWorld transform of the oriented imagedata and applying this transform to the model later again:
seg = slicer.util.getNode('Segmentation')
segID = 'Segment_1'
import vtkSegmentationCorePython
modelsLogic = slicer.modules.models.logic()
orImg = vtkSegmentationCorePython.vtkOrientedImageData()
slicer.vtkSlicerSegmentationsModuleLogic.GetSegmentBinaryLabelmapRepresentation(seg, segID, orImg)
mat = vtk.vtkMatrix4x4()
orImg.GetImageToWorldMatrix(mat)
orImg.SetImageToWorldMatrix(vtk.vtkMatrix4x4())
inputDiscreteCubes = vtk.vtkDiscreteMarchingCubes()
inputDiscreteCubes.SetInputData(orImg)
inputDiscreteCubes.GenerateValues(1,0,0)
inputDiscreteCubes.Update()
transform = vtk.vtkTransform()
transform.SetMatrix(mat)
transformFilter=vtk.vtkTransformPolyDataFilter()
transformFilter.SetTransform(transform)
transformFilter.SetInputData(inputDiscreteCubes.GetOutput())
transformFilter.Update()
modelNode = modelsLogic.AddModel(transformFilter.GetOutput())
But why does it not work in the first place without removing and reapplying the transform? And which transform has to be applied to the resulting model without removing the matrix from the oriented imagedata?
Thank you, Sebastian
1 Like
cpinter
(Csaba Pinter)
July 16, 2019, 4:05pm
2
Instead of reimplementing existing features, I would strongly suggest using what is already available and tested:
/// \param insertBeforeSegmentId New segments will be inserted before this segment.
static bool ImportLabelmapToSegmentationNode(vtkMRMLLabelMapVolumeNode* labelmapNode,
vtkMRMLSegmentationNode* segmentationNode, std::string insertBeforeSegmentId="");
/// Import all labels from a labelmap image to a segmentation node, each label to a separate segment
/// The colors of the new segments are randomly generated, unless terminology context is specified, in which case the terminology
/// entries are attempted to be mapped to the imported labels
/// LabelmapImage is defined in the segmentation node's coordinate system
/// (parent transform of the segmentation node is not used during import).
/// \param baseSegmentName Prefix for the names of the new segments. Empty by default, in which case the prefix will be "Label"
static bool ImportLabelmapToSegmentationNode(vtkOrientedImageData* labelmapImage,
vtkMRMLSegmentationNode* segmentationNode, std::string baseSegmentName="", std::string insertBeforeSegmentId="") ;
/// Update segmentation from segments in a labelmap node.
/// \param updatedSegmentIDs Defines how label values 1..N are mapped to segment IDs (0..N-1).
static bool ImportLabelmapToSegmentationNode(vtkMRMLLabelMapVolumeNode* labelmapNode,
vtkMRMLSegmentationNode* segmentationNode, vtkStringArray* updatedSegmentIDs);
/// Update segmentation from segments in a labelmap node.
/// \param updatedSegmentIDs Defines how label values 1..N are mapped to segment IDs (0..N-1).
static bool ImportLabelmapToSegmentationNode(vtkOrientedImageData* labelmapImage,
/// 1. If representation node is a labelmap node, then the binary labelmap representation of the
/// segment is copied
/// 2. If representation node is a model node, then the closed surface representation is copied
/// Otherwise return with failure.
static bool ExportSegmentToRepresentationNode(vtkSegment* segment, vtkMRMLNode* representationNode);
/// Export multiple segments into a model hierarchy, a model node from each segment
/// \param segmentationNode Segmentation node from which the the segments are exported
/// \param segmentIds List of segment IDs to export
/// \param modelHierarchyNode Model hierarchy to export the segments to
static bool ExportSegmentsToModelHierarchy(vtkMRMLSegmentationNode* segmentationNode,
std::vector<std::string>& segmentIDs, vtkMRMLModelHierarchyNode* modelHierarchyNode);
/// Export multiple segments into a model hierarchy, a model node from each segment
/// \param segmentationNode Segmentation node from which the the segments are exported
/// \param segmentIds List of segment IDs to export
/// \param modelHierarchyNode Model hierarchy to export the segments to
static bool ExportSegmentsToModelHierarchy(vtkMRMLSegmentationNode* segmentationNode,
vtkStringArray* segmentIds, vtkMRMLModelHierarchyNode* modelHierarchyNode);
/// Export visible segments into a model hierarchy, a model node from each segment
lassoan
(Andras Lasso)
July 16, 2019, 4:17pm
3
I fully agree, just use these existing methods for that. You can find examples in the script repository .
We plan to retire vtkOrientedImageData in Slicer5 by this fall (as image orientation is now part of vtkImageData ) and that will make things much simpler.