diff --git a/Modules/Segmentation/Algorithms/mitkSurfaceStampImageFilter.cpp b/Modules/Segmentation/Algorithms/mitkSurfaceStampImageFilter.cpp new file mode 100644 index 0000000000..9684f93931 --- /dev/null +++ b/Modules/Segmentation/Algorithms/mitkSurfaceStampImageFilter.cpp @@ -0,0 +1,301 @@ +/*=================================================================== + +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 "mitkSurfaceStampImageFilter.h" +#include "mitkTimeHelper.h" +#include "mitkImageWriteAccessor.h" +#include "mitkImageAccessByItk.h" +#include + +#include +#include +#include +#include +#include +#include + +#include + +mitk::SurfaceStampImageFilter::SurfaceStampImageFilter() : +m_MakeOutputBinary( false ), +m_OverwriteBackground( false ), +m_ForegroundValue( 1.0 ), +m_BackgroundValue( 0.0 ) +{ +} + +mitk::SurfaceStampImageFilter::~SurfaceStampImageFilter() +{ +} + +void mitk::SurfaceStampImageFilter::GenerateInputRequestedRegion() +{ + mitk::Image* outputImage = this->GetOutput(); + if((outputImage->IsInitialized()==false) ) + return; + + GenerateTimeInInputRegion(outputImage, const_cast< mitk::Image * > ( this->GetInput() )); +} + +void mitk::SurfaceStampImageFilter::GenerateOutputInformation() +{ + mitk::Image::ConstPointer inputImage = this->GetInput(); + mitk::Image::Pointer outputImage = this->GetOutput(); + + itkDebugMacro(<<"GenerateOutputInformation()"); + + if( inputImage.IsNull() || + (inputImage->IsInitialized() == false) || + (inputImage->GetTimeGeometry() == NULL)) return; + + if (m_MakeOutputBinary) + outputImage->Initialize(mitk::MakeScalarPixelType() , *inputImage->GetTimeGeometry()); + else + outputImage->Initialize(inputImage->GetPixelType(), *inputImage->GetTimeGeometry()); + + outputImage->SetPropertyList(inputImage->GetPropertyList()->Clone()); +} + +void mitk::SurfaceStampImageFilter::SetSurface(mitk::Surface *surface) +{ + m_Surface = surface; +} + +void mitk::SurfaceStampImageFilter::GenerateData() +{ + mitk::Image::ConstPointer inputImage = this->GetInput(); + + if (inputImage.IsNull()) + return; + + mitk::Image::Pointer outputImage = this->GetOutput(); + if(outputImage->IsInitialized()==false ) + return; + + if (m_Surface.IsNull()) + return; + + mitk::Image::RegionType outputRegion = outputImage->GetRequestedRegion(); + + int tstart=outputRegion.GetIndex(3); + int tmax=tstart+outputRegion.GetSize(3); + + if ( tmax > 0) + { + int t; + for(t=tstart;tSurfaceStamp( t ); + } + } + else + { + this->SurfaceStamp( 0 ); + } +} + +void mitk::SurfaceStampImageFilter::SurfaceStamp(int time) +{ + mitk::Image::Pointer inputImage = this->GetInput(); + + const mitk::TimeGeometry *surfaceTimeGeometry = GetInput()->GetTimeGeometry(); + const mitk::TimeGeometry *imageTimeGeometry = inputImage->GetTimeGeometry(); + + // Convert time step from image time-frame to surface time-frame + mitk::TimePointType matchingTimePoint = imageTimeGeometry->TimeStepToTimePoint(time); + mitk::TimeStepType surfaceTimeStep = surfaceTimeGeometry->TimePointToTimeStep(matchingTimePoint); + + vtkPolyData * polydata = m_Surface->GetVtkPolyData( surfaceTimeStep ); + if (!polydata) + mitkThrow() << "Polydata is null."; + + vtkSmartPointer transformFilter = vtkSmartPointer::New(); + transformFilter->SetInputData(polydata); +// transformFilter->ReleaseDataFlagOn(); + + vtkSmartPointer transform = vtkSmartPointer::New(); + BaseGeometry::Pointer geometry = surfaceTimeGeometry->GetGeometryForTimeStep( surfaceTimeStep ); + //MLI TODO + //geometry->TransferItkToVtkTransform(); + transform->PostMultiply(); + transform->Concatenate(geometry->GetVtkTransform()->GetMatrix()); + // take image geometry into account. vtk-Image information will be changed to unit spacing and zero origin below. + BaseGeometry::Pointer imageGeometry = imageTimeGeometry->GetGeometryForTimeStep(time); + //MLI TODO + //imageGeometry->TransferItkToVtkTransform(); + transform->Concatenate(imageGeometry->GetVtkTransform()->GetLinearInverse()); + transformFilter->SetTransform(transform); + transformFilter->Update(); + + polydata = transformFilter->GetOutput(); + + if ( !polydata || !polydata->GetNumberOfPoints() ) + mitkThrow() << "Polydata retrieved from transformation is null or has no points."; + + MeshType::Pointer mesh = MeshType::New(); + mesh->SetCellsAllocationMethod( MeshType::CellsAllocatedDynamicallyCellByCell ); + unsigned 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(); + vtkCellArray* polys = polydata->GetPolys(); + + PointIdentifierType numberOfCellPoints = 3; + CellIdentifierType i = 0; + + for (i=0; iGetCell(i); + cellIds = vcell->GetPointIds(); + + CellAutoPointerType cell; + TriangleCellType * triangleCell = new TriangleCellType; + PointIdentifierType k; + for( k = 0; k < numberOfCellPoints; k++ ) + { + triangleCell->SetPointId( k, cellIds->GetId(k) ); + } + + cell.TakeOwnership( triangleCell ); + mesh->SetCell( i, cell ); + } + + if ( !mesh->GetNumberOfPoints() ) + mitkThrow() << "Generated itk mesh is empty."; + + if (m_MakeOutputBinary) + { + this->SurfaceStampBinaryOutputProcessing( mesh ); + } + else + { + AccessFixedDimensionByItk_1(inputImage, SurfaceStampProcessing, 3, mesh); + } +} + +void mitk::SurfaceStampImageFilter::SurfaceStampBinaryOutputProcessing( MeshType* mesh ) +{ + mitk::Image* inputImage = const_cast< mitk::Image* >( this->GetInput() ); + + mitk::Image::Pointer outputImage = this->GetOutput(); + + typedef itk::Image< unsigned char, 3 > BinaryImageType; + BinaryImageType::Pointer itkInputImage; + mitk::CastToItkImage(inputImage, itkInputImage); + + typedef itk::TriangleMeshToBinaryImageFilter FilterType; + + FilterType::Pointer filter = FilterType::New(); + filter->SetInput(mesh); + filter->SetInfoImage(itkInputImage); + filter->SetInsideValue(1); + filter->SetOutsideValue(0); + filter->Update(); + + BinaryImageType::Pointer resultImage = filter->GetOutput(); + resultImage->DisconnectPipeline(); + + mitk::CastToMitkImage(resultImage, outputImage); +} + +template < typename TPixel > +void mitk::SurfaceStampImageFilter::SurfaceStampProcessing(itk::Image< TPixel, 3 >* input, MeshType* mesh) +{ + typedef itk::Image< TPixel, 3 > ImageType; + typedef itk::Image< unsigned char, 3 > BinaryImageType; + + typedef itk::TriangleMeshToBinaryImageFilter FilterType; + + BinaryImageType::Pointer binaryInput = BinaryImageType::New(); + binaryInput->SetSpacing( input->GetSpacing() ); + binaryInput->SetOrigin( input->GetOrigin() ); + binaryInput->SetDirection( input->GetDirection() ); + binaryInput->SetRegions( input->GetLargestPossibleRegion() ); + binaryInput->Allocate(); + binaryInput->FillBuffer(0); + + FilterType::Pointer filter = FilterType::New(); + filter->SetInput(mesh); + filter->SetInfoImage(binaryInput); + filter->SetInsideValue(1); + filter->SetOutsideValue(0); + filter->Update(); + + BinaryImageType::Pointer resultImage = filter->GetOutput(); + resultImage->DisconnectPipeline(); + + mitk::Image::Pointer outputImage = this->GetOutput(); + typename ImageType::Pointer itkOutputImage; + mitk::CastToItkImage(outputImage, itkOutputImage); + + typedef itk::ImageRegionConstIterator< BinaryImageType > BinaryIteratorType; + typedef itk::ImageRegionConstIterator< ImageType > InputIteratorType; + typedef itk::ImageRegionIterator< ImageType > OutputIteratorType; + + BinaryIteratorType sourceIter( resultImage, resultImage->GetLargestPossibleRegion() ); + sourceIter.GoToBegin(); + + InputIteratorType inputIter( input, input->GetLargestPossibleRegion() ); + inputIter.GoToBegin(); + + OutputIteratorType outputIter( itkOutputImage, itkOutputImage->GetLargestPossibleRegion() ); + outputIter.GoToBegin(); + + typename ImageType::PixelType inputValue; + unsigned char sourceValue; + + typename ImageType::PixelType fgValue = static_cast< typename ImageType::PixelType >(m_ForegroundValue); + typename ImageType::PixelType bgValue = static_cast< typename ImageType::PixelType >(m_BackgroundValue); + + while ( !sourceIter.IsAtEnd() ) + { + sourceValue = static_cast< unsigned char >(sourceIter.Get()); + inputValue = static_cast< typename ImageType::PixelType >(inputIter.Get()); + + if (sourceValue != 0) + outputIter.Set( fgValue ); + else if (m_OverwriteBackground) + outputIter.Set( bgValue ); + else + outputIter.Set( inputValue ); + + ++sourceIter; + ++inputIter; + ++outputIter; + } +} \ No newline at end of file diff --git a/Modules/Segmentation/Algorithms/mitkSurfaceStampImageFilter.h b/Modules/Segmentation/Algorithms/mitkSurfaceStampImageFilter.h new file mode 100644 index 0000000000..96fdd3885b --- /dev/null +++ b/Modules/Segmentation/Algorithms/mitkSurfaceStampImageFilter.h @@ -0,0 +1,104 @@ +/*=================================================================== + +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 _mitkSurfaceStampImageFilter_h__ +#define _mitkSurfaceStampImageFilter_h__ + +#include "mitkCommon.h" +#include "MitkSegmentationExports.h" +#include "mitkImageToImageFilter.h" +#include "mitkSurface.h" + +#include + +class vtkPolyData; + +namespace mitk { +/** + * + * @brief Converts surface data to pixel data. Requires a surface and an + * image, which header information defines the output image. + * + * The resulting image has the same dimension, size, and Geometry3D + * as the input image. The image is cut using a vtkStencil. + * The user can decide if he wants to keep the original values or create a + * binary image by setting MakeBinaryOutputOn (default is \a false). If + * set to \a true all voxels inside the surface are set to one and all + * outside voxel are set to zero. + * + * NOTE: Since the reference input image is passed to the vtkStencil in + * any case, the image needs to be initialized with pixel values greater than + * the numerical minimum of the used pixel type (e.g. at least -127 for + * unsigned char images, etc.) to produce a correct binary image + * representation of the surface in MakeOutputBinary mode. + * + * @ingroup SurfaceFilters + * @ingroup Process + */ +class MitkSegmentation_EXPORT SurfaceStampImageFilter : public ImageToImageFilter +{ +public: + mitkClassMacro(SurfaceStampImageFilter, ImageToImageFilter); + itkNewMacro(Self); + + itkSetMacro(MakeOutputBinary, bool); + itkGetMacro(MakeOutputBinary, bool); + itkBooleanMacro(MakeOutputBinary); + + itkSetMacro(OverwriteBackground, bool); + itkGetMacro(OverwriteBackground, bool); + itkBooleanMacro(OverwriteBackground); + + itkGetConstMacro(BackgroundValue, float); + itkSetMacro(BackgroundValue, float); + + itkGetConstMacro(ForegroundValue, float); + itkSetMacro(ForegroundValue, float); + + virtual void GenerateInputRequestedRegion(); + + virtual void GenerateOutputInformation(); + + virtual void GenerateData(); + + void SetSurface(mitk::Surface *surface); + + typedef itk::QuadEdgeMesh< double, 3 > MeshType; + +protected: + + SurfaceStampImageFilter(); + + virtual ~SurfaceStampImageFilter(); + + void SurfaceStamp(int time = 0); + + + template < typename TPixel > + void SurfaceStampProcessing( itk::Image< TPixel, 3 >* input, MeshType* mesh); + + void SurfaceStampBinaryOutputProcessing( MeshType* mesh ); + + bool m_MakeOutputBinary; + bool m_OverwriteBackground; + float m_BackgroundValue; + float m_ForegroundValue; + + mitk::Surface::Pointer m_Surface; +}; +} // namespace mitk + +#endif /* MITKCOONSPATCHFILTER_H_HEADER_INCLUDED_C10B22CD */ diff --git a/Modules/Segmentation/Controllers/mitkSliceBasedInterpolationController.cpp b/Modules/Segmentation/Controllers/mitkSliceBasedInterpolationController.cpp new file mode 100644 index 0000000000..ae2524d013 --- /dev/null +++ b/Modules/Segmentation/Controllers/mitkSliceBasedInterpolationController.cpp @@ -0,0 +1,419 @@ +/*=================================================================== + +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 "mitkSliceBasedInterpolationController.h" + +#include "mitkImageCast.h" +#include "mitkImageAccessByItk.h" +#include "mitkImageTimeSelector.h" +#include "mitkExtractSliceFilter.h" +#include "mitkImageReadAccessor.h" + +#include "mitkShapeBasedInterpolationAlgorithm.h" + +#include +#include +#include + +mitk::SliceBasedInterpolationController::InterpolatorMapType mitk::SliceBasedInterpolationController::s_InterpolatorForImage; // static member initialization + +mitk::SliceBasedInterpolationController* mitk::SliceBasedInterpolationController::InterpolatorForImage(const Image* image) +{ + InterpolatorMapType::iterator iter = s_InterpolatorForImage.find( image ); + if ( iter != s_InterpolatorForImage.end() ) + { + return iter->second; + } + else + { + return NULL; + } +} + +mitk::SliceBasedInterpolationController::SliceBasedInterpolationController() : +m_WorkingImage(NULL), +m_ReferenceImage(NULL) +{ +} + +mitk::SliceBasedInterpolationController::~SliceBasedInterpolationController() +{ + // remove this from the list of interpolators + for ( InterpolatorMapType::iterator iter = s_InterpolatorForImage.begin(); + iter != s_InterpolatorForImage.end(); + ++iter ) + { + if (iter->second == this) + { + s_InterpolatorForImage.erase( iter ); + break; + } + } +} + +void mitk::SliceBasedInterpolationController::ResetLabelCount() +{ + m_LabelCountInSlice.clear(); + int numberOfLabels = m_WorkingImage->GetNumberOfLabels(); + m_LabelCountInSlice.resize( m_WorkingImage->GetTimeSteps() ); + + for (unsigned int timeStep = 0; timeStep < m_WorkingImage->GetTimeSteps(); ++timeStep) + { + m_LabelCountInSlice[timeStep].resize(3); + for (unsigned int dim = 0; dim < 3; ++dim) + { + m_LabelCountInSlice[timeStep][dim].clear(); + m_LabelCountInSlice[timeStep][dim].resize( m_WorkingImage->GetDimension(dim) ); + for (unsigned int slice = 0; slice < m_WorkingImage->GetDimension(dim); ++slice) + { + m_LabelCountInSlice[timeStep][dim][slice].clear(); + m_LabelCountInSlice[timeStep][dim][slice].resize( numberOfLabels ); + m_LabelCountInSlice[timeStep][dim][slice].assign( numberOfLabels, 0 ); + } + } + } +} + +void mitk::SliceBasedInterpolationController::SetWorkingImage( LabelSetImage* newImage ) +{ + if (m_WorkingImage != newImage) + { + // delete the current working image from the list of interpolators + InterpolatorMapType::iterator iter = s_InterpolatorForImage.find( m_WorkingImage); + if ( iter != s_InterpolatorForImage.end() ) + { + s_InterpolatorForImage.erase( iter ); + } + + m_WorkingImage = newImage; + + s_InterpolatorForImage.insert( std::make_pair( m_WorkingImage, this ) ); + } + + this->ResetLabelCount(); + + AccessFixedDimensionByItk_1( m_WorkingImage, ScanImageITKProcessing, 3, 0 ); + + // for all timesteps, scan whole image: TODO: enable this again for 3D+time +/* + for (unsigned int timeStep = 0; timeStep < m_WorkingImage->GetTimeSteps(); ++timeStep) + { + ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); + timeSelector->SetInput( m_WorkingImage ); + timeSelector->SetTimeNr( timeStep ); + timeSelector->UpdateLargestPossibleRegion(); + Image::Pointer segmentation3D = timeSelector->GetOutput(); + this->SetChangedVolume( segmentation3D.GetPointer(), timeStep ); + } +*/ +// this->Modified(); +} + +void mitk::SliceBasedInterpolationController::SetReferenceImage( Image* newImage ) +{ + if (!newImage) return; + + m_ReferenceImage = newImage; + + // ensure the reference image has the same dimensionality and extents as the segmentation image + if ( m_WorkingImage.IsNull() + || m_ReferenceImage->GetDimension() != m_WorkingImage->GetDimension() + || m_ReferenceImage->GetPixelType().GetNumberOfComponents() != 1 + || m_WorkingImage->GetPixelType().GetNumberOfComponents() != 1 + ) + { + MITK_WARN << "Segmentation image has different image characteristics than reference image." << std::endl; + m_ReferenceImage = NULL; + return; + } + + for (unsigned int dim = 0; dim < m_WorkingImage->GetDimension(); ++dim) + { + if ( m_ReferenceImage->GetDimension(dim) != m_WorkingImage->GetDimension(dim) ) + { + MITK_WARN << "original patient image does not match segmentation (different extent in dimension " << dim + << "), ignoring patient image" << std::endl; + m_ReferenceImage = NULL; + return; + } + } +} + +void mitk::SliceBasedInterpolationController::SetChangedSlice( const Image* slice, unsigned int sliceDimension, unsigned int sliceIndex, unsigned int timeStep ) +{ + if ( !slice ) return; + if ( slice->GetDimension() != 2 ) return; + if ( sliceDimension > 2 ) return; + if ( m_WorkingImage.IsNull() ) return; + + // check if the number of labels has changed + int numberOfLabels = m_WorkingImage->GetNumberOfLabels(); + if (m_LabelCountInSlice[0][0][0].size() != numberOfLabels) + return; + + unsigned int dim0(0); + unsigned int dim1(1); + + // determine the other two dimensions + switch (sliceDimension) + { + default: + case 2: + dim0 = 0; dim1 = 1; break; + case 1: + dim0 = 0; dim1 = 2; break; + case 0: + dim0 = 1; dim1 = 2; break; + } + + AccessFixedDimensionByItk_1( slice, ScanSliceITKProcessing, 2, SetChangedSliceOptions(sliceDimension, sliceIndex, dim0, dim1, timeStep) ); + +// this->Modified(); +} + +template < typename PixelType > +void mitk::SliceBasedInterpolationController::ScanSliceITKProcessing( const itk::Image* input, const SetChangedSliceOptions& options ) +{ + unsigned int timeStep = options.timeStep; + unsigned int sliceDimension = options.sliceDimension; + unsigned int sliceIndex = options.sliceIndex; + + if ( sliceDimension > 2 ) return; + if ( sliceIndex >= m_LabelCountInSlice[timeStep][sliceDimension].size() ) return; + + unsigned int dim0(options.dim0); + unsigned int dim1(options.dim1); + + std::vector numberOfPixels; // number of pixels in the current slice that are equal to the active label + int numberOfLabels = m_WorkingImage->GetNumberOfLabels(); + numberOfPixels.resize( numberOfLabels ); + + typedef itk::Image ImageType; + typedef itk::ImageRegionConstIteratorWithIndex< ImageType > IteratorType; + + IteratorType iter( input, input->GetLargestPossibleRegion() ); + iter.GoToBegin(); + + typename IteratorType::IndexType index; + + while ( !iter.IsAtEnd() ) + { + index = iter.GetIndex(); + int value = static_cast< int >(iter.Get()); + ++ m_LabelCountInSlice[timeStep][dim0][index[0]][value]; + ++ m_LabelCountInSlice[timeStep][dim1][index[1]][value]; + ++ numberOfPixels[value]; + ++iter; + } + + for (unsigned int label=0; label +void mitk::SliceBasedInterpolationController::ScanImageITKProcessing( itk::Image* input, unsigned int timeStep ) +{ + typedef itk::ImageSliceConstIteratorWithIndex< itk::Image > IteratorType; + + IteratorType iter( input, input->GetLargestPossibleRegion() ); + iter.SetFirstDirection(0); + iter.SetSecondDirection(1); + + typename IteratorType::IndexType index; + unsigned int x = 0; + unsigned int y = 0; + unsigned int z = 0; + + std::vector numberOfPixels; // number of pixels per slice that are equal to the active label + int numberOfLabels = m_WorkingImage->GetNumberOfLabels(); + numberOfPixels.resize( numberOfLabels ); + + iter.GoToBegin(); + while ( !iter.IsAtEnd() ) + { + while ( !iter.IsAtEndOfSlice() ) + { + while ( !iter.IsAtEndOfLine() ) + { + index = iter.GetIndex(); + x = index[0]; + y = index[1]; + z = index[2]; + + int value = static_cast( iter.Get() ); + ++m_LabelCountInSlice[timeStep][0][x][value]; + ++m_LabelCountInSlice[timeStep][1][y][value]; + ++numberOfPixels[value]; + + ++iter; + } + iter.NextLine(); + } + + for (unsigned int label = 0; label < numberOfLabels; ++label) + m_LabelCountInSlice[timeStep][2][z][label] += numberOfPixels[label]; + + // clear label counter + numberOfPixels.assign(numberOfLabels, 0); + iter.NextSlice(); + } +} + +mitk::Image::Pointer mitk::SliceBasedInterpolationController::Interpolate(unsigned int sliceDimension, + unsigned int sliceIndex, + const mitk::PlaneGeometry* currentPlane, + unsigned int timeStep ) +{ + if (m_WorkingImage.IsNull()) return NULL; + if (!currentPlane) return NULL; + if ( timeStep >= m_LabelCountInSlice.size() ) return NULL; + if ( sliceDimension > 2 ) return NULL; + int upperLimit = m_LabelCountInSlice[timeStep][sliceDimension].size(); + if ( sliceIndex >= upperLimit - 1 ) return NULL; // can't interpolate first and last slice + if ( sliceIndex < 1 ) return NULL; + + int pixelValue = m_WorkingImage->GetActiveLabel()->GetValue(); + + // slice contains a segmentation, won't interpolate anything then + if ( m_LabelCountInSlice[timeStep][sliceDimension][sliceIndex][pixelValue] > 0 ) return NULL; + + int lowerBound(0); + int upperBound(0); + bool bounds(false); + + for (lowerBound = sliceIndex - 1; /*lowerBound >= 0*/; --lowerBound) + { + if ( m_LabelCountInSlice[timeStep][sliceDimension][lowerBound][pixelValue] > 0 ) + { + bounds = true; + break; + } + + if (lowerBound == 0) break; + } + + if (!bounds) return NULL; + + bounds = false; + for (upperBound = sliceIndex + 1 ; upperBound < upperLimit; ++upperBound) + { + if ( m_LabelCountInSlice[timeStep][sliceDimension][upperBound][pixelValue] > 0 ) + { + bounds = true; + break; + } + } + + if (!bounds) return NULL; + + // ok, we have found two neighboring slices with the active label + // (and we made sure that the current slice does NOT contain the active label + //Setting up the ExtractSliceFilter + mitk::ExtractSliceFilter::Pointer extractor = ExtractSliceFilter::New(); + extractor->SetInput(m_WorkingImage); + extractor->SetTimeStep(timeStep); + extractor->SetResliceTransformByGeometry( m_WorkingImage->GetTimeGeometry()->GetGeometryForTimeStep( timeStep ) ); + extractor->SetVtkOutputRequest(false); + + //Reslicing the current plane + extractor->SetWorldGeometry(currentPlane); + extractor->Modified(); + + try + { + extractor->Update(); + } + catch(const std::exception &e) + { + MITK_ERROR<<"Error in 2D interpolation: " << e.what(); + return NULL; + } + + mitk::Image::Pointer resultImage = extractor->GetOutput(); + resultImage->DisconnectPipeline(); + + //Creating PlaneGeometry for lower slice + mitk::PlaneGeometry::Pointer reslicePlane = currentPlane->Clone(); + + //Transforming the current origin so that it matches the lower slice + mitk::Point3D origin = currentPlane->GetOrigin(); + m_WorkingImage->GetSlicedGeometry()->WorldToIndex(origin, origin); + origin[sliceDimension] = lowerBound; + m_WorkingImage->GetSlicedGeometry()->IndexToWorld(origin, origin); + reslicePlane->SetOrigin(origin); + + //Extract the lower slice + extractor->SetWorldGeometry(reslicePlane); + extractor->Modified(); + + try + { + extractor->Update(); + } + catch(const std::exception &e) + { + MITK_ERROR<<"Error in 2D interpolation: " << e.what(); + return NULL; + } + + mitk::Image::Pointer lowerMITKSlice = extractor->GetOutput(); + lowerMITKSlice->DisconnectPipeline(); + + //Transforming the current origin so that it matches the upper slice + m_WorkingImage->GetSlicedGeometry()->WorldToIndex(origin, origin); + origin[sliceDimension] = upperBound; + m_WorkingImage->GetSlicedGeometry()->IndexToWorld(origin, origin); + reslicePlane->SetOrigin(origin); + + //Extract the upper slice + extractor->SetWorldGeometry(reslicePlane); + extractor->Modified(); + + try + { + extractor->Update(); + } + catch(const std::exception &e) + { + MITK_ERROR<<"Error in 2D interpolation: " << e.what(); + return NULL; + } + + mitk::Image::Pointer upperMITKSlice = extractor->GetOutput(); + upperMITKSlice->DisconnectPipeline(); + + if ( lowerMITKSlice.IsNull() || upperMITKSlice.IsNull() ) return NULL; + + // interpolation algorithm gets some inputs + // two segmentations (guaranteed to be of the same data type, but no special data type guaranteed) + // orientation (sliceDimension) of the segmentations + // position of the two slices (sliceIndices) + // one volume image (original patient image) + // + // interpolation algorithm can use e.g. itk::ImageSliceConstIteratorWithIndex to + // inspect the original patient image at appropriate positions + + mitk::SegmentationInterpolationAlgorithm::Pointer algorithm = mitk::ShapeBasedInterpolationAlgorithm::New().GetPointer(); + //MLI TODO + //algorithm->Interpolate( lowerMITKSlice.GetPointer(), lowerBound, + // upperMITKSlice.GetPointer(), upperBound, + // sliceIndex, + // resultImage); + + return resultImage; +} \ No newline at end of file diff --git a/Modules/Segmentation/Controllers/mitkSliceBasedInterpolationController.h b/Modules/Segmentation/Controllers/mitkSliceBasedInterpolationController.h new file mode 100644 index 0000000000..7cb9872c1c --- /dev/null +++ b/Modules/Segmentation/Controllers/mitkSliceBasedInterpolationController.h @@ -0,0 +1,193 @@ +/*=================================================================== + +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 mitkSliceBasedInterpolationController_h_Included +#define mitkSliceBasedInterpolationController_h_Included + +#include +#include "mitkLabelSetImage.h" + +#include +#include + +#include +#include + +namespace mitk +{ +class Image; + +/** + \brief Generates interpolations of 2D slices. + + \sa QmitkSlicesInterpolator + \sa QmitkInteractiveSegmentation + + \ingroup ToolManagerEtAl + + There is a separate page describing the general design of QmitkInteractiveSegmentation: \ref QmitkInteractiveSegmentationTechnicalPage + + This class keeps track of the contents of a 3D segmentation image. + \attention mitk::SliceBasedInterpolationController assumes that the image contains pixel values of 0 and 1. + + After you set the segmentation image using SetSegmentationVolume(), the whole image is scanned for pixels other than 0. + SliceBasedInterpolationController registers as an observer to the segmentation image, and repeats the scan whenvever the + image is modified. + + You can prevent this (time consuming) scan if you do the changes slice-wise and send difference images to SliceBasedInterpolationController. + For this purpose SetChangedSlice() should be used. mitk::OverwriteImageFilter already does this every time it changes a + slice of an image. There is a static method InterpolatorForImage(), which can be used to find out if there already is an interpolator + instance for a specified image. OverwriteImageFilter uses this to get to know its interpolator. + + SliceBasedInterpolationController needs to maintain some information about the image slices (in every dimension). + This information is stored internally in m_SegmentationCountInSlice, which is basically three std::vectors (one for each dimension). + Each item describes one image dimension, each vector item holds the count of pixels in "its" slice. This is perhaps better to understand + from the following picture (where red items just mean to symbolize "there is some segmentation" - in reality there is an integer count). + + \image html slice_based_segmentation_interpolator.png + + $Author$ +*/ +class MitkSegmentation_EXPORT SliceBasedInterpolationController : public itk::Object +{ + public: + + mitkClassMacro(SliceBasedInterpolationController, itk::Object); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + /** + \brief Find interpolator for a given image. + \return NULL if there is no interpolator yet. + + This method is useful if several "clients" modify the same image and want to access the interpolations. + Then they can share the same object. + */ + static SliceBasedInterpolationController* InterpolatorForImage(const Image*); + + /** + \brief Initialize with a whole volume. + + Will scan the volume for segmentation pixels (values other than 0) and fill some internal data structures. + You don't have to call this method every time something changes, but only + when several slices at once change. + + When you change a single slice, call SetChangedSlice() instead. + */ + void SetWorkingImage( LabelSetImage* image ); + + /** + \brief Set a reference image (original patient image) - optional. + + If this image is set (must exactly match the dimensions of the segmentation), + the interpolation algorithm may consider image content to improve the interpolated + (estimated) segmentation. + */ + void SetReferenceImage( Image* image ); + + /** + \brief Update after changing a single slice in the working image. + + \param image is a 2D image with the difference image of the slice determined by sliceDimension and sliceIndex. + The difference is (pixel value in the new slice minus pixel value in the old slice). + + \param sliceDimension Number of the dimension which is constant for all pixels of the meant slice. + + \param sliceIndex Which slice to take, in the direction specified by sliceDimension. Count starts from 0. + + \param timeStep Which time step is changed + */ + void SetChangedSlice( const Image* image, unsigned int sliceDimension, unsigned int sliceIndex, unsigned int timeStep ); + + /** + \brief Update after changing the whole working image. + + \param image is a 3D image with the difference image of the slice determined by sliceDimension and sliceIndex. + The difference is (pixel value in the new slice minus pixel value in the old slice). + + \param timeStep Which time step is changed + */ +// void SetChangedImage( const Image* image, unsigned int timeStep ); + + /** + \brief Generates an interpolated image for the given slice. + + \param sliceDimension Number of the dimension which is constant for all pixels of the meant slice. + + \param sliceIndex Which slice to take, in the direction specified by sliceDimension. Count starts from 0. + + \param timeStep Which time step to use + */ + Image::Pointer Interpolate( unsigned int sliceDimension, unsigned int sliceIndex, const mitk::PlaneGeometry* currentPlane, unsigned int timeStep ); + + /** + \brief Initializes the internal container with the number of voxels per label. + */ + void ResetLabelCount(); + + protected: + + /** + \brief Protected class of mitk::SliceBasedInterpolationController. Don't use (you shouldn't be able to do so)! + */ + class MitkSegmentation_EXPORT SetChangedSliceOptions + { + public: + SetChangedSliceOptions( unsigned int sd, unsigned int si, unsigned int d0, unsigned int d1, unsigned int t) + : sliceDimension(sd), sliceIndex(si), dim0(d0), dim1(d1), timeStep(t) + { + } + + unsigned int sliceDimension; + unsigned int sliceIndex; + unsigned int dim0; + unsigned int dim1; + unsigned int timeStep; +// void* pixelData; + }; + + typedef std::vector LabelCounterVectorType; + typedef std::vector< LabelCounterVectorType > LabelCounterSliceVectorType; + typedef std::vector< std::vector< LabelCounterSliceVectorType > > LabelCounterSliceTimeVectorType; + typedef std::map< const Image*, SliceBasedInterpolationController* > InterpolatorMapType; + + SliceBasedInterpolationController();// purposely hidden + virtual ~SliceBasedInterpolationController(); + + /// internal scan of a single slice + template < typename PixelType > + void ScanSliceITKProcessing( const itk::Image*, const SetChangedSliceOptions& options ); + + /// internal scan of the whole image + template < typename TPixel, unsigned int VImageDimension > + void ScanImageITKProcessing( itk::Image*, unsigned int timeStep ); + + /** + An array that of flags. One for each dimension of the image. A flag is set, when a slice in a certain dimension + has at least one pixel that is not 0 (which would mean that it has to be considered by the interpolation algorithm). + E.g. flags for axial slices are stored in m_SegmentationCountInSlice[0][index]. + Enhanced with time steps it is now m_SegmentationCountInSlice[timeStep][0][index] + */ + LabelCounterSliceTimeVectorType m_LabelCountInSlice; + + static InterpolatorMapType s_InterpolatorForImage; + + LabelSetImage::Pointer m_WorkingImage; + Image::Pointer m_ReferenceImage; +}; +} // namespace + +#endif diff --git a/Modules/Segmentation/Interactions/mitkSegmentationInteractor.cpp b/Modules/Segmentation/Interactions/mitkSegmentationInteractor.cpp new file mode 100644 index 0000000000..cc5ffa0bfd --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkSegmentationInteractor.cpp @@ -0,0 +1,63 @@ +/*=================================================================== + + 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 "mitkSegmentationInteractor.h" +#include "mitkLabelSetImage.h" +#include "mitkInteractionPositionEvent.h" +#include "mitkToolManager.h" +#include "mitkToolManagerProvider.h" + +#include + +void mitk::SegmentationInteractor::ConnectActionsAndFunctions() +{ + Superclass::ConnectActionsAndFunctions(); + + CONNECT_FUNCTION("change_active_label", ChangeActiveLabel); +} + +bool mitk::SegmentationInteractor::ChangeActiveLabel(StateMachineAction*, InteractionEvent* interactionEvent) +{ + BaseRenderer::Pointer sender = interactionEvent->GetSender(); + InteractionPositionEvent* positionEvent = static_cast(interactionEvent); + + //MLI TODO + //m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; + //m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); + + mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); + assert(toolManager); + + DataNode* workingNode( toolManager->GetWorkingData(0) ); + if (workingNode) + { + mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); + assert(workingImage); + + int timestep = positionEvent->GetSender()->GetTimeStep(); + int pixelValue = workingImage->GetPixelValueByWorldCoordinate( positionEvent->GetPositionInWorld(), timestep ); + workingImage->GetActiveLabelSet()->SetActiveLabel(pixelValue); // can be the background + + // Call Events + //workingImage->ActiveLabelEvent.Send(pixelValue); + + //MLI TODO + //toolManager->WorkingDataModified.Send(); + } + + sender->GetRenderingManager()->RequestUpdateAll(); + return true; +} \ No newline at end of file diff --git a/Modules/Segmentation/Interactions/mitkSegmentationInteractor.h b/Modules/Segmentation/Interactions/mitkSegmentationInteractor.h new file mode 100644 index 0000000000..1d6f6cb5e5 --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkSegmentationInteractor.h @@ -0,0 +1,56 @@ +/*=================================================================== + + 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 mitkSegmentationInteractor_h +#define mitkSegmentationInteractor_h + +#include "MitkSegmentationExports.h" +#include "mitkDisplayInteractor.h" + +namespace mitk +{ + /** + *\class SegmentationInteractor + *@brief Observer that adds interaction with a segmentation session to the default display interaction. + * + * At the moment, this includes changing the active label. + * + * @ingroup Interaction + **/ + + class MitkSegmentation_EXPORT SegmentationInteractor: public DisplayInteractor + { + public: + mitkClassMacro(SegmentationInteractor, DisplayInteractor) + itkNewMacro(Self) + + protected: + SegmentationInteractor() {}; + virtual ~SegmentationInteractor() {}; + /** + * Derived function. + * Connects the action names used in the state machine pattern with functions implemented within + * this InteractionEventObserver. This is only necessary here because the events are processed by the state machine. + */ + virtual void ConnectActionsAndFunctions(); + + /** + * Changes the active label. + */ + bool ChangeActiveLabel(StateMachineAction*, InteractionEvent*); + }; +} +#endif diff --git a/Modules/Segmentation/files.cmake b/Modules/Segmentation/files.cmake index 981f749ddf..38a92d1e84 100644 --- a/Modules/Segmentation/files.cmake +++ b/Modules/Segmentation/files.cmake @@ -1,118 +1,122 @@ set(CPP_FILES Algorithms/mitkCalculateSegmentationVolume.cpp Algorithms/mitkContourModelSetToImageFilter.cpp Algorithms/mitkContourSetToPointSetFilter.cpp Algorithms/mitkContourUtils.cpp Algorithms/mitkCorrectorAlgorithm.cpp Algorithms/mitkDiffImageApplier.cpp Algorithms/mitkDiffSliceOperation.cpp Algorithms/mitkDiffSliceOperationApplier.cpp Algorithms/mitkImageLiveWireContourModelFilter.cpp Algorithms/mitkImageToContourFilter.cpp #Algorithms/mitkImageToContourModelFilter.cpp Algorithms/mitkImageToLiveWireContourFilter.cpp Algorithms/mitkManualSegmentationToSurfaceFilter.cpp Algorithms/mitkOtsuSegmentationFilter.cpp Algorithms/mitkOverwriteDirectedPlaneImageFilter.cpp Algorithms/mitkOverwriteSliceImageFilter.cpp Algorithms/mitkSegmentationObjectFactory.cpp Algorithms/mitkShapeBasedInterpolationAlgorithm.cpp Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp Algorithms/mitkShowSegmentationAsSurface.cpp Algorithms/mitkVtkImageOverwrite.cpp Controllers/mitkSegmentationInterpolationController.cpp Controllers/mitkToolManager.cpp Controllers/mitkSegmentationModuleActivator.cpp Controllers/mitkToolManagerProvider.cpp DataManagement/mitkContour.cpp #DataManagement/mitkContourElement.cpp #DataManagement/mitkContourModel.cpp DataManagement/mitkContourSet.cpp DataManagement/mitkExtrudedContour.cpp Interactions/mitkAdaptiveRegionGrowingTool.cpp Interactions/mitkAddContourTool.cpp Interactions/mitkAutoCropTool.cpp Interactions/mitkAutoSegmentationTool.cpp Interactions/mitkBinaryThresholdTool.cpp Interactions/mitkBinaryThresholdULTool.cpp Interactions/mitkCalculateGrayValueStatisticsTool.cpp Interactions/mitkCalculateVolumetryTool.cpp Interactions/mitkContourInteractor.cpp Interactions/mitkContourModelInteractor.cpp Interactions/mitkContourModelLiveWireInteractor.cpp Interactions/mitkContourTool.cpp Interactions/mitkCorrectorTool2D.cpp Interactions/mitkCreateSurfaceTool.cpp Interactions/mitkDrawPaintbrushTool.cpp Interactions/mitkErasePaintbrushTool.cpp Interactions/mitkEraseRegionTool.cpp Interactions/mitkExtrudedContourInteractor.cpp Interactions/mitkFastMarchingTool.cpp Interactions/mitkFastMarchingTool3D.cpp Interactions/mitkFeedbackContourTool.cpp Interactions/mitkFillRegionTool.cpp Interactions/mitkLiveWireTool2D.cpp Interactions/mitkOtsuTool3D.cpp Interactions/mitkPaintbrushTool.cpp Interactions/mitkPixelManipulationTool.cpp Interactions/mitkRegionGrow3DTool.cpp Interactions/mitkRegionGrowingTool.cpp Interactions/mitkSegmentationsProcessingTool.cpp Interactions/mitkSetRegionTool.cpp Interactions/mitkSegTool2D.cpp Interactions/mitkSubtractContourTool.cpp Interactions/mitkTool.cpp Interactions/mitkToolCommand.cpp Interactions/mitkWatershedTool.cpp Interactions/mitkPickingTool.cpp + Interactions/mitkSegmentationInteractor.cpp #SO #IO/mitkContourModelIOFactory.cpp #IO/mitkContourModelReader.cpp #IO/mitkContourModelWriter.cpp #IO/mitkContourModelWriterFactory.cpp Rendering/mitkContourMapper2D.cpp #Rendering/mitkContourModelGLMapper2D.cpp #Rendering/mitkContourModelMapper2D.cpp #Rendering/mitkContourModelMapper3D.cpp Rendering/mitkContourSetMapper2D.cpp Rendering/mitkContourSetVtkMapper3D.cpp Rendering/mitkContourVtkMapper3D.cpp SegmentationUtilities/BooleanOperations/mitkBooleanOperation.cpp SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp +#Added from ML + Controllers/mitkSliceBasedInterpolationController.cpp + Algorithms/mitkSurfaceStampImageFilter.cpp ) set(RESOURCE_FILES Add_48x48.png Add_Cursor_32x32.png Correction_48x48.png Correction_Cursor_32x32.png Erase_48x48.png Erase_Cursor_32x32.png FastMarching_48x48.png FastMarching_Cursor_32x32.png Fill_48x48.png Fill_Cursor_32x32.png LiveWire_48x48.png LiveWire_Cursor_32x32.png Otsu_48x48.png Paint_48x48.png Paint_Cursor_32x32.png Pick_48x48.png RegionGrowing_48x48.png RegionGrowing_Cursor_32x32.png Subtract_48x48.png Subtract_Cursor_32x32.png Threshold_48x48.png TwoThresholds_48x48.png Watershed_48x48.png Watershed_Cursor_32x32.png Wipe_48x48.png Wipe_Cursor_32x32.png Interactions/dummy.xml Interactions/LiveWireTool.xml Interactions/PressMoveRelease.xml Interactions/PressMoveReleaseAndPointSetting.xml Interactions/PressMoveReleaseWithCTRLInversion.xml Interactions/PressMoveReleaseWithCTRLInversionAllMouseMoves.xml Interactions/SegmentationToolsConfig.xml ) diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkLabelSetWidget.cpp b/Modules/SegmentationUI/Qmitk/QmitkLabelSetWidget.cpp similarity index 98% rename from Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkLabelSetWidget.cpp rename to Modules/SegmentationUI/Qmitk/QmitkLabelSetWidget.cpp index 07f4512cd4..d7fd86f21a 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkLabelSetWidget.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkLabelSetWidget.cpp @@ -1,1249 +1,1248 @@ /*=================================================================== 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 "QmitkLabelSetWidget.h" // mitk #include #include #include #include #include #include #include #include #include #include #include // Qmitk #include #include +// MLI Integration #include // Qt #include #include #include #include #include #include #include #include +// MLI TODO +#include // itk #include // todo: // berry //#include QmitkLabelSetWidget::QmitkLabelSetWidget(QWidget* parent) : QWidget(parent) , m_ToolManager(NULL) , m_DataStorage(NULL) , m_Completer(NULL) { m_Controls.setupUi(this); m_ColorSequenceRainbow.GoToBegin(); m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); assert(m_ToolManager); m_Controls.m_LabelSearchBox->setAlwaysShowClearIcon(true); m_Controls.m_LabelSearchBox->setShowSearchIcon(true); QStringList completionList; completionList << ""; m_Completer = new QCompleter(completionList, this); m_Completer->setCaseSensitivity(Qt::CaseInsensitive); m_Controls.m_LabelSearchBox->setCompleter(m_Completer); connect( m_Controls.m_LabelSearchBox, SIGNAL(returnPressed()), this, SLOT(OnSearchLabel()) ); //connect( m_Controls.m_LabelSetTableWidget, SIGNAL(labelListModified(const QStringList&)), this, SLOT( OnLabelListModified(const QStringList&)) ); //connect( m_Controls.m_LabelSetTableWidget, SIGNAL(mergeLabel(int)), this, SLOT( OnMergeLabel(int)) ); QStringListModel* completeModel = static_cast (m_Completer->model()); completeModel->setStringList(GetLabelStringList()); m_Controls.m_LabelSearchBox->setEnabled(false); m_Controls.m_lblCaption->setText(""); InitializeTableWidget(); - } QmitkLabelSetWidget::~QmitkLabelSetWidget() { } void QmitkLabelSetWidget::OnTableViewContextMenuRequested(const QPoint& pos) { QTableWidgetItem *itemAt = m_Controls.m_LabelSetTableWidget->itemAt(pos); //OnItemClicked(itemAt); if (!itemAt) return; int pixelValue = itemAt->data(Qt::UserRole).toInt(); QMenu* menu = new QMenu(m_Controls.m_LabelSetTableWidget); if (m_Controls.m_LabelSetTableWidget->selectedItems().size()>1) { QAction* mergeAction = new QAction(QIcon(":/Qmitk/MergeLabels.png"), "Merge selection on current label", this ); mergeAction->setEnabled(true); QObject::connect( mergeAction, SIGNAL( triggered(bool) ), this, SLOT( OnMergeLabels(bool) ) ); menu->addAction(mergeAction); QAction* removeLabelsAction = new QAction(QIcon(":/Qmitk/RemoveLabel.png"), "Remove selected labels", this ); removeLabelsAction->setEnabled(true); QObject::connect( removeLabelsAction, SIGNAL( triggered(bool) ), this, SLOT( OnRemoveLabels(bool) ) ); menu->addAction(removeLabelsAction); QAction* eraseLabelsAction = new QAction(QIcon(":/Qmitk/EraseLabel.png"), "Erase selected labels", this ); eraseLabelsAction->setEnabled(true); QObject::connect( eraseLabelsAction, SIGNAL( triggered(bool) ), this, SLOT( OnEraseLabels(bool) ) ); menu->addAction(eraseLabelsAction); QAction* combineAndCreateSurfaceAction = new QAction(QIcon(":/Qmitk/CreateSurface.png"), "Combine and create a surface", this ); combineAndCreateSurfaceAction->setEnabled(true); QObject::connect( combineAndCreateSurfaceAction, SIGNAL( triggered(bool) ), this, SLOT( OnCombineAndCreateSurface(bool) ) ); menu->addAction(combineAndCreateSurfaceAction); QAction* createMasksAction = new QAction(QIcon(":/Qmitk/CreateMask.png"), "Create a mask for each selected label", this ); createMasksAction->setEnabled(true); QObject::connect( createMasksAction, SIGNAL( triggered(bool) ), this, SLOT( OnCreateMasks(bool) ) ); menu->addAction(createMasksAction); QAction* combineAndCreateMaskAction = new QAction(QIcon(":/Qmitk/CreateMask.png"), "Combine and create a mask", this ); combineAndCreateMaskAction->setEnabled(true); QObject::connect( combineAndCreateMaskAction, SIGNAL( triggered(bool) ), this, SLOT( OnCombineAndCreateMask(bool) ) ); menu->addAction(combineAndCreateMaskAction); } else { QAction* renameAction = new QAction(QIcon(":/Qmitk/RenameLabel.png"), "Rename...", this ); renameAction->setEnabled(true); QObject::connect( renameAction, SIGNAL( triggered(bool) ), this, SLOT( OnRenameLabel(bool) ) ); menu->addAction(renameAction); QAction* removeAction = new QAction(QIcon(":/Qmitk/RemoveLabel.png"), "Remove...", this ); removeAction->setEnabled(true); QObject::connect( removeAction, SIGNAL( triggered(bool) ), this, SLOT( OnRemoveLabel(bool) ) ); menu->addAction(removeAction); QAction* eraseAction = new QAction(QIcon(":/Qmitk/EraseLabel.png"), "Erase...", this ); eraseAction->setEnabled(true); QObject::connect( eraseAction, SIGNAL( triggered(bool) ), this, SLOT( OnEraseLabel(bool) ) ); menu->addAction(eraseAction); QAction* mergeAction = new QAction(QIcon(":/Qmitk/MergeLabels.png"), "Merge...", this ); mergeAction->setEnabled(true); QObject::connect( mergeAction, SIGNAL( triggered(bool) ), this, SLOT( OnMergeLabel(bool) ) ); menu->addAction(mergeAction); QAction* randomColorAction = new QAction(QIcon(":/Qmitk/RandomColor.png"), "Random color", this ); randomColorAction->setEnabled(true); QObject::connect( randomColorAction, SIGNAL( triggered(bool) ), this, SLOT( OnRandomColor(bool) ) ); menu->addAction(randomColorAction); QAction* viewOnlyAction = new QAction(QIcon(":/Qmitk/visible.png"), "View only", this ); viewOnlyAction->setEnabled(true); QObject::connect( viewOnlyAction, SIGNAL( triggered(bool) ), this, SLOT( OnSetOnlyActiveLabelVisible(bool) ) ); menu->addAction(viewOnlyAction); QAction* viewAllAction = new QAction(QIcon(":/Qmitk/visible.png"), "View all", this ); viewAllAction->setEnabled(true); QObject::connect( viewAllAction, SIGNAL( triggered(bool) ), this, SLOT( OnSetAllLabelsVisible(bool) ) ); menu->addAction(viewAllAction); QAction* hideAllAction = new QAction(QIcon(":/Qmitk/invisible.png"), "Hide all", this ); hideAllAction->setEnabled(true); QObject::connect( hideAllAction, SIGNAL( triggered(bool) ), this, SLOT( OnSetAllLabelsInvisible(bool) ) ); menu->addAction(hideAllAction); QAction* lockAllAction = new QAction(QIcon(":/Qmitk/lock.png"), "Lock all", this ); lockAllAction->setEnabled(true); QObject::connect( lockAllAction, SIGNAL( triggered(bool) ), this, SLOT( OnLockAllLabels(bool) ) ); menu->addAction(lockAllAction); QAction* unlockAllAction = new QAction(QIcon(":/Qmitk/unlock.png"), "Unlock all", this ); unlockAllAction->setEnabled(true); QObject::connect( unlockAllAction, SIGNAL( triggered(bool) ), this, SLOT( OnUnlockAllLabels(bool) ) ); menu->addAction(unlockAllAction); QAction* createSurfaceAction = new QAction(QIcon(":/Qmitk/CreateSurface.png"), "Create surface", this ); createSurfaceAction->setEnabled(true); createSurfaceAction->setMenu(new QMenu()); QAction* tmp1 = createSurfaceAction->menu()->addAction(QString("Detailed")); QAction* tmp2 = createSurfaceAction->menu()->addAction(QString("Smoothed")); QObject::connect( tmp1, SIGNAL( triggered(bool) ), this, SLOT( OnCreateDetailedSurface(bool) ) ); QObject::connect( tmp2, SIGNAL( triggered(bool) ), this, SLOT( OnCreateSmoothedSurface(bool) ) ); menu->addAction(createSurfaceAction); QAction* createMaskAction = new QAction(QIcon(":/Qmitk/CreateMask.png"), "Create mask", this ); createMaskAction->setEnabled(true); QObject::connect( createMaskAction, SIGNAL( triggered(bool) ), this, SLOT( OnCreateMask(bool) ) ); menu->addAction(createMaskAction); QAction* createCroppedMaskAction = new QAction(QIcon(":/Qmitk/CreateMask.png"), "Create cropped mask", this ); createCroppedMaskAction->setEnabled(true); QObject::connect( createCroppedMaskAction, SIGNAL( triggered(bool) ), this, SLOT( OnCreateCroppedMask(bool) ) ); // QAction* importAction = new QAction(QIcon(":/Qmitk/RenameLabel.png"), "Import...", this ); // importAction->setEnabled(true); // QObject::connect( importAction, SIGNAL( triggered(bool) ), this, SLOT( OnImportSegmentationSession(bool) ) ); // menu->addAction(importAction); menu->addAction(createCroppedMaskAction); QSlider * opacitySlider = new QSlider; opacitySlider->setMinimum(0); opacitySlider->setMaximum(100); opacitySlider->setOrientation(Qt::Horizontal); QObject::connect( opacitySlider, SIGNAL( valueChanged(int) ), this, SLOT( OnOpacityChanged(int) ) ); QLabel* _OpacityLabel = new QLabel("Opacity: "); QVBoxLayout* _OpacityWidgetLayout = new QVBoxLayout; _OpacityWidgetLayout->setContentsMargins(4,4,4,4); _OpacityWidgetLayout->addWidget(_OpacityLabel); _OpacityWidgetLayout->addWidget(opacitySlider); QWidget* _OpacityWidget = new QWidget; _OpacityWidget->setLayout(_OpacityWidgetLayout); QWidgetAction * OpacityAction = new QWidgetAction(this); OpacityAction->setDefaultWidget(_OpacityWidget); // QObject::connect( m_OpacityAction, SIGNAL( changed() ), this, SLOT( OpacityActionChanged() ) ); opacitySlider->setValue(static_cast(GetWorkingImage()->GetLabel(pixelValue)->GetOpacity()*100)); menu->addAction(OpacityAction); } menu->popup(QCursor::pos()); } void QmitkLabelSetWidget::OnUnlockAllLabels(bool /*value*/) { GetWorkingImage()->GetLabelSet()->SetAllLabelsLocked(false); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnLockAllLabels(bool /*value*/) { GetWorkingImage()->GetLabelSet()->SetAllLabelsLocked(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnSetAllLabelsVisible(bool /*value*/) { GetWorkingImage()->GetLabelSet()->SetAllLabelsVisible(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::OnSetAllLabelsInvisible(bool /*value*/) { GetWorkingImage()->GetLabelSet()->SetAllLabelsVisible(false); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::OnSetOnlyActiveLabelVisible(bool /*value*/) { mitk::LabelSetImage * workingImage = GetWorkingImage(); int pixelValue = GetPixelValueOfSelectedItem(); workingImage->GetActiveLabelSet()->SetAllLabelsVisible(false); workingImage->GetLabel(pixelValue)->SetVisible(true); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); this->WaitCursorOn(); const mitk::Point3D& pos = workingImage->GetLabel(pixelValue)->GetCenterOfMassCoordinates(); this->WaitCursorOff(); if (pos.GetVnlVector().max_value() > 0.0) emit goToLabel(pos); UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::OnMergeLabel(bool /*value*/) { QmitkSearchLabelDialog dialog(this); dialog.setWindowTitle("Select a second label.."); dialog.SetLabelSuggestionList(GetLabelStringList()); int dialogReturnValue = dialog.exec(); if ( dialogReturnValue == QDialog::Rejected ) return; int pixelValue = -1; for(int i = 0 ; i < m_Controls.m_LabelSetTableWidget->columnCount();i++) { if( dialog.GetLabelSetWidgetTableCompleteWord() == QString( m_Controls.m_LabelSetTableWidget->item( i ,0)->text() ) ) pixelValue = m_Controls.m_LabelSetTableWidget->item(i ,0)->data(Qt::UserRole).toInt(); } if(pixelValue == -1 ) { MITK_INFO << "unknown label";; return; } GetWorkingImage()->MergeLabel(pixelValue); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnEraseLabel(bool /*value*/) { int pixelValue = GetPixelValueOfSelectedItem(); QString question = "Do you really want to erase the contents of label \""; question.append(QString::fromStdString(GetWorkingImage()->GetLabel(pixelValue)->GetName())); question.append("\"?"); QMessageBox::StandardButton answerButton = QMessageBox::question( this, "Erase label", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { this->WaitCursorOn(); GetWorkingImage()->EraseLabel(pixelValue); this->WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkLabelSetWidget::OnRemoveLabel(bool /*value*/) { int pixelValue = GetPixelValueOfSelectedItem(); QString question = "Do you really want to remove label \""; question.append(QString::fromStdString(GetWorkingImage()->GetLabel(pixelValue)->GetName())); question.append("\"?"); QMessageBox::StandardButton answerButton = QMessageBox::question( this, "Remove label", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { this->WaitCursorOn(); GetWorkingImage()->GetActiveLabelSet()->RemoveLabel(pixelValue); GetWorkingImage()->EraseLabel(pixelValue); this->WaitCursorOff(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnRenameLabel(bool /*value*/) { - QmitkNewSegmentationDialog dialog(this); dialog.setWindowTitle("Rename Label"); dialog.SetSuggestionList( m_OrganColors ); - dialog.SetColor(GetWorkingImage()->GetActiveLabel()->GetColor()); - dialog.SetSegmentationName(GetWorkingImage()->GetActiveLabel()->GetName()); + //MLI TODO + //dialog.SetColor(GetWorkingImage()->GetActiveLabel()->GetColor()); + //dialog.SetSegmentationName(GetWorkingImage()->GetActiveLabel()->GetName()); if ( dialog.exec() == QDialog::Rejected ) return; int pixelValue = GetWorkingImage()->GetActiveLabel()->GetValue(); GetWorkingImage()->GetLabel(pixelValue)->SetColor(dialog.GetColor()); GetWorkingImage()->GetLabel(pixelValue)->SetName(dialog.GetSegmentationName().toStdString()); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); } void QmitkLabelSetWidget::OnCombineAndCreateMask( bool /*value*/ ) { m_Controls.m_LabelSetTableWidget->selectedRanges(); // ...to do... // } void QmitkLabelSetWidget::OnCreateMasks(bool /*value*/) { m_Controls.m_LabelSetTableWidget->selectedRanges(); // ..to do.. // } void QmitkLabelSetWidget::OnCombineAndCreateSurface(bool /*value*/) { m_Controls.m_LabelSetTableWidget->selectedRanges(); // ..to do.. // } void QmitkLabelSetWidget::OnEraseLabels(bool /*value*/) { QString question = "Do you really want to erase the selected labels?"; QMessageBox::StandardButton answerButton = QMessageBox::question( this, "Erase selected labels", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { QList ranges = m_Controls.m_LabelSetTableWidget->selectedRanges(); if ( ranges.isEmpty() ) return; std::vector VectorOfLablePixelValues; foreach (QTableWidgetSelectionRange a, ranges) for(int i = a.topRow(); i <= a.bottomRow(); i++) VectorOfLablePixelValues.push_back(m_Controls.m_LabelSetTableWidget->item(i,0)->data(Qt::UserRole).toInt()); this->WaitCursorOn(); - GetWorkingImage()->EraseLabels(VectorOfLablePixelValues); + //MLI TODO + //GetWorkingImage()->EraseLabels(VectorOfLablePixelValues); this->WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkLabelSetWidget::OnRemoveLabels(bool /*value*/) { QString question = "Do you really want to remove selected labels?"; QMessageBox::StandardButton answerButton = QMessageBox::question( this, "Remove selected labels", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { QList ranges = m_Controls.m_LabelSetTableWidget->selectedRanges(); if ( ranges.isEmpty() ) return; std::vector VectorOfLablePixelValues; foreach (QTableWidgetSelectionRange a, ranges) for(int i = a.topRow(); i <= a.bottomRow(); i++) VectorOfLablePixelValues.push_back(m_Controls.m_LabelSetTableWidget->item(i,0)->data(Qt::UserRole).toInt()); this->WaitCursorOn(); - GetWorkingImage()->RemoveLabels(VectorOfLablePixelValues); + //MLI TODO + //GetWorkingImage()->RemoveLabels(VectorOfLablePixelValues); this->WaitCursorOff(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnMergeLabels(bool /*value*/) { int pixelValue = GetPixelValueOfSelectedItem(); QString question = "Do you really want to merge selected labels into \""; question.append(QString::fromStdString(GetWorkingImage()->GetLabel(pixelValue)->GetName())); question.append("\"?"); QMessageBox::StandardButton answerButton = QMessageBox::question( this, "Merge selected label", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { QList ranges = m_Controls.m_LabelSetTableWidget->selectedRanges(); if ( ranges.isEmpty() ) return; std::vector VectorOfLablePixelValues; foreach (QTableWidgetSelectionRange a, ranges) for(int i = a.topRow(); i <= a.bottomRow(); i++) VectorOfLablePixelValues.push_back(m_Controls.m_LabelSetTableWidget->item(i,0)->data(Qt::UserRole).toInt()); this->WaitCursorOn(); int pixelValue = m_Controls.m_LabelSetTableWidget->item(m_Controls.m_LabelSetTableWidget->currentRow(),0)->data(Qt::UserRole).toInt(); - GetWorkingImage()->MergeLabels(VectorOfLablePixelValues,pixelValue); + //MLI TODO + //GetWorkingImage()->MergeLabels(VectorOfLablePixelValues,pixelValue); this->WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkLabelSetWidget::OnLockedButtonClicked() { int row; for(int i=0; irowCount(); i++) { if (sender() == m_Controls.m_LabelSetTableWidget->cellWidget(i,LOCKED_COL)) { row = i; } } if (row >= 0 && row < m_Controls.m_LabelSetTableWidget->rowCount()) { int pixelValue = m_Controls.m_LabelSetTableWidget->item(row,0)->data(Qt::UserRole).toInt(); GetWorkingImage()->GetLabel(pixelValue)->SetLocked(!GetWorkingImage()->GetLabel(pixelValue)->GetLocked() ); } } void QmitkLabelSetWidget::OnVisibleButtonClicked() { int row; for(int i=0; irowCount(); i++) { if (sender() == m_Controls.m_LabelSetTableWidget->cellWidget(i,VISIBLE_COL)) { row = i; break; } } if (row >= 0 && row < m_Controls.m_LabelSetTableWidget->rowCount()) { QTableWidgetItem * item = m_Controls.m_LabelSetTableWidget->item(row,0); OnItemClicked(item); int pixelValue = item->data(Qt::UserRole).toInt(); GetWorkingImage()->GetLabel(pixelValue)->SetVisible(!GetWorkingImage()->GetLabel(pixelValue)->GetVisible() ); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkLabelSetWidget::OnColorButtonClicked() { int row; for(int i=0; irowCount(); i++) { if (sender() == m_Controls.m_LabelSetTableWidget->cellWidget(i,COLOR_COL)) { row = i; } } if (row >= 0 && row < m_Controls.m_LabelSetTableWidget->rowCount()) { int pixelValue = m_Controls.m_LabelSetTableWidget->item(row,0)->data(Qt::UserRole).toInt(); const mitk::Color& color = GetWorkingImage()->GetLabel(pixelValue)->GetColor(); QColor initial(color.GetRed()*255,color.GetGreen()*255,color.GetBlue()*255); QColor qcolor = QColorDialog::getColor(initial,0,QString("Change color")); if (!qcolor.isValid()) return; QPushButton* button = (QPushButton*) m_Controls.m_LabelSetTableWidget->cellWidget(row,COLOR_COL); if (!button) return; button->setAutoFillBackground(true); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(qcolor.red())); styleSheet.append(","); styleSheet.append(QString::number(qcolor.green())); styleSheet.append(","); styleSheet.append(QString::number(qcolor.blue())); styleSheet.append(")"); button->setStyleSheet(styleSheet); mitk::Color newColor; newColor.SetRed(qcolor.red()/255.0); newColor.SetGreen(qcolor.green()/255.0); newColor.SetBlue(qcolor.blue()/255.0); GetWorkingImage()->GetLabel(pixelValue)->SetColor(newColor); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); } } void QmitkLabelSetWidget::OnRandomColor(bool /*value*/) { int pixelValue = GetPixelValueOfSelectedItem(); GetWorkingImage()->GetLabel(pixelValue)->SetColor(m_ColorSequenceRainbow.GetNextColor() ); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); } void QmitkLabelSetWidget::SetOrganColors(const QStringList& organColors) { m_OrganColors = organColors; } void QmitkLabelSetWidget::OnActiveLabelChanged(int pixelValue) { mitk::LabelSetImage* workingImage = GetWorkingImage(); assert(workingImage); workingImage->GetActiveLabelSet()->SetActiveLabel(pixelValue); //MITK_INFO << "Active Label set to << " << pixelValue; mitk::SurfaceBasedInterpolationController* interpolator = mitk::SurfaceBasedInterpolationController::GetInstance(); if (interpolator) interpolator->SetActiveLabel(pixelValue); } void QmitkLabelSetWidget::OnItemClicked(QTableWidgetItem *item) { if (!item) return; int pixelValue = item->data(Qt::UserRole).toInt(); QList ranges = m_Controls.m_LabelSetTableWidget->selectedRanges(); if(!ranges.empty() && ranges.back().rowCount() == 1) { SelectLabelByPixelValue(pixelValue); OnActiveLabelChanged(pixelValue); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } - } void QmitkLabelSetWidget::OnItemDoubleClicked(QTableWidgetItem *item) { if (!item) return; int pixelValue = item->data(Qt::UserRole).toInt(); //OnItemClicked(item); <<-- Double click first call OnItemClicked WaitCursorOn(); mitk::LabelSetImage * workingImage = GetWorkingImage(); workingImage->UpdateCenterOfMass(pixelValue); const mitk::Point3D& pos = workingImage->GetLabel(pixelValue)->GetCenterOfMassCoordinates(); WaitCursorOff(); if (pos.GetVnlVector().max_value() > 0.0) emit goToLabel(pos); } -void QmitkLabelSetWidget::SelectLabelByPixelValue(int pixelValue) +void QmitkLabelSetWidget::SelectLabelByPixelValue(mitk::Label::PixelType pixelValue) { - //MITK_INFO << "QmitkLabelSetWidget::SelectLabelByPixelValue " << pixelValue; if(!GetWorkingImage()->ExistLabel(pixelValue)) return; for(int row = 0 ; row < m_Controls.m_LabelSetTableWidget->rowCount(); row++) { if(m_Controls.m_LabelSetTableWidget->item(row,0)->data(Qt::UserRole).toInt() == pixelValue) { m_Controls.m_LabelSetTableWidget->clearSelection(); m_Controls.m_LabelSetTableWidget->setSelectionMode(QAbstractItemView::SingleSelection); m_Controls.m_LabelSetTableWidget->selectRow(row); m_Controls.m_LabelSetTableWidget->scrollToItem(m_Controls.m_LabelSetTableWidget->item(row,0)); m_Controls.m_LabelSetTableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); //SelectTableWidgetItem(m_Controls.m_LabelSetTableWidget->item(i,0)); //emit resetView(); //GetWorkingImage()->Modified(); return; } } } void QmitkLabelSetWidget::InsertTableWidgetItem(mitk::Label * label) { const mitk::Color& color = label->GetColor(); QTableWidget * tableWidget = m_Controls.m_LabelSetTableWidget; QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(color[0]*255)); styleSheet.append(","); styleSheet.append(QString::number(color[1]*255)); styleSheet.append(","); styleSheet.append(QString::number(color[2]*255)); styleSheet.append(")"); int colWidth = (tableWidget->columnWidth(NAME_COL) < 180) ? 180 : tableWidget->columnWidth(NAME_COL)-2; QString text = fontMetrics().elidedText(label->GetName().c_str(), Qt::ElideMiddle, colWidth); QTableWidgetItem *nameItem = new QTableWidgetItem(text); nameItem->setTextAlignment(Qt::AlignCenter | Qt::AlignLeft); // ---!--- // IMPORTANT: ADD PIXELVALUE TO TABLEWIDGETITEM.DATA nameItem->setData(Qt::UserRole,QVariant(label->GetValue())); // ---!--- QPushButton * pbColor = new QPushButton(tableWidget); pbColor->setFixedSize(24,24); pbColor->setCheckable(false); pbColor->setAutoFillBackground(true); pbColor->setToolTip("Change label color"); pbColor->setStyleSheet(styleSheet); connect( pbColor, SIGNAL(clicked()), this, SLOT(OnColorButtonClicked()) ); QPushButton * pbLocked = new QPushButton(tableWidget); pbLocked->setFixedSize(24,24); QIcon * iconLocked = new QIcon(); iconLocked->addFile(QString::fromUtf8(":/Qmitk/lock.png"), QSize(), QIcon::Normal, QIcon::Off); iconLocked->addFile(QString::fromUtf8(":/Qmitk/unlock.png"), QSize(), QIcon::Normal, QIcon::On); pbLocked->setIcon(*iconLocked); pbLocked->setIconSize(QSize(24,24)); pbLocked->setCheckable(true); pbLocked->setToolTip("Lock/unlock label"); pbLocked->setChecked(!label->GetLocked()); connect( pbLocked, SIGNAL(clicked()), this, SLOT(OnLockedButtonClicked()) ); QPushButton * pbVisible = new QPushButton(tableWidget); pbVisible->setFixedSize(24,24); pbVisible->setAutoRepeat(false); QIcon * iconVisible = new QIcon(); iconVisible->addFile(QString::fromUtf8(":/Qmitk/visible.png"), QSize(), QIcon::Normal, QIcon::Off); iconVisible->addFile(QString::fromUtf8(":/Qmitk/invisible.png"), QSize(), QIcon::Normal, QIcon::On); pbVisible->setIcon(*iconVisible); pbVisible->setIconSize(QSize(24,24)); pbVisible->setCheckable(true); pbVisible->setToolTip("Show/hide label"); pbVisible->setChecked(!label->GetVisible()); connect( pbVisible, SIGNAL(clicked()), this, SLOT(OnVisibleButtonClicked()) ); int row = tableWidget->rowCount(); tableWidget->insertRow(row); tableWidget->setRowHeight(row,24); tableWidget->setItem(row, 0, nameItem ); tableWidget->setCellWidget(row, 1, pbLocked); tableWidget->setCellWidget(row, 2, pbColor); tableWidget->setCellWidget(row, 3, pbVisible); tableWidget->selectRow(row); //m_LabelSetImage->SetActiveLabel(label->GetPixelValue()); //m_ToolManager->WorkingDataModified.Send(); //emit activeLabelChanged(label->GetPixelValue()); if (row == 0) tableWidget->hideRow(row); // hide exterior label mitk::LabelSetImage * workingImage; if((workingImage = GetWorkingImage()) == NULL) return; - } void QmitkLabelSetWidget::UpdateAllTableWidgetItems() { QTableWidget * tableWidget = m_Controls.m_LabelSetTableWidget; mitk::LabelSetImage * workingImage = GetWorkingImage(); if(!workingImage) return; // add all labels m_LabelStringList.clear(); for(int i = 0 ; i < tableWidget->rowCount(); i++) { UpdateTableWidgetItem(tableWidget->item(i,0)); m_LabelStringList.append( tableWidget->item(i,0)->text() ); } OnLabelListModified(m_LabelStringList); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::UpdateTableWidgetItem(QTableWidgetItem *item) { mitk::LabelSetImage * workingImage = GetWorkingImage(); mitk::Label * label = workingImage->GetLabel(item->data(Qt::UserRole).toInt()); const mitk::Color& color = label->GetColor(); QTableWidget * tableWidget = m_Controls.m_LabelSetTableWidget; QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(color[0]*255)); styleSheet.append(","); styleSheet.append(QString::number(color[1]*255)); styleSheet.append(","); styleSheet.append(QString::number(color[2]*255)); styleSheet.append(")"); // Update text Label tableWdget->item(row,0) int colWidth = (tableWidget->columnWidth(NAME_COL) < 180) ? 180 : tableWidget->columnWidth(NAME_COL)-2; QString text = fontMetrics().elidedText(label->GetName().c_str(), Qt::ElideMiddle, colWidth); item->setText(text); QPushButton * pbLocked = dynamic_cast(tableWidget->cellWidget(item->row(),1)); pbLocked->setChecked(!label->GetLocked()); QPushButton * pbColor = dynamic_cast(tableWidget->cellWidget(item->row(),2)); pbColor->setStyleSheet(styleSheet); QPushButton * pbVisible = dynamic_cast(tableWidget->cellWidget(item->row(),3)); pbVisible->setChecked(!label->GetVisible()); if (item->row() == 0)tableWidget->hideRow(item->row()); // hide exterior label } void QmitkLabelSetWidget::ResetAllTableWidgetItems() { QTableWidget * tableWidget = m_Controls.m_LabelSetTableWidget; // remove all rows while (tableWidget->rowCount()) tableWidget->removeRow( 0 ); mitk::LabelSetImage * workingImage = GetWorkingImage(); if(!workingImage) return; // add all labels m_LabelStringList.clear(); mitk::LabelSet::LabelContainerConstIteratorType it = workingImage->GetActiveLabelSet()->IteratorConstBegin(); mitk::LabelSet::LabelContainerConstIteratorType end = workingImage->GetActiveLabelSet()->IteratorConstEnd(); int pixelValue =-1; while (it != end) { InsertTableWidgetItem(it->second); if(GetWorkingImage()->GetActiveLabel() == it->second) // get active pixelValue = it->first; m_LabelStringList.append( QString(it->second->GetName().c_str()) ); it++; } SelectLabelByPixelValue(pixelValue); OnLabelListModified(m_LabelStringList); std::stringstream captionText; captionText << "Number of labels: " << workingImage->GetNumberOfLabels() - 1; m_Controls.m_lblCaption->setText(captionText.str().c_str()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } int QmitkLabelSetWidget::GetPixelValueOfSelectedItem() { if(m_Controls.m_LabelSetTableWidget->currentItem()) return m_Controls.m_LabelSetTableWidget->currentItem()->data(Qt::UserRole).toInt(); return -1; } QStringList & QmitkLabelSetWidget::GetLabelStringList() { return m_LabelStringList; } void QmitkLabelSetWidget::InitializeTableWidget() { QTableWidget * tableWidged = m_Controls.m_LabelSetTableWidget; tableWidged->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); tableWidged->setTabKeyNavigation(false); tableWidged->setAlternatingRowColors(false); tableWidged->setFocusPolicy(Qt::NoFocus); tableWidged->setColumnCount(4); tableWidged->resizeColumnToContents(NAME_COL); tableWidged->setColumnWidth(LOCKED_COL,25); tableWidged->setColumnWidth(COLOR_COL,25); tableWidged->setColumnWidth(VISIBLE_COL,25); tableWidged->horizontalHeader()->setResizeMode( 0, QHeaderView::Stretch ); tableWidged->setContextMenuPolicy(Qt::CustomContextMenu); tableWidged->horizontalHeader()->hide(); tableWidged->setSortingEnabled ( false ); tableWidged->verticalHeader()->hide(); tableWidged->setEditTriggers(QAbstractItemView::NoEditTriggers); tableWidged->setSelectionMode(QAbstractItemView::ExtendedSelection); tableWidged->setSelectionBehavior(QAbstractItemView::SelectRows); connect(tableWidged, SIGNAL(itemClicked(QTableWidgetItem *)), this, SLOT(OnItemClicked(QTableWidgetItem *))); connect(tableWidged, SIGNAL(itemDoubleClicked(QTableWidgetItem *)), this, SLOT(OnItemDoubleClicked(QTableWidgetItem *))); connect(tableWidged, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OnTableViewContextMenuRequested(const QPoint&)) ); //connect( m_Controls.m_LabelSetTableWidget, SIGNAL(activeLabelChanged(int)), this, SLOT(OnActiveLabelChanged(int)) ); //connect( m_Controls.m_LabelSetTableWidget, SIGNAL(importSegmentation()), this, SLOT( OnImportSegmentation()) ); //connect( m_Controls.m_LabelSetTableWidget, SIGNAL(importLabeledImage()), this, SLOT( OnImportLabeledImage()) ); //connect( m_Controls.m_LabelSetTableWidget, SIGNAL(renameLabel(int, const mitk::Color&, const std::string&)), this, SLOT(OnRenameLabel(int, const mitk::Color&, const std::string&)) ); //connect( m_Controls.m_LabelSetTableWidget, SIGNAL(createSurface(int, bool)), this, SLOT(OnCreateSurface(int, bool)) ); //connect( m_Controls.m_LabelSetTableWidget, SIGNAL(toggleOutline(bool)), this, SLOT(OnToggleOutline(bool)) ); //connect( m_Controls.m_LabelSetTableWidget, SIGNAL(goToLabel(const mitk::Point3D&)), this, SIGNAL(goToLabel(const mitk::Point3D&)) ); //connect( m_Controls.m_LabelSetTableWidget, SIGNAL(combineAndCreateSurface( const QList& )), // this, SLOT(OnCombineAndCreateSurface( const QList&)) ); //connect( m_Controls.m_LabelSetTableWidget, SIGNAL(createMask(int)), this, SLOT(OnCreateMask(int)) ); //connect( m_Controls.m_LabelSetTableWidget, SIGNAL(createCroppedMask(int)), this, SLOT(OnCreateCroppedMask(int)) ); //connect( m_Controls.m_LabelSetTableWidget, SIGNAL(combineAndCreateMask( const QList& )), // this, SLOT(OnCombineAndCreateMask( const QList&)) ); } void QmitkLabelSetWidget::OnOpacityChanged(int value) { int pixelValue = m_Controls.m_LabelSetTableWidget->currentItem()->data(Qt::UserRole).toInt(); float opacity = static_cast(value)/100.0f; GetWorkingImage()->GetLabel(pixelValue)->SetOpacity(opacity); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); } void QmitkLabelSetWidget::setEnabled(bool enabled) { QWidget::setEnabled(enabled); UpdateControls(); } void QmitkLabelSetWidget::SetDataStorage( mitk::DataStorage* storage ) { m_DataStorage = storage; } void QmitkLabelSetWidget::OnSearchLabel() { std::string text = m_Controls.m_LabelSearchBox->text().toStdString(); int pixelValue = -1; int row = -1; for(int i = 0; i < m_Controls.m_LabelSetTableWidget->rowCount(); i++){ if( m_Controls.m_LabelSetTableWidget->item(i,0)->text().toStdString().compare(text) == 0) { pixelValue = m_Controls.m_LabelSetTableWidget->item(i,0)->data(Qt::UserRole).toInt(); row = i; break; } } if(pixelValue == -1) return; GetWorkingImage()->GetActiveLabelSet()->SetActiveLabel(pixelValue); QTableWidgetItem* nameItem = m_Controls.m_LabelSetTableWidget->item(row,NAME_COL); if (!nameItem) return; m_Controls.m_LabelSetTableWidget->clearSelection(); m_Controls.m_LabelSetTableWidget->setSelectionMode(QAbstractItemView::SingleSelection); m_Controls.m_LabelSetTableWidget->selectRow(row); m_Controls.m_LabelSetTableWidget->scrollToItem(nameItem); m_Controls.m_LabelSetTableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); this->WaitCursorOn(); mitk::Point3D pos = GetWorkingImage()->GetLabel(pixelValue)->GetCenterOfMassCoordinates(); - m_ToolManager->WorkingDataModified.Send(); + //MLI TODO + //m_ToolManager->WorkingDataModified.Send(); if (pos.GetVnlVector().max_value() > 0.0) emit goToLabel(pos); else { GetWorkingImage()->UpdateCenterOfMass(pixelValue); mitk::Point3D pos = GetWorkingImage()->GetLabel(pixelValue)->GetCenterOfMassCoordinates(); emit goToLabel(pos); } this->WaitCursorOff(); } void QmitkLabelSetWidget::OnLabelListModified(const QStringList& list) { QStringListModel* completeModel = static_cast (m_Completer->model()); completeModel->setStringList(list); } mitk::LabelSetImage * QmitkLabelSetWidget::GetWorkingImage() { mitk::DataNode* workingNode = GetWorkingNode(); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); return workingImage; } mitk::DataNode * QmitkLabelSetWidget::GetWorkingNode() { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); return workingNode; } void QmitkLabelSetWidget::UpdateControls() { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); bool hasWorkingData = (workingNode != NULL); m_Controls.m_LabelSetTableWidget->setEnabled(hasWorkingData); m_Controls.m_LabelSearchBox->setEnabled(hasWorkingData); if (!hasWorkingData) return; QStringListModel* completeModel = static_cast (m_Completer->model()); completeModel->setStringList(GetLabelStringList()); - } void QmitkLabelSetWidget::OnCreateCroppedMask(bool) { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = GetWorkingNode(); mitk::LabelSetImage* workingImage = GetWorkingImage(); mitk::Image::Pointer maskImage; int pixelValue = GetPixelValueOfSelectedItem(); try { this->WaitCursorOn(); mitk::AutoCropImageFilter::Pointer cropFilter = mitk::AutoCropImageFilter::New(); cropFilter->SetInput( workingImage->CreateLabelMask(pixelValue) ); cropFilter->SetBackgroundValue( 0 ); cropFilter->SetMarginFactor(1.15); cropFilter->Update(); maskImage = cropFilter->GetOutput(); this->WaitCursorOff(); } catch ( mitk::Exception& e ) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Create Mask", "Could not create a mask out of the selected label.\n"); return; } if (maskImage.IsNull()) { QMessageBox::information(this, "Create Mask", "Could not create a mask out of the selected label.\n"); return; } mitk::DataNode::Pointer maskNode = mitk::DataNode::New(); std::string name = workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->GetName(); name += "-mask"; maskNode->SetName(name); maskNode->SetData(maskImage); maskNode->SetBoolProperty("binary", true); maskNode->SetBoolProperty("outline binary", true); maskNode->SetBoolProperty("outline binary shadow", true); maskNode->SetFloatProperty("outline width", 2.0); maskNode->SetColor(workingImage->GetLabel(pixelValue)->GetColor()); maskNode->SetOpacity(1.0); m_DataStorage->Add(maskNode, workingNode); } void QmitkLabelSetWidget::OnCreateMask(bool /*triggered*/) { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = GetWorkingNode(); mitk::LabelSetImage* workingImage = GetWorkingImage(); mitk::Image::Pointer maskImage; int pixelValue = GetPixelValueOfSelectedItem(); try { this->WaitCursorOn(); maskImage = workingImage->CreateLabelMask(pixelValue); this->WaitCursorOff(); } catch ( mitk::Exception& e ) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Create Mask", "Could not create a mask out of the selected label.\n"); return; } if (maskImage.IsNull()) { QMessageBox::information(this, "Create Mask", "Could not create a mask out of the selected label.\n"); return; } mitk::DataNode::Pointer maskNode = mitk::DataNode::New(); std::string name = workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->GetName(); name += "-mask"; maskNode->SetName(name); maskNode->SetData(maskImage); maskNode->SetBoolProperty("binary", true); maskNode->SetBoolProperty("outline binary", true); maskNode->SetBoolProperty("outline binary shadow", true); maskNode->SetFloatProperty("outline width", 2.0); maskNode->SetColor(workingImage->GetLabel(pixelValue)->GetColor()); maskNode->SetOpacity(1.0); m_DataStorage->Add(maskNode, workingNode); } void QmitkLabelSetWidget::OnToggleOutline(bool value) { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); workingNode->SetBoolProperty( "labelset.contour.all", value); workingNode->GetData()->Modified(); // fixme: workaround to force data-type rendering (and not only property-type) mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnCreateSmoothedSurface(bool /*triggered*/) { m_ToolManager->ActivateTool(-1); mitk::DataNode::Pointer workingNode = GetWorkingNode(); mitk::LabelSetImage* workingImage = GetWorkingImage(); int pixelValue = GetPixelValueOfSelectedItem(); mitk::LabelSetImageToSurfaceThreadedFilter::Pointer surfaceFilter = mitk::LabelSetImageToSurfaceThreadedFilter::New(); itk::SimpleMemberCommand::Pointer successCommand = itk::SimpleMemberCommand::New(); successCommand->SetCallbackFunction(this, &QmitkLabelSetWidget::OnThreadedCalculationDone); surfaceFilter->AddObserver(mitk::ResultAvailable(), successCommand); itk::SimpleMemberCommand::Pointer errorCommand = itk::SimpleMemberCommand::New(); errorCommand->SetCallbackFunction(this, &QmitkLabelSetWidget::OnThreadedCalculationDone); surfaceFilter->AddObserver(mitk::ProcessingError(), errorCommand); mitk::DataNode::Pointer groupNode = workingNode; surfaceFilter->SetPointerParameter("Group node", groupNode); surfaceFilter->SetPointerParameter("Input", workingImage); surfaceFilter->SetParameter("RequestedLabel", pixelValue); surfaceFilter->SetParameter("Smooth", true); surfaceFilter->SetDataStorage( *m_DataStorage ); mitk::StatusBar::GetInstance()->DisplayText("Surface creation is running in background..."); try { surfaceFilter->StartAlgorithm(); } catch ( mitk::Exception & e ) { MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Create Surface", "Could not create a surface mesh out of the selected label. See error log for details.\n"); } - } void QmitkLabelSetWidget::OnCreateDetailedSurface(bool /*triggered*/) { m_ToolManager->ActivateTool(-1); mitk::DataNode::Pointer workingNode = GetWorkingNode(); mitk::LabelSetImage* workingImage = GetWorkingImage(); int pixelValue = GetPixelValueOfSelectedItem(); mitk::LabelSetImageToSurfaceThreadedFilter::Pointer surfaceFilter = mitk::LabelSetImageToSurfaceThreadedFilter::New(); itk::SimpleMemberCommand::Pointer successCommand = itk::SimpleMemberCommand::New(); successCommand->SetCallbackFunction(this, &QmitkLabelSetWidget::OnThreadedCalculationDone); surfaceFilter->AddObserver(mitk::ResultAvailable(), successCommand); itk::SimpleMemberCommand::Pointer errorCommand = itk::SimpleMemberCommand::New(); errorCommand->SetCallbackFunction(this, &QmitkLabelSetWidget::OnThreadedCalculationDone); surfaceFilter->AddObserver(mitk::ProcessingError(), errorCommand); mitk::DataNode::Pointer groupNode = workingNode; surfaceFilter->SetPointerParameter("Group node", groupNode); surfaceFilter->SetPointerParameter("Input", workingImage); surfaceFilter->SetParameter("RequestedLabel", pixelValue); surfaceFilter->SetParameter("Smooth", false); surfaceFilter->SetDataStorage( *m_DataStorage ); mitk::StatusBar::GetInstance()->DisplayText("Surface creation is running in background..."); try { surfaceFilter->StartAlgorithm(); } catch ( mitk::Exception & e ) { MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Create Surface", "Could not create a surface mesh out of the selected label. See error log for details.\n"); } - } void QmitkLabelSetWidget::OnImportLabeledImage() { /* m_ToolManager->ActivateTool(-1); mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); assert(referenceNode); // Ask the user for a list of files to open QStringList fileNames = QFileDialog::getOpenFileNames( this, "Open Image", m_LastFileOpenPath, mitk::CoreObjectFactory::GetInstance()->GetFileExtensions()); if (fileNames.empty()) return; try { this->WaitCursorOn(); mitk::Image::Pointer image = mitk::IOUtil::LoadImage( fileNames.front().toStdString() ); if (image.IsNull()) { this->WaitCursorOff(); QMessageBox::information(this, "Import Labeled Image", "Could not load the selected segmentation.\n"); return; } mitk::LabelSetImage::Pointer newImage = mitk::LabelSetImage::New(); newImage->InitializeByLabeledImage(image); this->WaitCursorOff(); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); std::string newName = referenceNode->GetName(); newName += "-labels"; newNode->SetName(newName); newNode->SetData(newImage); m_DataStorage->Add(newNode, referenceNode); } catch (mitk::Exception & e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Import Labeled Image", "Could not load the selected segmentation. See error log for details.\n"); return; } this->UpdateControls(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); */ } void QmitkLabelSetWidget::OnImportSegmentation() { /* m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast( workingNode->GetData() ); assert(workingImage); std::string fileExtensions("Segmentation files (*.lset);;"); QString qfileName = QFileDialog::getOpenFileName(this, "Import Segmentation", m_LastFileOpenPath, fileExtensions.c_str() ); if (qfileName.isEmpty() ) return; mitk::NrrdLabelSetImageReader::Pointer reader = mitk::NrrdLabelSetImageReader::New(); reader->SetFileName(qfileName.toLatin1()); try { this->WaitCursorOn(); reader->Update(); mitk::LabelSetImage::Pointer newImage = reader->GetOutput(); workingImage->Concatenate(newImage); this->WaitCursorOff(); } catch ( mitk::Exception& e ) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Import Segmentation", "Could not import the selected segmentation session.\n See error log for details.\n"); } */ mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::WaitCursorOn() { QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); } void QmitkLabelSetWidget::WaitCursorOff() { this->RestoreOverrideCursor(); } void QmitkLabelSetWidget::RestoreOverrideCursor() { QApplication::restoreOverrideCursor(); } void QmitkLabelSetWidget::OnThreadedCalculationDone() { mitk::StatusBar::GetInstance()->Clear(); -} - +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkLabelSetWidget.h b/Modules/SegmentationUI/Qmitk/QmitkLabelSetWidget.h similarity index 97% rename from Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkLabelSetWidget.h rename to Modules/SegmentationUI/Qmitk/QmitkLabelSetWidget.h index 262a5ab860..13e97bfe9c 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkLabelSetWidget.h +++ b/Modules/SegmentationUI/Qmitk/QmitkLabelSetWidget.h @@ -1,158 +1,158 @@ /*=================================================================== 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 QmitkLabelSetWidget_h #define QmitkLabelSetWidget_h #include "MitkSegmentationUIExports.h" #include #include "mitkColorSequenceRainbow.h" -#include "mitkVector.h" +#include "mitkNumericTypes.h" +#include "mitkLabel.h" class QmitkDataStorageComboBox; class QCompleter; namespace mitk { class LabelSetImage; class LabelSet; class Label; class DataStorage; class ToolManager; class DataNode; } class MitkSegmentationUI_EXPORT QmitkLabelSetWidget : public QWidget { Q_OBJECT public: explicit QmitkLabelSetWidget(QWidget* parent = NULL); ~QmitkLabelSetWidget(); void SetDataStorage( mitk::DataStorage* storage ); void SetOrganColors(const QStringList& organColors); void UpdateControls(); virtual void setEnabled(bool enabled); QStringList &GetLabelStringList(); signals: /// \brief Send a signal when it was requested to go to a label. void goToLabel(const mitk::Point3D&); void resetView(); public slots: void ResetAllTableWidgetItems(); void UpdateAllTableWidgetItems(); - void SelectLabelByPixelValue(int pixelValue); + void SelectLabelByPixelValue(mitk::Label::PixelType pixelValue); private slots: // Label Set Dependend void OnOpacityChanged(int); void OnUnlockAllLabels(bool); void OnLockAllLabels(bool); void OnSetAllLabelsVisible(bool); void OnSetAllLabelsInvisible(bool); void OnSetOnlyActiveLabelVisible(bool); void OnRandomColor(bool); void OnRemoveLabel(bool); void OnRemoveLabels(bool); void OnRenameLabel(bool); void OnLockedButtonClicked(); void OnVisibleButtonClicked(); void OnColorButtonClicked(); void OnItemClicked(QTableWidgetItem *item); void OnItemDoubleClicked(QTableWidgetItem *item); void OnTableViewContextMenuRequested(const QPoint&); void InsertTableWidgetItem(mitk::Label * label); void UpdateTableWidgetItem(QTableWidgetItem *item); // reaction to "returnPressed" signal from ... void OnSearchLabel(); // reaction to the button "Change Label" void OnActiveLabelChanged(int pixelValue); //LabelSetImage Dependet void OnCreateDetailedSurface(bool); void OnCreateSmoothedSurface(bool); // reaction to the signal "createMask" from QmitkLabelSetTableWidget void OnCreateMask(bool); void OnCreateMasks(bool); // reaction to the signal "createCroppedMask" from QmitkLabelSetTableWidget void OnCreateCroppedMask(bool); void OnCombineAndCreateMask(bool); void OnCombineAndCreateSurface(bool); void OnEraseLabel(bool); void OnEraseLabels(bool); // reaction to signal "mergeLabel" from QmitkLabelSetTableWidget void OnMergeLabel(bool); void OnMergeLabels(bool); // reaction to the button "Import Segmentation" void OnImportSegmentation(); // reaction to the button "Import Labeled Image" void OnImportLabeledImage(); // reaction to signal "labelListModified" from QmitkLabelSetTableWidget void OnLabelListModified(const QStringList& list); // reaction to the signal "toggleOutline" from QmitkLabelSetTableWidget void OnToggleOutline(bool); private: enum TableColumns { NAME_COL=0, LOCKED_COL, COLOR_COL, VISIBLE_COL }; void WaitCursorOn(); void WaitCursorOff(); void RestoreOverrideCursor(); void OnThreadedCalculationDone(); void InitializeTableWidget(); int GetPixelValueOfSelectedItem(); mitk::LabelSetImage * GetWorkingImage(); mitk::DataNode * GetWorkingNode(); Ui::QmitkLabelSetWidgetControls m_Controls; mitk::ColorSequenceRainbow m_ColorSequenceRainbow; QCompleter* m_Completer; mitk::DataStorage* m_DataStorage; mitk::ToolManager* m_ToolManager; QStringList m_OrganColors; QStringList m_LabelStringList; - }; #endif diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkLabelSetWidgetControls.ui b/Modules/SegmentationUI/Qmitk/QmitkLabelSetWidgetControls.ui similarity index 100% rename from Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkLabelSetWidgetControls.ui rename to Modules/SegmentationUI/Qmitk/QmitkLabelSetWidgetControls.ui diff --git a/Modules/SegmentationUI/Qmitk/QmitkMaskStampWidget.cpp b/Modules/SegmentationUI/Qmitk/QmitkMaskStampWidget.cpp new file mode 100644 index 0000000000..76a37c3786 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkMaskStampWidget.cpp @@ -0,0 +1,121 @@ +/*=================================================================== + +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 "QmitkMaskStampWidget.h" + +#include +#include +#include + +#include + +QmitkMaskStampWidget::QmitkMaskStampWidget(QWidget* parent, const char* /*name*/) : +QWidget(parent), +m_ToolManager(NULL), +m_DataStorage(NULL) +{ + m_Controls.setupUi(this); + m_Controls.m_InformationWidget->hide(); + + m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); + assert(m_ToolManager); + m_ToolManager->ActivateTool(-1); + + mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); + mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); + mitk::NodePredicateAnd::Pointer isMask = mitk::NodePredicateAnd::New(isBinary, isImage); + + mitk::NodePredicateAnd::Pointer maskPredicate = mitk::NodePredicateAnd::New(); + maskPredicate->AddPredicate(isMask); + maskPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); + + m_Controls.m_cbMaskNodeSelector->SetPredicate( maskPredicate ); + + connect(m_Controls.m_pbStamp, SIGNAL(clicked()), this, SLOT(OnStamp())); + connect( m_Controls.m_cbShowInformation, SIGNAL(toggled(bool)), this, SLOT(OnShowInformation(bool)) ); + m_Controls.m_InformationWidget->hide(); +} + +QmitkMaskStampWidget::~QmitkMaskStampWidget() +{ +} + +void QmitkMaskStampWidget::SetDataStorage( mitk::DataStorage* storage ) +{ + m_DataStorage = storage; + m_Controls.m_cbMaskNodeSelector->SetDataStorage(m_DataStorage); +} + +void QmitkMaskStampWidget::OnStamp() +{ + mitk::DataNode* maskNode = m_Controls.m_cbMaskNodeSelector->GetSelectedNode(); + + if (!maskNode) + { + QMessageBox::information( this, "Mask Stamp", "Please load and select a mask before starting some action."); + return; + } + + mitk::Image* mask = dynamic_cast(maskNode->GetData() ); + if (!mask) + { + QMessageBox::information( this, "Mask Stamp", "Please load and select a mask before starting some action."); + return; + } + + mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + + if (!workingNode) + { + QMessageBox::information( this, "Mask Stamp", "Please load and select a segmentation before starting some action."); + return; + } + + mitk::LabelSetImage* workingImage = dynamic_cast( workingNode->GetData() ); + + if (!workingImage) + { + QMessageBox::information( this, "Mask Stamp", "Please load and select a segmentation before starting some action."); + return; + } + + QApplication::setOverrideCursor( QCursor(Qt::BusyCursor) ); + try + { + workingImage->MaskStamp( mask, m_Controls.m_chkOverwrite->isChecked() ); + } + catch ( mitk::Exception & e ) + { + QApplication::restoreOverrideCursor(); + MITK_ERROR << "Exception caught: " << e.GetDescription(); + QMessageBox::information( this, "Mask Stamp", "Could not stamp the selected mask.\n See error log for details.\n"); + return; + } + + QApplication::restoreOverrideCursor(); + + maskNode->SetVisibility(false); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +void QmitkMaskStampWidget::OnShowInformation(bool on) +{ + if (on) + m_Controls.m_InformationWidget->show(); + else + m_Controls.m_InformationWidget->hide(); +} diff --git a/Modules/SegmentationUI/Qmitk/QmitkMaskStampWidget.h b/Modules/SegmentationUI/Qmitk/QmitkMaskStampWidget.h new file mode 100644 index 0000000000..8371f17b95 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkMaskStampWidget.h @@ -0,0 +1,65 @@ +/*=================================================================== + +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 QmitkMaskStampWidget_h_Included +#define QmitkMaskStampWidget_h_Included + +#include "MitkSegmentationUIExports.h" +#include "mitkDataNode.h" + +#include + +#include "ui_QmitkMaskStampWidgetGUIControls.h" + +namespace mitk { + class ToolManager; +} + +/** + \brief GUI for mask stamp functionality + + \ingroup ToolManagerEtAl + \ingroup Widgets +*/ + +class MitkSegmentationUI_EXPORT QmitkMaskStampWidget : public QWidget +{ + Q_OBJECT + + public: + + QmitkMaskStampWidget(QWidget* parent = 0, const char* name = 0); + virtual ~QmitkMaskStampWidget(); + + void SetDataStorage( mitk::DataStorage* storage ); + + protected slots: + + void OnShowInformation(bool); + + void OnStamp(); + + private: + + mitk::ToolManager* m_ToolManager; + + mitk::DataStorage* m_DataStorage; + + Ui::QmitkMaskStampWidgetGUIControls m_Controls; + +}; + +#endif diff --git a/Modules/SegmentationUI/Qmitk/QmitkMaskStampWidgetGUIControls.ui b/Modules/SegmentationUI/Qmitk/QmitkMaskStampWidgetGUIControls.ui new file mode 100644 index 0000000000..77ed1255c6 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkMaskStampWidgetGUIControls.ui @@ -0,0 +1,139 @@ + + + QmitkMaskStampWidgetGUIControls + + + + 0 + 0 + 267 + 276 + + + + + 0 + 0 + + + + + 0 + 0 + + + + GUI Controls + + + + + + + 2 + + + 2 + + + + + + + force overwrite + + + + + + + Apply + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + usage information + + + + + + + + 0 + 0 + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">This tool fills the interior of the selected mask with the active label. Other labels within the same region will be overwritten if they are not locked.</span> </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">Select a surface from the combo box above.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">Check &quot;Force Overwrite&quot; to force the filling of regions occupied with other labels.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">Press &quot;Apply&quot; to run the tool.</span></p></body></html> + + + Qt::AlignVCenter + + + true + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + QmitkDataStorageComboBox + QComboBox +
QmitkDataStorageComboBox.h
+
+
+ + + + +
diff --git a/Modules/SegmentationUI/Qmitk/QmitkSearchLabelDialog.cpp b/Modules/SegmentationUI/Qmitk/QmitkSearchLabelDialog.cpp new file mode 100644 index 0000000000..b9f558edf3 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSearchLabelDialog.cpp @@ -0,0 +1,84 @@ +/*=================================================================== + +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 "QmitkSearchLabelDialog.h" + + +#include "mitkOrganTypeProperty.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +QmitkSearchLabelDialog::QmitkSearchLabelDialog(QWidget* parent, Qt::WindowFlags f) +:QDialog(parent, f) +{ + m_Controls = new Ui::QmitkSearchLabelDialogGUI(); + m_Controls->setupUi(this); + + m_LabelIndex = -1; + + QStringList completionList; + completionList << ""; + m_Completer = new QCompleter(completionList); + m_Completer->setCaseSensitivity(Qt::CaseInsensitive); + m_Controls->m_LabelName->setCompleter(m_Completer); + + connect( m_Completer, SIGNAL(activated(const QString&)), this, SLOT(OnLabelCompleterChanged(const QString&)) ); + connect( m_Controls->m_pbCancel, SIGNAL(clicked()), this, SLOT(reject()) ); + connect( m_Controls->m_pbAccept, SIGNAL(clicked()), this, SLOT(accept()) ); + + m_Controls->m_LabelName->setFocus(); +} + +QmitkSearchLabelDialog::~QmitkSearchLabelDialog() +{ +} + +int QmitkSearchLabelDialog::GetLabelSetWidgetTableIndex() +{ + return m_LabelIndex; +} + +QString QmitkSearchLabelDialog::GetLabelSetWidgetTableCompleteWord() +{ + return m_CompleteWord; +} + +void QmitkSearchLabelDialog::SetLabelSuggestionList(QStringList stringList) +{ + m_LabelList = stringList; + QStringListModel* completeModel = static_cast (m_Completer->model()); + completeModel->setStringList(m_LabelList); +} + +void QmitkSearchLabelDialog::OnLabelCompleterChanged(const QString& completedWord) +{ + if (m_LabelList.contains(completedWord)) + { + m_LabelIndex = m_LabelList.indexOf(completedWord); + m_CompleteWord = completedWord; +// emit(goToLabel(m_LabelIndex)); + } +} diff --git a/Modules/SegmentationUI/Qmitk/QmitkSearchLabelDialog.h b/Modules/SegmentationUI/Qmitk/QmitkSearchLabelDialog.h new file mode 100644 index 0000000000..523cce9f0b --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSearchLabelDialog.h @@ -0,0 +1,66 @@ +/*=================================================================== + +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 QmitkSearchLabelDialog_h_Included +#define QmitkSearchLabelDialog_h_Included + +#include "MitkSegmentationUIExports.h" + +#include + +#include +#include + +class MitkSegmentationUI_EXPORT QmitkSearchLabelDialog : public QDialog +{ + Q_OBJECT + + public: + + QmitkSearchLabelDialog(QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~QmitkSearchLabelDialog(); + + int GetLabelSetWidgetTableIndex(); + + QString GetLabelSetWidgetTableCompleteWord(); + + void SetLabelSuggestionList(QStringList stringList); + +signals: + + void goToLabel(int); + + public slots: + + protected slots: + + void OnLabelCompleterChanged(const QString& completedWord); + + protected: + + Ui::QmitkSearchLabelDialogGUI *m_Controls; + + QCompleter* m_Completer; + + QStringList m_LabelList; + + int m_LabelIndex; + + QString m_CompleteWord; + +}; + +#endif diff --git a/Modules/SegmentationUI/Qmitk/QmitkSearchLabelDialogGUI.ui b/Modules/SegmentationUI/Qmitk/QmitkSearchLabelDialogGUI.ui new file mode 100644 index 0000000000..f665e53128 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSearchLabelDialogGUI.ui @@ -0,0 +1,70 @@ + + + QmitkSearchLabelDialogGUI + + + + 0 + 0 + 259 + 71 + + + + + 0 + 0 + + + + Search Label + + + false + + + false + + + true + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Accept + + + + + + + Cancel + + + + + + + + + + diff --git a/Modules/SegmentationUI/Qmitk/QmitkSliceBasedInterpolatorWidget.cpp b/Modules/SegmentationUI/Qmitk/QmitkSliceBasedInterpolatorWidget.cpp new file mode 100644 index 0000000000..66538b23c7 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSliceBasedInterpolatorWidget.cpp @@ -0,0 +1,640 @@ +/*=================================================================== + +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 "QmitkSliceBasedInterpolatorWidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "QmitkStdMultiWidget.h" + +#include + +#include +#include +#include +#include + +QmitkSliceBasedInterpolatorWidget::QmitkSliceBasedInterpolatorWidget(QWidget* parent, const char* /*name*/) : QWidget(parent), +m_SliceInterpolatorController( mitk::SliceBasedInterpolationController::New() ), +m_ToolManager(NULL), +m_DataStorage(NULL), +m_Activated(false), +m_LastSNC(0), +m_LastSliceIndex(0) +{ + m_Controls.setupUi(this); + + m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); + Q_ASSERT(m_ToolManager); + + m_ToolManager->WorkingDataChanged += mitk::MessageDelegate( this, &QmitkSliceBasedInterpolatorWidget::OnToolManagerWorkingDataModified ); + + connect(m_Controls.m_btStart, SIGNAL(toggled(bool)), this, SLOT(OnToggleWidgetActivation(bool))); + connect(m_Controls.m_btApplyForCurrentSlice, SIGNAL(clicked()), this, SLOT(OnAcceptInterpolationClicked())); + connect(m_Controls.m_btApplyForAllSlices, SIGNAL(clicked()), this, SLOT(OnAcceptAllInterpolationsClicked())); + + itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); + command->SetCallbackFunction( this, &QmitkSliceBasedInterpolatorWidget::OnSliceInterpolationInfoChanged ); + m_InterpolationInfoChangedObserverTag = m_SliceInterpolatorController->AddObserver( itk::ModifiedEvent(), command ); + + // feedback node and its visualization properties + m_PreviewNode = mitk::DataNode::New(); + m_PreviewNode->SetName("3D tool preview"); + + m_PreviewNode->SetProperty("texture interpolation", mitk::BoolProperty::New(false) ); + m_PreviewNode->SetProperty("layer", mitk::IntProperty::New(100) ); + m_PreviewNode->SetProperty("binary", mitk::BoolProperty::New(true) ); + m_PreviewNode->SetProperty("outline binary", mitk::BoolProperty::New(true) ); + m_PreviewNode->SetProperty("outline binary shadow", mitk::BoolProperty::New(true) ); + m_PreviewNode->SetProperty("helper object", mitk::BoolProperty::New(true) ); + m_PreviewNode->SetOpacity(1.0); + m_PreviewNode->SetColor(0.0, 1.0, 0.0); + + m_Controls.m_btApplyForCurrentSlice->setEnabled(false); + m_Controls.m_btApplyForAllSlices->setEnabled(false); + + this->setEnabled(false); +} + +QmitkSliceBasedInterpolatorWidget::~QmitkSliceBasedInterpolatorWidget() +{ + m_ToolManager->WorkingDataChanged -= mitk::MessageDelegate(this, &QmitkSliceBasedInterpolatorWidget::OnToolManagerWorkingDataModified); + + foreach(mitk::SliceNavigationController* slicer, m_ControllerToSliceObserverTag.keys()) + { + slicer->RemoveObserver(m_ControllerToDeleteObserverTag.take(slicer)); + slicer->RemoveObserver(m_ControllerToTimeObserverTag.take(slicer)); + slicer->RemoveObserver(m_ControllerToSliceObserverTag.take(slicer)); + } + + m_ActionToSliceDimensionMap.clear(); + + // remove observer + m_SliceInterpolatorController->RemoveObserver( m_InterpolationInfoChangedObserverTag ); +} + +const QmitkSliceBasedInterpolatorWidget::ActionToSliceDimensionMapType QmitkSliceBasedInterpolatorWidget::CreateActionToSliceDimension() +{ + ActionToSliceDimensionMapType actionToSliceDimension; + foreach(mitk::SliceNavigationController* slicer, m_ControllerToDeleteObserverTag.keys()) + { + std::string name = slicer->GetRenderer()->GetName(); + if (name == "stdmulti.widget1") + name = "Axial (red window)"; + else if (name == "stdmulti.widget2") + name = "Sagittal (green window)"; + else if (name == "stdmulti.widget3") + name = "Coronal (blue window)"; + actionToSliceDimension[new QAction(QString::fromStdString(name),0)] = slicer; + } + + return actionToSliceDimension; +} + +void QmitkSliceBasedInterpolatorWidget::SetDataStorage(mitk::DataStorage& storage) +{ + m_DataStorage = &storage; +} + +void QmitkSliceBasedInterpolatorWidget::SetSliceNavigationControllers(const QList &controllers) +{ + Q_ASSERT(!controllers.empty()); + + // connect to the slice navigation controller. after each change, call the interpolator + foreach(mitk::SliceNavigationController* slicer, controllers) + { + //Has to be initialized + m_LastSNC = slicer; + + m_TimeStep.insert(slicer, slicer->GetTime()->GetPos()); + + itk::MemberCommand::Pointer deleteCommand = itk::MemberCommand::New(); + deleteCommand->SetCallbackFunction( this, &QmitkSliceBasedInterpolatorWidget::OnSliceNavigationControllerDeleted); + m_ControllerToDeleteObserverTag.insert(slicer, slicer->AddObserver(itk::DeleteEvent(), deleteCommand)); + + itk::MemberCommand::Pointer timeChangedCommand = itk::MemberCommand::New(); + timeChangedCommand->SetCallbackFunction( this, &QmitkSliceBasedInterpolatorWidget::OnTimeChanged); + m_ControllerToTimeObserverTag.insert(slicer, slicer->AddObserver(mitk::SliceNavigationController::TimeSlicedGeometryEvent(NULL,0), timeChangedCommand)); + + itk::MemberCommand::Pointer sliceChangedCommand = itk::MemberCommand::New(); + sliceChangedCommand->SetCallbackFunction( this, &QmitkSliceBasedInterpolatorWidget::OnSliceChanged); + m_ControllerToSliceObserverTag.insert(slicer, slicer->AddObserver(mitk::SliceNavigationController::GeometrySliceEvent(NULL,0), sliceChangedCommand)); + } + + m_ActionToSliceDimensionMap = this->CreateActionToSliceDimension(); +} + +void QmitkSliceBasedInterpolatorWidget::OnToolManagerWorkingDataModified() +{ + mitk::DataNode* workingNode = this->m_ToolManager->GetWorkingData(0); + if (!workingNode) + { + this->setEnabled(false); + return; + } + + mitk::LabelSetImage* workingImage = dynamic_cast< mitk::LabelSetImage* >( workingNode->GetData() ); + Q_ASSERT(workingImage); + + if (workingImage->GetDimension() > 4 || workingImage->GetDimension() < 3) + { + this->setEnabled(false); + return; + } + + m_WorkingImage = workingImage; + + this->setEnabled(true); +} + +void QmitkSliceBasedInterpolatorWidget::OnTimeChanged(itk::Object* sender, const itk::EventObject& e) +{ + //Check if we really have a GeometryTimeEvent + if (!dynamic_cast(&e)) + return; + + mitk::SliceNavigationController* slicer = dynamic_cast(sender); + Q_ASSERT(slicer); + + m_TimeStep[slicer]/* = event.GetPos()*/; + + //TODO Macht das hier wirklich Sinn???? + if (m_LastSNC == slicer) + { + slicer->SendSlice();//will trigger a new interpolation + } +} + +void QmitkSliceBasedInterpolatorWidget::OnSliceChanged(itk::Object *sender, const itk::EventObject &e) +{ + if (m_Activated && m_WorkingImage.IsNotNull()) + { + //Check whether we really have a GeometrySliceEvent + if (!dynamic_cast(&e)) + return; + + mitk::SliceNavigationController* slicer = dynamic_cast(sender); + if (slicer) + { + this->TranslateAndInterpolateChangedSlice(e, slicer); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + // slicer->GetRenderer()->RequestUpdate(); + } + } +} + +void QmitkSliceBasedInterpolatorWidget::TranslateAndInterpolateChangedSlice(const itk::EventObject& e, mitk::SliceNavigationController* slicer) +{ + if (m_Activated && m_WorkingImage.IsNotNull()) + { + const mitk::SliceNavigationController::GeometrySliceEvent& geometrySliceEvent = dynamic_cast(e); + mitk::TimeGeometry* timeGeometry = geometrySliceEvent.GetTimeGeometry(); + if (timeGeometry && m_TimeStep.contains(slicer)) + { + mitk::SlicedGeometry3D* slicedGeometry = dynamic_cast(timeGeometry->GetGeometryForTimeStep(m_TimeStep[slicer]).GetPointer()); + if (slicedGeometry) + { + mitk::PlaneGeometry* plane = slicedGeometry->GetPlaneGeometry(geometrySliceEvent.GetPos()); + if (plane) + { + m_LastSNC = slicer; + this->Interpolate(plane, m_TimeStep[slicer], slicer); + } + } + } + } +} + +void QmitkSliceBasedInterpolatorWidget::Interpolate( mitk::PlaneGeometry* plane, unsigned int timeStep, mitk::SliceNavigationController* slicer ) +{ + int clickedSliceDimension(-1); + int clickedSliceIndex(-1); + + // calculate real slice position, i.e. slice of the image and not slice of the TimeSlicedGeometry + // see if timestep is needed here + mitk::SegTool2D::DetermineAffectedImageSlice( m_WorkingImage, plane, clickedSliceDimension, clickedSliceIndex ); + + mitk::Image::Pointer interpolation = m_SliceInterpolatorController->Interpolate( clickedSliceDimension, clickedSliceIndex, plane, timeStep ); + + m_PreviewNode->SetData( interpolation ); + + const mitk::Color& color = m_WorkingImage->GetActiveLabel()->GetColor(); + m_PreviewNode->SetColor(color); + + m_LastSNC = slicer; + m_LastSliceIndex = clickedSliceIndex; +} + +mitk::Image::Pointer QmitkSliceBasedInterpolatorWidget::GetWorkingSlice(const mitk::PlaneGeometry* planeGeometry) +{ + unsigned int timeStep = m_LastSNC->GetTime()->GetPos(); + + //Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk reslicer + vtkSmartPointer reslice = vtkSmartPointer::New(); + //set to false to extract a slice + reslice->SetOverwriteMode(false); + reslice->Modified(); + + //use ExtractSliceFilter with our specific vtkImageReslice for overwriting and extracting + mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); + extractor->SetInput( m_WorkingImage ); + extractor->SetTimeStep( timeStep ); + extractor->SetWorldGeometry( planeGeometry ); + extractor->SetVtkOutputRequest(false); + extractor->SetResliceTransformByGeometry( m_WorkingImage->GetTimeGeometry()->GetGeometryForTimeStep(timeStep) ); + + extractor->Modified(); + + try + { + extractor->Update(); + } + catch ( itk::ExceptionObject & excep ) + { + MITK_ERROR << "Exception caught: " << excep.GetDescription(); + return NULL; + } + + mitk::Image::Pointer slice = extractor->GetOutput(); + + //specify the undo operation with the non edited slice + //MLI TODO added code starts here + mitk::SlicedGeometry3D* sliceGeometry = dynamic_cast(slice->GetGeometry()); + //m_undoOperation = new mitk::DiffSliceOperation(m_WorkingImage, extractor->GetVtkOutput(), slice->GetGeometry(), timeStep, const_cast(planeGeometry)); + // added code ends here + m_undoOperation = new mitk::DiffSliceOperation(m_WorkingImage, extractor->GetVtkOutput(), sliceGeometry, timeStep, const_cast(planeGeometry)); + + slice->DisconnectPipeline(); + + return slice; +} + +void QmitkSliceBasedInterpolatorWidget::OnToggleWidgetActivation(bool enabled) +{ + Q_ASSERT(m_ToolManager); + + mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + if (!workingNode) return; + + m_Controls.m_btApplyForCurrentSlice->setEnabled(enabled); + m_Controls.m_btApplyForAllSlices->setEnabled(enabled); + + if (enabled) + m_Controls.m_btStart->setText("Stop"); + else + m_Controls.m_btStart->setText("Start"); + + unsigned int numberOfExistingTools = m_ToolManager->GetTools().size(); + for (unsigned int i = 0; i < numberOfExistingTools; i++) + { + mitk::SegTool2D* tool = dynamic_cast(m_ToolManager->GetToolById(i)); + //MLI TODO + //if (tool) tool->SetEnable2DInterpolation( enabled ); + } + + if (enabled) + { + if (!m_DataStorage->Exists(m_PreviewNode)) + { + m_DataStorage->Add( m_PreviewNode ); + } + + m_SliceInterpolatorController->SetWorkingImage( m_WorkingImage ); + this->UpdateVisibleSuggestion(); + } + else + { + if (m_DataStorage->Exists(m_PreviewNode)) + { + m_DataStorage->Remove( m_PreviewNode ); + } + + mitk::UndoController::GetCurrentUndoModel()->Clear(); + } + + m_Activated = enabled; + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +template +void QmitkSliceBasedInterpolatorWidget::WritePreviewOnWorkingImage( itk::Image* targetSlice, const mitk::Image* sourceSlice, int overwritevalue ) +{ + typedef itk::Image ImageType; + + typename ImageType::Pointer sourceSliceITK; + mitk::CastToItkImage( sourceSlice, sourceSliceITK ); + + // now the original slice and the ipSegmentation-painted slice are in the same format, and we can just copy all pixels that are non-zero + typedef itk::ImageRegionIterator< ImageType > OutputIteratorType; + typedef itk::ImageRegionConstIterator< ImageType > InputIteratorType; + + InputIteratorType inputIterator( sourceSliceITK, sourceSliceITK->GetLargestPossibleRegion() ); + OutputIteratorType outputIterator( targetSlice, targetSlice->GetLargestPossibleRegion() ); + + outputIterator.GoToBegin(); + inputIterator.GoToBegin(); + + int activePixelValue = m_WorkingImage->GetActiveLabel()->GetValue(); + + if (activePixelValue == 0) // if exterior is the active label + { + while ( !outputIterator.IsAtEnd() ) + { + if (inputIterator.Get() != 0) + { + outputIterator.Set( overwritevalue ); + } + ++outputIterator; + ++inputIterator; + } + } + else if (overwritevalue != 0) // if we are not erasing + { + while ( !outputIterator.IsAtEnd() ) + { + int targetValue = static_cast(outputIterator.Get()); + if ( inputIterator.Get() != 0 ) + { + if (!m_WorkingImage->GetLabel(targetValue)->GetLocked()) + outputIterator.Set( overwritevalue ); + } + + ++outputIterator; + ++inputIterator; + } + } + else // if we are erasing + { + while ( !outputIterator.IsAtEnd() ) + { + const int targetValue = outputIterator.Get(); + if (inputIterator.Get() != 0) + { + if (targetValue == activePixelValue) + outputIterator.Set( overwritevalue ); + } + + ++outputIterator; + ++inputIterator; + } + } +} + +void QmitkSliceBasedInterpolatorWidget::OnAcceptInterpolationClicked() +{ + if (m_WorkingImage.IsNotNull() && m_PreviewNode->GetData()) + { + const mitk::PlaneGeometry* planeGeometry = m_LastSNC->GetCurrentPlaneGeometry(); + if (!planeGeometry) return; + + mitk::Image::Pointer sliceImage = this->GetWorkingSlice(planeGeometry); + if (sliceImage.IsNull()) return; + + mitk::Image::Pointer previewSlice = dynamic_cast( m_PreviewNode->GetData() ); + + AccessFixedDimensionByItk_2( sliceImage, WritePreviewOnWorkingImage, 2, previewSlice, m_WorkingImage->GetActiveLabel()->GetValue() ); + + //Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk reslicer + vtkSmartPointer overwrite = vtkSmartPointer::New(); + overwrite->SetInputSlice(sliceImage->GetVtkImageData()); + //set overwrite mode to true to write back to the image volume + overwrite->SetOverwriteMode(true); + overwrite->Modified(); + + unsigned int timeStep = m_LastSNC->GetTime()->GetPos(); + + mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(overwrite); + extractor->SetInput( m_WorkingImage ); + extractor->SetTimeStep( timeStep ); + extractor->SetWorldGeometry( planeGeometry ); + extractor->SetVtkOutputRequest(true); + extractor->SetResliceTransformByGeometry( m_WorkingImage->GetTimeGeometry()->GetGeometryForTimeStep(timeStep) ); + + extractor->Modified(); + + try + { + extractor->Update(); + } + catch ( itk::ExceptionObject & excep ) + { + MITK_ERROR << "Exception caught: " << excep.GetDescription(); + return; + } + + //the image was modified within the pipeline, but not marked so + m_WorkingImage->Modified(); + + int clickedSliceDimension(-1); + int clickedSliceIndex(-1); + + mitk::SegTool2D::DetermineAffectedImageSlice( m_WorkingImage, planeGeometry, clickedSliceDimension, clickedSliceIndex ); + + m_SliceInterpolatorController->SetChangedSlice( sliceImage, clickedSliceDimension, clickedSliceIndex, timeStep ); + + //specify the undo operation with the edited slice + //MLI TODO added code starts here + mitk::SlicedGeometry3D* sliceGeometry = dynamic_cast(sliceImage->GetGeometry()); + //m_undoOperation = new mitk::DiffSliceOperation(m_WorkingImage, extractor->GetVtkOutput(), slice->GetGeometry(), timeStep, const_cast(planeGeometry)); + // added code ends here + m_doOperation = new mitk::DiffSliceOperation( + m_WorkingImage, extractor->GetVtkOutput(), sliceGeometry, timeStep, const_cast(planeGeometry)); + + //create an operation event for the undo stack + mitk::OperationEvent* undoStackItem = new mitk::OperationEvent( + mitk::DiffSliceOperationApplier::GetInstance(), m_doOperation, m_undoOperation, "Slice Interpolation" ); + + //add it to the undo controller + mitk::UndoController::GetCurrentUndoModel()->SetOperationEvent( undoStackItem ); + + //clear the pointers as the operation are stored in the undo controller and also deleted from there + m_undoOperation = NULL; + m_doOperation = NULL; + + m_PreviewNode->SetData(NULL); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } +} + +void QmitkSliceBasedInterpolatorWidget::AcceptAllInterpolations(mitk::SliceNavigationController* slicer) +{ + // Since we need to shift the plane it must be clone so that the original plane isn't altered + mitk::PlaneGeometry::Pointer reslicePlane = slicer->GetCurrentPlaneGeometry()->Clone(); + unsigned int timeStep = slicer->GetTime()->GetPos(); + + int sliceDimension(-1); + int sliceIndex(-1); + + mitk::SegTool2D::DetermineAffectedImageSlice( m_WorkingImage, reslicePlane, sliceDimension, sliceIndex ); + + unsigned int zslices = m_WorkingImage->GetDimension( sliceDimension ); + + mitk::ProgressBar::GetInstance()->Reset(); + mitk::ProgressBar::GetInstance()->AddStepsToDo(zslices); + + mitk::Point3D origin = reslicePlane->GetOrigin(); + + for (unsigned int idx = 0; idx < zslices; ++idx) + { + // Transforming the current origin of the reslice plane + // so that it matches the one of the next slice + m_WorkingImage->GetSlicedGeometry()->WorldToIndex(origin, origin); + origin[sliceDimension] = idx; + m_WorkingImage->GetSlicedGeometry()->IndexToWorld(origin, origin); + reslicePlane->SetOrigin(origin); + + mitk::Image::Pointer interpolation = m_SliceInterpolatorController->Interpolate( sliceDimension, idx, reslicePlane, timeStep ); + + if (interpolation.IsNotNull()) + { + m_PreviewNode->SetData(interpolation); + + mitk::Image::Pointer sliceImage = this->GetWorkingSlice(reslicePlane); + if (sliceImage.IsNull()) return; + + AccessFixedDimensionByItk_2( sliceImage, WritePreviewOnWorkingImage, 2, interpolation, m_WorkingImage->GetActiveLabel()->GetValue() ); + + //Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk reslicer + vtkSmartPointer overwrite = vtkSmartPointer::New(); + overwrite->SetInputSlice(sliceImage->GetVtkImageData()); + //set overwrite mode to true to write back to the image volume + overwrite->SetOverwriteMode(true); + overwrite->Modified(); + + mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(overwrite); + extractor->SetInput( m_WorkingImage ); + extractor->SetTimeStep( timeStep ); + extractor->SetWorldGeometry( reslicePlane ); + extractor->SetVtkOutputRequest(true); + extractor->SetResliceTransformByGeometry( m_WorkingImage->GetTimeGeometry()->GetGeometryForTimeStep(timeStep) ); + + extractor->Modified(); + + try + { + extractor->Update(); + } + catch ( itk::ExceptionObject & excep ) + { + MITK_ERROR << "Exception caught: " << excep.GetDescription(); + return; + } + + m_WorkingImage->Modified(); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); + } + + mitk::ProgressBar::GetInstance()->Progress(); + } + + m_SliceInterpolatorController->SetWorkingImage(m_WorkingImage); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +void QmitkSliceBasedInterpolatorWidget::OnAcceptAllInterpolationsClicked() +{ + QMenu orientationPopup(this); + std::map::const_iterator it; + for(it = m_ActionToSliceDimensionMap.begin(); it != m_ActionToSliceDimensionMap.end(); it++) + orientationPopup.addAction(it->first); + + connect( &orientationPopup, SIGNAL(triggered(QAction*)), this, SLOT(OnAcceptAllPopupActivated(QAction*)) ); + + orientationPopup.exec( QCursor::pos() ); +} + +void QmitkSliceBasedInterpolatorWidget::OnAcceptAllPopupActivated(QAction* action) +{ + ActionToSliceDimensionMapType::const_iterator iter = m_ActionToSliceDimensionMap.find( action ); + if (iter != m_ActionToSliceDimensionMap.end()) + { + mitk::SliceNavigationController* slicer = iter->second; + this->AcceptAllInterpolations( slicer ); + } +} + +void QmitkSliceBasedInterpolatorWidget::UpdateVisibleSuggestion() +{ + if (m_Activated && m_LastSNC) + { + // determine which one is the current view, try to do an initial interpolation + mitk::BaseRenderer* renderer = m_LastSNC->GetRenderer(); + if (renderer && renderer->GetMapperID() == mitk::BaseRenderer::Standard2D) + { + const mitk::TimeGeometry* timeGeometry = dynamic_cast( renderer->GetWorldGeometry() ); + if (timeGeometry) + { + mitk::SliceNavigationController::GeometrySliceEvent event( const_cast(timeGeometry), renderer->GetSlice() ); + this->TranslateAndInterpolateChangedSlice(event, m_LastSNC); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + } + } +} + +void QmitkSliceBasedInterpolatorWidget::OnSliceInterpolationInfoChanged(const itk::EventObject& /*e*/) +{ + // something (e.g. undo) changed the interpolation info, we should refresh our display + this->UpdateVisibleSuggestion(); +} + +void QmitkSliceBasedInterpolatorWidget::OnSliceNavigationControllerDeleted(const itk::Object *sender, const itk::EventObject& /*e*/) +{ + //Don't know how to avoid const_cast here?! + mitk::SliceNavigationController* slicer = dynamic_cast(const_cast(sender)); + if (slicer) + { + m_ControllerToTimeObserverTag.remove(slicer); + m_ControllerToSliceObserverTag.remove(slicer); + m_ControllerToDeleteObserverTag.remove(slicer); + } +} + +void QmitkSliceBasedInterpolatorWidget::WaitCursorOn() +{ + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); +} + +void QmitkSliceBasedInterpolatorWidget::WaitCursorOff() +{ + this->RestoreOverrideCursor(); +} + +void QmitkSliceBasedInterpolatorWidget::RestoreOverrideCursor() +{ + QApplication::restoreOverrideCursor(); +} \ No newline at end of file diff --git a/Modules/SegmentationUI/Qmitk/QmitkSliceBasedInterpolatorWidget.h b/Modules/SegmentationUI/Qmitk/QmitkSliceBasedInterpolatorWidget.h new file mode 100644 index 0000000000..0ef52d4fd6 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSliceBasedInterpolatorWidget.h @@ -0,0 +1,199 @@ +/*=================================================================== + +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 QmitkSliceBasedInterpolatorWidget_h_Included +#define QmitkSliceBasedInterpolatorWidget_h_Included + +#include "MitkSegmentationUIExports.h" +#include "mitkDataStorage.h" +#include "mitkSliceBasedInterpolationController.h" + +#include + +#include + +#include "ui_QmitkSliceBasedInterpolatorWidgetGUIControls.h" + +namespace mitk +{ + class PlaneGeometry; + class SliceNavigationController; + class LabelSetImage; + class ToolManager; + class DiffSliceOperation; +} + +/** + \brief GUI for slices interpolation. + + \ingroup ToolManagerEtAl + \ingroup Widgets + + \sa QmitkInteractiveSegmentation + \sa mitk::SegmentationInterpolation + + There is a separate page describing the general design of QmitkInteractiveSegmentation: \ref QmitkInteractiveSegmentationTechnicalPage + + While mitk::SegmentationInterpolation does the bookkeeping of interpolation + (keeping track of which slices contain how much segmentation) and the algorithmic work, + QmitkSliceBasedInterpolatorWidget is responsible to watch the GUI, to notice, which slice is currently + visible. It triggers generation of interpolation suggestions and also triggers acception of + suggestions. + + \todo show/hide feedback on demand + + Last contributor: $Author: maleike $ +*/ + +class MitkSegmentationUI_EXPORT QmitkSliceBasedInterpolatorWidget : public QWidget +{ + Q_OBJECT + + public: + + QmitkSliceBasedInterpolatorWidget(QWidget* parent = 0, const char* name = 0); + virtual ~QmitkSliceBasedInterpolatorWidget(); + + void SetDataStorage(mitk::DataStorage& storage); + + /** + Sets the slice navigation controllers for getting slice changed events from the views. + */ + void SetSliceNavigationControllers(const QList &controllers); + + void OnToolManagerWorkingDataModified(); + + void OnTimeChanged(itk::Object* sender, const itk::EventObject&); + + void OnSliceChanged(itk::Object* sender, const itk::EventObject&); + + void OnSliceNavigationControllerDeleted(const itk::Object *sender, const itk::EventObject& ); + + /** + Just public because it is called by itk::Commands. You should not need to call this. + */ + void OnSliceInterpolationInfoChanged(const itk::EventObject&); + + Ui::QmitkSliceBasedInterpolatorWidgetGUIControls m_Controls; + + signals: + + void signalSliceBasedInterpolationEnabled(bool); + + public slots: + + /** + \brief Reaction to "Start/Stop" button click + */ + void OnToggleWidgetActivation(bool); + + protected slots: + + /** + \brief Reaction to "Accept Current Slice" button click. + */ + void OnAcceptInterpolationClicked(); + + /* + \brief Reaction to "Accept All Slices" button click. + Opens popup to ask about which orientation should be interpolated + */ + void OnAcceptAllInterpolationsClicked(); + + /* + \brief Called from popup menu of OnAcceptAllInterpolationsClicked() + Will trigger interpolation for all slices in given orientation + */ + void OnAcceptAllPopupActivated(QAction* action); + + protected: + + typedef std::map ActionToSliceDimensionMapType; + + const ActionToSliceDimensionMapType CreateActionToSliceDimension(); + + ActionToSliceDimensionMapType m_ActionToSliceDimensionMap; + + void AcceptAllInterpolations(mitk::SliceNavigationController* slicer); + + void WaitCursorOn(); + + void WaitCursorOff(); + + void RestoreOverrideCursor(); + + /** + Gets the working slice based on the given plane geometry and last saved interaction + + \param planeGeometry a plane geometry + */ + mitk::Image::Pointer GetWorkingSlice(const mitk::PlaneGeometry* planeGeometry); + + /** + Retrieves the currently selected PlaneGeometry from a SlicedGeometry3D that is generated by a SliceNavigationController + and calls Interpolate to further process this PlaneGeometry into an interpolation. + + \param e is a actually a mitk::SliceNavigationController::GeometrySliceEvent, sent by a SliceNavigationController + \param slice the SliceNavigationController + */ + void TranslateAndInterpolateChangedSlice(const itk::EventObject& e, mitk::SliceNavigationController* slicer); + + /** + Given a PlaneGeometry, this method figures out which slice of the first working image (of the associated ToolManager) + should be interpolated. The actual work is then done by our SegmentationInterpolation object. + */ + void Interpolate( mitk::PlaneGeometry* plane, unsigned int timeStep, mitk::SliceNavigationController *slicer ); + + /** + Called internally to update the interpolation suggestion. Finds out about the focused render window and requests an interpolation. + */ + void UpdateVisibleSuggestion(); + +private: + + mitk::SliceBasedInterpolationController::Pointer m_SliceInterpolatorController; + + mitk::ToolManager* m_ToolManager; + + bool m_Activated; + + template + void WritePreviewOnWorkingImage( itk::Image* target, const mitk::Image* source, int overwritevalue ); + + QHash m_ControllerToTimeObserverTag; + QHash m_ControllerToSliceObserverTag; + QHash m_ControllerToDeleteObserverTag; + + unsigned int m_InterpolationInfoChangedObserverTag; + + mitk::DiffSliceOperation* m_doOperation; + mitk::DiffSliceOperation* m_undoOperation; + + mitk::DataNode::Pointer m_PreviewNode; + mitk::Image::Pointer m_PreviewImage; + + mitk::LabelSetImage::Pointer m_WorkingImage; + + mitk::SliceNavigationController* m_LastSNC; + + unsigned int m_LastSliceIndex; + + QHash m_TimeStep; + + mitk::DataStorage::Pointer m_DataStorage; +}; + +#endif diff --git a/Modules/SegmentationUI/Qmitk/QmitkSliceBasedInterpolatorWidgetGUIControls.ui b/Modules/SegmentationUI/Qmitk/QmitkSliceBasedInterpolatorWidgetGUIControls.ui new file mode 100644 index 0000000000..d8e8eeeca3 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSliceBasedInterpolatorWidgetGUIControls.ui @@ -0,0 +1,159 @@ + + + QmitkSliceBasedInterpolatorWidgetGUIControls + + + + 0 + 0 + 265 + 94 + + + + + 0 + 0 + + + + + 0 + 0 + + + + Slice-Based Interpolation + + + + + + + QLayout::SetDefaultConstraint + + + 6 + + + + + QLayout::SetDefaultConstraint + + + + + true + + + + 0 + 0 + + + + Start/Stop the 3D interpolation utility + + + Start + + + + :/Qmitk/Start.png + :/Qmitk/Stop.png:/Qmitk/Start.png + + + + 32 + 32 + + + + true + + + false + + + Qt::ToolButtonTextUnderIcon + + + Qt::NoArrow + + + + + + + + 0 + 0 + + + + Accept Single + + + + :/Qmitk/AcceptCurrentInterpolation.png:/Qmitk/AcceptCurrentInterpolation.png + + + + 32 + 32 + + + + Qt::ToolButtonTextUnderIcon + + + + + + + + 0 + 0 + + + + Accept All + + + + :/Qmitk/AcceptAllInterpolations.png:/Qmitk/AcceptAllInterpolations.png + + + + 32 + 32 + + + + Qt::ToolButtonTextUnderIcon + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + diff --git a/Modules/SegmentationUI/Qmitk/QmitkSurfaceBasedInterpolatorWidget.cpp b/Modules/SegmentationUI/Qmitk/QmitkSurfaceBasedInterpolatorWidget.cpp new file mode 100644 index 0000000000..4b69f8ad7b --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSurfaceBasedInterpolatorWidget.cpp @@ -0,0 +1,340 @@ +/*=================================================================== + +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 "QmitkSurfaceBasedInterpolatorWidget.h" + +#include "mitkColorProperty.h" +#include "mitkProperties.h" +#include "mitkRenderingManager.h" +#include "mitkProgressBar.h" +#include "mitkOperationEvent.h" +#include "mitkInteractionConst.h" +#include "mitkVtkRepresentationProperty.h" +#include "mitkUndoController.h" +#include "mitkSegTool2D.h" +#include "mitkSurfaceToImageFilter.h" +#include "mitkSliceNavigationController.h" +#include + +#include "QmitkStdMultiWidget.h" + +#include +#include + +#include + + +QmitkSurfaceBasedInterpolatorWidget::QmitkSurfaceBasedInterpolatorWidget(QWidget* parent, const char* /*name*/) : QWidget(parent), +m_SurfaceBasedInterpolatorController(mitk::SurfaceBasedInterpolationController::GetInstance()), +m_ToolManager(NULL), +m_DataStorage(NULL), +m_Activated(false) +{ + m_Controls.setupUi(this); + + m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); + Q_ASSERT(m_ToolManager); + + m_ToolManager->WorkingDataChanged += mitk::MessageDelegate( this, &QmitkSurfaceBasedInterpolatorWidget::OnToolManagerWorkingDataModified ); + + connect(m_Controls.m_btStart, SIGNAL(toggled(bool)), this, SLOT(OnToggleWidgetActivation(bool))); + connect(m_Controls.m_btAccept, SIGNAL(clicked()), this, SLOT(OnAcceptInterpolationClicked())); + connect(m_Controls.m_cbShowPositionNodes, SIGNAL(toggled(bool)), this, SLOT(OnShowMarkers(bool))); + + itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); + command->SetCallbackFunction( this, &QmitkSurfaceBasedInterpolatorWidget::OnSurfaceInterpolationInfoChanged ); + m_SurfaceInterpolationInfoChangedObserverTag = m_SurfaceBasedInterpolatorController->AddObserver( itk::ModifiedEvent(), command ); + + m_InterpolatedSurfaceNode = mitk::DataNode::New(); + m_InterpolatedSurfaceNode->SetName( "Surface Interpolation feedback" ); + m_InterpolatedSurfaceNode->SetProperty( "color", mitk::ColorProperty::New(255.0,255.0,0.0) ); + m_InterpolatedSurfaceNode->SetProperty( "opacity", mitk::FloatProperty::New(0.5) ); + m_InterpolatedSurfaceNode->SetProperty( "includeInBoundingBox", mitk::BoolProperty::New(false)); + m_InterpolatedSurfaceNode->SetProperty( "helper object", mitk::BoolProperty::New(true) ); + m_InterpolatedSurfaceNode->SetVisibility(false); + + m_3DContourNode = mitk::DataNode::New(); + m_3DContourNode->SetName( "Drawn Contours" ); + m_3DContourNode->SetProperty( "color", mitk::ColorProperty::New(0.0, 0.0, 0.0) ); + m_3DContourNode->SetProperty( "helper object", mitk::BoolProperty::New(true)); + m_3DContourNode->SetProperty( "material.representation", mitk::VtkRepresentationProperty::New(VTK_WIREFRAME)); + m_3DContourNode->SetProperty( "material.wireframeLineWidth", mitk::FloatProperty::New(2.0f)); + m_3DContourNode->SetProperty( "includeInBoundingBox", mitk::BoolProperty::New(false)); + m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))); + m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget2"))); + m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))); + m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); + + connect(&m_Watcher, SIGNAL(started()), this, SLOT(StartUpdateInterpolationTimer())); + connect(&m_Watcher, SIGNAL(finished()), this, SLOT(OnSurfaceInterpolationFinished())); + connect(&m_Watcher, SIGNAL(finished()), this, SLOT(StopUpdateInterpolationTimer())); + + m_Timer = new QTimer(this); + connect(m_Timer, SIGNAL(timeout()), this, SLOT(ChangeSurfaceColor())); + + m_Controls.m_btAccept->setEnabled(false); + m_Controls.m_cbShowPositionNodes->setEnabled(false); + + this->setEnabled(false); +} + +void QmitkSurfaceBasedInterpolatorWidget::SetDataStorage(mitk::DataStorage& storage) +{ + m_DataStorage = &storage; +} + +QmitkSurfaceBasedInterpolatorWidget::~QmitkSurfaceBasedInterpolatorWidget() +{ + m_ToolManager->WorkingDataChanged -= mitk::MessageDelegate(this, &QmitkSurfaceBasedInterpolatorWidget::OnToolManagerWorkingDataModified); + + if(m_DataStorage->Exists(m_3DContourNode)) + m_DataStorage->Remove(m_3DContourNode); + + if(m_DataStorage->Exists(m_InterpolatedSurfaceNode)) + m_DataStorage->Remove(m_InterpolatedSurfaceNode); + + // remove observer + m_SurfaceBasedInterpolatorController->RemoveObserver( m_SurfaceInterpolationInfoChangedObserverTag ); + + delete m_Timer; +} + +void QmitkSurfaceBasedInterpolatorWidget::ShowInterpolationResult(bool status) +{ + if (m_InterpolatedSurfaceNode.IsNotNull()) + m_InterpolatedSurfaceNode->SetVisibility(status); + + if (m_3DContourNode.IsNotNull()) + m_3DContourNode->SetVisibility(status, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + + void QmitkSurfaceBasedInterpolatorWidget::OnSurfaceInterpolationFinished() + { + mitk::Surface::Pointer interpolatedSurface = m_SurfaceBasedInterpolatorController->GetInterpolationResult(); + + if ( interpolatedSurface.IsNotNull() ) + { + m_InterpolatedSurfaceNode->SetData(interpolatedSurface); + m_3DContourNode->SetData(m_SurfaceBasedInterpolatorController->GetContoursAsSurface()); + this->ShowInterpolationResult(true); + } + else + { + m_InterpolatedSurfaceNode->SetData(NULL); + m_3DContourNode->SetData(NULL); + this->ShowInterpolationResult(false); + } + } + +void QmitkSurfaceBasedInterpolatorWidget::OnShowMarkers(bool state) +{ + mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = m_DataStorage->GetSubset( + mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); + + for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) + { + it->Value()->SetProperty("helper object", mitk::BoolProperty::New(!state)); + } + + mitk::SegTool2D::Pointer manualSegmentationTool; + + unsigned int numberOfExistingTools = m_ToolManager->GetTools().size(); + + for(unsigned int i = 0; i < numberOfExistingTools; i++) + { + manualSegmentationTool = dynamic_cast(m_ToolManager->GetToolById(i)); + + if (manualSegmentationTool) + { + manualSegmentationTool->SetShowMarkerNodes( state ); + } + } +} + +void QmitkSurfaceBasedInterpolatorWidget::StartUpdateInterpolationTimer() +{ + m_Timer->start(500); +} + +void QmitkSurfaceBasedInterpolatorWidget::StopUpdateInterpolationTimer() +{ + m_Timer->stop(); + m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(255.0,255.0,0.0)); + mitk::RenderingManager::GetInstance()->RequestUpdate(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetRenderWindow() ); +} + +void QmitkSurfaceBasedInterpolatorWidget::ChangeSurfaceColor() +{ + float currentColor[3]; + m_InterpolatedSurfaceNode->GetColor(currentColor); + + float yellow[3] = {255.0,255.0,0.0}; + + if( currentColor[2] == yellow[2]) + { + m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(255.0,255.0,255.0)); + } + else + { + m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(yellow)); + } + m_InterpolatedSurfaceNode->Update(); + mitk::RenderingManager::GetInstance()->RequestUpdate(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetRenderWindow()); +} + +void QmitkSurfaceBasedInterpolatorWidget::OnToolManagerWorkingDataModified() +{ + mitk::DataNode* workingNode = this->m_ToolManager->GetWorkingData(0); + if (!workingNode) + { + this->setEnabled(false); + return; + } + + mitk::LabelSetImage* workingImage = dynamic_cast< mitk::LabelSetImage* >( workingNode->GetData() ); + Q_ASSERT(workingImage); + + if (workingImage->GetDimension() > 4 || workingImage->GetDimension() < 3) + { + this->setEnabled(false); + return; + } + + m_WorkingImage = workingImage; + + this->setEnabled(true); +} + +void QmitkSurfaceBasedInterpolatorWidget::OnRunInterpolation() +{ + m_SurfaceBasedInterpolatorController->Interpolate(); +} + +void QmitkSurfaceBasedInterpolatorWidget::OnToggleWidgetActivation(bool enabled) +{ + Q_ASSERT(m_ToolManager); + + mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + if (!workingNode) return; + + m_Controls.m_btAccept->setEnabled(enabled); + m_Controls.m_cbShowPositionNodes->setEnabled(enabled); + + if (enabled) + m_Controls.m_btStart->setText("Stop"); + else + m_Controls.m_btStart->setText("Start"); + + for (unsigned int i = 0; i < m_ToolManager->GetTools().size(); i++) + { + mitk::SegTool2D* tool = dynamic_cast(m_ToolManager->GetToolById(i)); + if (tool) tool->SetEnable3DInterpolation( enabled ); + } + + if (enabled) + { + if (!m_DataStorage->Exists(m_InterpolatedSurfaceNode)) + { + m_DataStorage->Add( m_InterpolatedSurfaceNode ); + } + + if (!m_DataStorage->Exists(m_3DContourNode)) + { + m_DataStorage->Add( m_3DContourNode ); + } + + mitk::Vector3D spacing = m_WorkingImage->GetGeometry(0)->GetSpacing(); + double minSpacing (100); + double maxSpacing (0); + for (int i =0; i < 3; i++) + { + if (spacing[i] < minSpacing) + { + minSpacing = spacing[i]; + } + else if (spacing[i] > maxSpacing) + { + maxSpacing = spacing[i]; + } + } + + m_SurfaceBasedInterpolatorController->SetWorkingImage(m_WorkingImage); + m_SurfaceBasedInterpolatorController->SetActiveLabel(m_WorkingImage->GetActiveLabel()->GetValue()); + m_SurfaceBasedInterpolatorController->SetMaxSpacing(maxSpacing); + m_SurfaceBasedInterpolatorController->SetMinSpacing(minSpacing); + m_SurfaceBasedInterpolatorController->SetDistanceImageVolume(50000); + + int ret = QMessageBox::Yes; + + if (m_SurfaceBasedInterpolatorController->EstimatePortionOfNeededMemory() > 0.5) + { + QMessageBox msgBox; + msgBox.setText("Due to short handed system memory the 3D interpolation may be very slow!"); + msgBox.setInformativeText("Are you sure you want to activate the 3D interpolation?"); + msgBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes); + ret = msgBox.exec(); + } + + if (m_Watcher.isRunning()) + m_Watcher.waitForFinished(); + + if (ret == QMessageBox::Yes) + { + m_Future = QtConcurrent::run(this, &QmitkSurfaceBasedInterpolatorWidget::OnRunInterpolation); + m_Watcher.setFuture(m_Future); + } + } + else + { + if (m_DataStorage->Exists(m_InterpolatedSurfaceNode)) + { + m_DataStorage->Remove( m_InterpolatedSurfaceNode ); + } + if (m_DataStorage->Exists(m_3DContourNode)) + { + m_DataStorage->Remove( m_3DContourNode ); + } + + mitk::UndoController::GetCurrentUndoModel()->Clear(); + } + + m_Activated = enabled; + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +void QmitkSurfaceBasedInterpolatorWidget::OnAcceptInterpolationClicked() +{ + if (m_InterpolatedSurfaceNode.IsNotNull() && m_InterpolatedSurfaceNode->GetData()) + { + m_WorkingImage->SurfaceStamp(dynamic_cast(m_InterpolatedSurfaceNode->GetData()), false); + this->ShowInterpolationResult(false); + } +} + +void QmitkSurfaceBasedInterpolatorWidget::OnSurfaceInterpolationInfoChanged(const itk::EventObject& /*e*/) +{ + if (m_Activated) + { + if (m_Watcher.isRunning()) + m_Watcher.waitForFinished(); + + m_Future = QtConcurrent::run(this, &QmitkSurfaceBasedInterpolatorWidget::OnRunInterpolation); + m_Watcher.setFuture(m_Future); + } +} diff --git a/Modules/SegmentationUI/Qmitk/QmitkSurfaceBasedInterpolatorWidget.h b/Modules/SegmentationUI/Qmitk/QmitkSurfaceBasedInterpolatorWidget.h new file mode 100644 index 0000000000..8badd7b121 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSurfaceBasedInterpolatorWidget.h @@ -0,0 +1,126 @@ +/*=================================================================== + +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 QmitkSurfaceBasedInterpolatorWidgetWidget_h_Included +#define QmitkSurfaceBasedInterpolatorWidgetWidget_h_Included + +#include "MitkSegmentationUIExports.h" +#include "mitkDataNode.h" +#include "mitkDataStorage.h" +#include "mitkSurfaceBasedInterpolationController.h" +#include "mitkLabelSetImage.h" + +#include + +#include + +//For running 3D interpolation in background +#include +#include +#include +#include + +#include "ui_QmitkSurfaceBasedInterpolatorWidgetGUIControls.h" + +namespace mitk { + class ToolManager; +} + +/** + \brief GUI for surface-based interpolation. + + \ingroup ToolManagerEtAl + \ingroup Widgets + + \sa QmitkInteractiveSegmentation + \sa mitk::SurfaceBasedInterpolationController + + There is a separate page describing the general design of QmitkInteractiveSegmentation: \ref QmitkInteractiveSegmentationTechnicalPage + + QmitkSurfaceBasedInterpolatorWidgetController is responsible to watch the GUI, to notice, which slice is currently + visible. It triggers generation of interpolation suggestions and also triggers acception of suggestions. +*/ +class MitkSegmentationUI_EXPORT QmitkSurfaceBasedInterpolatorWidget : public QWidget +{ + Q_OBJECT + + public: + + QmitkSurfaceBasedInterpolatorWidget(QWidget* parent = 0, const char* name = 0); + virtual ~QmitkSurfaceBasedInterpolatorWidget(); + + void SetDataStorage(mitk::DataStorage& storage); + + void OnToolManagerWorkingDataModified(); + + /** + Just public because it is called by itk::Commands. You should not need to call this. + */ + void OnSurfaceInterpolationInfoChanged(const itk::EventObject&); + + /** + * @brief Set the visibility of the interpolation + */ + void ShowInterpolationResult(bool); + + Ui::QmitkSurfaceBasedInterpolatorWidgetGUIControls m_Controls; + + public slots: + + /** + \brief Reaction to "Start/Stop" button click + */ + void OnToggleWidgetActivation(bool); + + protected slots: + + void OnAcceptInterpolationClicked(); + + void OnSurfaceInterpolationFinished(); + + void OnRunInterpolation(); + + void OnShowMarkers(bool); + + void StartUpdateInterpolationTimer(); + + void StopUpdateInterpolationTimer(); + + void ChangeSurfaceColor(); + +private: + + mitk::SurfaceBasedInterpolationController::Pointer m_SurfaceBasedInterpolatorController; + + mitk::ToolManager* m_ToolManager; + + bool m_Activated; + + unsigned int m_SurfaceInterpolationInfoChangedObserverTag; + + mitk::DataNode::Pointer m_InterpolatedSurfaceNode; + mitk::DataNode::Pointer m_3DContourNode; + + mitk::DataStorage::Pointer m_DataStorage; + + mitk::LabelSetImage::Pointer m_WorkingImage; + + QFuture m_Future; + QFutureWatcher m_Watcher; + QTimer* m_Timer; +}; + +#endif diff --git a/Modules/SegmentationUI/Qmitk/QmitkSurfaceBasedInterpolatorWidgetGUIControls.ui b/Modules/SegmentationUI/Qmitk/QmitkSurfaceBasedInterpolatorWidgetGUIControls.ui new file mode 100644 index 0000000000..7f639be5fb --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSurfaceBasedInterpolatorWidgetGUIControls.ui @@ -0,0 +1,136 @@ + + + QmitkSurfaceBasedInterpolatorWidgetGUIControls + + + + 0 + 0 + 248 + 94 + + + + + 0 + 0 + + + + + 0 + 0 + + + + Surface-Based Interpolation + + + + + + + 2 + + + QLayout::SetMinimumSize + + + 6 + + + + + 6 + + + + + true + + + + 0 + 0 + + + + Start/Stop the 3D interpolation utility + + + Start + + + + :/Qmitk/Start.png + :/Qmitk/Stop.png:/Qmitk/Start.png + + + + 32 + 32 + + + + true + + + false + + + Qt::ToolButtonTextUnderIcon + + + Qt::NoArrow + + + + + + + true + + + + 0 + 0 + + + + Accept + + + + :/Qmitk/AcceptSurfaceInterpolation.png:/Qmitk/AcceptSurfaceInterpolation.png + + + + 32 + 32 + + + + Qt::ToolButtonTextUnderIcon + + + + + + + + + true + + + show position nodes + + + + + + + + + + + diff --git a/Modules/SegmentationUI/Qmitk/QmitkSurfaceStampWidget.cpp b/Modules/SegmentationUI/Qmitk/QmitkSurfaceStampWidget.cpp new file mode 100644 index 0000000000..be4993c966 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSurfaceStampWidget.cpp @@ -0,0 +1,121 @@ +/*=================================================================== + +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 "QmitkSurfaceStampWidget.h" + +#include +#include +#include + +#include + + +QmitkSurfaceStampWidget::QmitkSurfaceStampWidget(QWidget* parent, const char* /*name*/) +: QWidget(parent), +m_ToolManager(NULL), +m_DataStorage(NULL) +{ + m_Controls.setupUi(this); + m_Controls.m_InformationWidget->hide(); + + m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); + assert(m_ToolManager); + m_ToolManager->ActivateTool(-1); + + mitk::NodePredicateAnd::Pointer m_SurfacePredicate = mitk::NodePredicateAnd::New(); + m_SurfacePredicate->AddPredicate(mitk::NodePredicateDataType::New("Surface")); + m_SurfacePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); + + m_Controls.m_cbSurfaceNodeSelector->SetPredicate( m_SurfacePredicate ); + + connect(m_Controls.m_pbStamp, SIGNAL(clicked()), this, SLOT(OnStamp())); + connect( m_Controls.m_cbShowInformation, SIGNAL(toggled(bool)), this, SLOT(OnShowInformation(bool)) ); + m_Controls.m_InformationWidget->hide(); +} + +QmitkSurfaceStampWidget::~QmitkSurfaceStampWidget() +{ +} + +void QmitkSurfaceStampWidget::SetDataStorage( mitk::DataStorage* storage ) +{ + m_DataStorage = storage; + m_Controls.m_cbSurfaceNodeSelector->SetDataStorage(m_DataStorage); +} + +void QmitkSurfaceStampWidget::OnStamp() +{ + mitk::DataNode* surfaceNode = m_Controls.m_cbSurfaceNodeSelector->GetSelectedNode(); + + if (!surfaceNode) + { + QMessageBox::information(this, "Surface Stamp", "Please load and select a surface before starting some action."); + return; + } + + m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); + assert(m_ToolManager); + m_ToolManager->ActivateTool(-1); + + mitk::Surface* surface = dynamic_cast(surfaceNode->GetData() ); + if ( !surface ) + { + QMessageBox::information(this, "Surface Stamp", "Please load and select a surface before starting some action."); + return; + } + + mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + + if (!workingNode) + { + QMessageBox::information( this, "Surface Stamp", "Please load and select a segmentation before starting some action."); + return; + } + + mitk::LabelSetImage* workingImage = dynamic_cast( workingNode->GetData() ); + + if (!workingImage) + { + QMessageBox::information( this, "Surface Stamp", "Please load and select a segmentation before starting some action."); + return; + } + + QApplication::setOverrideCursor( QCursor(Qt::BusyCursor) ); + + try + { + workingImage->SurfaceStamp( surface, m_Controls.m_chkOverwrite->isChecked() ); + } + catch ( mitk::Exception & e ) + { + QApplication::restoreOverrideCursor(); + MITK_ERROR << "Exception caught: " << e.GetDescription(); + QMessageBox::information( this, "Surface Stamp", "Could not stamp the selected surface.\n See error log for details.\n"); + return; + } + + QApplication::restoreOverrideCursor(); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +void QmitkSurfaceStampWidget::OnShowInformation(bool on) +{ + if (on) + m_Controls.m_InformationWidget->show(); + else + m_Controls.m_InformationWidget->hide(); +} diff --git a/Modules/SegmentationUI/Qmitk/QmitkSurfaceStampWidget.h b/Modules/SegmentationUI/Qmitk/QmitkSurfaceStampWidget.h new file mode 100644 index 0000000000..ec70d23829 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSurfaceStampWidget.h @@ -0,0 +1,64 @@ +/*=================================================================== + +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 QmitkSurfaceStampWidget_h_Included +#define QmitkSurfaceStampWidget_h_Included + +#include "MitkSegmentationUIExports.h" + +#include + +#include "ui_QmitkSurfaceStampWidgetGUIControls.h" + +namespace mitk { + class ToolManager; +} + +/** + \brief GUI for surface-based interpolation. + + \ingroup ToolManagerEtAl + \ingroup Widgets +*/ + +class MitkSegmentationUI_EXPORT QmitkSurfaceStampWidget : public QWidget +{ + Q_OBJECT + + public: + + QmitkSurfaceStampWidget(QWidget* parent = 0, const char* name = 0); + virtual ~QmitkSurfaceStampWidget(); + + + void SetDataStorage( mitk::DataStorage* storage ); + + protected slots: + + void OnShowInformation(bool); + + void OnStamp(); + +private: + + mitk::ToolManager* m_ToolManager; + + mitk::DataStorage* m_DataStorage; + + Ui::QmitkSurfaceStampWidgetGUIControls m_Controls; +}; + +#endif diff --git a/Modules/SegmentationUI/Qmitk/QmitkSurfaceStampWidgetGUIControls.ui b/Modules/SegmentationUI/Qmitk/QmitkSurfaceStampWidgetGUIControls.ui new file mode 100644 index 0000000000..2f7ff23dba --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSurfaceStampWidgetGUIControls.ui @@ -0,0 +1,139 @@ + + + QmitkSurfaceStampWidgetGUIControls + + + + 0 + 0 + 228 + 308 + + + + + 0 + 0 + + + + + 0 + 0 + + + + GUI Controls + + + + + + + 2 + + + 2 + + + + + + + force overwrite + + + + + + + Apply + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + usage information + + + + + + + + 0 + 0 + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">This functionality fills the interior of the selected surface with the active label. Other labels within the same region will be overwritten if they are not locked.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">Select a surface from the combo box above.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">Check &quot;Force Overwrite&quot; to force the filling of regions occupied with other labels.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">Press &quot;Apply&quot; to run the tool.</span></p></body></html> + + + Qt::AlignVCenter + + + true + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + QmitkDataStorageComboBox + QComboBox +
QmitkDataStorageComboBox.h
+
+
+ + + + +
diff --git a/Modules/SegmentationUI/files.cmake b/Modules/SegmentationUI/files.cmake index 1ab07d65fa..7f08340168 100644 --- a/Modules/SegmentationUI/files.cmake +++ b/Modules/SegmentationUI/files.cmake @@ -1,63 +1,84 @@ set( CPP_FILES Qmitk/QmitkAdaptiveRegionGrowingToolGUI.cpp Qmitk/QmitkBinaryThresholdToolGUI.cpp Qmitk/QmitkBinaryThresholdULToolGUI.cpp Qmitk/QmitkCalculateGrayValueStatisticsToolGUI.cpp Qmitk/QmitkConfirmSegmentationDialog.cpp Qmitk/QmitkCopyToClipBoardDialog.cpp Qmitk/QmitkDrawPaintbrushToolGUI.cpp Qmitk/QmitkErasePaintbrushToolGUI.cpp Qmitk/QmitkFastMarchingTool3DGUI.cpp Qmitk/QmitkFastMarchingToolGUI.cpp Qmitk/QmitkLiveWireTool2DGUI.cpp Qmitk/QmitkNewSegmentationDialog.cpp Qmitk/QmitkOtsuTool3DGUI.cpp Qmitk/QmitkPaintbrushToolGUI.cpp Qmitk/QmitkPickingToolGUI.cpp Qmitk/QmitkPixelManipulationToolGUI.cpp Qmitk/QmitkRegionGrow3DToolGUI.cpp Qmitk/QmitkSlicesInterpolator.cpp Qmitk/QmitkToolGUI.cpp Qmitk/QmitkToolGUIArea.cpp Qmitk/QmitkToolReferenceDataSelectionBox.cpp Qmitk/QmitkToolRoiDataSelectionBox.cpp Qmitk/QmitkToolSelectionBox.cpp Qmitk/QmitkToolWorkingDataSelectionBox.cpp Qmitk/QmitkWatershedToolGUI.cpp +#Added from ML +Qmitk/QmitkLabelSetWidget.cpp +Qmitk/QmitkSurfaceStampWidget.cpp +Qmitk/QmitkMaskStampWidget.cpp +Qmitk/QmitkSliceBasedInterpolatorWidget.cpp +Qmitk/QmitkSurfaceBasedInterpolatorWidget.cpp +Qmitk/QmitkSearchLabelDialog.cpp ) set(MOC_H_FILES Qmitk/QmitkAdaptiveRegionGrowingToolGUI.h Qmitk/QmitkBinaryThresholdToolGUI.h Qmitk/QmitkBinaryThresholdULToolGUI.h Qmitk/QmitkCalculateGrayValueStatisticsToolGUI.h Qmitk/QmitkConfirmSegmentationDialog.h Qmitk/QmitkCopyToClipBoardDialog.h Qmitk/QmitkDrawPaintbrushToolGUI.h Qmitk/QmitkErasePaintbrushToolGUI.h Qmitk/QmitkFastMarchingTool3DGUI.h Qmitk/QmitkFastMarchingToolGUI.h Qmitk/QmitkLiveWireTool2DGUI.h Qmitk/QmitkNewSegmentationDialog.h Qmitk/QmitkOtsuTool3DGUI.h Qmitk/QmitkPaintbrushToolGUI.h Qmitk/QmitkPickingToolGUI.h Qmitk/QmitkPixelManipulationToolGUI.h Qmitk/QmitkRegionGrow3DToolGUI.h Qmitk/QmitkSlicesInterpolator.h Qmitk/QmitkToolGUI.h Qmitk/QmitkToolGUIArea.h Qmitk/QmitkToolReferenceDataSelectionBox.h Qmitk/QmitkToolRoiDataSelectionBox.h Qmitk/QmitkToolSelectionBox.h Qmitk/QmitkToolWorkingDataSelectionBox.h Qmitk/QmitkWatershedToolGUI.h +#Added from ML +Qmitk/QmitkLabelSetWidget.h +Qmitk/QmitkSurfaceStampWidget.h +Qmitk/QmitkMaskStampWidget.h +Qmitk/QmitkSliceBasedInterpolatorWidget.h +Qmitk/QmitkSurfaceBasedInterpolatorWidget.h +Qmitk/QmitkSearchLabelDialog.h ) set(UI_FILES Qmitk/QmitkAdaptiveRegionGrowingToolGUIControls.ui Qmitk/QmitkConfirmSegmentationDialog.ui Qmitk/QmitkOtsuToolWidgetControls.ui Qmitk/QmitkPickingToolGUIControls.ui Qmitk/QmitkLiveWireTool2DGUIControls.ui +#Added from ML +Qmitk/QmitkLabelSetWidgetControls.ui +Qmitk/QmitkSurfaceStampWidgetGUIControls.ui +Qmitk/QmitkMaskStampWidgetGUIControls.ui +Qmitk/QmitkSliceBasedInterpolatorWidgetGUIControls.ui +Qmitk/QmitkSurfaceBasedInterpolatorWidgetGUIControls.ui +Qmitk/QmitkSearchLabelDialogGUI.ui ) diff --git a/Modules/SurfaceInterpolation/CMakeLists.txt b/Modules/SurfaceInterpolation/CMakeLists.txt index 843831ba5b..b6b1ac0ae5 100644 --- a/Modules/SurfaceInterpolation/CMakeLists.txt +++ b/Modules/SurfaceInterpolation/CMakeLists.txt @@ -1,7 +1,7 @@ MITK_CREATE_MODULE( - DEPENDS MitkAlgorithmsExt + DEPENDS MitkAlgorithmsExt MitkContourModel PACKAGE_DEPENDS Eigen WARNINGS_AS_ERRORS ) add_subdirectory(Testing) diff --git a/Modules/SurfaceInterpolation/files.cmake b/Modules/SurfaceInterpolation/files.cmake index 0dd9c14810..c10f666d20 100644 --- a/Modules/SurfaceInterpolation/files.cmake +++ b/Modules/SurfaceInterpolation/files.cmake @@ -1,6 +1,8 @@ set(CPP_FILES mitkComputeContourSetNormalsFilter.cpp mitkCreateDistanceImageFromSurfaceFilter.cpp mitkReduceContourSetFilter.cpp mitkSurfaceInterpolationController.cpp +#Added from ML + mitkSurfaceBasedInterpolationController.cpp ) \ No newline at end of file diff --git a/Modules/SurfaceInterpolation/mitkSurfaceBasedInterpolationController.cpp b/Modules/SurfaceInterpolation/mitkSurfaceBasedInterpolationController.cpp new file mode 100644 index 0000000000..ee80180e03 --- /dev/null +++ b/Modules/SurfaceInterpolation/mitkSurfaceBasedInterpolationController.cpp @@ -0,0 +1,300 @@ +/*=================================================================== + +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 "mitkSurfaceBasedInterpolationController.h" + +#include "mitkMemoryUtilities.h" +#include "mitkImageAccessByItk.h" +#include "mitkImageCast.h" +#include "mitkImageToSurfaceFilter.h" +#include "mitkRestorePlanePositionOperation.h" +#include "mitkContourModelToSurfaceFilter.h" +#include "mitkInteractionConst.h" +#include "mitkColorProperty.h" +#include "mitkProperties.h" +#include "mitkIOUtil.h" +#include "mitkComputeContourSetNormalsFilter.h" + +#include "vtkPolyData.h" +#include "vtkSmartPointer.h" +#include "vtkAppendPolyData.h" +#include "mitkVtkRepresentationProperty.h" +#include "vtkProperty.h" + +#include + +mitk::SurfaceBasedInterpolationController::SurfaceBasedInterpolationController() : +m_MinSpacing(1.0), +m_MaxSpacing(1.0), +m_WorkingImage(NULL), +m_ActiveLabel(0) +{ + this->Initialize(); +} + +mitk::SurfaceBasedInterpolationController::~SurfaceBasedInterpolationController() +{ + ContourListMap::iterator it = m_MapOfContourLists.begin(); + for (; it != m_MapOfContourLists.end(); it++) + { + for (unsigned int j = 0; j < m_MapOfContourLists[(*it).first].size(); ++j) + { + delete(m_MapOfContourLists[(*it).first].at(j).second); + } + m_MapOfContourLists.erase(it); + } +} + +void mitk::SurfaceBasedInterpolationController::Initialize() +{ + m_InterpolateSurfaceFilter = CreateDistanceImageFromSurfaceFilter::New(); + m_InterpolateSurfaceFilter->SetUseProgressBar(false); + + m_Contours = Surface::New(); + + m_InterpolationResult = NULL; +} + +mitk::SurfaceBasedInterpolationController* mitk::SurfaceBasedInterpolationController::GetInstance() +{ + static mitk::SurfaceBasedInterpolationController* m_Instance; + + if ( m_Instance == 0) + { + m_Instance = new SurfaceBasedInterpolationController(); + } + + return m_Instance; +} + +void mitk::SurfaceBasedInterpolationController::AddNewContour(mitk::ContourModel::Pointer newContour, RestorePlanePositionOperation* op) +{ + if (m_ActiveLabel == 0) + return; + + AffineTransform3D::Pointer transform = AffineTransform3D::New(); + transform = op->GetTransform(); + + mitk::Vector3D direction = op->GetDirectionVector(); + int pos(-1); + + for (unsigned int i=0; i < m_MapOfContourLists[m_ActiveLabel].size(); i++) + { + itk::Matrix diffM = transform->GetMatrix()-m_MapOfContourLists[m_ActiveLabel].at(i).second->GetTransform()->GetMatrix(); + bool isSameMatrix(true); + for (unsigned int j = 0; j < 3; j++) + { + if (fabs(diffM[j][0]) > 0.0001 && fabs(diffM[j][1]) > 0.0001 && fabs(diffM[j][2]) > 0.0001) + { + isSameMatrix = false; + break; + } + } + itk::Vector diffV = m_MapOfContourLists[m_ActiveLabel].at(i).second->GetTransform()->GetOffset()-transform->GetOffset(); + if ( isSameMatrix && m_MapOfContourLists[m_ActiveLabel].at(i).second->GetPos() == op->GetPos() && (fabs(diffV[0]) < 0.0001 && fabs(diffV[1]) < 0.0001 && fabs(diffV[2]) < 0.0001) ) + { + pos = i; + break; + } + } + + if (pos == -1 && newContour->GetNumberOfVertices() > 0) // add a new contour + { + mitk::RestorePlanePositionOperation* newOp = new mitk::RestorePlanePositionOperation (OpRESTOREPLANEPOSITION, op->GetWidth(), + op->GetHeight(), op->GetSpacing(), op->GetPos(), direction, transform); + ContourPositionPair newData = std::make_pair(newContour,newOp); + m_MapOfContourLists[m_ActiveLabel].push_back(newData); + } + else if (pos != -1) // replace existing contour + { + m_MapOfContourLists[m_ActiveLabel].at(pos).first = newContour; + } + + this->Modified(); +} + +void mitk::SurfaceBasedInterpolationController::Interpolate() +{ + if (m_MapOfContourLists[m_ActiveLabel].size() < 2) + { + //If no interpolation is possible reset the interpolation result + m_InterpolationResult = NULL; + return; + } + + m_InterpolateSurfaceFilter->Reset(); + + //MLI TODO + //m_InterpolateSurfaceFilter->SetReferenceImage( m_WorkingImage ); + + //CreateDistanceImageFromSurfaceFilter::Pointer interpolateSurfaceFilter = CreateDistanceImageFromSurfaceFilter::New(); + vtkSmartPointer polyDataAppender = vtkSmartPointer::New(); + + for (unsigned int i=0; i < m_MapOfContourLists[m_ActiveLabel].size(); i++) + { + mitk::ContourModelToSurfaceFilter::Pointer converter = mitk::ContourModelToSurfaceFilter::New(); + converter->SetInput(m_MapOfContourLists[m_ActiveLabel].at(i).first); + converter->Update(); + + mitk::Surface::Pointer surface = converter->GetOutput(); + surface->DisconnectPipeline(); + + ReduceContourSetFilter::Pointer reduceFilter = ReduceContourSetFilter::New(); + reduceFilter->SetUseProgressBar(false); + reduceFilter->SetInput(surface); + reduceFilter->SetMinSpacing(m_MinSpacing); + reduceFilter->SetMaxSpacing(m_MaxSpacing); + reduceFilter->Update(); + + ComputeContourSetNormalsFilter::Pointer normalsFilter = ComputeContourSetNormalsFilter::New(); + normalsFilter->SetUseProgressBar(false); + normalsFilter->SetInput(reduceFilter->GetOutput()); + normalsFilter->SetMaxSpacing(m_MaxSpacing); + //MLI TODO + //normalsFilter->SetSegmentationBinaryImage(m_WorkingImage, m_ActiveLabel); + normalsFilter->Update(); + + m_InterpolateSurfaceFilter->SetInput(i, normalsFilter->GetOutput()); + + polyDataAppender->AddInputData(reduceFilter->GetOutput()->GetVtkPolyData()); + } + + polyDataAppender->Update(); + m_Contours->SetVtkPolyData(polyDataAppender->GetOutput()); + + // update the filter and get the resulting distance-image + m_InterpolateSurfaceFilter->Update(); + Image::Pointer distanceImage = m_InterpolateSurfaceFilter->GetOutput(); + if (distanceImage.IsNull()) + { + //If no interpolation is possible reset the interpolation result + m_InterpolationResult = NULL; + return; + } + + // create a surface from the distance-image + mitk::ImageToSurfaceFilter::Pointer imageToSurfaceFilter = mitk::ImageToSurfaceFilter::New(); + imageToSurfaceFilter->SetInput( distanceImage ); + imageToSurfaceFilter->SetThreshold( 0 ); + imageToSurfaceFilter->SetSmooth(true); + imageToSurfaceFilter->SetSmoothIteration(20); + imageToSurfaceFilter->Update(); + m_InterpolationResult = imageToSurfaceFilter->GetOutput(); + + m_InterpolationResult->DisconnectPipeline(); +} + +mitk::Surface::Pointer mitk::SurfaceBasedInterpolationController::GetInterpolationResult() +{ + return m_InterpolationResult; +} + +mitk::Surface* mitk::SurfaceBasedInterpolationController::GetContoursAsSurface() +{ + return m_Contours; +} + +void mitk::SurfaceBasedInterpolationController::SetMinSpacing(double minSpacing) +{ + m_MinSpacing = minSpacing; +} + +void mitk::SurfaceBasedInterpolationController::SetMaxSpacing(double maxSpacing) +{ + m_MaxSpacing = maxSpacing; +} + +void mitk::SurfaceBasedInterpolationController::SetDistanceImageVolume(unsigned int value) +{ + m_DistanceImageVolume = value; +} + +void mitk::SurfaceBasedInterpolationController::SetWorkingImage(Image* workingImage) +{ + m_WorkingImage = workingImage; +} + +mitk::Image* mitk::SurfaceBasedInterpolationController::GetImage() +{ + return m_InterpolateSurfaceFilter->GetOutput(); +} + +double mitk::SurfaceBasedInterpolationController::EstimatePortionOfNeededMemory() +{ + double numberOfPoints = 0.0; + for (unsigned int i = 0; i < m_MapOfContourLists[m_ActiveLabel].size(); i++) + { + numberOfPoints += m_MapOfContourLists[m_ActiveLabel].at(i).first->GetNumberOfVertices()*3; + } + + double sizeOfPoints = pow(numberOfPoints,2)*sizeof(double); + double totalMem = mitk::MemoryUtilities::GetTotalSizeOfPhysicalRam(); + double percentage = sizeOfPoints/totalMem; + return percentage; +} + +void mitk::SurfaceBasedInterpolationController::SetActiveLabel(int activeLabel) +{ + if (m_ActiveLabel == activeLabel) + return; + + if (activeLabel == 0) + return; + + m_ActiveLabel = activeLabel; + + ContourListMap::iterator it = m_MapOfContourLists.find(m_ActiveLabel); + + if (it == m_MapOfContourLists.end()) + { + ContourPositionPairList newList; + m_MapOfContourLists.insert(std::pair(m_ActiveLabel, newList)); + m_InterpolationResult = NULL; + } + + this->Modified(); +} + +/* +void mitk::SurfaceBasedInterpolationController::RemoveSegmentationFromContourList(mitk::Image *segmentation) +{ + if (segmentation != 0) + { + m_MapOfContourLists.erase(segmentation); + if (m_SelectedSegmentation == segmentation) + { + SetSegmentationImage(NULL); + m_SelectedSegmentation = 0; + } + } +} +*/ + +/* +void mitk::SurfaceBasedInterpolationController::OnSegmentationDeleted(const itk::Object *caller, const itk::EventObject &event) +{ + mitk::Image* tempImage = dynamic_cast(const_cast(caller)); + if (tempImage) + { + RemoveSegmentationFromContourList(tempImage); + if (tempImage == m_SelectedSegmentation) + { + SetSegmentationImage(NULL); + m_SelectedSegmentation = 0; + } + } +} +*/ \ No newline at end of file diff --git a/Modules/SurfaceInterpolation/mitkSurfaceBasedInterpolationController.h b/Modules/SurfaceInterpolation/mitkSurfaceBasedInterpolationController.h new file mode 100644 index 0000000000..b88ce11be2 --- /dev/null +++ b/Modules/SurfaceInterpolation/mitkSurfaceBasedInterpolationController.h @@ -0,0 +1,150 @@ +/*=================================================================== + +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 mitkSurfaceBasedInterpolationController_h_Included +#define mitkSurfaceBasedInterpolationController_h_Included + +//#include "mitkCommon.h" +#include +#include "mitkRestorePlanePositionOperation.h" +#include "mitkSurface.h" +#include "mitkContourModel.h" + +#include "mitkCreateDistanceImageFromSurfaceFilter.h" +#include "mitkReduceContourSetFilter.h" + +#include "mitkProgressBar.h" + +namespace mitk +{ + class RestorePlanePositionOperation; + + class MitkSurfaceInterpolation_EXPORT SurfaceBasedInterpolationController : public itk::Object + { + public: + + mitkClassMacro(SurfaceBasedInterpolationController, itk::Object) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + static SurfaceBasedInterpolationController* GetInstance(); + + /** + * Adds a new extracted contour to the list + */ + void AddNewContour(ContourModel::Pointer newContour, RestorePlanePositionOperation *op); + + /** + * Launches the interpolation method. A surface mesh is generated out of the given extracted contours. + */ + void Interpolate(); + + /** + * Retrieves a surface mesh resulting from the interpolation of the given extracted contours. + */ + mitk::Surface::Pointer GetInterpolationResult(); + + /** + * Sets the minimum spacing of the current selected segmentation + * This is needed since the contour points we reduced before, are used to interpolate the surface + */ + void SetMinSpacing(double minSpacing); + + /** + * Sets the minimum spacing of the current selected segmentation + * This is needed since the contour points we reduced before, are used to interpolate the surface + */ + void SetMaxSpacing(double maxSpacing); + + /** + * Sets the volume i.e. the number of pixels that the distance image should have + * By evaluation we found out that 50.000 pixel delivers a good result + */ + void SetDistanceImageVolume(unsigned int value); + + /** + * Sets the working image used by the interpolation method. + * This is needed because the calculation of the normals needs to now wheather a normal points toward the inside of a segmentation or not + */ + void SetWorkingImage(Image* workingImage); + + /** + * Retrieves the input contours as a mitk::Surface + */ + Surface* GetContoursAsSurface(); + + /** + * Sets the current list of contour points which is used for the surface interpolation + * @param activeLabel The active label in the current working image + */ + void SetActiveLabel(int activeLabel); + + mitk::Image* GetImage(); + + /** + * Estimates the memory that is needed to build up the equation system for the interpolation. + * \returns The percentage of the real memory which will be used by the interpolation calculation + */ + double EstimatePortionOfNeededMemory(); + + protected: + + SurfaceBasedInterpolationController(); + + ~SurfaceBasedInterpolationController(); + + void Initialize(); + + private: + +// void OnSegmentationDeleted(const itk::Object *caller, const itk::EventObject &event); + /* + struct ContourPositionPair { + ContourModel::Pointer contour; + RestorePlanePositionOperation* position; + }; + */ + typedef std::pair< ContourModel::Pointer, RestorePlanePositionOperation* > ContourPositionPair; + typedef std::vector< ContourPositionPair > ContourPositionPairList; + typedef std::map ContourListMap; + + //ReduceContourSetFilter::Pointer m_ReduceFilter; + //ComputeContourSetNormalsFilter::Pointer m_NormalsFilter; + CreateDistanceImageFromSurfaceFilter::Pointer m_InterpolateSurfaceFilter; + + double m_MinSpacing; + double m_MaxSpacing; + + unsigned int m_DistanceImageVolume; + + Image* m_WorkingImage; + + Surface::Pointer m_Contours; + +// vtkSmartPointer m_PolyData; + + ContourListMap m_MapOfContourLists; + + mitk::Surface::Pointer m_InterpolationResult; + +// unsigned int m_CurrentNumberOfReducedContours; + + int m_ActiveLabel; + +// std::map m_SegmentationObserverTags; + }; +} +#endif diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/files.cmake b/Plugins/org.mitk.gui.qt.multilabelsegmentation/files.cmake index d9c8851988..7ce0480bd4 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/files.cmake +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/files.cmake @@ -1,90 +1,87 @@ set(SRC_CPP_FILES QmitkMultiLabelSegmentationPreferencePage.cpp - QmitkLabelSetWidget.cpp ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkMultiLabelSegmentationView.cpp QmitkThresholdAction.cpp QmitkCreatePolygonModelAction.cpp QmitkAutocropAction.cpp QmitkConvertSurfaceToLabelAction.cpp QmitkConvertMaskToLabelAction.cpp QmitkConvertToMultiLabelSegmentationAction.cpp QmitkCreateMultiLabelSegmentationAction.cpp QmitkLoadMultiLabelPresetAction.cpp QmitkCreateMultiLabelPresetAction.cpp Common/QmitkDataSelectionWidget.cpp SegmentationUtilities/QmitkMultiLabelSegmentationUtilitiesView.cpp SegmentationUtilities/QmitkSegmentationUtilityWidget.cpp SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.cpp SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp ) set(UI_FILES src/internal/QmitkMultiLabelSegmentationControls.ui src/internal/Common/QmitkDataSelectionWidgetControls.ui src/internal/SegmentationUtilities/QmitkMultiLabelSegmentationUtilitiesViewControls.ui src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidgetControls.ui src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidgetControls.ui src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidgetControls.ui src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidgetControls.ui - src/QmitkLabelSetWidgetControls.ui ) set(MOC_H_FILES src/QmitkMultiLabelSegmentationPreferencePage.h - src/QmitkLabelSetWidget.h src/internal/mitkPluginActivator.h src/internal/QmitkMultiLabelSegmentationView.h src/internal/QmitkThresholdAction.h src/internal/QmitkCreatePolygonModelAction.h src/internal/QmitkAutocropAction.h src/internal/QmitkConvertSurfaceToLabelAction.h src/internal/QmitkLoadMultiLabelPresetAction.h src/internal/QmitkCreateMultiLabelPresetAction.h src/internal/QmitkConvertMaskToLabelAction.h src/internal/QmitkConvertToMultiLabelSegmentationAction.h src/internal/QmitkCreateMultiLabelSegmentationAction.h src/internal/Common/QmitkDataSelectionWidget.h src/internal/SegmentationUtilities/QmitkMultiLabelSegmentationUtilitiesView.h src/internal/SegmentationUtilities/QmitkSegmentationUtilityWidget.h src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.h src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.h src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.h src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.h ) set(CACHED_RESOURCE_FILES resources/multilabelsegmentation.png resources/MultiLabelSegmentationUtilities_48x48.png plugin.xml ) set(QRC_FILES resources/multilabelsegmentation.qrc resources/MultiLabelSegmentationUtilities.qrc resources/MorphologicalOperationsWidget.qrc resources/BooleanOperationsWidget.qrc ) set(CPP_FILES) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) #usFunctionEmbedResources( #CPP_FILES # LIBRARY_NAME "liborg_mitk_gui_qt_multilabelsegmentation" #ROOT_DIR resources #FILES Interactions/SegmentationInteraction.xml # Interactions/ConfigSegmentation.xml #) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkCreateMultiLabelPresetAction.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkCreateMultiLabelPresetAction.cpp index bf09d77e7c..bf0e1c3e95 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkCreateMultiLabelPresetAction.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkCreateMultiLabelPresetAction.cpp @@ -1,84 +1,84 @@ /*=================================================================== 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 "QmitkCreateMultiLabelPresetAction.h" #include "mitkLabelSetImage.h" #include "QMessageBox" #include #include "QFileDialog" -#include "mitkLabelSetImageWriter.h" +//MLI TODO +//#include "mitkLabelSetImageWriter.h" #include "tinyxml.h" QmitkCreateMultiLabelPresetAction::QmitkCreateMultiLabelPresetAction() { } QmitkCreateMultiLabelPresetAction::~QmitkCreateMultiLabelPresetAction() { } void QmitkCreateMultiLabelPresetAction::Run( const QList &selectedNodes ) { foreach ( mitk::DataNode::Pointer referenceNode, selectedNodes ) { if (referenceNode.IsNotNull()) { - mitk::LabelSetImage::Pointer referenceImage = dynamic_cast( referenceNode->GetData() ); assert(referenceImage); if(referenceImage->GetNumberOfLabels() <= 1) { QMessageBox::information(NULL, "Create LabelSetImage Preset", "Could not create a LabelSetImage preset.\nNo Labels defined!\n");\ return; } std::string sName = referenceNode->GetName(); QString qName; qName.sprintf("%s.lsetp",sName.c_str()); QString filename = QFileDialog::getSaveFileName( NULL,"save file dialog",QString(),"LabelSet Preset(*.lsetp)"); if ( filename.isEmpty() ) return; - - bool wasSaved = mitk::LabelSetImageWriter::SaveLabelSetImagePreset(filename.toStdString(),referenceImage); + //MLI TODO + bool wasSaved;// = mitk::LabelSetImageWriter::SaveLabelSetImagePreset(filename.toStdString(),referenceImage); if(!wasSaved) { QMessageBox::information(NULL, "Create LabelSetImage Preset", "Could not save a LabelSetImage preset as Xml.\n");\ return; } } } } void QmitkCreateMultiLabelPresetAction::SetDataStorage(mitk::DataStorage* dataStorage) { m_DataStorage = dataStorage; } void QmitkCreateMultiLabelPresetAction::SetFunctionality(berry::QtViewPart* /*functionality*/) { //not needed } void QmitkCreateMultiLabelPresetAction::SetSmoothed(bool smoothed) { //not needed } void QmitkCreateMultiLabelPresetAction::SetDecimated(bool decimated) { //not needed -} +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp index 62a81db415..a319ad5a4e 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp @@ -1,895 +1,894 @@ /*=================================================================== 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 "QmitkMultiLabelSegmentationView.h" // blueberry #include #include // mitk #include "mitkLabelSetImage.h" #include "mitkStatusBar.h" #include "mitkApplicationCursor.h" #include "mitkToolManagerProvider.h" //#include "mitkSegmentationObjectFactory.h" #include "mitkSegTool2D.h" #include "mitkPlanePositionManager.h" #include "mitkPluginActivator.h" #include "mitkInteractionEventObserver.h" // Qmitk #include "QmitkMultiLabelSegmentationOrganNamesHandling.cpp" #include "QmitkRenderWindow.h" #include "QmitkNewSegmentationDialog.h" // us #include #include #include #include #include // Qt #include #include #include #include #include "tinyxml.h" #include const std::string QmitkMultiLabelSegmentationView::VIEW_ID = "org.mitk.views.multilabelsegmentation"; QmitkMultiLabelSegmentationView::QmitkMultiLabelSegmentationView() : m_Parent(NULL), m_IRenderWindowPart(NULL), m_ReferenceNode(NULL), m_WorkingNode(NULL), m_ToolManager(NULL), m_MouseCursorSet(false) { m_SegmentationPredicate = mitk::NodePredicateAnd::New(); m_SegmentationPredicate->AddPredicate(mitk::TNodePredicateDataType::New()); m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); m_SegmentationPredicate->AddPredicate(mitk::NodePredicateProperty::New("visible", mitk::BoolProperty::New(true))); mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isMask = mitk::NodePredicateAnd::New(isBinary, isImage); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isQbi = mitk::NodePredicateDataType::New("QBallImage"); mitk::NodePredicateOr::Pointer validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(isImage); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isQbi); m_ReferencePredicate = mitk::NodePredicateAnd::New(); m_ReferencePredicate->AddPredicate(validImages); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(m_SegmentationPredicate)); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(isMask)); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); } QmitkMultiLabelSegmentationView::~QmitkMultiLabelSegmentationView() { m_ToolManager->ActivateTool(-1); /* todo: check this m_Controls.m_SliceBasedInterpolatorWidget->EnableInterpolation(false); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); service->RemoveAllPlanePositions(); context->ungetService(ppmRef); */ m_ToolManager->SetReferenceData(NULL); m_ToolManager->SetWorkingData(NULL); m_ServiceRegistration.Unregister(); } void QmitkMultiLabelSegmentationView::CreateQtPartControl(QWidget* parent) { // setup the basic GUI of this view m_Parent = parent; m_Controls.setupUi(parent); m_Controls.m_cbReferenceNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.m_cbReferenceNodeSelector->SetPredicate(m_ReferencePredicate); m_Controls.m_cbReferenceNodeSelector->SetAutoSelectNewItems(true); m_Controls.m_cbWorkingNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.m_cbWorkingNodeSelector->SetPredicate(m_SegmentationPredicate); m_Controls.m_cbWorkingNodeSelector->SetAutoSelectNewItems(true); m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); assert(m_ToolManager); m_ToolManager->SetDataStorage( *(this->GetDataStorage()) ); m_ToolManager->InitializeTools(); //use the same ToolManager instance for our 3D Tools m_Controls.m_ManualToolSelectionBox3D->SetToolManager(*m_ToolManager); m_Controls.m_LabelSetWidget->SetDataStorage(this->GetDataStorage()); m_Controls.m_LabelSetWidget->SetOrganColors(mitk::OrganNamesHandling::GetDefaultOrganColorString()); m_Controls.m_LabelSetWidget->hide(); m_Controls.m_SurfaceBasedInterpolatorWidget->SetDataStorage( *(this->GetDataStorage()) ); m_Controls.m_SliceBasedInterpolatorWidget->SetDataStorage( *(this->GetDataStorage()) ); // all part of open source MITK m_Controls.m_ManualToolSelectionBox2D->SetGenerateAccelerators(true); m_Controls.m_ManualToolSelectionBox2D->SetToolGUIArea( m_Controls.m_ManualToolGUIContainer2D ); //m_Controls.m_ManualToolSelectionBox2D->SetDisplayedToolGroups(); m_Controls.m_ManualToolSelectionBox2D->SetDisplayedToolGroups("Add Subtract Fill Erase Paint Wipe 'Region Growing' FastMarching2D Correction 'Live Wire'");// todo: "Correction 'Live Wire'" m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible ); connect( m_Controls.m_ManualToolSelectionBox2D, SIGNAL(ToolSelected(int)), this, SLOT(OnManualTool2DSelected(int)) ); //setup 3D Tools m_Controls.m_ManualToolSelectionBox3D->SetGenerateAccelerators(true); m_Controls.m_ManualToolSelectionBox3D->SetToolGUIArea( m_Controls.m_ManualToolGUIContainer3D ); //specify tools to be added to 3D Tool area m_Controls.m_ManualToolSelectionBox3D->SetDisplayedToolGroups("Threshold 'Two Thresholds' 'Auto Threshold' 'Multiple Otsu'"); // todo add : FastMarching3D RegionGrowing Watershed m_Controls.m_ManualToolSelectionBox3D->SetLayoutColumns(2); m_Controls.m_ManualToolSelectionBox3D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible ); connect( m_Controls.m_cbReferenceNodeSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnReferenceSelectionChanged( const mitk::DataNode* ) ) ); connect( m_Controls.m_cbWorkingNodeSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnSegmentationSelectionChanged( const mitk::DataNode* ) ) ); connect( m_Controls.m_pbNewLabel, SIGNAL(clicked()), this, SLOT( OnNewLabel()) ); connect( m_Controls.m_pbNewSegmentationSession, SIGNAL(clicked()), this, SLOT( OnNewSegmentationSession()) ); connect( m_Controls.m_pbShowLabelTable, SIGNAL(toggled(bool)), this, SLOT( OnShowLabelTable(bool)) ); connect(m_Controls.m_LabelSetWidget, SIGNAL(goToLabel(const mitk::Point3D&)), this, SLOT(OnGoToLabel(const mitk::Point3D&)) ); connect(m_Controls.m_LabelSetWidget, SIGNAL(resetView()), this, SLOT(OnResetView()) ); connect( m_Controls.m_cbInterpolation, SIGNAL( activated (int) ), this, SLOT( OnInterpolationSelectionChanged(int) ) ); m_Controls.m_cbInterpolation->setCurrentIndex(0); m_Controls.m_swInterpolation->hide(); this->OnReferenceSelectionChanged( m_Controls.m_cbReferenceNodeSelector->GetSelectedNode() ); m_IRenderWindowPart = this->GetRenderWindowPart(); if (m_IRenderWindowPart) { QList controllers; controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls.m_SliceBasedInterpolatorWidget->SetSliceNavigationControllers(controllers); // m_Controls.m_LabelSetWidget->SetRenderWindowPart(this->m_IRenderWindowPart); } this->InitializeListeners(); connect( m_Controls.m_btAddLayer, SIGNAL(clicked()), this, SLOT( OnAddLayer()) ); connect( m_Controls.m_btDeleteLayer, SIGNAL(clicked()), this, SLOT( OnDeleteLayer()) ); connect( m_Controls.m_btPreviousLayer, SIGNAL(clicked()), this, SLOT( OnPreviousLayer()) ); connect( m_Controls.m_btNextLayer, SIGNAL(clicked()), this, SLOT( OnNextLayer()) ); connect( m_Controls.m_btLockExterior, SIGNAL(toggled(bool)), this, SLOT( OnLockExteriorToggled(bool)) ); connect( m_Controls.m_btDeactivateTool, SIGNAL(clicked()), this, SLOT( OnDeactivateActiveTool()) ); connect( m_Controls.m_cbActiveLayer, SIGNAL(currentIndexChanged(int)), this, SLOT( OnChangeLayer(int)) ); m_Controls.m_btAddLayer->hide(); m_Controls.m_btDeactivateTool->hide(); m_Controls.m_btDeleteLayer->hide(); m_Controls.m_btLockExterior->hide(); m_Controls.m_btNextLayer->hide(); m_Controls.m_btPreviousLayer->hide(); m_Controls.m_cbActiveLayer->hide(); - } void QmitkMultiLabelSegmentationView::InitializeListeners() { if (m_Interactor.IsNull()) { us::Module* module = us::GetModuleContext()->GetModule(); std::vector resources = module->FindResources("/", "*", true); for (std::vector::iterator iter = resources.begin(); iter != resources.end(); ++iter) { MITK_INFO << iter->GetResourcePath(); } m_Interactor = mitk::SegmentationInteractor::New(); if (!m_Interactor->LoadStateMachine("SegmentationInteraction.xml", module)) { MITK_WARN << "Error loading state machine"; } if (!m_Interactor->SetEventConfig ("ConfigSegmentation.xml", module)) { MITK_WARN << "Error loading state machine configuration"; } // Register as listener via micro services us::ServiceProperties props; props["name"] = std::string("SegmentationInteraction"); m_ServiceRegistration = us::GetModuleContext()->RegisterService(m_Interactor.GetPointer(), props); } } void QmitkMultiLabelSegmentationView::SetFocus () { } bool QmitkMultiLabelSegmentationView::CheckForSameGeometry(const mitk::Image *image1, const mitk::Image *image2) const { bool isSameGeometry(true); if (image1 && image2) { - mitk::Geometry3D* geo1 = image1->GetGeometry(); - mitk::Geometry3D* geo2 = image2->GetGeometry(); + mitk::BaseGeometry::Pointer geo1 = image1->GetGeometry(); + mitk::BaseGeometry::Pointer geo2 = image2->GetGeometry(); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetOrigin(), geo2->GetOrigin()); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(0), geo2->GetExtent(0)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(1), geo2->GetExtent(1)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(2), geo2->GetExtent(2)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetSpacing(), geo2->GetSpacing()); isSameGeometry = isSameGeometry && mitk::MatrixEqualElementWise(geo1->GetIndexToWorldTransform()->GetMatrix(), geo2->GetIndexToWorldTransform()->GetMatrix()); return isSameGeometry; } else { return false; } } void QmitkMultiLabelSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_IRenderWindowPart != renderWindowPart) { m_IRenderWindowPart = renderWindowPart; m_Parent->setEnabled(true); QList controllers; controllers.push_back(renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls.m_SliceBasedInterpolatorWidget->SetSliceNavigationControllers(controllers); } } void QmitkMultiLabelSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_ToolManager->ActivateTool(-1); m_IRenderWindowPart = 0; m_Parent->setEnabled(false); } int QmitkMultiLabelSegmentationView::GetSizeFlags(bool width) { if(!width) { return berry::Constants::MIN | berry::Constants::MAX | berry::Constants::FILL; } else { return 0; } } int QmitkMultiLabelSegmentationView::ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult) { if(width==false) { return 100; } else { return preferredResult; } } void QmitkMultiLabelSegmentationView::UpdateControls() { mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); bool hasReferenceNode = referenceNode != NULL; mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); bool hasWorkingNode = workingNode != NULL; m_Controls.m_pbNewSegmentationSession->setEnabled(false); m_Controls.m_pbNewLabel->setEnabled(false); m_Controls.m_gbInterpolation->setEnabled(false); m_Controls.m_SliceBasedInterpolatorWidget->setEnabled(false); m_Controls.m_SurfaceBasedInterpolatorWidget->setEnabled(false); m_Controls.m_btDeactivateTool->setEnabled(false); m_Controls.m_LabelSetWidget->setEnabled(false); m_Controls.m_btAddLayer->setEnabled(false); m_Controls.m_btDeleteLayer->setEnabled(false); m_Controls.m_cbActiveLayer->setEnabled(false); m_Controls.m_btPreviousLayer->setEnabled(false); m_Controls.m_btNextLayer->setEnabled(false); m_Controls.m_btLockExterior->setChecked(false); m_Controls.m_pbShowLabelTable->setChecked(false); m_Controls.m_ManualToolSelectionBox3D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); if(hasReferenceNode) { m_Controls.m_pbNewSegmentationSession->setEnabled(true); } if(hasWorkingNode) { m_Controls.m_pbNewLabel->setEnabled(true); m_Controls.m_gbInterpolation->setEnabled(true); m_Controls.m_SliceBasedInterpolatorWidget->setEnabled(true); m_Controls.m_SurfaceBasedInterpolatorWidget->setEnabled(true); m_Controls.m_btDeactivateTool->setEnabled(true); m_Controls.m_LabelSetWidget->setEnabled(true); m_Controls.m_btAddLayer->setEnabled(true); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); int activeLayer = workingImage->GetActiveLayer(); int numberOfLayers = workingImage->GetNumberOfLayers(); m_Controls.m_cbActiveLayer->blockSignals(true); m_Controls.m_cbActiveLayer->clear(); for (int lidx=0; lidxGetNumberOfLayers(); ++lidx) m_Controls.m_cbActiveLayer->addItem(QString::number(lidx)); m_Controls.m_cbActiveLayer->setCurrentIndex(activeLayer); m_Controls.m_cbActiveLayer->blockSignals(false); m_Controls.m_btDeleteLayer->setEnabled(numberOfLayers>1); m_Controls.m_cbActiveLayer->setEnabled(numberOfLayers>1); m_Controls.m_btPreviousLayer->setEnabled(activeLayer>0); m_Controls.m_btNextLayer->setEnabled(activeLayer!=numberOfLayers-1); m_Controls.m_btLockExterior->setChecked(workingImage->GetLabel(0)->GetLocked()); m_Controls.m_pbShowLabelTable->setChecked(workingImage->GetNumberOfLabels() > 1 /*1st is exterior*/); - m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithWorkingDataVisible); + //MLI TODO + //m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithWorkingDataVisible); } if(hasWorkingNode && hasReferenceNode) { int layer = -1; referenceNode->GetIntProperty("layer", layer); workingNode->SetIntProperty("layer", layer+1); } this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_ALL); } void QmitkMultiLabelSegmentationView::OnNewSegmentationSession() { mitk::DataNode* referenceNode = m_Controls.m_cbReferenceNodeSelector->GetSelectedNode(); if (!referenceNode) { QMessageBox::information( m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); return; } m_ToolManager->ActivateTool(-1); mitk::Image* referenceImage = dynamic_cast( referenceNode->GetData() ); assert(referenceImage); QString newName = QString::fromStdString(referenceNode->GetName()); newName.append("-labels"); bool ok = false; newName = QInputDialog::getText(m_Parent, "New Segmentation Session", "New name:", QLineEdit::Normal, newName, &ok); if(!ok) return; this->WaitCursorOn(); mitk::LabelSetImage::Pointer workingImage = mitk::LabelSetImage::New(); try { workingImage->Initialize(referenceImage); } catch ( mitk::Exception& e ) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(m_Parent, "New Segmentation Session", "Could not create a new segmentation session.\n"); return; } this->WaitCursorOff(); mitk::DataNode::Pointer workingNode = mitk::DataNode::New(); workingNode->SetData(workingImage); workingNode->SetName(newName.toStdString()); workingImage->GetExteriorLabel()->SetProperty("name.parent",mitk::StringProperty::New(referenceNode->GetName().c_str())); workingImage->GetExteriorLabel()->SetProperty("name.image",mitk::StringProperty::New(newName.toStdString().c_str())); if (!this->GetDataStorage()->Exists(workingNode)) this->GetDataStorage()->Add(workingNode, referenceNode); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); OnNewLabel(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnNewLabel() { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); QmitkNewSegmentationDialog* dialog = new QmitkNewSegmentationDialog( m_Parent ); dialog->SetSuggestionList( mitk::OrganNamesHandling::GetDefaultOrganColorString() ); dialog->setWindowTitle("New Label"); int dialogReturnValue = dialog->exec(); if ( dialogReturnValue == QDialog::Rejected ) return; QString segName = dialog->GetSegmentationName(); if(segName.isEmpty()) segName = "Unnamed"; workingImage->GetActiveLabelSet()->AddLabel(segName.toStdString(), dialog->GetColor()); UpdateControls(); } void QmitkMultiLabelSegmentationView::OnShowLabelTable(bool value) { if (value) { m_Controls.m_LabelSetWidget->show(); m_Controls.m_btAddLayer->show(); m_Controls.m_btDeactivateTool->show(); m_Controls.m_btDeleteLayer->show(); m_Controls.m_btLockExterior->show(); m_Controls.m_btNextLayer->show(); m_Controls.m_btPreviousLayer->show(); m_Controls.m_cbActiveLayer->show(); } else { m_Controls.m_LabelSetWidget->hide(); m_Controls.m_btAddLayer->hide(); m_Controls.m_btDeactivateTool->hide(); m_Controls.m_btDeleteLayer->hide(); m_Controls.m_btLockExterior->hide(); m_Controls.m_btNextLayer->hide(); m_Controls.m_btPreviousLayer->hide(); m_Controls.m_cbActiveLayer->hide(); } } void QmitkMultiLabelSegmentationView::OnNextLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); OnChangeLayer(workingImage->GetActiveLayer() + 1 ); } void QmitkMultiLabelSegmentationView::OnPreviousLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); OnChangeLayer(workingImage->GetActiveLayer() - 1 ); } void QmitkMultiLabelSegmentationView::OnChangeLayer(int layer) { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); this->WaitCursorOn(); workingImage->SetActiveLayer( layer ); this->WaitCursorOff(); UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnDeleteLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); if (workingImage->GetNumberOfLayers() < 2) return; QString question = "Do you really want to delete the current layer?"; QMessageBox::StandardButton answerButton = QMessageBox::question( m_Controls.m_LabelSetWidget, "Delete layer", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton != QMessageBox::Yes) return; try { this->WaitCursorOn(); workingImage->RemoveLayer(); this->WaitCursorOff(); } catch ( mitk::Exception& e ) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(m_Controls.m_LabelSetWidget, "Delete Layer", "Could not delete the currently active layer. See error log for details.\n"); return; } UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnAddLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); QString question = "Do you really want to add a layer to the current segmentation session?"; QMessageBox::StandardButton answerButton = QMessageBox::question( m_Controls.m_LabelSetWidget, "Add layer", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton != QMessageBox::Yes) return; int newLabelSetId = -1; try { WaitCursorOn(); newLabelSetId = workingImage->AddLayer(); WaitCursorOff(); } catch ( mitk::Exception& e ) { WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(m_Controls.m_LabelSetWidget, "Add Layer", "Could not add a new layer. See error log for details.\n"); return; } // Update controls and label set list for direct response m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); OnNewLabel(); UpdateControls(); } void QmitkMultiLabelSegmentationView::OnDeactivateActiveTool() { m_ToolManager->ActivateTool(-1); } void QmitkMultiLabelSegmentationView::OnLockExteriorToggled(bool checked) { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); workingImage->GetLabel(0)->SetLocked(checked); } void QmitkMultiLabelSegmentationView::NodeAdded(const mitk::DataNode* node) { /* bool isHelperObject(false); node->GetBoolProperty("helper object", isHelperObject); if (isHelperObject) return; if (m_ReferenceNode.IsNotNull() && dynamic_cast(node->GetData())) { mitk::LabelSetImage* workingImage = dynamic_cast(node->GetData()); if (workingImage->GetNumberOfLabels() > 2) m_Controls.m_LabelSetWidget->show(); else m_Controls.m_LabelSetWidget->hide(); } */ } void QmitkMultiLabelSegmentationView::NodeRemoved(const mitk::DataNode* node) { bool isHelperObject(false); node->GetBoolProperty("helper object", isHelperObject); if (isHelperObject) return; if (m_ReferenceNode.IsNotNull() && dynamic_cast(node->GetData())) { // remove all possible contour markers of the segmentation mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations(node, mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t+1).c_str())-1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } context->ungetService(ppmRef); service = NULL; } } void QmitkMultiLabelSegmentationView::OnInterpolationSelectionChanged(int index) { if (index == 1) { m_Controls.m_SurfaceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false);//OnToggleWidgetActivation(false); m_Controls.m_swInterpolation->setCurrentIndex(0); m_Controls.m_swInterpolation->show(); } else if (index == 2) { m_Controls.m_SliceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_swInterpolation->setCurrentIndex(1); m_Controls.m_swInterpolation->show(); } else { m_Controls.m_SurfaceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_SliceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_swInterpolation->setCurrentIndex(2); m_Controls.m_swInterpolation->hide(); } } void QmitkMultiLabelSegmentationView::OnReferenceSelectionChanged( const mitk::DataNode* node ) { m_ToolManager->ActivateTool(-1); m_ReferenceNode = const_cast(node); m_ToolManager->SetReferenceData(m_ReferenceNode); //check match of segmentation and reference image geometries if (node && m_WorkingNode.IsNotNull()) { mitk::Image* workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); mitk::Image* refImage = dynamic_cast(node->GetData()); assert(refImage); if (!this->CheckForSameGeometry(refImage, workingImage)) return; } this->UpdateControls(); //m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnEstablishLabelSetConnection() { MITK_INFO << "Connection Established"; mitk::LabelSetImage* workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); workingImage->GetActiveLabelSet()->AddLabelEvent += mitk::MessageDelegate(m_Controls.m_LabelSetWidget,&QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->RemoveLabelEvent += mitk::MessageDelegate(m_Controls.m_LabelSetWidget,&QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->ModifyLabelEvent += mitk::MessageDelegate(m_Controls.m_LabelSetWidget,&QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->AllLabelsModifiedEvent += mitk::MessageDelegate(m_Controls.m_LabelSetWidget,&QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->ActiveLabelEvent - += mitk::MessageDelegate1(m_Controls.m_LabelSetWidget,&QmitkLabelSetWidget::SelectLabelByPixelValue); + += mitk::MessageDelegate1(m_Controls.m_LabelSetWidget,&QmitkLabelSetWidget::SelectLabelByPixelValue); } void QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection() { MITK_INFO << "Connection Lost"; mitk::LabelSetImage* workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); // Reset LabelSetWidget Events workingImage->GetActiveLabelSet()->AddLabelEvent -= mitk::MessageDelegate(m_Controls.m_LabelSetWidget,&QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->RemoveLabelEvent -= mitk::MessageDelegate(m_Controls.m_LabelSetWidget,&QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->ModifyLabelEvent -= mitk::MessageDelegate(m_Controls.m_LabelSetWidget,&QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->AllLabelsModifiedEvent -= mitk::MessageDelegate(m_Controls.m_LabelSetWidget,&QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->ActiveLabelEvent - -= mitk::MessageDelegate1(m_Controls.m_LabelSetWidget,&QmitkLabelSetWidget::SelectLabelByPixelValue); - + -= mitk::MessageDelegate1(m_Controls.m_LabelSetWidget,&QmitkLabelSetWidget::SelectLabelByPixelValue); } void QmitkMultiLabelSegmentationView::OnSegmentationSelectionChanged(const mitk::DataNode *node) { m_ToolManager->ActivateTool(-1); if(m_WorkingNode.IsNotNull()) { mitk::LabelSetImage* workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); //Loose LabelSetConnections OnLooseLabelSetConnection(); workingImage->BeforeChangeLayerEvent -= mitk::MessageDelegate(this,&QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection); workingImage->AfterchangeLayerEvent -= mitk::MessageDelegate(this,&QmitkMultiLabelSegmentationView::OnEstablishLabelSetConnection); } m_WorkingNode = const_cast(node); if(m_WorkingNode.IsNotNull()) { mitk::LabelSetImage* workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); //Establish LabelSetConnection OnEstablishLabelSetConnection(); workingImage->BeforeChangeLayerEvent += mitk::MessageDelegate(this,&QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection); workingImage->AfterchangeLayerEvent += mitk::MessageDelegate(this,&QmitkMultiLabelSegmentationView::OnEstablishLabelSetConnection); } m_ToolManager->SetWorkingData(m_WorkingNode); //check match of segmentation and reference image geometries if (node && m_ReferenceNode.IsNotNull()) { mitk::Image* refImage = dynamic_cast(m_ReferenceNode->GetData()); assert(refImage); mitk::Image* workingImage = dynamic_cast(node->GetData()); assert(workingImage); if (!this->CheckForSameGeometry(refImage, workingImage)) return; } if (m_WorkingNode.IsNotNull()) { mitk::DataStorage::SetOfObjects::ConstPointer segNodes = this->GetDataStorage()->GetSubset(m_SegmentationPredicate); for(mitk::DataStorage::SetOfObjects::const_iterator iter = segNodes->begin(); iter != segNodes->end(); ++iter) { mitk::DataNode* _segNode = *iter; _segNode->SetVisibility(false); } m_WorkingNode->SetVisibility(true); } this->UpdateControls(); if (m_WorkingNode.IsNotNull()) { m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } } void QmitkMultiLabelSegmentationView::OnManualTool2DSelected(int id) { this->ResetMouseCursor(); mitk::StatusBar::GetInstance()->DisplayText(""); if (id >= 0) { std::string text = "Active Tool: \""; text += m_ToolManager->GetToolById(id)->GetName(); text += "\""; mitk::StatusBar::GetInstance()->DisplayText(text.c_str()); us::ModuleResource resource = m_ToolManager->GetToolById(id)->GetCursorIconResource(); if (resource.IsValid()) this->SetMouseCursor(resource, 0, 0); } } void QmitkMultiLabelSegmentationView::ResetMouseCursor() { if ( m_MouseCursorSet ) { mitk::ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } } void QmitkMultiLabelSegmentationView::SetMouseCursor( const us::ModuleResource resource, int hotspotX, int hotspotY ) { // Remove previously set mouse cursor if ( m_MouseCursorSet ) { mitk::ApplicationCursor::GetInstance()->PopCursor(); } us::ModuleResourceStream cursor(resource, std::ios::binary); mitk::ApplicationCursor::GetInstance()->PushCursor( cursor, hotspotX, hotspotY ); m_MouseCursorSet = true; } void QmitkMultiLabelSegmentationView::OnGoToLabel(const mitk::Point3D& pos) { if (m_IRenderWindowPart) m_IRenderWindowPart->SetSelectedPosition(pos); } void QmitkMultiLabelSegmentationView::OnResetView() { if (m_IRenderWindowPart) m_IRenderWindowPart->ForceImmediateUpdate(); } QString QmitkMultiLabelSegmentationView::GetLastFileOpenPath() { return QString::fromStdString(this->GetPreferences()->Get("LastFileOpenPath", "")); } void QmitkMultiLabelSegmentationView::SetLastFileOpenPath(const QString& path) { this->GetPreferences()->Put("LastFileOpenPath", path.toStdString()); this->GetPreferences()->Flush(); -} +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp index 1719ef2db6..481d159c3d 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp @@ -1,340 +1,341 @@ /*=================================================================== 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 "QmitkImageMaskingWidget.h" #include "../../Common/QmitkDataSelectionWidget.h" #include #include #include #include #include #include #include #include #include #include #include static const char* const HelpText = "Select a patient image and a mask"; QmitkImageMaskingWidget::QmitkImageMaskingWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) : QmitkSegmentationUtilityWidget(timeNavigationController, parent) { m_Controls.setupUi(this); m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::ImagePredicate); m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::MaskPredicate); m_Controls.dataSelectionWidget->SetHelpText(HelpText); mitk::IDataStorageService::Pointer service = berry::Platform::GetServiceRegistry().GetServiceById(mitk::IDataStorageService::ID); assert(service.IsNotNull()); m_Controls.m_LabelSetWidget->SetDataStorage(service->GetDefaultDataStorage()->GetDataStorage()); m_Controls.m_LabelSetWidget->setEnabled(true); m_Controls.m_MaskStampWidget->SetDataStorage(service->GetDefaultDataStorage()->GetDataStorage()); this->EnableButtons(false); connect (m_Controls.rbMaskImage, SIGNAL(toggled(bool)), this, SLOT(OnImageMaskingToggled(bool))); connect (m_Controls.rbMaskSurface, SIGNAL(toggled(bool)), this, SLOT(OnSurfaceMaskingToggled(bool))); connect (m_Controls.btnMaskImage, SIGNAL(pressed()), this, SLOT(OnMaskImagePressed())); connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); if( m_Controls.dataSelectionWidget->GetSelection(0).IsNotNull() && m_Controls.dataSelectionWidget->GetSelection(1).IsNotNull() ) { this->OnSelectionChanged( 0, m_Controls.dataSelectionWidget->GetSelection(0)); } } QmitkImageMaskingWidget::~QmitkImageMaskingWidget() { } void QmitkImageMaskingWidget::OnSelectionChanged(unsigned int index, const mitk::DataNode* selection) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node0 = dataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer node1 = dataSelectionWidget->GetSelection(1); if (node0.IsNull() || node1.IsNull() ) { if( m_Controls.rbMaskImage->isChecked() ) { dataSelectionWidget->SetHelpText(HelpText); } else { dataSelectionWidget->SetHelpText("Select a patient image and a surface"); } this->EnableButtons(false); } else { this->SelectionControl(index, selection); } } void QmitkImageMaskingWidget::SelectionControl(unsigned int index, const mitk::DataNode* selection) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(index); //if Image-Masking is enabled, check if image-dimension of reference and binary image is identical if( m_Controls.rbMaskImage->isChecked() ) { if( dataSelectionWidget->GetSelection(0) == dataSelectionWidget->GetSelection(1) ) { dataSelectionWidget->SetHelpText("Select two different images above"); this->EnableButtons(false); return; } /* else if( node.IsNotNull() && selection ) { mitk::Image::Pointer referenceImage = dynamic_cast ( dataSelectionWidget->GetSelection(0)->GetData() ); mitk::Image::Pointer maskImage = dynamic_cast ( dataSelectionWidget->GetSelection(1)->GetData() ); if( referenceImage->GetLargestPossibleRegion().GetSize() != maskImage->GetLargestPossibleRegion().GetSize() ) { dataSelectionWidget->SetHelpText("Different image sizes cannot be masked"); this->EnableButtons(false); return; } } else { dataSelectionWidget->SetHelpText(HelpText); return; } */ } dataSelectionWidget->SetHelpText(""); this->EnableButtons(); } void QmitkImageMaskingWidget::EnableButtons(bool enable) { m_Controls.btnMaskImage->setEnabled(enable); } void QmitkImageMaskingWidget::OnImageMaskingToggled(bool status) { if (status) { m_Controls.dataSelectionWidget->SetHelpText("Select a patient image and a mask"); m_Controls.dataSelectionWidget->SetPredicate(1, QmitkDataSelectionWidget::MaskPredicate); } } void QmitkImageMaskingWidget::OnSurfaceMaskingToggled(bool status) { if (status) { m_Controls.dataSelectionWidget->SetHelpText("Select a patient image and a surface"); m_Controls.dataSelectionWidget->SetPredicate(1, QmitkDataSelectionWidget::SurfacePredicate); } } void QmitkImageMaskingWidget::OnMaskImagePressed() { //Disable Buttons during calculation and initialize Progressbar this->EnableButtons(false); mitk::ProgressBar::GetInstance()->AddStepsToDo(4); mitk::ProgressBar::GetInstance()->Progress(); QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; //create result image, get mask node and reference image mitk::Image::Pointer resultImage(0); mitk::DataNode::Pointer maskingNode = dataSelectionWidget->GetSelection(1); mitk::Image::Pointer referenceImage = static_cast(dataSelectionWidget->GetSelection(0)->GetData()); if(referenceImage.IsNull() || maskingNode.IsNull() ) { MITK_ERROR << "Selection does not contain an image"; QMessageBox::information( this, "Image and Surface Masking", "Selection does not contain an image", QMessageBox::Ok ); m_Controls.btnMaskImage->setEnabled(true); return; } //Do Image-Masking if (m_Controls.rbMaskImage->isChecked()) { mitk::ProgressBar::GetInstance()->Progress(); mitk::Image::Pointer maskImage = dynamic_cast ( maskingNode->GetData() ); if( referenceImage->GetLargestPossibleRegion().GetSize() != maskImage->GetLargestPossibleRegion().GetSize() ) { mitk::PadImageFilter::Pointer padImageFilter = mitk::PadImageFilter::New(); padImageFilter->SetInput(0, maskImage); padImageFilter->SetInput(1, referenceImage); padImageFilter->SetPadConstant(0); padImageFilter->SetBinaryFilter(false); padImageFilter->SetLowerThreshold(0); padImageFilter->SetUpperThreshold(1); MITK_INFO << "Padding mask ..."; padImageFilter->Update(); maskImage = padImageFilter->GetOutput(); } if(maskImage.IsNull() ) { MITK_ERROR << "Selection does not contain a binary image"; QMessageBox::information( this, "Image and Surface Masking", "Selection does not contain a binary image", QMessageBox::Ok ); this->EnableButtons(); return; } resultImage = this->MaskImage( referenceImage, maskImage ); } //Do Surface-Masking else { mitk::ProgressBar::GetInstance()->Progress(); //1. convert surface to image mitk::Surface::Pointer surface = dynamic_cast ( maskingNode->GetData() ); //TODO Get 3D Surface of current time step if(surface.IsNull()) { MITK_ERROR << "Selection does not contain a surface"; QMessageBox::information( this, "Image and Surface Masking", "Selection does not contain a surface", QMessageBox::Ok ); this->EnableButtons(); return; } mitk::Image::Pointer maskImage = this->ConvertSurfaceToImage( referenceImage, surface ); //2. mask reference image with mask image if(maskImage.IsNotNull() && referenceImage->GetLargestPossibleRegion().GetSize() == maskImage->GetLargestPossibleRegion().GetSize() ) { resultImage = this->MaskImage( referenceImage, maskImage ); } } mitk::ProgressBar::GetInstance()->Progress(); if( resultImage.IsNull() ) { MITK_ERROR << "Masking failed"; QMessageBox::information( this, "Image and Surface Masking", "Masking failed. For more information please see logging window.", QMessageBox::Ok ); this->EnableButtons(); mitk::ProgressBar::GetInstance()->Progress(4); return; } //Add result to data storage this->AddToDataStorage( dataSelectionWidget->GetDataStorage(), resultImage, dataSelectionWidget->GetSelection(0)->GetName() + "_" + dataSelectionWidget->GetSelection(1)->GetName(), dataSelectionWidget->GetSelection(0)); this->EnableButtons(); mitk::ProgressBar::GetInstance()->Progress(); } mitk::Image::Pointer QmitkImageMaskingWidget::MaskImage(mitk::Image::Pointer referenceImage, mitk::Image::Pointer maskImage ) { mitk::Image::Pointer resultImage(0); mitk::MaskImageFilter::Pointer maskFilter = mitk::MaskImageFilter::New(); maskFilter->SetInput( referenceImage ); maskFilter->SetMask( maskImage ); - if ( m_Controls.m_chkMakeOutputBinary->isChecked() ) - { - maskFilter->SetInsideValue(1.0); - maskFilter->SetOutsideValue(0.0); - maskFilter->SetOverrideOutsideValue(true); - maskFilter->SetOverrideInsideValue(true); - } - - maskFilter->SetOverrideOutsideValue( m_Controls.m_chkOverwriteBackground->isChecked() ); - maskFilter->SetOverrideInsideValue( m_Controls.m_chkOverwriteForeground->isChecked() ); - maskFilter->SetInsideValue( m_Controls.m_leForegroundValue->text().toFloat() );//referenceImage->GetStatistics()->GetScalarValueMin() ); - maskFilter->SetOutsideValue( m_Controls.m_leBackgroundValue->text().toFloat() );//referenceImage->GetStatistics()->GetScalarValueMin() ); + //MLI TODO + //if ( m_Controls.m_chkMakeOutputBinary->isChecked() ) + //{ + // maskFilter->SetInsideValue(1.0); + // maskFilter->SetOutsideValue(0.0); + // maskFilter->SetOverrideOutsideValue(true); + // maskFilter->SetOverrideInsideValue(true); + //} + + //maskFilter->SetOverrideOutsideValue( m_Controls.m_chkOverwriteBackground->isChecked() ); + //maskFilter->SetOverrideInsideValue( m_Controls.m_chkOverwriteForeground->isChecked() ); + //maskFilter->SetInsideValue( m_Controls.m_leForegroundValue->text().toFloat() );//referenceImage->GetStatistics()->GetScalarValueMin() ); + //maskFilter->SetOutsideValue( m_Controls.m_leBackgroundValue->text().toFloat() );//referenceImage->GetStatistics()->GetScalarValueMin() ); try { maskFilter->Update(); } catch(itk::ExceptionObject& excpt) { MITK_ERROR << excpt.GetDescription(); return 0; } resultImage = maskFilter->GetOutput(); return resultImage; } mitk::Image::Pointer QmitkImageMaskingWidget::ConvertSurfaceToImage( mitk::Image::Pointer image, mitk::Surface::Pointer surface ) { mitk::ProgressBar::GetInstance()->AddStepsToDo(2); mitk::ProgressBar::GetInstance()->Progress(); mitk::SurfaceToImageFilter::Pointer surfaceToImageFilter = mitk::SurfaceToImageFilter::New(); surfaceToImageFilter->MakeOutputBinaryOn(); surfaceToImageFilter->SetInput(surface); surfaceToImageFilter->SetImage(image); try { surfaceToImageFilter->Update(); } catch(itk::ExceptionObject& excpt) { MITK_ERROR << excpt.GetDescription(); return 0; } mitk::ProgressBar::GetInstance()->Progress(); mitk::Image::Pointer resultImage = mitk::Image::New(); resultImage = surfaceToImageFilter->GetOutput(); return resultImage; } void QmitkImageMaskingWidget::AddToDataStorage(mitk::DataStorage::Pointer dataStorage, mitk::Image::Pointer segmentation, const std::string& name, mitk::DataNode::Pointer parent ) { mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); dataNode->SetName(name); dataNode->SetData(segmentation); dataStorage->Add(dataNode, parent); -} +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.h b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.h index e370cefa40..9dde336331 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.h +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.h @@ -1,80 +1,81 @@ /*=================================================================== 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 QmitkImageMaskingWidget_h #define QmitkImageMaskingWidget_h #include "../QmitkSegmentationUtilityWidget.h" #include #include +#include /*! \brief QmitkImageMaskingWidget Tool masks an image with a binary image or a surface. The Method requires an image and a binary image mask or a surface. The input image and the binary image mask must be of the same size. Masking with a surface creates first a binary image of the surface and then use this for the masking of the input image. */ class QmitkImageMaskingWidget : public QmitkSegmentationUtilityWidget { Q_OBJECT public: /** @brief Default constructor, including creation of GUI elements and signals/slots connections. */ explicit QmitkImageMaskingWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent = NULL); /** @brief Defaul destructor. */ ~QmitkImageMaskingWidget(); private slots: /** @brief This slot is called if the selection in the workbench is changed. */ void OnSelectionChanged(unsigned int index, const mitk::DataNode* selection); /** @brief This slot is called if user activates the radio button for masking an image with a binary image mask. */ void OnImageMaskingToggled(bool); /** @brief This slot is called if user activates the radio button for masking an image with a surface. */ void OnSurfaceMaskingToggled(bool); /** @brief This slot is called if user activates the button to mask an image. */ void OnMaskImagePressed(); private: /** @brief Check if selections is valid. */ void SelectionControl( unsigned int index, const mitk::DataNode* selection); /** @brief Enable buttons if data selction is valid. */ void EnableButtons(bool enable = true); /** @brief Mask an image with a given binary mask. Note that the input image and the mask image must be of the same size. */ mitk::Image::Pointer MaskImage(mitk::Image::Pointer referenceImage, mitk::Image::Pointer maskImage ); /** @brief Convert a surface into an binary image. */ mitk::Image::Pointer ConvertSurfaceToImage( mitk::Image::Pointer image, mitk::Surface::Pointer surface ); /** @brief Adds a new data object to the DataStorage.*/ void AddToDataStorage(mitk::DataStorage::Pointer dataStorage, mitk::Image::Pointer segmentation, const std::string& name, mitk::DataNode::Pointer parent = NULL); Ui::QmitkImageMaskingWidgetControls m_Controls; }; #endif diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.h b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.h index ef7aff69c6..471b06d90c 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.h +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.h @@ -1,66 +1,67 @@ /*=================================================================== 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 QmitkSurfaceToImageWidget_h #define QmitkSurfaceToImageWidget_h #include "../QmitkSegmentationUtilityWidget.h" #include #include +#include /*! \brief QmitkSurfaceToImageWidget The Tool converts a surface to a binary image. The Method requires a surface and an image, which header information defines the output image. The resulting binary image has the same dimension, size, and Geometry3D as the input image. */ class QmitkSurfaceToImageWidget : public QmitkSegmentationUtilityWidget { Q_OBJECT public: /** @brief Default constructor, including creation of GUI elements and signals/slots connections. */ explicit QmitkSurfaceToImageWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent = NULL); /** @brief Defaul destructor. */ ~QmitkSurfaceToImageWidget(); private slots: /** @brief This slot is called if the selection in the workbench is changed. */ void OnSelectionChanged(unsigned int index, const mitk::DataNode* selection); /** @brief This slot is called if user activates the button to convert a surface into a binary image. */ void OnSurface2ImagePressed(); void OnMakeOutputBinaryChanged(bool value); private: /** @brief Enable buttons if data selction is valid. */ void EnableButtons(bool enable = true); /** @brief Convert a surface into an binary image. */ mitk::Image::Pointer ConvertSurfaceToImage( mitk::Image::Pointer image, mitk::Surface::Pointer surface ); Ui::QmitkSurfaceToImageWidgetControls m_Controls; }; #endif diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.cpp index 8aaaf4006c..57444db7b5 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.cpp @@ -1,66 +1,67 @@ /*=================================================================== 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 "mitkPluginActivator.h" #include "QmitkMultiLabelSegmentationView.h" #include "QmitkThresholdAction.h" #include "QmitkCreatePolygonModelAction.h" #include "QmitkAutocropAction.h" #include "QmitkConvertSurfaceToLabelAction.h" #include "QmitkConvertMaskToLabelAction.h" #include "QmitkConvertToMultiLabelSegmentationAction.h" #include "QmitkCreateMultiLabelSegmentationAction.h" #include "QmitkMultiLabelSegmentationPreferencePage.h" #include "QmitkLoadMultiLabelPresetAction.h" #include "QmitkCreateMultiLabelPresetAction.h" #include "SegmentationUtilities/QmitkMultiLabelSegmentationUtilitiesView.h" #include ctkPluginContext* mitk::PluginActivator::m_Context = NULL; +//MLI TODO +US_INITIALIZE_MODULE //("MultiLabelSegmentation", "liborg_mitk_gui_qt_multilabelsegmentation") + void mitk::PluginActivator::start(ctkPluginContext *context) { BERRY_REGISTER_EXTENSION_CLASS(QmitkMultiLabelSegmentationView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkThresholdAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkCreatePolygonModelAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkAutocropAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConvertSurfaceToLabelAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConvertMaskToLabelAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConvertToMultiLabelSegmentationAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkCreateMultiLabelSegmentationAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkCreateMultiLabelPresetAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkLoadMultiLabelPresetAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkMultiLabelSegmentationPreferencePage, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkMultiLabelSegmentationUtilitiesView, context) m_Context = context; } void mitk::PluginActivator::stop(ctkPluginContext* context) { Q_UNUSED(context) m_Context = NULL; } ctkPluginContext* mitk::PluginActivator::getContext() { return m_Context; } -Q_EXPORT_PLUGIN2(org_mitk_gui_qt_multilabelsegmentation, mitk::PluginActivator) - -US_INITIALIZE_MODULE("MultiLabelSegmentation", "liborg_mitk_gui_qt_multilabelsegmentation") +Q_EXPORT_PLUGIN2(org_mitk_gui_qt_multilabelsegmentation, mitk::PluginActivator) \ No newline at end of file