Skip to content

Commit

Permalink
ENH: Consolidate segmentation masking options
Browse files Browse the repository at this point in the history
There were two sets of enums for the same purpose, the set in vtkMRMLSegmentEditorNode marked as deprecated. Now it is removed, and the enums in vtkMRMLSegmentationNode are used everywhere.
  • Loading branch information
cpinter authored and lassoan committed Mar 25, 2022
1 parent a258951 commit fc64d91
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 87 deletions.
56 changes: 44 additions & 12 deletions Libs/MRML/Core/vtkMRMLSegmentationNode.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -624,45 +624,45 @@ bool vtkMRMLSegmentationNode::GenerateEditMask(vtkOrientedImageData* maskImage,
}

std::vector<std::string> maskSegmentIDs;
bool paintInsideSegments = false;
bool editInsideSegments = false;
switch (editMode)
{
case vtkMRMLSegmentationNode::EditAllowedEverywhere:
paintInsideSegments = false;
editInsideSegments = false;
break;
case vtkMRMLSegmentationNode::EditAllowedInsideAllSegments:
paintInsideSegments = true;
editInsideSegments = true;
maskSegmentIDs = allSegmentIDs;
break;
case vtkMRMLSegmentationNode::EditAllowedInsideVisibleSegments:
paintInsideSegments = true;
editInsideSegments = true;
maskSegmentIDs = visibleSegmentIDs;
break;
case vtkMRMLSegmentationNode::EditAllowedOutsideAllSegments:
paintInsideSegments = false;
editInsideSegments = false;
maskSegmentIDs = allSegmentIDs;
break;
case vtkMRMLSegmentationNode::EditAllowedOutsideVisibleSegments:
paintInsideSegments = false;
editInsideSegments = false;
maskSegmentIDs = visibleSegmentIDs;
break;
case vtkMRMLSegmentationNode::EditAllowedInsideSingleSegment:
paintInsideSegments = true;
editInsideSegments = true;
if (!maskSegmentID.empty())
{
maskSegmentIDs.push_back(maskSegmentID);
}
else
{
vtkWarningMacro("vtkMRMLSegmentationNode::GenerateEditMask: PaintAllowedInsideSingleSegment selected but no mask segment is specified");
vtkWarningMacro("vtkMRMLSegmentationNode::GenerateEditMask: EditAllowedInsideSingleSegment selected but no mask segment is specified");
}
break;
default:
vtkErrorMacro("vtkMRMLSegmentationNode::GenerateEditMask: unknown mask mode");
return false;
}

if (!paintInsideSegments)
if (!editInsideSegments)
{
// Exclude edited segment from "outside" mask
maskSegmentIDs.erase(std::remove(maskSegmentIDs.begin(), maskSegmentIDs.end(), editedSegmentID), maskSegmentIDs.end());
Expand All @@ -678,7 +678,7 @@ bool vtkMRMLSegmentationNode::GenerateEditMask(vtkOrientedImageData* maskImage,
// If we passed empty segment list to GenerateSharedLabelmap then it would use all segment IDs,
// instead of filling the volume with a single value. Therefore, we need to handle this special case separately here.
maskImage->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
vtkOrientedImageDataResample::FillImage(maskImage, paintInsideSegments ? 1 : 0);
vtkOrientedImageDataResample::FillImage(maskImage, editInsideSegments ? 1 : 0);
}
else
{
Expand All @@ -687,8 +687,8 @@ bool vtkMRMLSegmentationNode::GenerateEditMask(vtkOrientedImageData* maskImage,

vtkNew<vtkImageThreshold> threshold;
threshold->SetInputData(maskImage);
threshold->SetInValue(paintInsideSegments ? 1 : 0);
threshold->SetOutValue(paintInsideSegments ? 0 : 1);
threshold->SetInValue(editInsideSegments ? 1 : 0);
threshold->SetOutValue(editInsideSegments ? 0 : 1);
threshold->ReplaceInOn();
threshold->ThresholdByLower(0);
threshold->SetOutputScalarType(VTK_UNSIGNED_CHAR);
Expand Down Expand Up @@ -1226,3 +1226,35 @@ void vtkMRMLSegmentationNode::OnNodeReferenceRemoved(vtkMRMLNodeReference* refer
this->InvokeCustomModifiedEvent(vtkMRMLSegmentationNode::ReferenceImageGeometryChangedEvent, reference->GetReferencedNode());
}
}

//----------------------------------------------------------------------------
const char* vtkMRMLSegmentationNode::ConvertMaskModeToString(int mode)
{
switch (mode)
{
case EditAllowedEverywhere: return "EditAllowedEverywhere";
case EditAllowedInsideAllSegments: return "EditAllowedInsideAllSegments";
case EditAllowedInsideVisibleSegments: return "EditAllowedInsideVisibleSegments";
case EditAllowedOutsideAllSegments: return "EditAllowedOutsideAllSegments";
case EditAllowedOutsideVisibleSegments: return "EditAllowedOutsideVisibleSegments";
case EditAllowedInsideSingleSegment: return "EditAllowedInsideSingleSegment";
default: return "";
}
}

//----------------------------------------------------------------------------
int vtkMRMLSegmentationNode::ConvertMaskModeFromString(const char* modeStr)
{
if (!modeStr)
{
return -1;
}
for (int i=0; i<EditAllowed_Last; i++)
{
if (strcmp(modeStr, vtkMRMLSegmentationNode::ConvertMaskModeToString(i)) == 0)
{
return i;
}
}
return -1;
}
6 changes: 6 additions & 0 deletions Libs/MRML/Core/vtkMRMLSegmentationNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ class VTK_MRML_EXPORT vtkMRMLSegmentationNode : public vtkMRMLDisplayableNode
EditAllowed_Last
};

//@{
/// Convert between constants IDs to/from string
static const char* ConvertMaskModeToString(int mode);
static int ConvertMaskModeFromString(const char* modeStr);
//@}

/// Generates an edit mask image.
/// If a mask voxel is non-zero it means that the image at that position is editable.
/// \param maskImage output image, contains non-zero voxels where editing is not allowed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ void qSlicerSegmentEditorAbstractEffect::modifySegmentByLabelmap(vtkMRMLSegmenta
SlicerRenderBlocker renderBlocker;

vtkSmartPointer<vtkOrientedImageData> modifierLabelmap = modifierLabelmapInput;
if ((!bypassMasking && parameterSetNode->GetMaskMode() != vtkMRMLSegmentEditorNode::PaintAllowedEverywhere) ||
if ((!bypassMasking && parameterSetNode->GetMaskMode() != vtkMRMLSegmentationNode::EditAllowedEverywhere) ||
parameterSetNode->GetMasterVolumeIntensityMask())
{
vtkNew<vtkOrientedImageData> maskImage;
Expand All @@ -315,7 +315,7 @@ void qSlicerSegmentEditorAbstractEffect::modifySegmentByLabelmap(vtkMRMLSegmenta
vtkOrientedImageDataResample::FillImage(maskImage, m_EraseValue);

// Apply mask to modifier labelmap if masking is enabled
if (!bypassMasking && parameterSetNode->GetMaskMode() != vtkMRMLSegmentEditorNode::PaintAllowedEverywhere)
if (!bypassMasking && parameterSetNode->GetMaskMode() != vtkMRMLSegmentationNode::EditAllowedEverywhere)
{
vtkOrientedImageDataResample::ModifyImage(maskImage, this->maskLabelmap(), vtkOrientedImageDataResample::OPERATION_MAXIMUM);
}
Expand Down Expand Up @@ -612,7 +612,7 @@ void qSlicerSegmentEditorAbstractEffect::modifySegmentByLabelmap(vtkMRMLSegmenta
}
}
else if (modificationMode == qSlicerSegmentEditorAbstractEffect::ModificationModeRemove
&& this->parameterSetNode()->GetMaskMode() == vtkMRMLSegmentEditorNode::PaintAllowedInsideSingleSegment
&& this->parameterSetNode()->GetMaskMode() == vtkMRMLSegmentationNode::EditAllowedInsideSingleSegment
&& this->parameterSetNode()->GetMaskSegmentID()
&& strcmp(this->parameterSetNode()->GetMaskSegmentID(), segmentID) != 0)
{
Expand Down
39 changes: 3 additions & 36 deletions Modules/Loadable/Segmentations/MRML/vtkMRMLSegmentEditorNode.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
// Segmentations MRML includes
#include "vtkMRMLSegmentEditorNode.h"

#include "vtkMRMLSegmentationNode.h"
#include "vtkOrientedImageDataResample.h"

// MRML includes
Expand Down Expand Up @@ -69,7 +68,7 @@ void vtkMRMLSegmentEditorNode::WriteXML(ostream& of, int nIndent)
// Write all MRML node attributes into output stream
of << " selectedSegmentID=\"" << (this->SelectedSegmentID?this->SelectedSegmentID:"") << "\"";
of << " activeEffectName=\"" << (this->ActiveEffectName?this->ActiveEffectName:"") << "\"";
of << " maskMode=\"" << vtkMRMLSegmentEditorNode::ConvertMaskModeToString(this->MaskMode) << "\"";
of << " maskMode=\"" << vtkMRMLSegmentationNode::ConvertMaskModeToString(this->MaskMode) << "\"";
of << " maskSegmentID=\"" << (this->MaskSegmentID?this->MaskSegmentID:"") << "\"";
of << " masterVolumeIntensityMask=\"" << (this->MasterVolumeIntensityMask ? "true" : "false") << "\"";
of << " masterVolumeIntensityMaskRange=\"" << this->MasterVolumeIntensityMaskRange[0] << " " << this->MasterVolumeIntensityMaskRange[1] << "\"";
Expand Down Expand Up @@ -102,7 +101,7 @@ void vtkMRMLSegmentEditorNode::ReadXMLAttributes(const char** atts)
}
else if (!strcmp(attName, "maskMode"))
{
this->SetMaskMode(vtkMRMLSegmentEditorNode::ConvertMaskModeFromString(attValue));
this->SetMaskMode(vtkMRMLSegmentationNode::ConvertMaskModeFromString(attValue));
}
else if (!strcmp(attName, "maskSegmentID"))
{
Expand Down Expand Up @@ -159,7 +158,7 @@ void vtkMRMLSegmentEditorNode::PrintSelf(ostream& os, vtkIndent indent)

os << indent << "SelectedSegmentID: " << (this->SelectedSegmentID ? this->SelectedSegmentID : "") << "\n";
os << indent << "ActiveEffectName: " << (this->ActiveEffectName ? this->ActiveEffectName : "") << "\n";
os << indent << "MaskMode: " << vtkMRMLSegmentEditorNode::ConvertMaskModeToString(this->MaskMode) << "\n";
os << indent << "MaskMode: " << vtkMRMLSegmentationNode::ConvertMaskModeToString(this->MaskMode) << "\n";
os << indent << "MaskSegmentID: " << (this->MaskSegmentID?this->MaskSegmentID:"") << "\n";
os << indent << "OverwriteMode: " << vtkMRMLSegmentEditorNode::ConvertOverwriteModeToString(this->OverwriteMode) << "\n";
os << indent << "MasterVolumeIntensityMask: " << (this->MasterVolumeIntensityMask ? "true" : "false") << "\n";
Expand Down Expand Up @@ -190,38 +189,6 @@ void vtkMRMLSegmentEditorNode::SetAndObserveSegmentationNode(vtkMRMLSegmentation
this->SetNodeReferenceID(SEGMENTATION_REFERENCE_ROLE, (node ? node->GetID() : nullptr));
}

//----------------------------------------------------------------------------
const char* vtkMRMLSegmentEditorNode::ConvertMaskModeToString(int mode)
{
switch (mode)
{
case PaintAllowedEverywhere: return "PaintAllowedEverywhere";
case PaintAllowedInsideAllSegments: return "PaintAllowedInsideAllSegments";
case PaintAllowedInsideVisibleSegments: return "PaintAllowedInsideVisibleSegments";
case PaintAllowedOutsideAllSegments: return "PaintAllowedOutsideAllSegments";
case PaintAllowedOutsideVisibleSegments: return "PaintAllowedOutsideVisibleSegments";
case PaintAllowedInsideSingleSegment: return "PaintAllowedInsideSingleSegment";
default: return "";
}
}

//----------------------------------------------------------------------------
int vtkMRMLSegmentEditorNode::ConvertMaskModeFromString(const char* modeStr)
{
if (!modeStr)
{
return -1;
}
for (int i=0; i<PaintAllowed_Last; i++)
{
if (strcmp(modeStr, vtkMRMLSegmentEditorNode::ConvertMaskModeToString(i))==0)
{
return i;
}
}
return -1;
}

//----------------------------------------------------------------------------
const char* vtkMRMLSegmentEditorNode::ConvertOverwriteModeToString(int mode)
{
Expand Down
37 changes: 8 additions & 29 deletions Modules/Loadable/Segmentations/MRML/vtkMRMLSegmentEditorNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

// MRML includes
#include <vtkMRMLNode.h>
#include <vtkMRMLSegmentationNode.h>

// Segmentations includes
#include "vtkSlicerSegmentationsModuleMRMLExport.h"
Expand All @@ -33,7 +34,6 @@

class vtkMRMLScene;
class vtkMRMLScalarVolumeNode;
class vtkMRMLSegmentationNode;

/// \ingroup Segmentations
/// \brief Parameter set node for the segment editor widget
Expand All @@ -54,26 +54,6 @@ class VTK_SLICER_SEGMENTATIONS_MODULE_MRML_EXPORT vtkMRMLSegmentEditorNode : pub
EffectParameterModified = 62200
};

/// These enums are kept here only for backward compatibility and will be removed in the future.
/// Use vtkMRMLSegmentationNode EditAllowed... enums instead.
enum
{
/// Modification is allowed everywhere.
PaintAllowedEverywhere=0,
/// Modification is allowed inside all segments.
PaintAllowedInsideAllSegments,
/// Modification is allowed inside all visible segments.
PaintAllowedInsideVisibleSegments,
/// Modification is allowed outside all segments.
PaintAllowedOutsideAllSegments,
/// Modification is allowed outside all visible segments.
PaintAllowedOutsideVisibleSegments,
/// Modification is allowed only over the area covered by segment specified in MaskSegmentID.
PaintAllowedInsideSingleSegment,
// Insert valid types above this line
PaintAllowed_Last
};

enum
{
/// Areas added to selected segment will be removed from all other segments. (no overlap)
Expand Down Expand Up @@ -110,8 +90,6 @@ class VTK_SLICER_SEGMENTATIONS_MODULE_MRML_EXPORT vtkMRMLSegmentEditorNode : pub
/// Convert between constants IDs to/from string
static int ConvertOverwriteModeFromString(const char* modeStr);
static const char* ConvertOverwriteModeToString(int mode);
static const char* ConvertMaskModeToString(int mode);
static int ConvertMaskModeFromString(const char* modeStr);
//@}

public:
Expand Down Expand Up @@ -144,17 +122,18 @@ class VTK_SLICER_SEGMENTATIONS_MODULE_MRML_EXPORT vtkMRMLSegmentEditorNode : pub

//@{
/// Defines which areas in the segmentation are editable.
/// Uses PaintAllowed_... constants.
/// \sa PaintAllowedEverywhere, PaintAllowedInsideAllSegments, PaintAllowedInsideVisibleSegments,
/// PaintAllowedOutsideAllSegments, PaintAllowedOutsideVisibleSegments, PaintAllowedInsideSingleSegment
/// Uses vtkMRMLSegmentationNode::EditAllowed_... constants.
/// \sa vtkMRMLSegmentationNode::EditAllowedEverywhere, vtkMRMLSegmentationNode::EditAllowedInsideAllSegments,
/// vtkMRMLSegmentationNode::EditAllowedInsideVisibleSegments, vtkMRMLSegmentationNode::EditAllowedOutsideAllSegments,
/// vtkMRMLSegmentationNode::EditAllowedOutsideVisibleSegments, vtkMRMLSegmentationNode::EditAllowedInsideSingleSegment
vtkSetMacro(MaskMode, int);
vtkGetMacro(MaskMode, int);
//@}

//@{
/// Get/set mask segment ID.
/// Painting is only allowed within the area of the mask segment if mask mode is PaintAllowedInsideSingleSegment.
/// \sa PaintAllowedInsideSingleSegment, SetMaskMode
/// Painting is only allowed within the area of the mask segment if mask mode is EditAllowedInsideSingleSegment.
/// \sa vtkMRMLSegmentationNode::EditAllowedInsideSingleSegment, SetMaskMode
vtkGetStringMacro(MaskSegmentID);
vtkSetStringMacro(MaskSegmentID);
//@}
Expand Down Expand Up @@ -194,7 +173,7 @@ class VTK_SLICER_SEGMENTATIONS_MODULE_MRML_EXPORT vtkMRMLSegmentEditorNode : pub
/// Active effect name
char* ActiveEffectName{nullptr};

int MaskMode{PaintAllowedEverywhere};
int MaskMode{vtkMRMLSegmentationNode::EditAllowedEverywhere};
char* MaskSegmentID{nullptr};

int OverwriteMode{OverwriteAllSegments};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,11 +400,11 @@ void qMRMLSegmentEditorWidgetPrivate::init()
this->SpecifyGeometryButton->setMaximumHeight(this->MasterVolumeNodeComboBox->sizeHint().height());
this->SpecifyGeometryButton->setMaximumWidth(this->MasterVolumeNodeComboBox->sizeHint().height());

this->MaskModeComboBox->addItem(qMRMLSegmentEditorWidget::tr("Everywhere"), vtkMRMLSegmentEditorNode::PaintAllowedEverywhere);
this->MaskModeComboBox->addItem(qMRMLSegmentEditorWidget::tr("Inside all segments"), vtkMRMLSegmentEditorNode::PaintAllowedInsideAllSegments);
this->MaskModeComboBox->addItem(qMRMLSegmentEditorWidget::tr("Inside all visible segments"), vtkMRMLSegmentEditorNode::PaintAllowedInsideVisibleSegments);
this->MaskModeComboBox->addItem(qMRMLSegmentEditorWidget::tr("Outside all segments"), vtkMRMLSegmentEditorNode::PaintAllowedOutsideAllSegments);
this->MaskModeComboBox->addItem(qMRMLSegmentEditorWidget::tr("Outside all visible segments"), vtkMRMLSegmentEditorNode::PaintAllowedOutsideVisibleSegments);
this->MaskModeComboBox->addItem(qMRMLSegmentEditorWidget::tr("Everywhere"), vtkMRMLSegmentationNode::EditAllowedEverywhere);
this->MaskModeComboBox->addItem(qMRMLSegmentEditorWidget::tr("Inside all segments"), vtkMRMLSegmentationNode::EditAllowedInsideAllSegments);
this->MaskModeComboBox->addItem(qMRMLSegmentEditorWidget::tr("Inside all visible segments"), vtkMRMLSegmentationNode::EditAllowedInsideVisibleSegments);
this->MaskModeComboBox->addItem(qMRMLSegmentEditorWidget::tr("Outside all segments"), vtkMRMLSegmentationNode::EditAllowedOutsideAllSegments);
this->MaskModeComboBox->addItem(qMRMLSegmentEditorWidget::tr("Outside all visible segments"), vtkMRMLSegmentationNode::EditAllowedOutsideVisibleSegments);
this->MaskModeComboBox->insertSeparator(this->MaskModeComboBox->count());
this->MaskModeComboBoxFixedItemsCount = this->MaskModeComboBox->count();

Expand Down Expand Up @@ -1341,7 +1341,7 @@ void qMRMLSegmentEditorWidget::updateMaskingSection()

bool wasBlocked = d->MaskModeComboBox->blockSignals(true);
int maskModeIndex = -1;
if (d->ParameterSetNode->GetMaskMode() == vtkMRMLSegmentEditorNode::PaintAllowedInsideSingleSegment)
if (d->ParameterSetNode->GetMaskMode() == vtkMRMLSegmentationNode::EditAllowedInsideSingleSegment)
{
// segment item
maskModeIndex = d->MaskModeComboBox->findData(d->ParameterSetNode->GetMaskSegmentID());
Expand Down Expand Up @@ -3000,7 +3000,7 @@ void qMRMLSegmentEditorWidget::onMaskModeChanged(int index)
{
// specific index is selected
d->ParameterSetNode->SetMaskSegmentID(d->MaskModeComboBox->itemData(index).toString().toUtf8());
d->ParameterSetNode->SetMaskMode(vtkMRMLSegmentEditorNode::PaintAllowedInsideSingleSegment);
d->ParameterSetNode->SetMaskMode(vtkMRMLSegmentationNode::EditAllowedInsideSingleSegment);
}
else
{
Expand Down

0 comments on commit fc64d91

Please sign in to comment.