bool mitk::CorrectorAlgorithm::ImprovedHeimannCorrectionAlgorithm(itk::Image< ipMITKSegmentationTYPE, 2 >::Pointer 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). */ ContourModel::Pointer projectedContour = mitk::ContourModelUtils::ProjectContourTo2DSlice( m_WorkingImage, m_Contour, true, false ); bool firstPointIsFillingColor = false; if (projectedContour.IsNull() || projectedContour->GetNumberOfVertices() < 2 ) { return false; } // Read the first point of the contour ContourModel::VertexIterator contourIter = projectedContour->Begin(); if (contourIter == projectedContour->End()) return false; itk::Index<2> previousIndex; previousIndex[0] = (*contourIter)->Coordinates[0]; previousIndex[1] = (*contourIter)->Coordinates[1]; ++contourIter; int currentColor = ( pic->GetPixel(previousIndex) == m_FillColor); firstPointIsFillingColor = currentColor; TSegData currentSegment; int countOfSegments = 1; bool firstSegment = true; ContourModel::VertexIterator contourEnd = projectedContour->End(); for (; contourIter != contourEnd; ++contourIter) { // Get current point itk::Index<2> currentIndex; currentIndex[0] = (*contourIter)->Coordinates[0] +0.5; currentIndex[1] = (*contourIter)->Coordinates[1] +0.5; // Calculate length and slope double slopeX = currentIndex[0] - previousIndex[0]; double slopeY = currentIndex[1] - previousIndex[1]; double length = std::sqrt(slopeX * slopeX + slopeY * slopeY); double deltaX = slopeX / length; double deltaY = slopeY / length; for (double i = 0; i <= length && length > 0; i+=1) { itk::Index<2> temporaryIndex; temporaryIndex[0] = previousIndex[0] + deltaX * i; temporaryIndex[1] = previousIndex[1] + deltaY * i; if ( ! pic->GetLargestPossibleRegion().IsInside(temporaryIndex)) continue; if ( (pic->GetPixel(temporaryIndex) == m_FillColor) != currentColor) { currentSegment.points.push_back(temporaryIndex); if ( ! firstSegment) { ModifySegment( currentSegment, pic); } else { firstSegment = false; } currentSegment = TSegData(); ++countOfSegments; currentColor = (pic->GetPixel(temporaryIndex) == m_FillColor); } currentSegment.points.push_back(temporaryIndex); } previousIndex = currentIndex; } // Check if only on Segment if (firstSegment && currentSegment.points.size() > 0) { ContourModel::Pointer projectedContour = mitk::ContourModelUtils::ProjectContourTo2DSlice( m_WorkingImage, m_Contour, true, false ); projectedContour->Close(); if (firstPointIsFillingColor) { ContourModelUtils::FillContourInSlice(projectedContour, 0, m_WorkingImage, m_EraseColor); } else { ContourModelUtils::FillContourInSlice(projectedContour, 0, m_WorkingImage, m_FillColor); } } return true; }
/** Insert the point to the feedback contour,finish to build the contour and at the same time the painting function */ void mitk::PaintbrushTool::MouseMoved(mitk::InteractionEvent* interactionEvent, bool leftMouseButtonPressed) { mitk::InteractionPositionEvent* positionEvent = dynamic_cast<mitk::InteractionPositionEvent*>( interactionEvent ); CheckIfCurrentSliceHasChanged( positionEvent ); if ( m_LastContourSize != m_Size ) { UpdateContour( positionEvent ); m_LastContourSize = m_Size; } Point3D worldCoordinates = positionEvent->GetPositionInWorld(); Point3D indexCoordinates; m_WorkingSlice->GetGeometry()->WorldToIndex( worldCoordinates, indexCoordinates ); MITK_DEBUG << "Mouse at W " << worldCoordinates << std::endl; MITK_DEBUG << "Mouse at I " << indexCoordinates << std::endl; // round to nearest voxel center (abort if this hasn't changed) if ( m_Size % 2 == 0 ) // even { indexCoordinates[0] = ROUND( indexCoordinates[0]);// /*+ 0.5*/) + 0.5; indexCoordinates[1] = ROUND( indexCoordinates[1]);// /*+ 0.5*/ ) + 0.5; } else // odd { indexCoordinates[0] = ROUND( indexCoordinates[0] ) ; indexCoordinates[1] = ROUND( indexCoordinates[1] ) ; } static Point3D lastPos; // uninitialized: if somebody finds out how this can be initialized in a one-liner, tell me if ( fabs(indexCoordinates[0] - lastPos[0]) > mitk::eps || fabs(indexCoordinates[1] - lastPos[1]) > mitk::eps || fabs(indexCoordinates[2] - lastPos[2]) > mitk::eps || leftMouseButtonPressed ) { lastPos = indexCoordinates; } else { MITK_DEBUG << "." << std::flush; return; } MITK_DEBUG << "Mouse at C " << indexCoordinates; int timestep = positionEvent->GetSender()->GetTimeStep(); ContourModel::Pointer contour = ContourModel::New(); contour->Expand(timestep + 1); contour->SetClosed(true, timestep); ContourModel::VertexIterator it = m_MasterContour->Begin(); ContourModel::VertexIterator end = m_MasterContour->End(); while(it != end) { Point3D point = (*it)->Coordinates; point[0] += indexCoordinates[ 0 ]; point[1] += indexCoordinates[ 1 ]; contour->AddVertex( point, timestep ); it++; } if (leftMouseButtonPressed) { FeedbackContourTool::FillContourInSlice( contour, timestep, m_WorkingSlice, m_PaintingPixelValue ); m_WorkingNode->SetData(m_WorkingSlice); m_WorkingNode->Modified(); } // visualize contour ContourModel::Pointer displayContour = this->GetFeedbackContour(); displayContour->Clear(); ContourModel::Pointer tmp = FeedbackContourTool::BackProjectContourFrom2DSlice( m_WorkingSlice->GetGeometry(), /*displayContour*/contour ); // copy transformed contour into display contour it = tmp->Begin(); end = tmp->End(); while(it != end) { Point3D point = (*it)->Coordinates; displayContour->AddVertex( point, timestep ); it++; } m_FeedbackContourNode->GetData()->Modified(); assert( positionEvent->GetSender()->GetRenderWindow() ); RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); }