Public Types | Public Member Functions | Static Public Member Functions | Protected Member Functions | Protected Attributes

mitk::RegionGrowingTool Class Reference
[Interaction ClassesClasses related to InteractiveSegmentation]

A slice based region growing tool. More...

#include <mitkRegionGrowingTool.h>

Inheritance diagram for mitk::RegionGrowingTool:
Inheritance graph
[legend]
Collaboration diagram for mitk::RegionGrowingTool:
Collaboration graph
[legend]

List of all members.

Public Types

typedef RegionGrowingTool Self
typedef FeedbackContourTool Superclass
typedef itk::SmartPointer< SelfPointer
typedef itk::SmartPointer
< const Self
ConstPointer

Public Member Functions

virtual const char * GetClassName () const
virtual const char ** GetXPM () const
 Returns an icon in the XPM format.
virtual const char * GetName () const
 Returns the name of this tool. Make it short!

Static Public Member Functions

static Pointer New ()

Protected Member Functions

 RegionGrowingTool ()
virtual ~RegionGrowingTool ()
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 OnMousePressedInside (Action *, const StateEvent *, mitkIpPicDescriptor *workingPicSlice, int initialWorkingOffset)
virtual bool OnMousePressedOutside (Action *, const StateEvent *)
virtual bool OnMouseMoved (Action *, const StateEvent *)
virtual bool OnMouseReleased (Action *, const StateEvent *)
mitkIpPicDescriptor * PerformRegionGrowingAndUpdateContour ()

Protected Attributes

Image::Pointer m_ReferenceSlice
Image::Pointer m_WorkingSlice
int m_LowerThreshold
int m_UpperThreshold
int m_InitialLowerThreshold
int m_InitialUpperThreshold
Point2I m_LastScreenPosition
int m_ScreenYDifference

Detailed Description

A slice based region growing tool.

See also:
FeedbackContourTool

When the user presses the mouse button, RegionGrowingTool will use the gray values at that position to initialize a region growing algorithm (in the affected 2D slice).

By moving the mouse up and down while the button is still pressed, the user can change the parameters of the region growing algorithm (selecting more or less of an object). The current result of region growing will always be shown as a contour to the user.

After releasing the button, the current result of the region growing algorithm will be written to the working image of this tool's ToolManager.

If the first click is inside a segmentation that was generated by region growing (recently), the tool will try to cut off a part of the segmentation. For this reason a skeletonization of the segmentation is generated and the optimal cut point is determined.

Warning:
Only to be instantiated by mitk::ToolManager.

$Author$

Definition at line 55 of file mitkRegionGrowingTool.h.


Member Typedef Documentation

typedef itk::SmartPointer<const Self> mitk::RegionGrowingTool::ConstPointer

Reimplemented from mitk::FeedbackContourTool.

Definition at line 59 of file mitkRegionGrowingTool.h.

typedef itk::SmartPointer<Self> mitk::RegionGrowingTool::Pointer

Reimplemented from mitk::FeedbackContourTool.

Definition at line 59 of file mitkRegionGrowingTool.h.

Reimplemented from mitk::FeedbackContourTool.

Definition at line 59 of file mitkRegionGrowingTool.h.

Reimplemented from mitk::FeedbackContourTool.

Definition at line 59 of file mitkRegionGrowingTool.h.


Constructor & Destructor Documentation

mitk::RegionGrowingTool::RegionGrowingTool (  ) [protected]

Definition at line 36 of file mitkRegionGrowingTool.cpp.

:FeedbackContourTool("PressMoveRelease"),
 m_LowerThreshold(200),
 m_UpperThreshold(200),
 m_InitialLowerThreshold(200),
 m_InitialUpperThreshold(200),
 m_ScreenYDifference(0),
 m_OriginalPicSlice(NULL),
 m_SeedPointMemoryOffset(0),
 m_VisibleWindow(0),
 m_DefaultWindow(0),
 m_MouseDistanceScaleFactor(3.0),
 m_LastWorkingSeed(-1),
 m_FillFeedbackContour(true)
{
}
mitk::RegionGrowingTool::~RegionGrowingTool (  ) [protected, virtual]

Definition at line 53 of file mitkRegionGrowingTool.cpp.

{
}

Member Function Documentation

void mitk::RegionGrowingTool::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 67 of file mitkRegionGrowingTool.cpp.

void mitk::RegionGrowingTool::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 72 of file mitkRegionGrowingTool.cpp.

virtual const char* mitk::RegionGrowingTool::GetClassName (  ) const [virtual]

Reimplemented from mitk::FeedbackContourTool.

const char * mitk::RegionGrowingTool::GetName (  ) const [virtual]

Returns the name of this tool. Make it short!

This name has to fit into some kind of button in most applications, so take some time to think of a good name!

Implements mitk::Tool.

Definition at line 62 of file mitkRegionGrowingTool.cpp.

{
  return "Region Growing";
}
const char ** mitk::RegionGrowingTool::GetXPM (  ) const [virtual]

Returns an icon in the XPM format.

This icon has to fit into some kind of button in most applications, so make it smaller than 25x25 pixels.

XPM is e.g. supported by The Gimp. But if you open any XPM file in your text editor, you will see that you could also "draw" it with an editor.

Implements mitk::Tool.

Definition at line 57 of file mitkRegionGrowingTool.cpp.

{
  return mitkRegionGrowingTool_xpm;
}
static Pointer mitk::RegionGrowingTool::New (  ) [static]
bool mitk::RegionGrowingTool::OnMouseMoved ( Action action,
const StateEvent stateEvent 
) [protected, virtual]

If in region growing mode (m_ReferenceSlice != NULL), then 1. Calculate the new thresholds from mouse position (relative to first position) 2. Perform a new region growing and update the feedback contour

Reimplemented from mitk::SegTool2D.

Definition at line 327 of file mitkRegionGrowingTool.cpp.

References mitk::RenderingManager::ForceImmediateUpdate(), mitk::ApplicationCursor::GetCursorPosition(), mitk::StateEvent::GetEvent(), mitk::RenderingManager::GetInstance(), mitk::ApplicationCursor::GetInstance(), mitk::BaseRenderer::GetRenderWindow(), mitk::Event::GetSender(), ipMITKSegmentationFree(), mitkIpPicDescriptor, mitk::SegTool2D::OnMouseMoved(), and mitk::ApplicationCursor::SetCursorPosition().

{
  if (FeedbackContourTool::OnMouseMoved( action, stateEvent ))
  {
    if ( m_ReferenceSlice.IsNotNull() && m_OriginalPicSlice ) 
    {
      const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
      if (positionEvent) 
      {
        ApplicationCursor* cursor = ApplicationCursor::GetInstance();
        if (!cursor) return false;
        m_ScreenYDifference += cursor->GetCursorPosition()[1] - m_LastScreenPosition[1];
        cursor->SetCursorPosition( m_LastScreenPosition );

        m_LowerThreshold = m_InitialLowerThreshold + static_cast<int>( m_ScreenYDifference * m_MouseDistanceScaleFactor );
        if (m_LowerThreshold < 1) m_LowerThreshold = 1;
        if (m_LowerThreshold > m_VisibleWindow / 2) m_LowerThreshold = m_VisibleWindow / 2;
        
        m_UpperThreshold = m_InitialUpperThreshold + static_cast<int>( m_ScreenYDifference * m_MouseDistanceScaleFactor );
        if (m_UpperThreshold < 1) m_UpperThreshold = 1;
        if (m_UpperThreshold > m_VisibleWindow / 2) m_UpperThreshold = m_VisibleWindow / 2;

        //MITK_INFO << "new interval: l " << m_LowerThreshold << " u " << m_UpperThreshold << std::endl;
        
        // 2. Perform region growing again and show the result
        mitkIpPicDescriptor* result = PerformRegionGrowingAndUpdateContour();
        ipMITKSegmentationFree( result );

        // 3. Update the contour
        mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(positionEvent->GetSender()->GetRenderWindow());
      }
    }
  }

  return true;
}
bool mitk::RegionGrowingTool::OnMousePressed ( Action action,
const StateEvent stateEvent 
) [protected, virtual]

1 Determine which slice is clicked into 2 Determine if the user clicked inside or outside of the segmentation 3 Depending on the pixel value under the mouse click position, two different things happen: (separated out into OnMousePressedInside and OnMousePressedOutside) 3.1 Create a skeletonization of the segmentation and try to find a nice cut 3.1.1 Call a ipSegmentation algorithm to create a nice cut 3.1.2 Set the result of this algorithm as the feedback contour 3.2 Initialize region growing 3.2.1 Determine memory offset inside the original image 3.2.2 Determine initial region growing parameters from the level window settings of the image 3.2.3 Perform a region growing (which generates a new feedback contour)

Reimplemented from mitk::SegTool2D.

Definition at line 89 of file mitkRegionGrowingTool.cpp.

References mitk::CastToItkImage(), mitk::CastToMitkImage(), mitk::SegTool2D::GetAffectedReferenceSlice(), mitk::SegTool2D::GetAffectedWorkingSlice(), mitk::StateEvent::GetEvent(), mitk::DisplayPositionEvent::GetWorldPosition(), ipMITKSegmentationTYPE, mitk::Geometry3D::IsIndexInside(), MITK_INFO, mitkIpPicDescriptor, mitk::Image::New(), mitk::SegTool2D::OnMousePressed(), and mitk::Geometry3D::WorldToIndex().

{
  //ToolLogger::SetVerboseness(3);

  MITK_INFO << "OnMousePressed" << std::endl;
  if (FeedbackContourTool::OnMousePressed( action, stateEvent ))
  {
    MITK_INFO << "OnMousePressed: FeedbackContourTool says ok" << std::endl;

    // 1. Find out which slice the user clicked, find out which slice of the toolmanager's reference and working image corresponds to that
    const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
    if (positionEvent)
    {
      MITK_INFO << "OnMousePressed: got positionEvent" << std::endl;
      
      m_ReferenceSlice = FeedbackContourTool::GetAffectedReferenceSlice( positionEvent );
      m_WorkingSlice   = FeedbackContourTool::GetAffectedWorkingSlice( positionEvent );

      if ( m_WorkingSlice.IsNotNull() ) // can't do anything without the segmentation
      {
        MITK_INFO << "OnMousePressed: got working slice" << std::endl;

        // 2. Determine if the user clicked inside or outside of the segmentation
          const Geometry3D* workingSliceGeometry = m_WorkingSlice->GetGeometry();
          Point3D mprojectedPointIn2D;
          workingSliceGeometry->WorldToIndex( positionEvent->GetWorldPosition(), mprojectedPointIn2D);
          itk::Index<2> projectedPointInWorkingSlice2D;
          projectedPointInWorkingSlice2D[0] = static_cast<int>( mprojectedPointIn2D[0] - 0.5 );
          projectedPointInWorkingSlice2D[1] = static_cast<int>( mprojectedPointIn2D[1] - 0.5 );

          if ( workingSliceGeometry->IsIndexInside( projectedPointInWorkingSlice2D ) )
          {
            MITK_INFO << "OnMousePressed: point " << positionEvent->GetWorldPosition() << " (index coordinates " << projectedPointInWorkingSlice2D << ") IS in working slice" << std::endl;

            // Convert to ipMITKSegmentationTYPE (because getting pixels relys on that data type)
            itk::Image< ipMITKSegmentationTYPE, 2 >::Pointer correctPixelTypeImage;
            CastToItkImage( m_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 );

          mitkIpPicDescriptor* workingPicSlice = temporarySlice->GetSliceData()->GetPicDescriptor();
         
          int initialWorkingOffset = projectedPointInWorkingSlice2D[1] * workingPicSlice->n[0] + projectedPointInWorkingSlice2D[0];

          if ( initialWorkingOffset < static_cast<int>( workingPicSlice->n[0] * workingPicSlice->n[1] ) &&
               initialWorkingOffset >= 0 )
          {
            // 3. determine the pixel value under the last click
            bool inside = static_cast<ipMITKSegmentationTYPE*>(workingPicSlice->data)[initialWorkingOffset] != 0;
            m_PaintingPixelValue = inside ? 0 : 1; // if inside, we want to remove a part, otherwise we want to add something

            if ( m_LastWorkingSeed >= static_cast<int>( workingPicSlice->n[0] * workingPicSlice->n[1] ) ||
                 m_LastWorkingSeed < 0 )
            {
              inside = false; 
            }
              
            if ( m_ReferenceSlice.IsNotNull() )
            {
              MITK_INFO << "OnMousePressed: got reference slice" << std::endl;

              m_OriginalPicSlice = m_ReferenceSlice->GetSliceData()->GetPicDescriptor();

              // 3.1. Switch depending on the pixel value
              if (inside)
              {
                OnMousePressedInside(action, stateEvent, workingPicSlice, initialWorkingOffset);
              }
              else
              {
                OnMousePressedOutside(action, stateEvent);
              }
            }
          }
        }
      }
    }
  }
  
  MITK_INFO << "end OnMousePressed" << std::endl;
  return true;
}
bool mitk::RegionGrowingTool::OnMousePressedInside ( Action ,
const StateEvent stateEvent,
mitkIpPicDescriptor *  workingPicSlice,
int  initialWorkingOffset 
) [protected, virtual]

3.1 Create a skeletonization of the segmentation and try to find a nice cut 3.1.1 Call a ipSegmentation algorithm to create a nice cut 3.1.2 Set the result of this algorithm as the feedback contour

Definition at line 189 of file mitkRegionGrowingTool.cpp.

References mitk::FeedbackContourTool::BackProjectContourFrom2DSlice(), tCutResult::cutIt, tCutResult::deleteCurve, tCutResult::deleteSize, mitk::StateEvent::GetEvent(), mitk::RenderingManager::GetInstance(), mitk::BaseRenderer::GetRenderWindow(), mitk::Event::GetSender(), ipMITKSegmentationCreateGrowerHistory(), ipMITKSegmentationGetCutPoints(), mitkIpPicDescriptor, mitk::Contour::New(), tCutResult::onGradient, mitk::RenderingManager::RequestUpdate(), mitk::FeedbackContourTool::SetFeedbackContour(), mitk::FeedbackContourTool::SetFeedbackContourVisible(), and tCutResult::traceline.

{
  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent()); // checked in OnMousePressed
  // 3.1.1. Create a skeletonization of the segmentation and try to find a nice cut
  // apply the skeletonization-and-cut algorithm
  // generate contour to remove
  // set m_ReferenceSlice = NULL so nothing will happen during mouse move
  // remember to fill the contour with 0 in mouserelease
  mitkIpPicDescriptor* segmentationHistory = ipMITKSegmentationCreateGrowerHistory( workingPicSlice, m_LastWorkingSeed, NULL ); // free again
  if (segmentationHistory)
  {
    tCutResult cutContour = ipMITKSegmentationGetCutPoints( workingPicSlice, segmentationHistory, initialWorkingOffset ); // tCutResult is a ipSegmentation type
    mitkIpPicFree( segmentationHistory );
    if (cutContour.cutIt) 
    {
      // 3.1.2 copy point from float* to mitk::Contour 
      Contour::Pointer contourInImageIndexCoordinates = Contour::New();
      contourInImageIndexCoordinates->Initialize();
      Point3D newPoint;
      for (int index = 0; index < cutContour.deleteSize; ++index)
      {
        newPoint[0] = cutContour.deleteCurve[ 2 * index + 0 ];
        newPoint[1] = cutContour.deleteCurve[ 2 * index + 1];
        newPoint[2] = 0.0;

        contourInImageIndexCoordinates->AddVertex( newPoint + 0.5 );
      }

      free(cutContour.traceline);
      free(cutContour.deleteCurve); // perhaps visualize this for fun?
      free(cutContour.onGradient);

      Contour::Pointer contourInWorldCoordinates = FeedbackContourTool::BackProjectContourFrom2DSlice( m_WorkingSlice, contourInImageIndexCoordinates, true ); // true: sub 0.5 for ipSegmentation correction

      FeedbackContourTool::SetFeedbackContour( *contourInWorldCoordinates );
      FeedbackContourTool::SetFeedbackContourVisible(true);
      mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );
      m_FillFeedbackContour = true;
    }
    else
    {
      m_FillFeedbackContour = false;
    }

  }
  else
  {
    m_FillFeedbackContour = false;
  }

  m_ReferenceSlice = NULL;

  return true;
}
bool mitk::RegionGrowingTool::OnMousePressedOutside ( Action ,
const StateEvent stateEvent 
) [protected, virtual]

3.2 Initialize region growing 3.2.1 Determine memory offset inside the original image 3.2.2 Determine initial region growing parameters from the level window settings of the image 3.2.3 Perform a region growing (which generates a new feedback contour)

Definition at line 250 of file mitkRegionGrowingTool.cpp.

References mitk::ApplicationCursor::GetCursorPosition(), mitk::LevelWindow::GetDefaultWindow(), mitk::BaseRenderer::GetDisplayGeometry(), mitk::DisplayGeometry::GetDisplayHeight(), mitk::StateEvent::GetEvent(), mitk::RenderingManager::GetInstance(), mitk::ApplicationCursor::GetInstance(), mitk::BaseRenderer::GetRenderWindow(), mitk::Event::GetSender(), mitk::LevelWindow::GetWindow(), mitk::DisplayPositionEvent::GetWorldPosition(), ipMITKSegmentationFree(), mitk::Geometry3D::IsIndexInside(), MITK_INFO, mitkIpPicDescriptor, mitk::RenderingManager::RequestUpdate(), mitk::FeedbackContourTool::SetFeedbackContourVisible(), and mitk::Geometry3D::WorldToIndex().

{
  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent()); // checked in OnMousePressed
  // 3.2 If we have a reference image, then perform an initial region growing, considering the reference image's level window

  // if click was outside the image, don't continue
  const Geometry3D* sliceGeometry = m_ReferenceSlice->GetGeometry();
  Point3D mprojectedPointIn2D;
  sliceGeometry->WorldToIndex( positionEvent->GetWorldPosition(), mprojectedPointIn2D );
  itk::Index<2> projectedPointIn2D;
  projectedPointIn2D[0] = static_cast<int>( mprojectedPointIn2D[0] - 0.5 );
  projectedPointIn2D[1] = static_cast<int>( mprojectedPointIn2D[1] - 0.5 );

  if ( sliceGeometry->IsIndexInside( mprojectedPointIn2D ) )
  {
    MITK_INFO << "OnMousePressed: point " << positionEvent->GetWorldPosition() << " (index coordinates " << mprojectedPointIn2D << ") IS in reference slice" << std::endl;

    // 3.2.1 Remember Y cursor position and initial seed point
    //m_ScreenYPositionAtStart = static_cast<int>(positionEvent->GetDisplayPosition()[1]);
    m_LastScreenPosition = ApplicationCursor::GetInstance()->GetCursorPosition();
    m_ScreenYDifference = 0;
   
    m_SeedPointMemoryOffset = projectedPointIn2D[1] * m_OriginalPicSlice->n[0] + projectedPointIn2D[0];
    m_LastWorkingSeed = m_SeedPointMemoryOffset; // remember for skeletonization

    if ( m_SeedPointMemoryOffset < static_cast<int>( m_OriginalPicSlice->n[0] * m_OriginalPicSlice->n[1] ) &&
         m_SeedPointMemoryOffset >= 0 )
    {

      // 3.2.2 Get level window from reference DataNode
      //       Use some logic to determine initial gray value bounds
      LevelWindow lw(0, 500);
      m_ToolManager->GetReferenceData(0)->GetLevelWindow(lw); // will fill lw if levelwindow property is present, otherwise won't touch it.

      m_VisibleWindow = lw.GetWindow();
      // necessary for limiting the upper and lower threshold to the maximum gray values
      m_DefaultWindow = lw.GetDefaultWindow();

      static bool initializedAlready = false; // just evaluated once

      if (!initializedAlready)
      {
        m_InitialLowerThreshold = static_cast<int>(m_VisibleWindow / 10.0); // 20% of the visible gray values
        m_InitialUpperThreshold = static_cast<int>(m_VisibleWindow / 10.0);

        initializedAlready = true;
      }
      
      m_LowerThreshold = m_InitialLowerThreshold;
      m_UpperThreshold = m_InitialUpperThreshold;

      DisplayGeometry* displayGeometry = positionEvent->GetSender()->GetDisplayGeometry();
      if (displayGeometry)
      {
        m_MouseDistanceScaleFactor = m_VisibleWindow / ( 3.0 * displayGeometry->GetDisplayHeight() );
      }

      // 3.2.3. Actually perform region growing
      mitkIpPicDescriptor* result = PerformRegionGrowingAndUpdateContour();
      ipMITKSegmentationFree( result);

      // display the contour
      FeedbackContourTool::SetFeedbackContourVisible(true);
      mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
        
        m_FillFeedbackContour = true;
    }
  }

  return true;
}
bool mitk::RegionGrowingTool::OnMouseReleased ( Action action,
const StateEvent stateEvent 
) [protected, virtual]

If the feedback contour should be filled, then it is done here. (Contour is NOT filled, when skeletonization is done but no nice cut was found)

Reimplemented from mitk::SegTool2D.

Definition at line 367 of file mitkRegionGrowingTool.cpp.

References mitk::SegTool2D::DetermineAffectedImageSlice(), mitk::FeedbackContourTool::FillContourInSlice(), mitk::BaseRenderer::GetCurrentWorldGeometry2D(), mitk::StateEvent::GetEvent(), mitk::FeedbackContourTool::GetFeedbackContour(), mitk::RenderingManager::GetInstance(), mitk::BaseRenderer::GetRenderWindow(), mitk::Event::GetSender(), mitk::BaseRenderer::GetTimeStep(), MITK_INFO, mitk::OverwriteSliceImageFilter::New(), mitk::SegTool2D::OnMouseReleased(), mitk::FeedbackContourTool::ProjectContourTo2DSlice(), mitk::RenderingManager::RequestUpdate(), and mitk::FeedbackContourTool::SetFeedbackContourVisible().

{
  if (FeedbackContourTool::OnMouseReleased( action, stateEvent ))
  {
    // 1. If we have a working slice, use the contour to fill a new piece on segmentation on it (or erase a piece that was selected by ipMITKSegmentationGetCutPoints)
    if ( m_WorkingSlice.IsNotNull() && m_OriginalPicSlice )
    {
      const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
      if (positionEvent)
      {
        // remember parameters for next time
        m_InitialLowerThreshold = m_LowerThreshold;
        m_InitialUpperThreshold = m_UpperThreshold;

        if (m_FillFeedbackContour)
        {
          // 3. use contour to fill a region in our working slice
          Contour* feedbackContour( FeedbackContourTool::GetFeedbackContour() );
          if (feedbackContour)
          {
            Contour::Pointer projectedContour = FeedbackContourTool::ProjectContourTo2DSlice( m_WorkingSlice, feedbackContour, false, false ); // false: don't add any 0.5
                                                                                                                                    // false: don't constrain the contour to the image's inside
            if (projectedContour.IsNotNull())
            {
              FeedbackContourTool::FillContourInSlice( projectedContour, m_WorkingSlice, m_PaintingPixelValue );

              // 4. write working slice back into image volume
              int affectedDimension( -1 );
              int affectedSlice( -1 );
              const PlaneGeometry* planeGeometry( dynamic_cast<const PlaneGeometry*> (positionEvent->GetSender()->GetCurrentWorldGeometry2D() ) );
              FeedbackContourTool::DetermineAffectedImageSlice( dynamic_cast<Image*>( m_ToolManager->GetWorkingData(0)->GetData() ), planeGeometry, affectedDimension, affectedSlice );

              MITK_INFO << "OnMouseReleased: writing back to dimension " << affectedDimension << ", slice " << affectedSlice << " in working image" << std::endl;

              OverwriteSliceImageFilter::Pointer slicewriter = OverwriteSliceImageFilter::New();
              Image::Pointer workingImage = dynamic_cast<Image*>( m_ToolManager->GetWorkingData(0)->GetData() );
              slicewriter->SetInput( workingImage );
              slicewriter->SetCreateUndoInformation( true );
              slicewriter->SetSliceImage( m_WorkingSlice );
              slicewriter->SetSliceDimension( affectedDimension );
              slicewriter->SetSliceIndex( affectedSlice );
              slicewriter->SetTimeStep( positionEvent->GetSender()->GetTimeStep( workingImage ) );
              slicewriter->Update();
            }
          }
        }
        
        FeedbackContourTool::SetFeedbackContourVisible(false);
        mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );
      }
    }
  }

  m_ReferenceSlice = NULL; // don't leak
  m_WorkingSlice = NULL;  
  m_OriginalPicSlice = NULL;
    
  return true;
}
mitkIpPicDescriptor * mitk::RegionGrowingTool::PerformRegionGrowingAndUpdateContour (  ) [protected]

Uses ipSegmentation algorithms to do the actual region growing. The result (binary image) is first smoothed by a 5x5 circle mask, then its contour is extracted and converted to MITK coordinates.

Definition at line 431 of file mitkRegionGrowingTool.cpp.

References mitk::FeedbackContourTool::BackProjectContourFrom2DSlice(), ipMITKSegmentationFree(), ipMITKSegmentationGetContour8N(), ipMITKSegmentationGrowRegion4N(), ipMITKSegmentationIsInsideContour(), ipMITKSegmentationReplaceRegion4N(), mitkIpPicDescriptor, mitk::Contour::New(), and mitk::FeedbackContourTool::SetFeedbackContour().

{
  // 1. m_OriginalPicSlice and m_SeedPointMemoryOffset are set to sensitive values, as well as m_LowerThreshold and m_UpperThreshold
  assert (m_OriginalPicSlice);
  if (m_OriginalPicSlice->n[0] != 256 || m_OriginalPicSlice->n[1] != 256) // ???
  assert( (m_SeedPointMemoryOffset < static_cast<int>( m_OriginalPicSlice->n[0] * m_OriginalPicSlice->n[1] )) && (m_SeedPointMemoryOffset >= 0) ); // inside the image

  // 2. ipSegmentation is used to perform region growing
  float ignored;
  int oneContourOffset( 0 );
  mitkIpPicDescriptor* regionGrowerResult = ipMITKSegmentationGrowRegion4N( m_OriginalPicSlice,
                                                                        m_SeedPointMemoryOffset,       // seed point
                                                                        true,              // grayvalue interval relative to seed point gray value?
                                                                        m_LowerThreshold,
                                                                        m_UpperThreshold,
                                                                        0,                  // continue until done (maxIterations == 0)
                                                                        NULL,               // allocate new memory (only this time, on mouse move we'll reuse the old buffer)
                                                                        oneContourOffset,   // a pixel that is near the resulting contour
                                                                        ignored             // ignored by us
                                                                      );

  if (!regionGrowerResult || oneContourOffset == -1)
  {
    Contour::Pointer dummyContour = Contour::New();
    dummyContour->Initialize();
    FeedbackContourTool::SetFeedbackContour( *dummyContour );
    
    if (regionGrowerResult) ipMITKSegmentationFree(regionGrowerResult);
    return NULL;
  }

  // 3. We smooth the result a little to reduce contour complexity
  bool smoothResult( true ); // currently fixed, perhaps remove else block
  mitkIpPicDescriptor* smoothedRegionGrowerResult;
  if (smoothResult)
  {
    // Smooth the result (otherwise very detailed contour)
    smoothedRegionGrowerResult = SmoothIPPicBinaryImage( regionGrowerResult, oneContourOffset );

    ipMITKSegmentationFree( regionGrowerResult );
  }
  else
  {
    smoothedRegionGrowerResult = regionGrowerResult;
  }

  // 4. convert the result of region growing into a mitk::Contour
  // At this point oneContourOffset could be useless, if smoothing destroyed a thin bridge. In these
  // cases, we have two or more unconnected segmentation regions, and we don't know, which one is touched by oneContourOffset.
  // In the bad case, the contour is not the one around our seedpoint, so the result looks very strange to the user.
  // -> we remove the point where the contour started so far. Then we look from the bottom of the image for the first segmentation pixel
  //    and start another contour extraction from there. This is done, until the seedpoint is inside the contour
  int numberOfContourPoints( 0 );
  int newBufferSize( 0 );
  float* contourPoints = ipMITKSegmentationGetContour8N( smoothedRegionGrowerResult, oneContourOffset, numberOfContourPoints, newBufferSize ); // memory allocated with malloc
  if (contourPoints)
  {
    while ( !ipMITKSegmentationIsInsideContour( contourPoints,                                               // contour
                                                numberOfContourPoints,                                       // points in contour
                                                m_SeedPointMemoryOffset % smoothedRegionGrowerResult->n[0],  // test point x
                                                m_SeedPointMemoryOffset / smoothedRegionGrowerResult->n[0]   // test point y
                                              ) )
    {
      // we decide that this cannot be part of the segmentation because the seedpoint is not contained in the contour (fill the 4-neighborhood with 0)
      ipMITKSegmentationReplaceRegion4N( smoothedRegionGrowerResult, oneContourOffset, 0 );

      // move the contour offset to the last row (x position of the seed point)
      int rowLength = smoothedRegionGrowerResult->n[0]; // number of pixels in a row
      oneContourOffset =    m_SeedPointMemoryOffset % smoothedRegionGrowerResult->n[0]  // x of seed point
                          + rowLength*(smoothedRegionGrowerResult->n[1]-1);              // y of last row

      while (    oneContourOffset >=0 
              && (*(static_cast<ipMITKSegmentationTYPE*>(smoothedRegionGrowerResult->data) + oneContourOffset) == 0) )
      {
        oneContourOffset -= rowLength; // if pixel at data+oneContourOffset is 0, then move up one row
      }
      
      if ( oneContourOffset < 0 )
      {
        break; // just use the last contour we found
      }
    
      free(contourPoints); // release contour memory
      contourPoints = ipMITKSegmentationGetContour8N( smoothedRegionGrowerResult, oneContourOffset, numberOfContourPoints, newBufferSize ); // memory allocated with malloc
    }

    // 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 );
    }

    free(contourPoints);

    Contour::Pointer contourInWorldCoordinates = FeedbackContourTool::BackProjectContourFrom2DSlice( m_ReferenceSlice, contourInImageIndexCoordinates, true );   // true: sub 0.5 for ipSegmentation correctio

    FeedbackContourTool::SetFeedbackContour( *contourInWorldCoordinates );
  }

  // 5. Result HAS TO BE freed by caller, contains the binary region growing result
  return smoothedRegionGrowerResult; 
}

Member Data Documentation

Definition at line 86 of file mitkRegionGrowingTool.h.

Definition at line 87 of file mitkRegionGrowingTool.h.

Definition at line 89 of file mitkRegionGrowingTool.h.

Definition at line 84 of file mitkRegionGrowingTool.h.

Definition at line 81 of file mitkRegionGrowingTool.h.

Definition at line 90 of file mitkRegionGrowingTool.h.

Definition at line 85 of file mitkRegionGrowingTool.h.

Definition at line 82 of file mitkRegionGrowingTool.h.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines