Fills or erases a 2D region. More...
#include <mitkSetRegionTool.h>
Public Types | |
typedef SetRegionTool | Self |
typedef FeedbackContourTool | Superclass |
typedef itk::SmartPointer< Self > | Pointer |
typedef itk::SmartPointer < const Self > | ConstPointer |
Public Member Functions | |
virtual const char * | GetClassName () const |
Protected Member Functions | |
SetRegionTool (int paintingPixelValue=1) | |
virtual | ~SetRegionTool () |
virtual void | Activated () |
Called when the tool gets activated (registered to mitk::GlobalInteraction). | |
virtual void | Deactivated () |
Called when the tool gets deactivated (unregistered from mitk::GlobalInteraction). | |
virtual bool | OnMousePressed (Action *, const StateEvent *) |
virtual bool | OnMouseReleased (Action *, const StateEvent *) |
virtual bool | OnInvertLogic (Action *, const StateEvent *) |
Protected Attributes | |
int | m_PaintingPixelValue |
bool | m_FillContour |
bool | m_StatusFillWholeSlice |
Contour::Pointer | m_SegmentationContourInWorldCoordinates |
Contour::Pointer | m_WholeImageContourInWorldCoordinates |
Fills or erases a 2D region.
Finds the outer contour of a shape in 2D (possibly including holes) and sets all the inside pixels to a specified value. This might fill holes or erase segmentations.
$Author$
Definition at line 47 of file mitkSetRegionTool.h.
typedef itk::SmartPointer<const Self> mitk::SetRegionTool::ConstPointer |
Reimplemented from mitk::FeedbackContourTool.
Reimplemented in mitk::EraseRegionTool, and mitk::FillRegionTool.
Definition at line 51 of file mitkSetRegionTool.h.
typedef itk::SmartPointer<Self> mitk::SetRegionTool::Pointer |
Reimplemented from mitk::FeedbackContourTool.
Reimplemented in mitk::EraseRegionTool, and mitk::FillRegionTool.
Definition at line 51 of file mitkSetRegionTool.h.
Reimplemented from mitk::FeedbackContourTool.
Reimplemented in mitk::EraseRegionTool, and mitk::FillRegionTool.
Definition at line 51 of file mitkSetRegionTool.h.
Reimplemented from mitk::FeedbackContourTool.
Reimplemented in mitk::EraseRegionTool, and mitk::FillRegionTool.
Definition at line 51 of file mitkSetRegionTool.h.
mitk::SetRegionTool::SetRegionTool | ( | int | paintingPixelValue = 1 ) |
[protected] |
Definition at line 27 of file mitkSetRegionTool.cpp.
:FeedbackContourTool("PressMoveReleaseWithCTRLInversion"), m_PaintingPixelValue(paintingPixelValue), m_FillContour(false), m_StatusFillWholeSlice(false) { }
mitk::SetRegionTool::~SetRegionTool | ( | ) | [protected, virtual] |
Definition at line 35 of file mitkSetRegionTool.cpp.
{ }
void mitk::SetRegionTool::Activated | ( | ) | [protected, virtual] |
Called when the tool gets activated (registered to mitk::GlobalInteraction).
Derived tools should call their parents implementation.
Reimplemented from mitk::Tool.
Definition at line 39 of file mitkSetRegionTool.cpp.
{ Superclass::Activated(); }
void mitk::SetRegionTool::Deactivated | ( | ) | [protected, virtual] |
Called when the tool gets deactivated (unregistered from mitk::GlobalInteraction).
Derived tools should call their parents implementation.
Reimplemented from mitk::Tool.
Definition at line 44 of file mitkSetRegionTool.cpp.
{ Superclass::Deactivated(); }
virtual const char* mitk::SetRegionTool::GetClassName | ( | ) | const [virtual] |
Reimplemented from mitk::FeedbackContourTool.
Reimplemented in mitk::EraseRegionTool, and mitk::FillRegionTool.
bool mitk::SetRegionTool::OnInvertLogic | ( | Action * | action, |
const StateEvent * | stateEvent | ||
) | [protected, virtual] |
Called when the CTRL key is pressed. Will change the painting pixel value from 0 to 1 or from 1 to 0.
Reimplemented from mitk::SegTool2D.
Definition at line 303 of file mitkSetRegionTool.cpp.
References mitk::StateEvent::GetEvent(), mitk::RenderingManager::GetInstance(), mitk::BaseRenderer::GetRenderWindow(), mitk::Event::GetSender(), mitk::SegTool2D::OnInvertLogic(), mitk::RenderingManager::RequestUpdate(), and mitk::FeedbackContourTool::SetFeedbackContour().
{ if (!FeedbackContourTool::OnInvertLogic(action, stateEvent)) return false; const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent()); if (!positionEvent) return false; if (m_StatusFillWholeSlice) { // use contour extracted from image data if (m_SegmentationContourInWorldCoordinates.IsNotNull()) FeedbackContourTool::SetFeedbackContour( *m_SegmentationContourInWorldCoordinates ); mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); } else { // use some artificial contour if (m_WholeImageContourInWorldCoordinates.IsNotNull()) FeedbackContourTool::SetFeedbackContour( *m_WholeImageContourInWorldCoordinates ); mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); } m_StatusFillWholeSlice = !m_StatusFillWholeSlice; return true; }
bool mitk::SetRegionTool::OnMousePressed | ( | Action * | action, |
const StateEvent * | stateEvent | ||
) | [protected, virtual] |
The logic of finding a starting point for the contour is the following:
In both cases the found contour point is used to extract a contour and then a test is applied to find out if the initial seed point is contained in the contour. If this is the case, filling should be applied, otherwise nothing is done.
Reimplemented from mitk::SegTool2D.
Definition at line 49 of file mitkSetRegionTool.cpp.
References mitk::FeedbackContourTool::BackProjectContourFrom2DSlice(), mitk::CastToItkImage(), mitk::CastToMitkImage(), mitk::SegTool2D::GetAffectedWorkingSlice(), mitk::StateEvent::GetEvent(), mitk::RenderingManager::GetInstance(), mitk::BaseRenderer::GetRenderWindow(), mitk::Event::GetSender(), mitk::DisplayPositionEvent::GetWorldPosition(), ipMITKSegmentationGetContour8N(), ipMITKSegmentationIsInsideContour(), ipMITKSegmentationTYPE, mitk::Geometry3D::IsIndexInside(), MITK_ERROR, mitkIpPicDescriptor, mitk::Contour::New(), mitk::Image::New(), mitk::SegTool2D::OnMousePressed(), mitk::RenderingManager::RequestUpdate(), mitk::FeedbackContourTool::SetFeedbackContour(), mitk::FeedbackContourTool::SetFeedbackContourVisible(), and mitk::Geometry3D::WorldToIndex().
{ if (!FeedbackContourTool::OnMousePressed( action, stateEvent )) return false; const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent()); if (!positionEvent) return false; // 1. Get the working image Image::Pointer workingSlice = FeedbackContourTool::GetAffectedWorkingSlice( positionEvent ); if ( workingSlice.IsNull() ) return false; // can't do anything without the segmentation // if click was outside the image, don't continue const Geometry3D* sliceGeometry = workingSlice->GetGeometry(); itk::Index<2> projectedPointIn2D; sliceGeometry->WorldToIndex( positionEvent->GetWorldPosition(), projectedPointIn2D ); if ( !sliceGeometry->IsIndexInside( projectedPointIn2D ) ) { MITK_ERROR << "point apparently not inside segmentation slice" << std::endl; return false; // can't use that as a seed point } // Convert to ipMITKSegmentationTYPE (because ipMITKSegmentationGetContour8N relys on that data type) itk::Image< ipMITKSegmentationTYPE, 2 >::Pointer correctPixelTypeImage; CastToItkImage( workingSlice, correctPixelTypeImage ); assert (correctPixelTypeImage.IsNotNull() ); // possible bug in CastToItkImage ? // direction maxtrix is wrong/broken/not working after CastToItkImage, leading to a failed assertion in // mitk/Core/DataStructures/mitkSlicedGeometry3D.cpp, 479: // virtual void mitk::SlicedGeometry3D::SetSpacing(const mitk::Vector3D&): Assertion `aSpacing[0]>0 && aSpacing[1]>0 && aSpacing[2]>0' failed // solution here: we overwrite it with an unity matrix itk::Image< ipMITKSegmentationTYPE, 2 >::DirectionType imageDirection; imageDirection.SetIdentity(); correctPixelTypeImage->SetDirection(imageDirection); Image::Pointer temporarySlice = Image::New(); // temporarySlice = ImportItkImage( correctPixelTypeImage ); CastToMitkImage( correctPixelTypeImage, temporarySlice ); // check index positions mitkIpPicDescriptor* originalPicSlice = temporarySlice->GetSliceData()->GetPicDescriptor(); int m_SeedPointMemoryOffset = projectedPointIn2D[1] * originalPicSlice->n[0] + projectedPointIn2D[0]; if ( m_SeedPointMemoryOffset >= static_cast<int>( originalPicSlice->n[0] * originalPicSlice->n[1] ) || m_SeedPointMemoryOffset < 0 ) { MITK_ERROR << "Memory offset calculation if mitk::SetRegionTool has some serious flaw! Aborting.." << std::endl; return false; } // 2. Determine the contour that surronds the selected "piece of the image" // find a contour seed point unsigned int oneContourOffset = static_cast<unsigned int>( m_SeedPointMemoryOffset ); // safe because of earlier check if m_SeedPointMemoryOffset < 0 unsigned int size = originalPicSlice->n[0] * originalPicSlice->n[1]; /* unsigned int rowSize = originalPicSlice->n[0]; */ ipMITKSegmentationTYPE* data = static_cast<ipMITKSegmentationTYPE*>(originalPicSlice->data); if ( data[oneContourOffset] == 0 ) // initial seed 0 { for ( ; oneContourOffset < size; ++oneContourOffset ) { if ( data[oneContourOffset] > 0 ) break; } } else if ( data[oneContourOffset] == 1 ) // initial seed 1 { unsigned int lastValidPixel = size-1; // initialization, will be changed lateron bool inSeg = true; // inside segmentation? for ( ; oneContourOffset < size; ++oneContourOffset ) { if ( ( data[oneContourOffset] == 0 ) && inSeg ) // pixel 0 and inside-flag set: this happens at the first pixel outside a filled region { inSeg = false; lastValidPixel = oneContourOffset - 1; // store the last pixel position inside a filled region break; } else // pixel 1, inside-flag doesn't matter: this happens while we are inside a filled region { inSeg = true; // first iteration lands here } } oneContourOffset = lastValidPixel; } else { MITK_ERROR << "Fill/Erase was never intended to work with other than binary images." << std::endl; m_FillContour = false; return false; } if (oneContourOffset == size) // nothing found until end of slice { m_FillContour = false; return false; } int numberOfContourPoints( 0 ); int newBufferSize( 0 ); //MITK_INFO << "getting contour from offset " << oneContourOffset << " ("<<oneContourOffset%originalPicSlice->n[0]<<","<<oneContourOffset/originalPicSlice->n[0]<<")"<<std::endl; float* contourPoints = ipMITKSegmentationGetContour8N( originalPicSlice, oneContourOffset, numberOfContourPoints, newBufferSize ); // memory allocated with malloc //MITK_INFO << "contourPoints " << contourPoints << " (N="<<numberOfContourPoints<<")"<<std::endl; assert(contourPoints == NULL || numberOfContourPoints > 0); bool cursorInsideContour = ipMITKSegmentationIsInsideContour( contourPoints, numberOfContourPoints, projectedPointIn2D[0], projectedPointIn2D[1]); // decide if contour should be filled or not m_FillContour = cursorInsideContour; if (m_FillContour) { // copy point from float* to mitk::Contour Contour::Pointer contourInImageIndexCoordinates = Contour::New(); contourInImageIndexCoordinates->Initialize(); Point3D newPoint; for (int index = 0; index < numberOfContourPoints; ++index) { newPoint[0] = contourPoints[ 2 * index + 0 ]; newPoint[1] = contourPoints[ 2 * index + 1]; newPoint[2] = 0; contourInImageIndexCoordinates->AddVertex( newPoint ); } m_SegmentationContourInWorldCoordinates = FeedbackContourTool::BackProjectContourFrom2DSlice( workingSlice, contourInImageIndexCoordinates, true ); // true, correct the result from ipMITKSegmentationGetContour8N // 3. Show the contour FeedbackContourTool::SetFeedbackContour( *m_SegmentationContourInWorldCoordinates ); FeedbackContourTool::SetFeedbackContourVisible(true); mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); } // always generate a second contour, containing the whole image (used when CTRL is pressed) { // copy point from float* to mitk::Contour Contour::Pointer contourInImageIndexCoordinates = Contour::New(); contourInImageIndexCoordinates->Initialize(); Point3D newPoint; newPoint[0] = 0; newPoint[1] = 0; newPoint[2] = 0.0; contourInImageIndexCoordinates->AddVertex( newPoint ); newPoint[0] = originalPicSlice->n[0]; newPoint[1] = 0; newPoint[2] = 0.0; contourInImageIndexCoordinates->AddVertex( newPoint ); newPoint[0] = originalPicSlice->n[0]; newPoint[1] = originalPicSlice->n[1]; newPoint[2] = 0.0; contourInImageIndexCoordinates->AddVertex( newPoint ); newPoint[0] = 0; newPoint[1] = originalPicSlice->n[1]; newPoint[2] = 0.0; contourInImageIndexCoordinates->AddVertex( newPoint ); m_WholeImageContourInWorldCoordinates = FeedbackContourTool::BackProjectContourFrom2DSlice( workingSlice, contourInImageIndexCoordinates, true ); // true, correct the result from ipMITKSegmentationGetContour8N // 3. Show the contour FeedbackContourTool::SetFeedbackContour( *m_SegmentationContourInWorldCoordinates ); FeedbackContourTool::SetFeedbackContourVisible(true); mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); } free(contourPoints); return true; }
bool mitk::SetRegionTool::OnMouseReleased | ( | Action * | action, |
const StateEvent * | stateEvent | ||
) | [protected, virtual] |
Reimplemented from mitk::SegTool2D.
Definition at line 233 of file mitkSetRegionTool.cpp.
References mitk::SegTool2D::DetermineAffectedImageSlice(), mitk::FeedbackContourTool::FillContourInSlice(), mitk::SegTool2D::GetAffectedImageSliceAs2DImage(), mitk::BaseRenderer::GetCurrentWorldGeometry2D(), mitk::StateEvent::GetEvent(), mitk::FeedbackContourTool::GetFeedbackContour(), mitk::RenderingManager::GetInstance(), mitk::BaseRenderer::GetRenderWindow(), mitk::Event::GetSender(), mitk::BaseRenderer::GetTimeStep(), MITK_ERROR, mitk::OverwriteSliceImageFilter::New(), mitk::SegTool2D::OnMouseReleased(), mitk::FeedbackContourTool::ProjectContourTo2DSlice(), mitk::RenderingManager::RequestUpdate(), and mitk::FeedbackContourTool::SetFeedbackContourVisible().
{ // 1. Hide the feedback contour, find out which slice the user clicked, find out which slice of the toolmanager's working image corresponds to that FeedbackContourTool::SetFeedbackContourVisible(false); const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent()); if (!positionEvent) return false; assert( positionEvent->GetSender()->GetRenderWindow() ); mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); if (!m_FillContour && !m_StatusFillWholeSlice) return true; if (!FeedbackContourTool::OnMouseReleased( action, stateEvent )) return false; DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); if (!workingNode) return false; Image* image = dynamic_cast<Image*>(workingNode->GetData()); const PlaneGeometry* planeGeometry( dynamic_cast<const PlaneGeometry*> (positionEvent->GetSender()->GetCurrentWorldGeometry2D() ) ); if ( !image || !planeGeometry ) return false; int affectedDimension( -1 ); int affectedSlice( -1 ); if ( FeedbackContourTool::DetermineAffectedImageSlice( image, planeGeometry, affectedDimension, affectedSlice ) ) { // 2. Slice is known, now we try to get it as a 2D image and project the contour into index coordinates of this slice Image::Pointer slice = FeedbackContourTool::GetAffectedImageSliceAs2DImage( positionEvent, image ); if ( slice.IsNull() ) { MITK_ERROR << "Unable to extract slice." << std::endl; return false; } Contour* feedbackContour( FeedbackContourTool::GetFeedbackContour() ); Contour::Pointer projectedContour = FeedbackContourTool::ProjectContourTo2DSlice( slice, feedbackContour, false, false ); // false: don't add 0.5 (done by FillContourInSlice) // false: don't constrain the contour to the image's inside if (projectedContour.IsNull()) return false; FeedbackContourTool::FillContourInSlice( projectedContour, slice, m_PaintingPixelValue ); // 5. Write the modified 2D working data slice back into the image OverwriteSliceImageFilter::Pointer slicewriter = OverwriteSliceImageFilter::New(); slicewriter->SetInput( image ); slicewriter->SetCreateUndoInformation( true ); slicewriter->SetSliceImage( slice ); slicewriter->SetSliceDimension( affectedDimension ); slicewriter->SetSliceIndex( affectedSlice ); slicewriter->SetTimeStep( positionEvent->GetSender()->GetTimeStep( image ) ); slicewriter->Update(); // 6. Make sure the result is drawn again --> is visible then. assert( positionEvent->GetSender()->GetRenderWindow() ); mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); } else { MITK_ERROR << "FeedbackContourTool could not determine which slice of the image you are drawing on." << std::endl; } m_WholeImageContourInWorldCoordinates = NULL; m_SegmentationContourInWorldCoordinates = NULL; return true; }
bool mitk::SetRegionTool::m_FillContour [protected] |
Definition at line 67 of file mitkSetRegionTool.h.
int mitk::SetRegionTool::m_PaintingPixelValue [protected] |
Definition at line 65 of file mitkSetRegionTool.h.
Definition at line 70 of file mitkSetRegionTool.h.
bool mitk::SetRegionTool::m_StatusFillWholeSlice [protected] |
Definition at line 68 of file mitkSetRegionTool.h.
Definition at line 71 of file mitkSetRegionTool.h.