示例#1
0
bool mitk::SetRegionTool::OnMouseReleased(Action* action, const StateEvent* stateEvent)
{
  // 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::CanHandleEvent(stateEvent) < 1.0 ) 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;

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

  this->WriteBackSegmentationResult(positionEvent, slice);

  m_WholeImageContourInWorldCoordinates = NULL;
  m_SegmentationContourInWorldCoordinates = NULL;

  return true;
}
void mitk::CorrectorAlgorithm::TobiasHeimannCorrectionAlgorithm(mitkIpPicDescriptor* pic)
{
/*!
Some documentation (not by the original author)

TobiasHeimannCorrectionAlgorithm will be called, when the user has finished drawing a freehand line.

There should be different results, depending on the line's properties:

1. Without any prior segmentation, the start point and the end point of the drawn line will be 
connected to a contour and the area enclosed by the contour will be marked as segmentation.

2. When the whole line is inside a segmentation, start and end point will be connected to
a contour and the area of this contour will be subtracted from the segmentation.

3. When the line starts inside a segmentation and ends outside with only a single
transition from segmentation to no-segmentation, nothing will happen.

4. When there are multiple transitions between inside-segmentation and
outside-segmentation, the line will be divided in so called segments. Each segment is
either fully inside or fully outside a segmentation. When it is inside a segmentation, its
enclosed area will be subtracted from the segmentation. When the segment is outside a
segmentation, its enclosed area it will be added to the segmentation.

The algorithm is described in full length in Tobias Heimann's diploma thesis 
(MBI Technical Report 145, p. 37 - 40).
*/

  int oaSize = 1000000; // if we need a fixed number, then let it be big
  int* _ofsArray = new int[ oaSize ];
  for (int i=0; i<oaSize; i++) _ofsArray[i] = 0;

  std::vector<TSegData> segData;
  segData.reserve( 16 );
    
  Contour* contour3D = const_cast<Contour*>(m_Contour.GetPointer());
  ContourUtils::Pointer contourUtils = ContourUtils::New();
  Contour::Pointer projectedContour = contourUtils->ProjectContourTo2DSlice( m_WorkingImage, contour3D, true, false ); 
      
  if (projectedContour.IsNull()) 
  {
    delete[] _ofsArray;
    return;
  }

  if (projectedContour->GetNumberOfPoints() < 2) 
  {
    delete[] _ofsArray;
    return;
  }
  
  // convert the projected contour into a ipSegmentation format
  mitkIpInt4_t* _points = new mitkIpInt4_t[2 * projectedContour->GetNumberOfPoints()];
  const Contour::PathType::VertexListType* pointsIn2D = projectedContour->GetContourPath()->GetVertexList();
  unsigned int index(0);
  for ( Contour::PathType::VertexListType::const_iterator iter = pointsIn2D->begin(); 
        iter != pointsIn2D->end();
        ++iter, ++index )
  {
    _points[ 2 * index + 0 ] = static_cast<mitkIpInt4_t>( (*iter)[0] + 0.5 );
    _points[ 2 * index + 1 ] = static_cast<mitkIpInt4_t>( (*iter)[1] + 0.5 );
  }
 
  // store ofsets of the drawn line in array
  int _ofsNum = 0;
  unsigned int num = projectedContour->GetNumberOfPoints();
  int lastOfs = -1;
  for (unsigned int i=0; i<num-1; i++) 
  {
    float x = _points [2*i] + 0.5;
    float y = _points [2*i+1] + 0.5;
    float difX = _points [2*i+2] - x + 0.5;
    float difY = _points [2*i+3] - y + 0.5;
    float length = sqrt( difX*difX + difY*difY );
    float dx = difX / length;
    float dy = difY / length;
    for (int p=0; ((float)p)<length; p++) 
    {
      // if ofs is out of bounds, very nasty things will happen, so better check coordinates:
      if (x<0) x=0.5;
      else if (x>=pic->n[0]) x = pic->n[0]-0.5;
      if (y<0) y=0.5;
      else if (y>=pic->n[1]) y = pic->n[1]-0.5;
      // ok, now store safe ofs
      int ofs = (int)(x) + pic->n[0]*((int)(y));
      x += dx;
      y += dy;
      if (ofs != lastOfs) 
      {
        _ofsArray[_ofsNum++] = ofs;
        lastOfs = ofs;
      }
    }
  }

  if (_ofsNum == 0)
  {
    // contour was completely outside the binary image
    delete[] _ofsArray;
    delete[] _points;
    return;
  }

  ipMITKSegmentationTYPE* picdata = static_cast<ipMITKSegmentationTYPE*>(pic->data);

  // divide line in logical segments:
  int numSegments = 0;
  ipMITKSegmentationTYPE state = *(picdata + _ofsArray[0]);
  int ofsP = 1;
  int modifyStart, modifyEnd;  // start of first and end of last segment
  bool nextSegment;
  segData.clear();
  do 
  {
    nextSegment = false;
    while (ofsP<_ofsNum && *(picdata + _ofsArray[ofsP])==state) ofsP++;
    if (ofsP<_ofsNum) 
    {
      int lineStart = ofsP-1;
      if (numSegments==0) modifyStart = ofsP;
      state = *(picdata + _ofsArray[ofsP]);
      while (ofsP<_ofsNum && *(picdata + _ofsArray[ofsP])==state) ofsP++;
      if (ofsP<_ofsNum) 
      {
        int lineEnd = ofsP;
        modifyEnd = lineEnd;
        nextSegment = true;
        // now we've got a valid segment from lineStart to lineEnd
        TSegData thisSegData;
        thisSegData.lineStart = lineStart;
        thisSegData.lineEnd = lineEnd;
        thisSegData.modified = modifySegment( lineStart, lineEnd, state, pic, _ofsArray );
        segData.push_back( thisSegData );
        numSegments++;
      }
    }
  } while (nextSegment);

  for (int segNr=0; segNr < numSegments; segNr++) 
  {
    // draw line if modified:
    if ( segData[segNr].modified ) 
    {
      for (int i=segData[segNr].lineStart+1; i<segData[segNr].lineEnd; i++) 
      {
        *(picdata + _ofsArray[i]) = 1;
      }
    }
  }

  if (numSegments == 0) 
  {
    if (num <= 1) 
    { // only a single pixel. _ofsArray[_ofsNum-1] in else statement would crash, so don't do anything
      // no movement: delete operation

      // This behaviour would probably confuse users when they use the correction 
      // tool to change a segmentation and it deletes much more than selected
     
      // if (state == 1)  ipMITKSegmentationReplaceRegion4N( pic, _ofsArray[0], 0 );
    }
    else if ( *(picdata + _ofsArray[_ofsNum-1]) == *(picdata + _ofsArray[0]))
    {
      // start point and end point both inside or both outside any segmentation
      // normal paint operation
      mitkIpInt4_t* p = new mitkIpInt4_t[2 * num];
      for (unsigned int i = 0; i < num; i++) 
      {
        p[2 * i] = (mitkIpInt4_t) _points [2 * i];
        p[2 * i + 1] = (mitkIpInt4_t) _points [2 * i + 1];
      }

      if (state == 0) ipMITKSegmentationCombineRegion (pic, p, num, 0, IPSEGMENTATION_OR,  1);
      else            ipMITKSegmentationCombineRegion (pic, p, num, 0, IPSEGMENTATION_AND, 0);

      delete[] p;
    }
  }

  int numberOfContourPoints( 0 );
  int oneContourOffset( 0 );
  int newBufferSize( 0 );

  int imageSize = pic->n[0]*pic->n[1];
  for (oneContourOffset = 0; oneContourOffset < imageSize; oneContourOffset++)
    if ( ((ipMITKSegmentationTYPE*) pic->data)[oneContourOffset]> 0) break;

  float* contourPoints = ipMITKSegmentationGetContour8N( pic, oneContourOffset, numberOfContourPoints, newBufferSize ); // memory allocated with malloc
  
  if (contourPoints) 
  {
    
    // 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);
    
    ContourUtils::Pointer contourUtils = ContourUtils::New();
    contourUtils->FillContourInSlice( contourInImageIndexCoordinates, m_WorkingImage );
  }
  
  delete[] _ofsArray;
  delete[] _points;
}