23 #include "mitkRegionGrowingTool.xpm"
40 #include <itkConnectedComponentImageFilter.h>
41 #include <itkConnectedThresholdImageFilter.h>
42 #include <itkImageRegionIteratorWithIndex.h>
43 #include <itkNeighborhoodIterator.h>
50 #define ROUND(a) ((a) > 0 ? (int)((a) + 0.5) : -(int)(0.5 - (a)))
55 m_ScreenYDifference(0),
56 m_ScreenXDifference(0),
58 m_MouseDistanceScaleFactor(0.5),
59 m_FillFeedbackContour(true),
60 m_ConnectedComponentValue(1)
77 return mitkRegionGrowingTool_xpm;
96 return "Region Growing";
101 Superclass::Activated();
106 Superclass::Deactivated();
110 template <
typename TPixel,
unsigned int imageDimension>
114 unsigned int neighborhood)
117 int neighborhoodInt = (int)neighborhood;
118 TPixel averageValue(0);
119 unsigned int numberOfPixels = (2 * neighborhood + 1) * (2 * neighborhood + 1);
120 if (imageDimension == 3)
122 numberOfPixels *= (2 * neighborhood + 1);
125 MITK_DEBUG <<
"Getting neighborhood of " << numberOfPixels <<
" pixels around " << index;
129 for (
int i = (0 - neighborhoodInt); i <= neighborhoodInt; ++i)
131 currentIndex[0] = index[0] + i;
133 for (
int j = (0 - neighborhoodInt); j <= neighborhoodInt; ++j)
135 currentIndex[1] = index[1] + j;
137 if (imageDimension == 3)
139 for (
int k = (0 - neighborhoodInt); k <= neighborhoodInt; ++k)
141 currentIndex[2] = index[2] + k;
143 if (itkImage->GetLargestPossibleRegion().IsInside(currentIndex))
145 averageValue += itkImage->GetPixel(currentIndex);
155 if (itkImage->GetLargestPossibleRegion().IsInside(currentIndex))
157 averageValue += itkImage->GetPixel(currentIndex);
168 *result /= numberOfPixels;
172 template <
typename TPixel,
unsigned int imageDimension>
177 if (itkImage->GetPixel(index) > 0)
188 template <
typename TPixel,
unsigned int imageDimension>
191 std::array<ScalarType, 2> thresholds,
194 MITK_DEBUG <<
"Starting region growing at index " << seedIndex <<
" with lower threshold " << thresholds[0]
195 <<
" and upper threshold " << thresholds[1];
198 typedef itk::Image<DefaultSegmentationDataType, imageDimension> OutputImageType;
200 typedef itk::ConnectedThresholdImageFilter<InputImageType, OutputImageType> RegionGrowingFilterType;
204 regionGrower->SetInput(inputImage);
205 regionGrower->AddSeed(seedIndex);
207 regionGrower->SetLower(thresholds[0]);
208 regionGrower->SetUpper(thresholds[1]);
212 regionGrower->Update();
222 typedef itk::NeighborhoodIterator<OutputImageType> NeighborhoodIteratorType;
223 typedef itk::ImageRegionIterator<OutputImageType> ImageIteratorType;
225 typename NeighborhoodIteratorType::RadiusType radius;
228 NeighborhoodIteratorType neighborhoodIterator(radius, resultImage, resultImage->GetRequestedRegion());
229 ImageIteratorType imageIterator(resultImage, resultImage->GetRequestedRegion());
231 for (neighborhoodIterator.GoToBegin(), imageIterator.GoToBegin(); !neighborhoodIterator.IsAtEnd();
232 ++neighborhoodIterator, ++imageIterator)
237 for (
unsigned int i = 0; i < neighborhoodIterator.Size(); ++i)
239 if (neighborhoodIterator.GetPixel(i) > 0)
249 if (voteYes > voteNo)
251 imageIterator.Set(1);
255 imageIterator.Set(0);
259 if (resultImage.IsNull())
261 MITK_DEBUG <<
"Region growing result is empty.";
265 typedef itk::ConnectedComponentImageFilter<OutputImageType, OutputImageType> ConnectedComponentImageFilterType;
268 connectedComponentFilter->SetInput(resultImage);
269 connectedComponentFilter->Update();
271 m_ConnectedComponentValue = resultImageCC->GetPixel(seedIndex);
284 m_LastEventSender = positionEvent->
GetSender();
285 m_LastEventSlice = m_LastEventSender->
GetSlice();
292 if (m_WorkingSlice.IsNotNull())
294 MITK_DEBUG <<
"OnMousePressed: got working slice";
298 workingSliceGeometry = m_WorkingSlice->GetGeometry();
301 indexInWorkingSlice2D[0] = m_SeedPoint[0];
302 indexInWorkingSlice2D[1] = m_SeedPoint[1];
304 if (workingSliceGeometry->IsIndexInside(m_SeedPoint))
307 << m_SeedPoint <<
") is inside working slice";
312 m_PaintingPixelValue = inside ? 0 : 1;
324 MITK_DEBUG <<
"Clicked outside of segmentation";
325 OnMousePressedOutside(
nullptr, interactionEvent);
407 workingSliceGeometry = m_WorkingSlice->GetGeometry();
409 indexInWorkingSlice2D[0] = m_SeedPoint[0];
410 indexInWorkingSlice2D[1] = m_SeedPoint[1];
413 referenceSliceGeometry =
414 m_ReferenceSlice->GetGeometry();
417 referenceSliceGeometry->WorldToIndex(positionEvent->
GetPositionInWorld(), indexInReferenceSlice);
418 indexInReferenceSlice2D[0] = indexInReferenceSlice[0];
419 indexInReferenceSlice2D[1] = indexInReferenceSlice[1];
424 m_SeedValue = averageValue;
425 MITK_DEBUG <<
"Seed value is " << m_SeedValue;
429 m_ToolManager->GetReferenceData(0)->GetLevelWindow(
432 MITK_DEBUG <<
"Level window width is " << currentVisibleWindow;
433 m_InitialThresholds[0] = m_SeedValue - currentVisibleWindow / 20.0;
436 m_InitialThresholds[1] = m_SeedValue + currentVisibleWindow / 20.0;
437 m_Thresholds[0] = m_InitialThresholds[0];
438 m_Thresholds[1] = m_InitialThresholds[1];
443 m_ReferenceSlice, StartRegionGrowing, 2, indexInWorkingSlice2D, m_Thresholds, resultImage);
444 resultImage->SetGeometry(workingSliceGeometry);
447 if (resultImage.IsNotNull() && m_ConnectedComponentValue >= 1)
450 contourExtractor->SetInput(resultImage);
451 contourExtractor->SetContourValue(m_ConnectedComponentValue - 0.5);
452 contourExtractor->Update();
454 resultContour = contourExtractor->GetOutput();
457 if (resultContour.IsNotNull())
466 int size = resultContourWorld->GetNumberOfVertices(0);
468 resultContourTimeWorld->Expand(timestep + 1);
469 for (
int loop = 0; loop < size; ++loop)
471 resultContourTimeWorld->AddVertex(resultContourWorld->GetVertexAt(loop, 0), timestep);
491 if (m_PaintingPixelValue == 0)
498 if (m_ReferenceSlice.IsNotNull() && positionEvent)
502 workingSliceGeometry = m_WorkingSlice->GetGeometry();
504 indexInWorkingSlice2D[0] = m_SeedPoint[0];
505 indexInWorkingSlice2D[1] = m_SeedPoint[1];
513 m_Thresholds[0] = std::min<ScalarType>(
514 m_SeedValue, m_InitialThresholds[0] - (m_ScreenYDifference - m_ScreenXDifference) * m_MouseDistanceScaleFactor);
515 m_Thresholds[1] = std::max<ScalarType>(
516 m_SeedValue, m_InitialThresholds[1] + (m_ScreenYDifference + m_ScreenXDifference) * m_MouseDistanceScaleFactor);
517 MITK_DEBUG <<
"Screen difference X: " << m_ScreenXDifference;
522 m_ReferenceSlice, StartRegionGrowing, 2, indexInWorkingSlice2D, m_Thresholds, resultImage);
523 resultImage->SetGeometry(workingSliceGeometry);
526 if (resultImage.IsNotNull() && m_ConnectedComponentValue >= 1)
529 contourExtractor->SetInput(resultImage);
530 contourExtractor->SetContourValue(m_ConnectedComponentValue - 0.5);
531 contourExtractor->Update();
533 resultContour = contourExtractor->GetOutput();
536 if (resultContour.IsNotNull())
545 int size = resultContourWorld->GetNumberOfVertices(0);
547 resultContourTimeWorld->Expand(timestep + 1);
548 for (
int loop = 0; loop < size; ++loop)
550 resultContourTimeWorld->AddVertex(resultContourWorld->GetVertexAt(loop, 0), timestep);
570 if (m_PaintingPixelValue == 0)
577 if (m_WorkingSlice.IsNotNull() && m_FillFeedbackContour && positionEvent)
590 feedbackContourTime->Expand(timestep + 1);
591 for (
int loop = 0; loop < size; ++loop)
593 feedbackContourTime->AddVertex(feedbackContour->
GetVertexAt(loop, timestep), 0);
606 if (projectedContour.IsNotNull())
622 auto activeLabel = labelImage->GetActiveLabel(labelImage->GetActiveLayer())->GetValue();
627 m_PaintingPixelValue * activeLabel);
635 m_PaintingPixelValue);
637 this->WriteBackSegmentationResult(positionEvent, m_WorkingSlice);
ContourModel is a structure of linked vertices defining a contour in 3D space. The vertices are store...
Super class for all position events.
itk::SmartPointer< Self > Pointer
virtual unsigned int GetSlice() const
BaseRenderer * GetSender() const
static void FillContourInSlice(ContourModel *projectedContour, Image *sliceImage, mitk::Image::Pointer workingImage, int paintingPixelValue=1)
Fill a contour in a 2D slice with a specified pixel value at time step 0.
Point3D GetPositionInWorld() const
#define MITKSEGMENTATION_EXPORT
DataCollection - Class to facilitate loading/accessing structured data.
#define AccessFixedDimensionByItk_3(mitkImage, itkImageTypeFunction, dimension, arg1, arg2, arg3)
Point2D GetPointerPositionOnScreen() const
Image::Pointer GrabItkImageMemory(itk::SmartPointer< ItkOutputImageType > &itkimage, mitk::Image *mitkImage=nullptr, const BaseGeometry *geometry=nullptr, bool update=true)
Grabs the memory of an itk::Image (with a specific type) and puts it into an mitk::Image.The memory is managed by the mitk::Image after calling this function. The itk::Image remains valid until the mitk::Image decides to free the memory.
The LevelWindow class Class to store level/window values.
itk::Image< double, 3 > InputImageType
#define AccessFixedDimensionByItk_2(mitkImage, itkImageTypeFunction, dimension, arg1, arg2)
static RenderingManager * GetInstance()
Represents an action, that is executed after a certain event (in statemachine-mechanism) TODO: implem...
Module * GetModule() const
void ForceImmediateUpdate(vtkRenderWindow *renderWindow)
virtual unsigned int GetTimeStep() const
void RequestUpdate(vtkRenderWindow *renderWindow)
LabelSetImage class for handling labels and layers in a segmentation session.
#define CONNECT_FUNCTION(a, f)
ModuleResource GetResource(const std::string &path) const
static ModuleContext * GetModuleContext()
Returns the module context of the calling module.
ScalarType GetWindow() const
returns the current window size, i.e the range size of the current grey value interval ...
vtkRenderWindow * GetRenderWindow() const
Access the RenderWindow into which this renderer renders.
Class for nodes of the DataTree.
virtual const VertexType * GetVertexAt(int index, int timestep=0) const
Returns the vertex at the index position within the container.
int GetNumberOfVertices(int timestep=0) const
Returns the number of vertices at a given timestep.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.