diff --git a/Modules/Multilabel/mitkLabelSetImage.cpp b/Modules/Multilabel/mitkLabelSetImage.cpp index ddbc35cfdc..6b773e72c8 100644 --- a/Modules/Multilabel/mitkLabelSetImage.cpp +++ b/Modules/Multilabel/mitkLabelSetImage.cpp @@ -1,983 +1,985 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkLabelSetImage.h" #include "mitkImageAccessByItk.h" #include "mitkInteractionConst.h" #include "mitkRenderingManager.h" #include "mitkImageCast.h" #include "mitkImageReadAccessor.h" #include "mitkLookupTableProperty.h" #include "mitkPadImageFilter.h" #include #include #include #include #include #include //#include #include mitk::LabelSetImage::LabelSetImage() : mitk::Image(), m_ActiveLayer(0), m_ExteriorLabel(nullptr) { // Iniitlaize Background Label mitk::Color color; color.Set(0,0,0); m_ExteriorLabel = mitk::Label::New(); m_ExteriorLabel->SetColor(color); m_ExteriorLabel->SetName("Exterior"); m_ExteriorLabel->SetOpacity(0.0); m_ExteriorLabel->SetLocked(false); m_ExteriorLabel->SetValue(0); } mitk::LabelSetImage::LabelSetImage(const mitk::LabelSetImage & other): Image(other), m_ActiveLayer(other.GetActiveLayer()), m_ExteriorLabel(other.GetExteriorLabel()->Clone()) { for(unsigned int i = 0 ; i < other.GetNumberOfLayers(); i++) { // Clone LabelSet data mitk::LabelSet::Pointer lsClone = other.GetLabelSet(i)->Clone(); // add modified event listener to LabelSet (listen to LabelSet changes) itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this,&mitk::LabelSetImage::OnLabelSetModified); lsClone->AddObserver(itk::ModifiedEvent(), command); m_LabelSetContainer.push_back( lsClone ); // clone layer Image data mitk::Image::Pointer liClone = other.GetLayerImage(i)->Clone(); m_LayerContainer.push_back( liClone ); } } void mitk::LabelSetImage::OnLabelSetModified() { Superclass::Modified(); } void mitk::LabelSetImage::SetExteriorLabel(mitk::Label * label) { m_ExteriorLabel = label; } mitk::Label* mitk::LabelSetImage::GetExteriorLabel() { return m_ExteriorLabel; } const mitk::Label* mitk::LabelSetImage::GetExteriorLabel() const { return m_ExteriorLabel; } void mitk::LabelSetImage::Initialize(const mitk::Image* other) { mitk::PixelType pixelType(mitk::MakeScalarPixelType() ); if (other->GetDimension() == 2) { const unsigned int dimensions[] = { other->GetDimension(0), other->GetDimension(1), 1 }; Superclass::Initialize(pixelType, 3, dimensions); } else { Superclass::Initialize(pixelType, other->GetDimension(), other->GetDimensions()); } mitk::TimeGeometry::Pointer originalGeometry = other->GetTimeGeometry()->Clone(); this->SetTimeGeometry( originalGeometry ); // Add a inital LabelSet ans corresponding image data to the stack AddLayer(); } mitk::LabelSetImage::~LabelSetImage() { m_LabelSetContainer.clear(); } mitk::Image* mitk::LabelSetImage::GetLayerImage(unsigned int layer) { return m_LayerContainer[layer]; } const mitk::Image* mitk::LabelSetImage::GetLayerImage(unsigned int layer) const { return m_LayerContainer[layer]; } unsigned int mitk::LabelSetImage::GetActiveLayer() const { return m_ActiveLayer; } unsigned int mitk::LabelSetImage::GetNumberOfLayers() const { return m_LabelSetContainer.size(); } void mitk::LabelSetImage::RemoveLayer() { int layerToDelete = GetActiveLayer(); // remove all observers from active label set GetLabelSet(layerToDelete)->RemoveAllObservers(); // set the active layer to one below, if exists. SetActiveLayer(layerToDelete-1); // remove labelset and image data m_LabelSetContainer.erase( m_LabelSetContainer.begin() + layerToDelete); m_LayerContainer.erase( m_LayerContainer.begin() + layerToDelete); this->Modified(); } +template +void SetToZero(itk::Image< TPixel, VDimensions> * source) +{ + source->FillBuffer(0); +} + unsigned int mitk::LabelSetImage::AddLayer(mitk::LabelSet::Pointer lset) { mitk::Image::Pointer newImage = mitk::Image::New(); newImage->Initialize( this->GetPixelType(), this->GetDimension(), this->GetDimensions(), this->GetImageDescriptor()->GetNumberOfChannels() ); newImage->SetGeometry(this->GetGeometry()->Clone()); - LabelSetImageType::Pointer itkImage; - mitk::CastToItkImage(newImage, itkImage); - itkImage->FillBuffer(0); + AccessByItk(newImage, SetToZero); unsigned int newLabelSetId = this->AddLayer(newImage, lset); - // important to release the itk image - itkImage = nullptr; return newLabelSetId; } unsigned int mitk::LabelSetImage::AddLayer(mitk::Image::Pointer layerImage, mitk::LabelSet::Pointer lset) { unsigned int newLabelSetId = m_LayerContainer.size(); // Add labelset to layer mitk::LabelSet::Pointer ls; if (lset.IsNotNull()) { ls = lset; } else { ls = mitk::LabelSet::New(); ls->AddLabel(GetExteriorLabel()); ls->SetActiveLabel(0 /*Exterior Label*/); } ls->SetLayer(newLabelSetId); // Add exterior Label to label set //mitk::Label::Pointer exteriorLabel = CreateExteriorLabel(); // push a new working image for the new layer m_LayerContainer.push_back(layerImage); // push a new labelset for the new layer m_LabelSetContainer.push_back(ls); // add modified event listener to LabelSet (listen to LabelSet changes) itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &mitk::LabelSetImage::OnLabelSetModified); ls->AddObserver(itk::ModifiedEvent(), command); SetActiveLayer(newLabelSetId); //MITK_INFO << GetActiveLayer(); this->Modified(); return newLabelSetId; } void mitk::LabelSetImage::AddLabelSetToLayer(const unsigned int layerIdx, const mitk::LabelSet::Pointer labelSet) { if (m_LayerContainer.size() <= layerIdx) { mitkThrow() << "Trying to add labelSet to non-existing layer."; } if (layerIdx < m_LabelSetContainer.size()) { m_LabelSetContainer[layerIdx] = labelSet; } else { while (layerIdx >= m_LabelSetContainer.size()) { mitk::LabelSet::Pointer defaultLabelSet = mitk::LabelSet::New(); defaultLabelSet->AddLabel(GetExteriorLabel()); defaultLabelSet->SetActiveLabel(0 /*Exterior Label*/); defaultLabelSet->SetLayer(m_LabelSetContainer.size()); m_LabelSetContainer.push_back(defaultLabelSet); } m_LabelSetContainer.push_back(labelSet); } } void mitk::LabelSetImage::SetActiveLayer(unsigned int layer) { try { if ( (layer != GetActiveLayer()) && (layerGetNumberOfLayers()) ) { BeforeChangeLayerEvent.Send(); AccessByItk_1(this, ImageToLayerContainerProcessing, GetActiveLayer()); m_ActiveLayer = layer; // only at this place m_ActiveLayer should be manipulated!!! Use Getter and Setter AccessByItk_1(this, LayerContainerToImageProcessing, GetActiveLayer()); AfterchangeLayerEvent.Send(); } } catch(itk::ExceptionObject& e) { mitkThrow() << e.GetDescription(); } this->Modified(); } void mitk::LabelSetImage::Concatenate(mitk::LabelSetImage* other) { const unsigned int* otherDims = other->GetDimensions(); const unsigned int* thisDims = this->GetDimensions(); if ( (otherDims[0] != thisDims[0]) || (otherDims[1] != thisDims[1]) || (otherDims[2] != thisDims[2]) ) mitkThrow() << "Dimensions do not match."; try { int numberOfLayers = other->GetNumberOfLayers(); for (int layer=0; layerSetActiveLayer(layer); AccessByItk_1(this, ConcatenateProcessing, other); mitk::LabelSet * ls = other->GetLabelSet(layer); auto it = ls->IteratorConstBegin(); auto end = ls->IteratorConstEnd(); it++;// skip exterior while(it != end) { GetLabelSet()->AddLabel((it->second)); //AddLabelEvent.Send(); it++; } } } catch(itk::ExceptionObject& e) { mitkThrow() << e.GetDescription(); } this->Modified(); } void mitk::LabelSetImage::ClearBuffer() { try { AccessByItk(this, ClearBufferProcessing); this->Modified(); } catch(itk::ExceptionObject& e) { mitkThrow() << e.GetDescription(); } } bool mitk::LabelSetImage::ExistLabel(PixelType pixelValue) const { bool exist = false; for(unsigned int lidx = 0 ; lidx < GetNumberOfLayers(); lidx++) exist |= m_LabelSetContainer[lidx]->ExistLabel(pixelValue); return exist; } bool mitk::LabelSetImage::ExistLabel(PixelType pixelValue, unsigned int layer) const { bool exist = m_LabelSetContainer[layer]->ExistLabel(pixelValue); return exist; } bool mitk::LabelSetImage::ExistLabelSet(unsigned int layer) const { return layer < m_LabelSetContainer.size(); } void mitk::LabelSetImage::MergeLabel(PixelType pixelValue, unsigned int /*layer*/) { int targetPixelValue = GetActiveLabel()->GetValue(); try { AccessByItk_2(this, MergeLabelProcessing, targetPixelValue, pixelValue); } catch(itk::ExceptionObject& e) { mitkThrow() << e.GetDescription(); } Modified(); } void mitk::LabelSetImage::MergeLabels(std::vector &VectorOfLablePixelValues, PixelType pixelValue, unsigned int layer) { GetLabelSet(layer)->SetActiveLabel(pixelValue); try { for (unsigned int idx=0; idx& VectorOfLabelPixelValues, unsigned int layer) { for (unsigned int idx=0; idxRemoveLabel(VectorOfLabelPixelValues[idx]); EraseLabel(VectorOfLabelPixelValues[idx],layer); } } void mitk::LabelSetImage::EraseLabels(std::vector &VectorOfLabelPixelValues, unsigned int layer) { for (unsigned int i=0; iEraseLabel(VectorOfLabelPixelValues[i], layer); } } void mitk::LabelSetImage::EraseLabel(PixelType pixelValue, unsigned int layer) { try { AccessByItk_2(this, EraseLabelProcessing, pixelValue, layer); } catch(itk::ExceptionObject& e) { mitkThrow() << e.GetDescription(); } Modified(); } mitk::Label *mitk::LabelSetImage::GetActiveLabel(unsigned int layer) { if (m_LabelSetContainer.size() > layer) return m_LabelSetContainer[layer]->GetActiveLabel(); else return nullptr; } mitk::Label *mitk::LabelSetImage::GetLabel(PixelType pixelValue, unsigned int layer) const { if(m_LabelSetContainer.size() <= layer) return nullptr; else return m_LabelSetContainer[layer]->GetLabel(pixelValue); } mitk::LabelSet* mitk::LabelSetImage::GetLabelSet(unsigned int layer) { if(m_LabelSetContainer.size() <= layer) return nullptr; else return m_LabelSetContainer[layer].GetPointer(); } const mitk::LabelSet* mitk::LabelSetImage::GetLabelSet(unsigned int layer) const { if(m_LabelSetContainer.size() <= layer) return nullptr; else return m_LabelSetContainer[layer].GetPointer(); } mitk::LabelSet* mitk::LabelSetImage::GetActiveLabelSet() { return m_LabelSetContainer[GetActiveLayer()].GetPointer(); } void mitk::LabelSetImage::UpdateCenterOfMass(PixelType pixelValue, unsigned int layer) { AccessByItk_2( this, CalculateCenterOfMassProcessing, pixelValue, layer ); } unsigned int mitk::LabelSetImage::GetNumberOfLabels(unsigned int layer) const { return m_LabelSetContainer[layer]->GetNumberOfLabels(); } unsigned int mitk::LabelSetImage::GetTotalNumberOfLabels() const { unsigned int totalLabels(0); auto layerIter = m_LabelSetContainer.begin(); for (; layerIter != m_LabelSetContainer.end(); ++layerIter) totalLabels += (*layerIter)->GetNumberOfLabels(); return totalLabels; } void mitk::LabelSetImage::MaskStamp(mitk::Image* mask, bool forceOverwrite) { try { mitk::PadImageFilter::Pointer padImageFilter = mitk::PadImageFilter::New(); padImageFilter->SetInput(0, mask); padImageFilter->SetInput(1, this); padImageFilter->SetPadConstant(0); padImageFilter->SetBinaryFilter(false); padImageFilter->SetLowerThreshold(0); padImageFilter->SetUpperThreshold(1); padImageFilter->Update(); mitk::Image::Pointer paddedMask = padImageFilter->GetOutput(); if (paddedMask.IsNull()) return; AccessByItk_2(this, MaskStampProcessing, paddedMask, forceOverwrite); } catch(...) { mitkThrow() << "Could not stamp the provided mask on the selected label."; } } mitk::Image::Pointer mitk::LabelSetImage::CreateLabelMask(PixelType index) { mitk::Image::Pointer mask = mitk::Image::New(); try { mask->Initialize(this); unsigned int byteSize = sizeof(LabelSetImage::PixelType); for (unsigned int dim = 0; dim < mask->GetDimension(); ++dim) { byteSize *= mask->GetDimension(dim); } mitk::ImageWriteAccessor* accessor = new mitk::ImageWriteAccessor(static_cast(mask)); memset( accessor->GetData(), 0, byteSize ); delete accessor; mitk::SlicedGeometry3D::Pointer geometry = this->GetSlicedGeometry()->Clone(); mask->SetGeometry( geometry ); AccessByItk_2(this, CreateLabelMaskProcessing, mask, index); } catch(...) { mitkThrow() << "Could not create a mask out of the selected label."; } return mask; } -void mitk::LabelSetImage::SurfaceStamp(mitk::Surface* surface, bool forceOverwrite) -{ - if (!surface) - { - MITK_ERROR << "Input surface is NULL."; - return; - } - - try - { - LabelSetImageType::Pointer itkImage; - mitk::CastToItkImage(this, itkImage); - - vtkPolyData *polydata = surface->GetVtkPolyData(); - - vtkSmartPointer transform = vtkSmartPointer::New(); - transform->SetMatrix( surface->GetGeometry()->GetVtkTransform()->GetMatrix() ); - transform->Update(); - - vtkSmartPointer transformer = vtkSmartPointer::New(); - transformer->SetInputData(polydata); - transformer->SetTransform(transform); - transformer->Update(); - - typedef double Coord; - typedef itk::QuadEdgeMesh< Coord, 3 > MeshType; - - MeshType::Pointer mesh = MeshType::New(); - mesh->SetCellsAllocationMethod( MeshType::CellsAllocatedDynamicallyCellByCell ); - int numberOfPoints = polydata->GetNumberOfPoints(); - mesh->GetPoints()->Reserve( numberOfPoints ); - - vtkPoints* points = polydata->GetPoints(); - - MeshType::PointType point; - for( int i=0; i < numberOfPoints; i++ ) - { - double* aux = points->GetPoint(i); - point[0] = aux[0]; - point[1] = aux[1]; - point[2] = aux[2]; - mesh->SetPoint( i, point ); - } - - // Load the polygons into the itk::Mesh - typedef MeshType::CellAutoPointer CellAutoPointerType; - typedef MeshType::CellType CellType; - typedef itk::TriangleCell< CellType > TriangleCellType; - typedef MeshType::PointIdentifier PointIdentifierType; - typedef MeshType::CellIdentifier CellIdentifierType; - - // Read the number of polygons - CellIdentifierType numberOfPolygons = 0; - numberOfPolygons = polydata->GetNumberOfPolys(); - - PointIdentifierType numberOfCellPoints = 3; - - for (CellIdentifierType i=0; iGetCell(i); - cellIds = vcell->GetPointIds(); - - CellAutoPointerType cell; - auto triangleCell = new TriangleCellType; - PointIdentifierType k; - for( k = 0; k < numberOfCellPoints; k++ ) - { - triangleCell->SetPointId( k, cellIds->GetId(k) ); - } - - cell.TakeOwnership( triangleCell ); - mesh->SetCell( i, cell ); - } - - typedef itk::TriangleMeshToBinaryImageFilter TriangleMeshToBinaryImageFilterType; - - TriangleMeshToBinaryImageFilterType::Pointer filter = TriangleMeshToBinaryImageFilterType::New(); - filter->SetInput(mesh); - filter->SetInfoImage(itkImage); - filter->SetInsideValue(1); - filter->SetOutsideValue(0); - filter->Update(); - - LabelSetImageType::Pointer resultImage = filter->GetOutput(); - resultImage->DisconnectPipeline(); - - typedef itk::ImageRegionConstIterator< LabelSetImageType > SourceIteratorType; - typedef itk::ImageRegionIterator< LabelSetImageType > TargetIteratorType; - - SourceIteratorType sourceIter( resultImage, resultImage->GetLargestPossibleRegion() ); - sourceIter.GoToBegin(); - - TargetIteratorType targetIter( itkImage, itkImage->GetLargestPossibleRegion() ); - targetIter.GoToBegin(); - - int activeLabel = GetActiveLabel(GetActiveLayer())->GetValue(); - - while ( !sourceIter.IsAtEnd() ) - { - int sourceValue = static_cast(sourceIter.Get()); - int targetValue = static_cast(targetIter.Get()); - - if ( (sourceValue != 0) && (forceOverwrite || !this->GetLabel(targetValue)->GetLocked()) ) // skip exterior and locked labels - { - targetIter.Set( activeLabel ); - } - ++sourceIter; - ++targetIter; - } - } - catch(itk::ExceptionObject& e) - { - mitkThrow() << e.GetDescription(); - } - this->Modified(); -} +//void mitk::LabelSetImage::SurfaceStamp(mitk::Surface* surface, bool forceOverwrite) +//{ +// if (!surface) +// { +// MITK_ERROR << "Input surface is NULL."; +// return; +// } +// +// try +// { +// LabelSetImageType::Pointer itkImage; +// mitk::CastToItkImage(this, itkImage); +// +// vtkPolyData *polydata = surface->GetVtkPolyData(); +// +// vtkSmartPointer transform = vtkSmartPointer::New(); +// transform->SetMatrix( surface->GetGeometry()->GetVtkTransform()->GetMatrix() ); +// transform->Update(); +// +// vtkSmartPointer transformer = vtkSmartPointer::New(); +// transformer->SetInputData(polydata); +// transformer->SetTransform(transform); +// transformer->Update(); +// +// typedef double Coord; +// typedef itk::QuadEdgeMesh< Coord, 3 > MeshType; +// +// MeshType::Pointer mesh = MeshType::New(); +// mesh->SetCellsAllocationMethod( MeshType::CellsAllocatedDynamicallyCellByCell ); +// int numberOfPoints = polydata->GetNumberOfPoints(); +// mesh->GetPoints()->Reserve( numberOfPoints ); +// +// vtkPoints* points = polydata->GetPoints(); +// +// MeshType::PointType point; +// for( int i=0; i < numberOfPoints; i++ ) +// { +// double* aux = points->GetPoint(i); +// point[0] = aux[0]; +// point[1] = aux[1]; +// point[2] = aux[2]; +// mesh->SetPoint( i, point ); +// } +// +// // Load the polygons into the itk::Mesh +// typedef MeshType::CellAutoPointer CellAutoPointerType; +// typedef MeshType::CellType CellType; +// typedef itk::TriangleCell< CellType > TriangleCellType; +// typedef MeshType::PointIdentifier PointIdentifierType; +// typedef MeshType::CellIdentifier CellIdentifierType; +// +// // Read the number of polygons +// CellIdentifierType numberOfPolygons = 0; +// numberOfPolygons = polydata->GetNumberOfPolys(); +// +// PointIdentifierType numberOfCellPoints = 3; +// +// for (CellIdentifierType i=0; iGetCell(i); +// cellIds = vcell->GetPointIds(); +// +// CellAutoPointerType cell; +// auto triangleCell = new TriangleCellType; +// PointIdentifierType k; +// for( k = 0; k < numberOfCellPoints; k++ ) +// { +// triangleCell->SetPointId( k, cellIds->GetId(k) ); +// } +// +// cell.TakeOwnership( triangleCell ); +// mesh->SetCell( i, cell ); +// } +// +// typedef itk::TriangleMeshToBinaryImageFilter TriangleMeshToBinaryImageFilterType; +// +// TriangleMeshToBinaryImageFilterType::Pointer filter = TriangleMeshToBinaryImageFilterType::New(); +// filter->SetInput(mesh); +// filter->SetInfoImage(itkImage); +// filter->SetInsideValue(1); +// filter->SetOutsideValue(0); +// filter->Update(); +// +// LabelSetImageType::Pointer resultImage = filter->GetOutput(); +// resultImage->DisconnectPipeline(); +// +// typedef itk::ImageRegionConstIterator< LabelSetImageType > SourceIteratorType; +// typedef itk::ImageRegionIterator< LabelSetImageType > TargetIteratorType; +// +// SourceIteratorType sourceIter( resultImage, resultImage->GetLargestPossibleRegion() ); +// sourceIter.GoToBegin(); +// +// TargetIteratorType targetIter( itkImage, itkImage->GetLargestPossibleRegion() ); +// targetIter.GoToBegin(); +// +// int activeLabel = GetActiveLabel(GetActiveLayer())->GetValue(); +// +// while ( !sourceIter.IsAtEnd() ) +// { +// int sourceValue = static_cast(sourceIter.Get()); +// int targetValue = static_cast(targetIter.Get()); +// +// if ( (sourceValue != 0) && (forceOverwrite || !this->GetLabel(targetValue)->GetLocked()) ) // skip exterior and locked labels +// { +// targetIter.Set( activeLabel ); +// } +// ++sourceIter; +// ++targetIter; +// } +// } +// catch(itk::ExceptionObject& e) +// { +// mitkThrow() << e.GetDescription(); +// } +// this->Modified(); +//} void mitk::LabelSetImage::InitializeByLabeledImage(mitk::Image::Pointer image) { if (image.IsNull() || image->IsEmpty() || !image->IsInitialized()) mitkThrow() << "Invalid labeled image."; try { this->Initialize(image); unsigned int byteSize = sizeof(LabelSetImage::PixelType); for (unsigned int dim = 0; dim < image->GetDimension(); ++dim) { byteSize *= image->GetDimension(dim); } mitk::ImageWriteAccessor* accessor = new mitk::ImageWriteAccessor(static_cast(this)); memset( accessor->GetData(), 0, byteSize ); delete accessor; mitk::SlicedGeometry3D::Pointer geometry = image->GetSlicedGeometry()->Clone(); this->SetGeometry( geometry ); AccessTwoImagesFixedDimensionByItk(this, image, InitializeByLabeledImageProcessing,3); } catch(...) { mitkThrow() << "Could not intialize by provided labeled image."; } this->Modified(); } template < typename ImageType1, typename ImageType2 > void mitk::LabelSetImage::InitializeByLabeledImageProcessing(ImageType1* output, ImageType2* input) { typedef itk::ImageRegionConstIterator< ImageType2 > SourceIteratorType; typedef itk::ImageRegionIterator< ImageType1 > TargetIteratorType; // typedef itk::RelabelComponentImageFilter FilterType; TargetIteratorType targetIter( output, output->GetLargestPossibleRegion() ); targetIter.GoToBegin(); //SourceIteratorType sourceIter( relabelFilter->GetOutput(), relabelFilter->GetOutput()->GetLargestPossibleRegion() ); SourceIteratorType sourceIter( input, input->GetLargestPossibleRegion() ); sourceIter.GoToBegin(); while ( !sourceIter.IsAtEnd() ) { PixelType sourceValue = static_cast(sourceIter.Get()); targetIter.Set( sourceValue ); if(!ExistLabel(sourceValue)) { std::stringstream name; name << "object-" << sourceValue; mitk::Label::Pointer label = mitk::Label::New(); label->SetName( name.str().c_str() ); double rgba[4]; m_LabelSetContainer[GetActiveLayer()]->GetLookupTable()->GetTableValue(sourceValue, rgba ); mitk::Color newColor; newColor.SetRed(rgba[0]); newColor.SetGreen(rgba[1]); newColor.SetBlue(rgba[2]); label->SetColor( newColor ); label->SetOpacity( rgba[3] ); label->SetValue( sourceValue ); GetLabelSet()->AddLabel(label); if(GetActiveLabelSet()->GetNumberOfLabels() >= mitk::Label::MAX_LABEL_VALUE || sourceValue >= mitk::Label::MAX_LABEL_VALUE) { AddLayer(); } } ++sourceIter; ++targetIter; } } template < typename ImageType > void mitk::LabelSetImage::MaskStampProcessing(ImageType* itkImage, mitk::Image* mask, bool forceOverwrite) { typename ImageType::Pointer itkMask; mitk::CastToItkImage(mask, itkMask); typedef itk::ImageRegionConstIterator< ImageType > SourceIteratorType; typedef itk::ImageRegionIterator< ImageType > TargetIteratorType; SourceIteratorType sourceIter( itkMask, itkMask->GetLargestPossibleRegion() ); sourceIter.GoToBegin(); TargetIteratorType targetIter( itkImage, itkImage->GetLargestPossibleRegion() ); targetIter.GoToBegin(); int activeLabel = this->GetActiveLabel(GetActiveLayer())->GetValue(); while ( !sourceIter.IsAtEnd() ) { PixelType sourceValue = sourceIter.Get(); PixelType targetValue = targetIter.Get(); if ( (sourceValue != 0) && (forceOverwrite || !this->GetLabel(targetValue)->GetLocked()) ) // skip exterior and locked labels { targetIter.Set( activeLabel ); } ++sourceIter; ++targetIter; } this->Modified(); } template < typename ImageType > void mitk::LabelSetImage::CreateLabelMaskProcessing(ImageType* itkImage, mitk::Image* mask, PixelType index) { typename ImageType::Pointer itkMask; mitk::CastToItkImage(mask, itkMask); typedef itk::ImageRegionConstIterator< ImageType > SourceIteratorType; typedef itk::ImageRegionIterator< ImageType > TargetIteratorType; SourceIteratorType sourceIter( itkImage, itkImage->GetLargestPossibleRegion() ); sourceIter.GoToBegin(); TargetIteratorType targetIter( itkMask, itkMask->GetLargestPossibleRegion() ); targetIter.GoToBegin(); while ( !sourceIter.IsAtEnd() ) { PixelType sourceValue = sourceIter.Get(); if ( sourceValue == index ) { targetIter.Set( 1 ); } ++sourceIter; ++targetIter; } } template < typename ImageType > void mitk::LabelSetImage::CalculateCenterOfMassProcessing(ImageType* itkImage, PixelType pixelValue, unsigned int layer) { // for now, we just retrieve the voxel in the middle typedef itk::ImageRegionConstIterator< ImageType > IteratorType; IteratorType iter( itkImage, itkImage->GetLargestPossibleRegion() ); iter.GoToBegin(); std::vector< typename ImageType::IndexType > indexVector; while ( !iter.IsAtEnd() ) { // TODO fix comparison warning more effective if ( iter.Get() == pixelValue ) { indexVector.push_back(iter.GetIndex()); } ++iter; } mitk::Point3D pos; pos.Fill(0.0); if (!indexVector.empty()) { typename itk::ImageRegionConstIteratorWithIndex< ImageType >::IndexType centerIndex; centerIndex = indexVector.at(indexVector.size()/2); if (centerIndex.GetIndexDimension() == 3) { pos[0] = centerIndex[0]; pos[1] = centerIndex[1]; pos[2] = centerIndex[2]; } else return; } GetLabelSet(layer)->GetLabel(pixelValue)->SetCenterOfMassIndex(pos); this->GetSlicedGeometry()->IndexToWorld(pos, pos); GetLabelSet(layer)->GetLabel(pixelValue)->SetCenterOfMassCoordinates(pos); } template < typename ImageType > void mitk::LabelSetImage::ClearBufferProcessing(ImageType* itkImage) { itkImage->FillBuffer(0); } // todo: concatenate all layers and not just the active one template < typename ImageType > void mitk::LabelSetImage::ConcatenateProcessing(ImageType* itkTarget, mitk::LabelSetImage* other) { typename ImageType::Pointer itkSource = ImageType::New(); mitk::CastToItkImage( other, itkSource ); typedef itk::ImageRegionConstIterator< ImageType > ConstIteratorType; typedef itk::ImageRegionIterator< ImageType > IteratorType; ConstIteratorType sourceIter( itkSource, itkSource->GetLargestPossibleRegion() ); IteratorType targetIter( itkTarget, itkTarget->GetLargestPossibleRegion() ); int numberOfTargetLabels = this->GetNumberOfLabels(GetActiveLayer()) - 1; // skip exterior sourceIter.GoToBegin(); targetIter.GoToBegin(); while (!sourceIter.IsAtEnd()) { PixelType sourceValue = sourceIter.Get(); PixelType targetValue = targetIter.Get(); if ( (sourceValue != 0) && !this->GetLabel(targetValue)->GetLocked() ) // skip exterior and locked labels { targetIter.Set( sourceValue + numberOfTargetLabels ); } ++sourceIter; ++targetIter; } } template < typename ImageType > void mitk::LabelSetImage::LayerContainerToImageProcessing(ImageType* target, unsigned int layer) { typename ImageType::Pointer itkSource; mitk::CastToItkImage(m_LayerContainer[layer], itkSource); typedef itk::ImageRegionConstIterator< ImageType > SourceIteratorType; typedef itk::ImageRegionIterator< ImageType > TargetIteratorType; SourceIteratorType sourceIter( itkSource, itkSource->GetLargestPossibleRegion() ); sourceIter.GoToBegin(); TargetIteratorType targetIter( target, target->GetLargestPossibleRegion() ); targetIter.GoToBegin(); while(!sourceIter.IsAtEnd()) { targetIter.Set( sourceIter.Get() ); ++sourceIter; ++targetIter; } } template < typename ImageType > void mitk::LabelSetImage::ImageToLayerContainerProcessing(ImageType* source, unsigned int layer) const { typename ImageType::Pointer itkTarget; mitk::CastToItkImage(m_LayerContainer[layer], itkTarget); typedef itk::ImageRegionConstIterator< ImageType > SourceIteratorType; typedef itk::ImageRegionIterator< ImageType > TargetIteratorType; SourceIteratorType sourceIter( source, source->GetLargestPossibleRegion() ); sourceIter.GoToBegin(); TargetIteratorType targetIter( itkTarget, itkTarget->GetLargestPossibleRegion() ); targetIter.GoToBegin(); while(!sourceIter.IsAtEnd()) { targetIter.Set( sourceIter.Get() ); ++sourceIter; ++targetIter; } } template < typename ImageType > void mitk::LabelSetImage::EraseLabelProcessing(ImageType* itkImage, PixelType pixelValue, unsigned int /*layer*/) { typedef itk::ImageRegionIterator< ImageType > IteratorType; IteratorType iter( itkImage, itkImage->GetLargestPossibleRegion() ); iter.GoToBegin(); while (!iter.IsAtEnd()) { PixelType value = iter.Get(); if (value == pixelValue) { iter.Set( 0 ); } ++iter; } } template < typename ImageType > void mitk::LabelSetImage::MergeLabelProcessing(ImageType* itkImage, PixelType pixelValue, PixelType index) { typedef itk::ImageRegionIterator< ImageType > IteratorType; IteratorType iter( itkImage, itkImage->GetLargestPossibleRegion() ); iter.GoToBegin(); while (!iter.IsAtEnd()) { if (iter.Get() == index) { iter.Set( pixelValue ); } ++iter; } } bool mitk::Equal(const mitk::LabelSetImage& leftHandSide, const mitk::LabelSetImage& rightHandSide, ScalarType eps, bool verbose) { bool returnValue = true; /* LabelSetImage members */ MITK_INFO(verbose) << "--- LabelSetImage Equal ---"; // number layers returnValue = leftHandSide.GetNumberOfLayers() == rightHandSide.GetNumberOfLayers(); if(!returnValue) { MITK_INFO(verbose) << "Number of layers not equal."; return false; } // total number labels returnValue = leftHandSide.GetTotalNumberOfLabels() == rightHandSide.GetTotalNumberOfLabels(); if(!returnValue) { MITK_INFO(verbose) << "Total number of labels not equal."; return false; } // active layer returnValue = leftHandSide.GetActiveLayer() == rightHandSide.GetActiveLayer(); if(!returnValue) { MITK_INFO(verbose) << "Active layer not equal."; return false; } // working image data returnValue = mitk::Equal((const mitk::Image&)leftHandSide,(const mitk::Image&)rightHandSide,eps,verbose); if(!returnValue) { MITK_INFO(verbose) << "Working image data not equal."; return false; } for(unsigned int layerIndex = 0 ; layerIndex < leftHandSide.GetNumberOfLayers(); layerIndex++) { // layer image data returnValue = mitk::Equal(*leftHandSide.GetLayerImage(layerIndex),*rightHandSide.GetLayerImage(layerIndex),eps,verbose); if(!returnValue) { MITK_INFO(verbose) << "Layer image data not equal."; return false; } // layer labelset data returnValue = mitk::Equal(*leftHandSide.GetLabelSet(layerIndex),*rightHandSide.GetLabelSet(layerIndex),eps,verbose); if(!returnValue) { MITK_INFO(verbose) << "Layer labelset data not equal."; return false; } } return returnValue; } diff --git a/Modules/Multilabel/mitkLabelSetImage.h b/Modules/Multilabel/mitkLabelSetImage.h index 1512c1c4fa..afa6143ed7 100644 --- a/Modules/Multilabel/mitkLabelSetImage.h +++ b/Modules/Multilabel/mitkLabelSetImage.h @@ -1,352 +1,352 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkLabelSetImage_H_ #define __mitkLabelSetImage_H_ #include "mitkImage.h" #include "MitkMultilabelExports.h" #include #include #include #include namespace mitk { //##Documentation //## @brief LabelSetImage class for handling labels and layers in a segmentation session. //## //## Handles operations for adding, removing, erasing and editing labels and layers. //## @ingroup Data class MITKMULTILABEL_EXPORT LabelSetImage : public Image { public: mitkClassMacro(LabelSetImage, Image) itkNewMacro(Self) typedef mitk::Label::PixelType PixelType; - typedef itk::Image< PixelType, 3 > LabelSetImageType; - typedef itk::VariableLengthVector< PixelType > VariableVectorType; - /** * \brief BeforeChangeLayerEvent (e.g. used for GUI integration) * As soon as active labelset should be changed, the signal emits. * Emitted by SetActiveLayer(int layer); */ Message<> BeforeChangeLayerEvent; /** * \brief AfterchangeLayerEvent (e.g. used for GUI integration) * As soon as active labelset was changed, the signal emits. * Emitted by SetActiveLayer(int layer); */ Message<> AfterchangeLayerEvent; /** * @brief Initialize an empty mitk::LabelSetImage using the information * of an mitk::Image * @param image the image which is used for initializing the mitk::LabelSetImage */ using mitk::Image::Initialize; virtual void Initialize(const mitk::Image* image) override; /** * \brief */ void Concatenate(mitk::LabelSetImage* image); /** * \brief */ void ClearBuffer(); /** * @brief Merges the mitk::Label with a given target value with the active label * @param targetPixelValue the value of the mitk::Label that should be merged with the active one * @param layer the layer in which the merge should be performed */ void MergeLabel(PixelType targetPixelValue, unsigned int layer = 0); /** * @brief Merges a list of mitk::Labels with the mitk::Label that has a specific value * @param VectorOfLablePixelValues the list of labels that should be merge with the specified one * @param index the value of the label into which the other should be merged * @param layer the layer in which the merge should be performed */ void MergeLabels(std::vector& VectorOfLablePixelValues, PixelType index, unsigned int layer = 0); /** * \brief */ void UpdateCenterOfMass(PixelType pixelValue, unsigned int layer =0); /** * @brief Removes labels from the mitk::LabelSet of given layer. * Calls mitk::LabelSetImage::EraseLabels() which also removes the labels from within the image. * @param VectorOfLabelPixelValues a list of labels to be removed * @param layer the layer in which the labels should be removed */ void RemoveLabels(std::vector& VectorOfLabelPixelValues, unsigned int layer = 0); /** * @brief Erases the label with the given value in the given layer from the underlying image. * The label itself will not be erased from the respective mitk::LabelSet. In order to * remove the label itself use mitk::LabelSetImage::RemoveLabels() * @param pixelValue the label which will be remove from the image * @param layer the layer in which the label should be removed */ void EraseLabel(PixelType pixelValue, unsigned int layer = 0); /** * @brief Similar to mitk::LabelSetImage::EraseLabel() this funtion erase a list of labels from the image * @param VectorOfLabelPixelValues the list of labels that should be remove * @param layer the layer for which the labels should be removed */ void EraseLabels(std::vector& VectorOfLabelPixelValues, unsigned int layer = 0); /** * \brief Returns true if the value exists in one of the labelsets*/ bool ExistLabel(PixelType pixelValue) const; /** * @brief Checks if a label exists in a certain layer * @param pixelValue the label value * @param layer the layer in which should be searched for the label * @return true if the label exists otherwise false */ bool ExistLabel(PixelType pixelValue, unsigned int layer) const; /** * \brief Returns true if the labelset exists*/ bool ExistLabelSet(unsigned int layer) const; /** * @brief Returns the active label of a specific layer * @param layer the layer ID for which the active label should be returned * @return the active label of the specified layer */ mitk::Label* GetActiveLabel(unsigned int layer = 0); /** * @brief Returns the mitk::Label with the given pixelValue and for the given layer * @param pixelValue the pixel value of the label * @param layer the layer in which the labels should be located * @return the mitk::Label if available otherwise NULL */ mitk::Label* GetLabel(PixelType pixelValue, unsigned int layer = 0) const; /** * @brief Returns the currently active mitk::LabelSet * @return the mitk::LabelSet of the active layer or NULL if non is present */ mitk::LabelSet* GetActiveLabelSet(); /** * @brief Gets the mitk::LabelSet for the given layer * @param layer the layer for which the mitk::LabelSet should be retrieved * @return the respective mitk::LabelSet or NULL if non exists for the given layer */ mitk::LabelSet * GetLabelSet(unsigned int layer = 0); const mitk::LabelSet * GetLabelSet(unsigned int layer = 0) const; /** * @brief Gets the ID of the currently active layer * @return the ID of the active layer */ unsigned int GetActiveLayer() const; /** * @brief Get the number of all existing mitk::Labels for a given layer * @param layer the layer ID for which the active mitk::Labels should be retrieved * @return the number of all existing mitk::Labels for the given layer */ unsigned int GetNumberOfLabels(unsigned int layer = 0) const; /** * @brief Returns the number of all labels summed up across all layers * @return the overall number of labels across all layers */ unsigned int GetTotalNumberOfLabels() const; - /** - * \brief */ - void SurfaceStamp(mitk::Surface* surface, bool forceOverwrite); + // This function will need to be ported to an external class + // it requires knowledge of pixeltype and dimension and includes + // too much algorithm to be sensibly part of a data class + ///** + // * \brief */ + //void SurfaceStamp(mitk::Surface* surface, bool forceOverwrite); /** * \brief */ mitk::Image::Pointer CreateLabelMask(PixelType index); /** * @brief Initialize a new mitk::LabelSetImage by an given image. * For all distinct pixel values of the parameter image new labels will * be created. If the number of distinct pixel values exceeds mitk::Label::MAX_LABEL_VALUE * a new layer will be created * @param image the image which is used for initialization */ void InitializeByLabeledImage(mitk::Image::Pointer image); /** * \brief */ void MaskStamp(mitk::Image* mask, bool forceOverwrite); /** * \brief */ void SetActiveLayer(unsigned int layer); /** * \brief */ unsigned int GetNumberOfLayers() const; /** * @brief Adds a new layer to the LabelSetImage. The new layer will be set as the active one * @param layer a mitk::LabelSet which will be set as new layer. * @return the layer ID of the new layer */ unsigned int AddLayer(mitk::LabelSet::Pointer layer =nullptr); /** * \brief Add a layer based on a provided mitk::Image * \param layerImage is added to the vector of label images * \param lset a label set that will be added to the new layer if provided *\return the layer ID of the new layer */ unsigned int AddLayer(mitk::Image::Pointer layerImage, mitk::LabelSet::Pointer lset = nullptr); /** * \brief Add a LabelSet to an existing layer * * This will replace an existing labelSet if one exists. Throws an exceptions if you are trying * to add a labelSet to a non-existing layer. * * If there are no labelSets for layers with an id less than layerIdx default ones will be added * for them. * * \param layerIdx The index of the layer the LabelSet should be added to * \param labelSet The LabelSet that should be added */ void AddLabelSetToLayer(const unsigned int layerIdx, const mitk::LabelSet::Pointer labelSet); /** * @brief Removes the active layer and the respective mitk::LabelSet and image information. * The new active layer is the one below, if exists */ void RemoveLayer(); /** * \brief */ mitk::Image* GetLayerImage(unsigned int layer); const mitk::Image* GetLayerImage(unsigned int layer) const; void OnLabelSetModified(); /** * @brief Sets the label which is used as default exterior label when creating a new layer * @param label the label which will be used as new exterior label */ void SetExteriorLabel(mitk::Label * label); /** * @brief Gets the mitk::Label which is used as default exterior label * @return the exterior mitk::Label */ mitk::Label* GetExteriorLabel(); const mitk::Label* GetExteriorLabel() const; protected: mitkCloneMacro(Self) LabelSetImage(); LabelSetImage(const LabelSetImage & other); virtual ~LabelSetImage(); template < typename ImageType1, typename ImageType2 > void ChangeLayerProcessing( ImageType1* source, ImageType2* target ); template < typename ImageType > void LayerContainerToImageProcessing( ImageType* source, unsigned int layer); template < typename ImageType > void ImageToLayerContainerProcessing( ImageType* source, unsigned int layer) const; template < typename ImageType > void CalculateCenterOfMassProcessing( ImageType* input, PixelType index, unsigned int layer); template < typename ImageType > void ClearBufferProcessing( ImageType* input); template < typename ImageType > void EraseLabelProcessing( ImageType* input, PixelType index, unsigned int layer); // template < typename ImageType > // void ReorderLabelProcessing( ImageType* input, int index, int layer); template < typename ImageType > void MergeLabelProcessing( ImageType* input, PixelType pixelValue, PixelType index); template < typename ImageType > void ConcatenateProcessing( ImageType* input, mitk::LabelSetImage* other); template < typename ImageType > void MaskStampProcessing( ImageType* input, mitk::Image* mask, bool forceOverwrite); template < typename ImageType > void CreateLabelMaskProcessing( ImageType* input, mitk::Image* mask, PixelType index); template < typename ImageType1, typename ImageType2 > void InitializeByLabeledImageProcessing( ImageType1* input, ImageType2* other); std::vector< LabelSet::Pointer > m_LabelSetContainer; std::vector< Image::Pointer > m_LayerContainer; int m_ActiveLayer; mitk::Label::Pointer m_ExteriorLabel; }; /** * @brief Equal A function comparing two label set images for beeing equal in meta- and imagedata * * @ingroup MITKTestingAPI * * Following aspects are tested for equality: * - LabelSetImage members * - working image data * - layer image data * - labels in label set * * @param rightHandSide An image to be compared * @param leftHandSide An image to be compared * @param eps Tolarence for comparison. You can use mitk::eps in most cases. * @param verbose Flag indicating if the user wants detailed console output or not. * @return true, if all subsequent comparisons are true, false otherwise */ MITKMULTILABEL_EXPORT bool Equal( const mitk::LabelSetImage& leftHandSide, const mitk::LabelSetImage& rightHandSide, ScalarType eps, bool verbose ); } // namespace mitk #endif // __mitkLabelSetImage_H_