diff --git a/Modules/DataTypesExt/include/mitkApplyDiffImageOperation.h b/Modules/DataTypesExt/include/mitkApplyDiffImageOperation.h index 49e3a2f539..6162b23d4c 100644 --- a/Modules/DataTypesExt/include/mitkApplyDiffImageOperation.h +++ b/Modules/DataTypesExt/include/mitkApplyDiffImageOperation.h @@ -1,88 +1,88 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkApplyDiffImageIIncluded #define mitkApplyDiffImageIIncluded #include "MitkDataTypesExtExports.h" #include "mitkCompressedImageContainer.h" #include "mitkOperation.h" namespace mitk { /** @brief Operation, that holds information about some image difference This class stores undo information for DiffImageApplier. - Instances of this class are created e.g. by OverwriteSliceImageFilter. + Instances of this class are created e.g. by QmitkSlicesInterpolator. This works only for images with 1 channel (gray scale images, no color images). ApplyDiffImageOperation of course refers to an image (a segmentation usually). The refered image is observed for itk::DeleteEvent, because there is no SmartPointer used to keep the image alive -- the purpose of this class is undo and the undo stack should not keep things alive forever. To save memory, compression is used via CompressedImageContainer. @ingroup Undo @ingroup ToolManagerEtAl */ class MITKDATATYPESEXT_EXPORT ApplyDiffImageOperation : public Operation { protected: void OnImageDeleted(); Image *m_Image; unsigned int m_SliceIndex; unsigned int m_SliceDimension; unsigned int m_TimeStep; double m_Factor; bool m_ImageStillValid; unsigned long m_DeleteTag; CompressedImageContainer m_CompressedImageContainer; public: /** Pass only 2D images here. \param operationType \param image \param diffImage \param timeStep \param sliceIndex brief Which slice to extract (first one has index 0). \param sliceDimension Number of the dimension which is constant for all pixels of the desired slice (e.g. 0 for axial) */ ApplyDiffImageOperation(OperationType operationType, Image *image, Image *diffImage, unsigned int timeStep = 0, unsigned int sliceDimension = 2, unsigned int sliceIndex = 0); ~ApplyDiffImageOperation() override; // Unfortunately cannot use itkGet/SetMacros here, since Operation does not inherit itk::Object unsigned int GetSliceIndex() { return m_SliceIndex; } unsigned int GetSliceDimension() { return m_SliceDimension; } unsigned int GetTimeStep() { return m_TimeStep; } void SetFactor(double factor) { m_Factor = factor; } double GetFactor() { return m_Factor; } Image *GetImage() { return m_Image; } Image::Pointer GetDiffImage(); bool IsImageStillValid() { return m_ImageStillValid; } }; } // namespace mitk #endif diff --git a/Modules/ImageExtraction/mitkExtractDirectedPlaneImageFilterNew.h b/Modules/ImageExtraction/mitkExtractDirectedPlaneImageFilterNew.h index db2c01511f..11daa46849 100644 --- a/Modules/ImageExtraction/mitkExtractDirectedPlaneImageFilterNew.h +++ b/Modules/ImageExtraction/mitkExtractDirectedPlaneImageFilterNew.h @@ -1,99 +1,98 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkExtractDirectedPlaneImageFilterNew_h_Included #define mitkExtractDirectedPlaneImageFilterNew_h_Included #include "itkImage.h" #include "mitkITKImageImport.h" #include "mitkImageToImageFilter.h" #include namespace mitk { /** \deprecated This class is deprecated. Use mitk::ExtractSliceFilter instead. \sa ExtractSliceFilter \brief A filter that can extract a 2D slice from a 3D or 4D image especially if the image`s axes are rotated \sa ContourTool \sa SegTool2D \sa ExtractImageFilter - \sa OverwriteSliceImageFilter \sa OverwriteDirectedPlaneImageFilter \ingroup Process \ingroup Reliver There is a separate page describing the general design of QmitkInteractiveSegmentation: \ref QmitkSegmentationTechnicalPage This class takes an 3D or 4D mitk::Image as input and extracts a slice from it. If you work with a 4D image as input you have to specify the desired timestep at which the slice shall be extracted, otherwise the lowest given timestep is selected by default. The special feature of this filter is, that the planes of the input image can be rotated in any way. To assure a proper extraction you have to set the currentWorldPlaneGeometry with you can obtain from the BaseRenderer, respectively the positionEvent send by the renderer. The output will not be set if there was a problem with the input image $Author: fetzer $ */ class MITKIMAGEEXTRACTION_EXPORT ExtractDirectedPlaneImageFilterNew : public ImageToImageFilter { public: mitkClassMacro(ExtractDirectedPlaneImageFilterNew, ImageToImageFilter); itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** \brief Set macro for the current worldgeometry \a Parameter The current wordgeometry that describes the position (rotation, translation) of the plane (and therefore the slice to be extracted) in our 3D(+t) image */ itkSetMacro(CurrentWorldPlaneGeometry, BaseGeometry *); /** * \deprecatedSince{2014_10} Please use SetCurrentWorldPlaneGeometry */ DEPRECATED(void SetCurrentWorldGeometry2D(BaseGeometry *geo)) { SetCurrentWorldPlaneGeometry(geo); }; itkSetMacro(ImageGeometry, BaseGeometry *); /** \brief Set macro for the current timestep \a Parameter The timestep of the image from which the slice shall be extracted */ itkSetMacro(ActualInputTimestep, int); protected: ExtractDirectedPlaneImageFilterNew(); ~ExtractDirectedPlaneImageFilterNew() override; void GenerateData() override; void GenerateOutputInformation() override; private: const BaseGeometry *m_CurrentWorldPlaneGeometry; const BaseGeometry *m_ImageGeometry; int m_ActualInputTimestep; template void ItkSliceExtraction(const itk::Image *inputImage); }; } // namespace #endif diff --git a/Modules/ImageExtraction/mitkExtractImageFilter.h b/Modules/ImageExtraction/mitkExtractImageFilter.h index 83b08e7009..911b5538d9 100644 --- a/Modules/ImageExtraction/mitkExtractImageFilter.h +++ b/Modules/ImageExtraction/mitkExtractImageFilter.h @@ -1,111 +1,110 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkExtractImageFilter_h_Included #define mitkExtractImageFilter_h_Included #include "mitkCommon.h" #include "mitkImageToImageFilter.h" #include #include "itkImage.h" namespace mitk { /** \deprecated This class is deprecated. Use mitk::ExtractSliceFilter instead. \sa ExtractSliceFilter \brief Extracts a 2D slice from a 3D image. \sa SegTool2D - \sa OverwriteSliceImageFilter \ingroup Process \ingroup ToolManagerEtAl There is a separate page describing the general design of QmitkInteractiveSegmentation: \ref QmitkSegmentationTechnicalPage This class takes a 3D mitk::Image as input and tries to extract one slice from it. Two parameters determine which slice is extracted: the "slice dimension" is that one, which is constant for all points in the plane, e.g. axial would mean 2. The "slice index" is the slice index in the image direction you specified with "affected dimension". Indices count from zero. Output will not be set if there was a problem extracting the desired slice. Last contributor: $Author$ */ class MITKIMAGEEXTRACTION_EXPORT ExtractImageFilter : public ImageToImageFilter { public: mitkClassMacro(ExtractImageFilter, ImageToImageFilter); itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** \brief Which slice to extract (first one has index 0). */ itkSetMacro(SliceIndex, unsigned int); itkGetConstMacro(SliceIndex, unsigned int); /** \brief The orientation of the slice to be extracted. \a Parameter SliceDimension Number of the dimension which is constant for all pixels of the desired slice (e.g. 2 for axial) */ itkSetMacro(SliceDimension, unsigned int); itkGetConstMacro(SliceDimension, unsigned int); /** \brief Time step of the image to be extracted. */ itkSetMacro(TimeStep, unsigned int); itkGetConstMacro(TimeStep, unsigned int); typedef enum DirectionCollapseStrategyEnum { DIRECTIONCOLLAPSETOUNKOWN = 0, DIRECTIONCOLLAPSETOIDENTITY = 1, DIRECTIONCOLLAPSETOSUBMATRIX = 2, DIRECTIONCOLLAPSETOGUESS = 3 } DIRECTIONCOLLAPSESTRATEGY; /** \brief Collapse strategy to be used. */ itkSetMacro(DirectionCollapseToStrategy, DIRECTIONCOLLAPSESTRATEGY); itkGetConstMacro(DirectionCollapseToStrategy, DIRECTIONCOLLAPSESTRATEGY); protected: ExtractImageFilter(); // purposely hidden ~ExtractImageFilter() override; void GenerateOutputInformation() override; void GenerateInputRequestedRegion() override; void GenerateData() override; template void ItkImageProcessing(const itk::Image *image); unsigned int m_SliceIndex; unsigned int m_SliceDimension; unsigned int m_TimeStep; DIRECTIONCOLLAPSESTRATEGY m_DirectionCollapseToStrategy; }; } // namespace #endif diff --git a/Modules/Segmentation/Algorithms/mitkDiffImageApplier.h b/Modules/Segmentation/Algorithms/mitkDiffImageApplier.h index 956fe8961c..6f28dbf217 100644 --- a/Modules/Segmentation/Algorithms/mitkDiffImageApplier.h +++ b/Modules/Segmentation/Algorithms/mitkDiffImageApplier.h @@ -1,82 +1,82 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkDiffImageApplier_h_Included #define mitkDiffImageApplier_h_Included #include "mitkCommon.h" #include "mitkImage.h" #include "mitkOperationActor.h" #include #include #include namespace mitk { /** \brief Applies difference images to 3D images. - This class is supposed to execute ApplyDiffImageOperations, which contain information about pixel changes within one - image slice. - Class should be called from the undo stack. At the moment, ApplyDiffImageOperations are only created by - OverwriteSliceImageFilter. + This class is supposed to execute ApplyDiffImageOperations, which contain information about + pixel changes within one image slice. + Class should be called from the undo stack. + At the moment, ApplyDiffImageOperations are only created by QmitkSlicesInterpolator. $Author: maleike $ */ class MITKSEGMENTATION_EXPORT DiffImageApplier : public itk::Object, public OperationActor { public: mitkClassMacroItkParent(DiffImageApplier, itk::Object); itkFactorylessNewMacro(Self); itkCloneMacro(Self); void ExecuteOperation(Operation *operation) override; static DiffImageApplier *GetInstanceForUndo(); protected: DiffImageApplier(); // purposely hidden ~DiffImageApplier() override; template void ItkImageSwitch2DDiff(itk::Image *image); template void ItkImageSwitch3DDiff(itk::Image *image); template void ItkImageProcessing2DDiff(itk::Image *itkImage1, itk::Image *itkImage2); template void ItkImageProcessing3DDiff(itk::Image *itkImage1, itk::Image *itkImage2); template void ItkInvertPixelValues(itk::Image *itkImage); Image::Pointer m_Image; Image::Pointer m_SliceDifferenceImage; unsigned int m_SliceIndex; unsigned int m_SliceDimension; unsigned int m_TimeStep; unsigned int m_Dimension0; unsigned int m_Dimension1; double m_Factor; }; } // namespace #endif diff --git a/Modules/Segmentation/Algorithms/mitkOverwriteDirectedPlaneImageFilter.cpp b/Modules/Segmentation/Algorithms/mitkOverwriteDirectedPlaneImageFilter.cpp deleted file mode 100644 index a732bc5414..0000000000 --- a/Modules/Segmentation/Algorithms/mitkOverwriteDirectedPlaneImageFilter.cpp +++ /dev/null @@ -1,511 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ - -#include "mitkOverwriteDirectedPlaneImageFilter.h" -#include "mitkApplyDiffImageOperation.h" -#include "mitkDiffImageApplier.h" -#include "mitkImageAccessByItk.h" -#include "mitkImageCast.h" -#include "mitkImageTimeSelector.h" -#include "mitkInteractionConst.h" -#include "mitkOperationEvent.h" -#include "mitkSegmentationInterpolationController.h" -#include "mitkUndoController.h" - -#include -#include - -mitk::OverwriteDirectedPlaneImageFilter::OverwriteDirectedPlaneImageFilter() - : m_PlaneGeometry(nullptr), - m_ImageGeometry3D(nullptr), - m_TimeStep(0), - m_Dimension0(0), - m_Dimension1(1), - m_CreateUndoInformation(false) -{ - MITK_WARN << "Class is deprecated! Use mitkVtkImageOverwrite instead."; -} - -mitk::OverwriteDirectedPlaneImageFilter::~OverwriteDirectedPlaneImageFilter() -{ -} - -void mitk::OverwriteDirectedPlaneImageFilter::GenerateData() -{ - // - // this is the place to implement the major part of undo functionality (bug #491) - // here we have to create undo/do operations - // - // WHO is the operation actor? This object may not be destroyed ever (design of undo stack)! - // -> some singleton method of this filter? - // - // neccessary additional objects: - // - something that executes the operations - // - the operation class (must hold a binary diff or something) - // - observer commands to know when the image is deleted (no further action then, perhaps even remove the operations - // from the undo stack) - // - // Image::ConstPointer input = ImageToImageFilter::GetInput(0); - Image::Pointer input3D = ImageToImageFilter::GetInput(0); - - // Image::ConstPointer slice = m_SliceImage; - - if (input3D.IsNull() || m_SliceImage.IsNull()) - return; - - if (input3D->GetDimension() == 4) - { - ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); - timeSelector->SetInput(input3D); - timeSelector->SetTimeNr(m_TimeStep); - timeSelector->UpdateLargestPossibleRegion(); - input3D = timeSelector->GetOutput(); - } - - m_ImageGeometry3D = input3D->GetGeometry(); - /* - if ( m_SliceDifferenceImage.IsNull() || - m_SliceDifferenceImage->GetDimension(0) != m_SliceImage->GetDimension(0) || - m_SliceDifferenceImage->GetDimension(1) != m_SliceImage->GetDimension(1) ) - { - m_SliceDifferenceImage = mitk::Image::New(); - mitk::PixelType pixelType( typeid(short signed int) ); - m_SliceDifferenceImage->Initialize( pixelType, 2, m_SliceImage->GetDimensions() ); - } - */ - // MITK_INFO << "Overwriting slice " << m_SliceIndex << " in dimension " << m_SliceDimension << " at time step " << - // m_TimeStep << std::endl; - // this will do a long long if/else to find out both pixel types - /*AccessFixedDimensionByItk( input3D, ItkImageSwitch, 3 );*/ - AccessFixedDimensionByItk(input3D, ItkSliceOverwriting, 3); - - // SegmentationInterpolationController* interpolator = SegmentationInterpolationController::InterpolatorForImage( - // input3D ); - // if (interpolator) - //{ - // interpolator->BlockModified(true); - // //interpolator->SetChangedSlice( m_SliceDifferenceImage, m_SliceDimension, m_SliceIndex, m_TimeStep ); - //} - /* - if ( m_CreateUndoInformation ) - { - // create do/undo operations (we don't execute the doOp here, because it has already been executed during calculation - of the diff image - ApplyDiffImageOperation* doOp = new ApplyDiffImageOperation( OpTEST, const_cast(input.GetPointer()), - m_SliceDifferenceImage, m_TimeStep, m_SliceDimension, m_SliceIndex ); - ApplyDiffImageOperation* undoOp = new ApplyDiffImageOperation( OpTEST, const_cast(input.GetPointer()), - m_SliceDifferenceImage, m_TimeStep, m_SliceDimension, m_SliceIndex ); - undoOp->SetFactor( -1.0 ); - OperationEvent* undoStackItem = new OperationEvent( DiffImageApplier::GetInstanceForUndo(), doOp, undoOp, - this->EventDescription(m_SliceDimension, m_SliceIndex, m_TimeStep) ); - UndoController::GetCurrentUndoModel()->SetOperationEvent( undoStackItem ); - } - */ - // this image is modified (good to know for the renderer) - input3D->Modified(); - - /*if (interpolator) - { - interpolator->BlockModified(false); - }*/ -} - -template -void mitk::OverwriteDirectedPlaneImageFilter::ItkSliceOverwriting(itk::Image *input3D) -{ - typedef itk::Image SliceImageType; - typedef itk::ImageRegionConstIterator SliceIteratorType; - - typename SliceImageType::Pointer sliceImage = SliceImageType::New(); - CastToItkImage(m_SliceImage, sliceImage); - - SliceIteratorType sliceIterator(sliceImage, sliceImage->GetLargestPossibleRegion()); - - sliceIterator.GoToBegin(); - - Point3D currentPointIn2D; - Point3D worldPointIn3D; - - // Here we just iterate over the slice which must be written into the 3D volumen and set the corresponding pixel in - // our 3D volume - while (!sliceIterator.IsAtEnd()) - { - currentPointIn2D[0] = sliceIterator.GetIndex()[0] + 0.5; - currentPointIn2D[1] = sliceIterator.GetIndex()[1] + 0.5; - currentPointIn2D[2] = 0; - - m_PlaneGeometry->IndexToWorld(currentPointIn2D, worldPointIn3D); - - typename itk::Image::IndexType outputIndex; - m_ImageGeometry3D->WorldToIndex(worldPointIn3D, outputIndex); - - // Only access ITK image if it's inside - if (m_ImageGeometry3D->IsIndexInside(outputIndex)) - { - input3D->SetPixel(outputIndex, (TPixel)sliceIterator.Get()); - } - - ++sliceIterator; - } -} - -/****TEST***/ -// Maybe a bit more efficient but doesn`t already work. See also ExtractCirectedPlaneImageFilter - -// typename itk::Image::IndexType outputIndex; - -// if ( columns == extent[0] ) -//{ -////If we are at the end of a row, then we have to go to the beginning of the next row -// currentImagePointIn3D = origin; -// currentImagePointIn3D += spacing[1]*bottom*currentPointIn2D[1]; -// columns = 0; -// m_ImageGeometry3D->WorldToIndex(currentImagePointIn3D, outputIndex); -//} -// else -//{ -// if ( columns != 0 ) -//{ -// currentImagePointIn3D += spacing[0]*right; -//} -// m_ImageGeometry3D->WorldToIndex(currentImagePointIn3D, outputIndex); -//} - -// if ( m_ImageGeometry3D->IsIndexInside( outputIndex )) -//{ -// outputImage->SetPixel( outputIndex, (TPixel2)inputIterator.Get() ); -//} -// else if (currentImagePointIn3D == origin) -//{ -// Point3D temp; -// temp[0] = bottom[0]*spacing[0]*0.5; -// temp[1] = bottom[1]*spacing[1]*0.5; -// temp[2] = bottom[2]*spacing[2]*0.5; -// origin[0] += temp[0]; -// origin[1] += temp[1]; -// origin[2] += temp[2]; -// currentImagePointIn3D = origin; -// m_ImageGeometry3D->WorldToIndex(currentImagePointIn3D, outputIndex); -// if ( m_ImageGeometry3D->IsIndexInside( outputIndex )) -//{ -// outputImage->SetPixel( outputIndex, (TPixel2)inputIterator.Get() ); -//} -//} -// columns++; - -/****TEST ENDE****/ - -//* -// // Offset the world coordinate by one pixel to compensate for -// // index/world origin differences. -// Point3D offsetIndex; -// offsetIndex.Fill( 1 ); -// Point3D offsetWorld; -// offsetWorld.Fill( 0 ); -// m_PlaneGeometry->IndexToWorld( offsetIndex, offsetWorld ); -// // remove origin shift -// const Point3D origin = m_PlaneGeometry->GetOrigin(); -// offsetWorld[0] -= origin[0]; -// offsetWorld[1] -= origin[1]; -// offsetWorld[2] -= origin[2]; -// // offset world coordinate -// worldPointIn3D[ 0 ] += offsetWorld[0]; -// worldPointIn3D[ 1 ] += offsetWorld[1]; -// worldPointIn3D[ 2 ] += offsetWorld[2]; -//*/ - -// basically copied from mitk/Core/Algorithms/mitkImageAccessByItk.h -/*#define myMITKOverwriteDirectedPlaneImageFilterAccessByItk(mitkImage, itkImageTypeFunction, pixeltype, dimension, -itkimage2) \ -// if ( typeId == typeid(pixeltype) ) \ -//{ \ -// typedef itk::Image ImageType; \ -// typedef mitk::ImageToItk ImageToItkType; \ -// itk::SmartPointer imagetoitk = ImageToItkType::New(); \ -// imagetoitk->SetInput(mitkImage); \ -// imagetoitk->Update(); \ -// itkImageTypeFunction(imagetoitk->GetOutput(), itkimage2); \ -//} -// -//#define myMITKOverwriteDirectedPlaneImageFilterAccessAllTypesByItk(mitkImage, itkImageTypeFunction, dimension, -itkimage2) \ -//{ \ -// myMITKOverwriteDirectedPlaneImageFilterAccessByItk(mitkImage, itkImageTypeFunction, double, dimension, -itkimage2) else \ -// myMITKOverwriteDirectedPlaneImageFilterAccessByItk(mitkImage, itkImageTypeFunction, float, dimension, -itkimage2) else \ -// myMITKOverwriteDirectedPlaneImageFilterAccessByItk(mitkImage, itkImageTypeFunction, int, dimension, -itkimage2) else \ -// myMITKOverwriteDirectedPlaneImageFilterAccessByItk(mitkImage, itkImageTypeFunction, unsigned int, dimension, -itkimage2) else \ -// myMITKOverwriteDirectedPlaneImageFilterAccessByItk(mitkImage, itkImageTypeFunction, short, dimension, -itkimage2) else \ -// myMITKOverwriteDirectedPlaneImageFilterAccessByItk(mitkImage, itkImageTypeFunction, unsigned short, dimension, -itkimage2) else \ -// myMITKOverwriteDirectedPlaneImageFilterAccessByItk(mitkImage, itkImageTypeFunction, char, dimension, -itkimage2) else \ -// myMITKOverwriteDirectedPlaneImageFilterAccessByItk(mitkImage, itkImageTypeFunction, unsigned char, dimension, -itkimage2) \ -//}*/ -// -// -// template -// void mitk::OverwriteDirectedPlaneImageFilter::ItkImageSwitch( itk::Image* itkImage ) -//{ -// const std::type_info& typeId=*(m_SliceImage->GetPixelType().GetTypeId()); -// -// myMITKOverwriteDirectedPlaneImageFilterAccessAllTypesByItk( m_SliceImage, ItkImageProcessing, 2, itkImage ); -//} - -// template -// void mitk::OverwriteDirectedPlaneImageFilter::ItkImageProcessing( itk::Image* inputImage, -// itk::Image* outputImage ) -//{ -// typedef itk::Image SliceImageType; -// typedef itk::Image DiffImageType; -// typedef itk::Image VolumeImageType; -// -// typedef itk::ImageSliceIteratorWithIndex< VolumeImageType > OutputSliceIteratorType; -// typedef itk::ImageRegionConstIterator< SliceImageType > InputSliceIteratorType; -// //typedef itk::ImageRegionIterator< DiffImageType > DiffSliceIteratorType; -// -// InputSliceIteratorType inputIterator( inputImage, inputImage->GetLargestPossibleRegion() ); -// -// //typename DiffImageType::Pointer diffImage; -// //CastToItkImage( m_SliceDifferenceImage, diffImage ); -// //DiffSliceIteratorType diffIterator( diffImage, diffImage->GetLargestPossibleRegion() ); -// -// inputIterator.GoToBegin(); -// //diffIterator.GoToBegin(); -// -// //TEST -// Point3D origin = m_PlaneGeometry->GetOrigin(); -// Vector3D right = m_PlaneGeometry->GetAxisVector(0); -// Vector3D bottom = m_PlaneGeometry->GetAxisVector(1); -// right.Normalize(); -// bottom.Normalize(); -// -// Vector2D spacing = inputImage->GetSpacing(); -// -// Vector2D extentInMM; -// extentInMM[0] = m_PlaneGeometry->GetExtentInMM(0); -// extentInMM[1] = m_PlaneGeometry->GetExtentInMM(1); -// -// Vector2D extent; -// extent[0] = m_PlaneGeometry->GetExtent(0); -// extent[1] = m_PlaneGeometry->GetExtent(1); -// //TEST ENDE -// -// Point3D currentPointIn2D, worldPointIn3D; -// TPixel2 outputPixel = 0; -// -// int debugCounter( 0 ); -// -// std::ofstream geometryFile; -// geometryFile.precision(30); -// geometryFile.open("C:/Users/fetzer/Desktop/TEST/geometryFileOv.txt"); -// -// geometryFile<<"Offset: [ "<GetIndexToWorldTransform()->GetOffset()[0]<<", -// "<GetIndexToWorldTransform()->GetOffset()[1]<<", -// "<GetIndexToWorldTransform()->GetOffset()[2]<<" ]"<GetIndexToWorldTransform()->GetMatrix()<IndexToWorld( currentPointIn2D, worldPointIn3D ); -// -// typename itk::Image::IndexType outputIndex; -// m_ImageGeometry3D->WorldToIndex( worldPointIn3D, outputIndex ); -// -// // Only access ITK image if it's inside -// if ( m_ImageGeometry3D->IsIndexInside( outputIndex ) ) -// { -// //outputPixel = outputImage->GetPixel( outputIndex ); -// outputImage->SetPixel( outputIndex, (TPixel2)inputIterator.Get() ); -// /*if( inputIterator.Get() == mitk::paint::addPixelValue ) -// { -// outputImage->SetPixel( outputIndex, (TPixel2)( 1 ) ); -// } -// else if( inputIterator.Get() == mitk::paint::subPixelValue ) -// { -// outputImage->SetPixel( outputIndex, (TPixel2)( 0 ) ); -// }*/ -// } -// -///****TEST***/ -// -////typename itk::Image::IndexType outputIndex; -// -////if ( columns == extent[0] ) -////{ -//////If we are at the end of a row, then we have to go to the beginning of the next row -////currentImagePointIn3D = origin; -////currentImagePointIn3D += spacing[1]*bottom*currentPointIn2D[1]; -// columns = 0; -////m_ImageGeometry3D->WorldToIndex(currentImagePointIn3D, outputIndex); -////} -////else -////{ -////if ( columns != 0 ) -////{ -////currentImagePointIn3D += spacing[0]*right; -////} -////m_ImageGeometry3D->WorldToIndex(currentImagePointIn3D, outputIndex); -////} -// -////if ( m_ImageGeometry3D->IsIndexInside( outputIndex )) -////{ -////outputImage->SetPixel( outputIndex, (TPixel2)inputIterator.Get() ); -////} -////else if (currentImagePointIn3D == origin) -////{ -////Point3D temp; -////temp[0] = bottom[0]*spacing[0]*0.5; -////temp[1] = bottom[1]*spacing[1]*0.5; -////temp[2] = bottom[2]*spacing[2]*0.5; -////origin[0] += temp[0]; -////origin[1] += temp[1]; -////origin[2] += temp[2]; -////currentImagePointIn3D = origin; -////m_ImageGeometry3D->WorldToIndex(currentImagePointIn3D, outputIndex); -////if ( m_ImageGeometry3D->IsIndexInside( outputIndex )) -////{ -////outputImage->SetPixel( outputIndex, (TPixel2)inputIterator.Get() ); -////} -////} -////columns++; -// -///****TEST ENDE****/ -// -////* -//// // Offset the world coordinate by one pixel to compensate for -//// // index/world origin differences. -//// Point3D offsetIndex; -//// offsetIndex.Fill( 1 ); -//// Point3D offsetWorld; -//// offsetWorld.Fill( 0 ); -//// m_PlaneGeometry->IndexToWorld( offsetIndex, offsetWorld ); -//// // remove origin shift -//// const Point3D origin = m_PlaneGeometry->GetOrigin(); -//// offsetWorld[0] -= origin[0]; -//// offsetWorld[1] -= origin[1]; -//// offsetWorld[2] -= origin[2]; -//// // offset world coordinate -//// worldPointIn3D[ 0 ] += offsetWorld[0]; -//// worldPointIn3D[ 1 ] += offsetWorld[1]; -//// worldPointIn3D[ 2 ] += offsetWorld[2]; -////*/ -// // Output index -// -// -////For the purpose of debug -////if( debugCounter%100 == 0) -//////{ -////Point3D contIndex; -////m_ImageGeometry3D->WorldToIndex(worldPointIn3D,contIndex); -////overriderFile.precision(10); -////overriderFile<<"2D-Index: [ "<(inputIterator.Get() - outputPixel ) ); // oh oh, not good for -// bigger values -// ++inputIterator; -////++debugCounter; -// //++diffIterator; -// } -// /*overriderFile.close(); -// overriderFileIndex.close();*/ -// geometryFile.close(); -// -///* -// typename VolumeImageType::RegionType sliceInVolumeRegion; -// -// sliceInVolumeRegion = outputImage->GetLargestPossibleRegion(); -// sliceInVolumeRegion.SetSize( m_SliceDimension, 1 ); // just one slice -// sliceInVolumeRegion.SetIndex( m_SliceDimension, m_SliceIndex ); // exactly this slice, please -// -// OutputSliceIteratorType outputIterator( outputImage, sliceInVolumeRegion ); -// outputIterator.SetFirstDirection(m_Dimension0); -// outputIterator.SetSecondDirection(m_Dimension1); -// -// // iterate over output slice (and over input slice simultaneously) -// outputIterator.GoToBegin(); -// while ( !outputIterator.IsAtEnd() ) -// { -// while ( !outputIterator.IsAtEndOfSlice() ) -// { -// while ( !outputIterator.IsAtEndOfLine() ) -// { -// diffIterator.Set( static_cast(inputIterator.Get() - outputIterator.Get()) ); // oh oh, not -// good for bigger values -// outputIterator.Set( (TPixel2) inputIterator.Get() ); -// ++outputIterator; -// ++inputIterator; -// ++diffIterator; -// } -// outputIterator.NextLine(); -// } -// outputIterator.NextSlice(); -// } -// */ -//} -/* -std::string mitk::OverwriteDirectedPlaneImageFilter::EventDescription( unsigned int sliceDimension, unsigned int -sliceIndex, unsigned int timeStep ) -{ -std::stringstream s; - -s << "Changed slice ("; - -switch (sliceDimension) -{ -default: -case 2: -s << "T"; -break; -case 1: -s << "C"; -break; -case 0: -s << "S"; -break; -} - -s << " " << sliceIndex << " " << timeStep << ")"; - -return s.str(); -} -*/ diff --git a/Modules/Segmentation/Algorithms/mitkOverwriteDirectedPlaneImageFilter.h b/Modules/Segmentation/Algorithms/mitkOverwriteDirectedPlaneImageFilter.h deleted file mode 100644 index c87c74a6dd..0000000000 --- a/Modules/Segmentation/Algorithms/mitkOverwriteDirectedPlaneImageFilter.h +++ /dev/null @@ -1,117 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ - -#ifndef mitkOverwriteDirectedPlaneImageFilter_h_Included -#define mitkOverwriteDirectedPlaneImageFilter_h_Included - -#include "mitkCommon.h" -#include "mitkImageToImageFilter.h" -#include - -#include - -namespace mitk -{ - /** - \deprecated This class is deprecated. Use mitkVtkImageOverwrite instead. - \sa mitkVtkImageOverwrite - - \brief Writes a 2D slice into a 3D image. - - \sa SegTool2D - \sa ContourTool - \sa ExtractImageFilter - - \ingroup Process - \ingroup Reliver - - This class takes a 3D mitk::Image as input and tries to replace one slice in it with the second input image, which - is specified - by calling SetSliceImage with a 2D mitk::Image. - - Two parameters determine which slice is replaced: the "slice dimension" is that one, which is constant for all - points in the plane, e.g. axial would mean 2. - The "slice index" is the slice index in the image direction you specified with "affected dimension". Indices count - from zero. - - This class works with all kind of image types, the only restrictions being that the input is 3D, and the slice image - is 2D. - - If requested by SetCreateUndoInformation(true), this class will create instances of ApplyDiffImageOperation for the - undo stack. - These operations will (on user request) be executed by DiffImageApplier to perform undo. - - Last contributor: $Author: maleike $ - */ - class MITKSEGMENTATION_EXPORT OverwriteDirectedPlaneImageFilter : public ImageToImageFilter - { - public: - mitkClassMacro(OverwriteDirectedPlaneImageFilter, ImageToImageFilter); - itkFactorylessNewMacro(Self); - itkCloneMacro(Self); - - /** - \brief Which plane to overwrite - */ - const BaseGeometry *GetPlaneGeometry3D() const - { - return m_PlaneGeometry; - } - void SetPlaneGeometry3D(const BaseGeometry *geometry) { m_PlaneGeometry = geometry; } - /** - \brief Time step of the slice to overwrite - */ - itkSetMacro(TimeStep, unsigned int); - itkGetConstMacro(TimeStep, unsigned int); - - /** - \brief Whether to create undo operation in the MITK undo stack - */ - itkSetMacro(CreateUndoInformation, bool); - itkGetConstMacro(CreateUndoInformation, bool); - - itkSetObjectMacro(SliceImage, Image); - const Image *GetSliceImage() { return m_SliceImage.GetPointer(); } - const Image *GetLastDifferenceImage() { return m_SliceDifferenceImage.GetPointer(); } - protected: - OverwriteDirectedPlaneImageFilter(); // purposely hidden - ~OverwriteDirectedPlaneImageFilter() override; - - void GenerateData() override; - - template - void ItkSliceOverwriting(itk::Image *input3D); - - template - void ItkImageSwitch(itk::Image *image); - - template - void ItkImageProcessing(itk::Image *itkImage1, - itk::Image *itkImage2); - - // std::string EventDescription( unsigned int sliceDimension, unsigned int sliceIndex, unsigned int timeStep ); - - Image::ConstPointer m_SliceImage; - Image::Pointer m_SliceDifferenceImage; - - const BaseGeometry *m_PlaneGeometry; - const BaseGeometry *m_ImageGeometry3D; - unsigned int m_TimeStep; - unsigned int m_Dimension0; - unsigned int m_Dimension1; - - bool m_CreateUndoInformation; - }; - -} // namespace - -#endif diff --git a/Modules/Segmentation/Algorithms/mitkOverwriteSliceImageFilter.cpp b/Modules/Segmentation/Algorithms/mitkOverwriteSliceImageFilter.cpp deleted file mode 100644 index 53fb98bbb2..0000000000 --- a/Modules/Segmentation/Algorithms/mitkOverwriteSliceImageFilter.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ - -#include "mitkOverwriteSliceImageFilter.h" -#include "mitkApplyDiffImageOperation.h" -#include "mitkDiffImageApplier.h" -#include "mitkImageAccessByItk.h" -#include "mitkImageCast.h" -#include "mitkImageTimeSelector.h" -#include "mitkInteractionConst.h" -#include "mitkOperationEvent.h" -#include "mitkSegmentationInterpolationController.h" -#include "mitkUndoController.h" - -#include -#include - -mitk::OverwriteSliceImageFilter::OverwriteSliceImageFilter() - : m_SliceIndex(0), - m_SliceDimension(0), - m_TimeStep(0), - m_Dimension0(0), - m_Dimension1(1), - m_CreateUndoInformation(false) -{ - MITK_WARN << "Class is deprecated! Use mitkVtkImageOverwrite instead."; -} - -mitk::OverwriteSliceImageFilter::~OverwriteSliceImageFilter() -{ -} - -void mitk::OverwriteSliceImageFilter::GenerateData() -{ - // - // this is the place to implement the major part of undo functionality (bug #491) - // here we have to create undo/do operations - // - // WHO is the operation actor? This object may not be destroyed ever (design of undo stack)! - // -> some singleton method of this filter? - // - // neccessary additional objects: - // - something that executes the operations - // - the operation class (must hold a binary diff or something) - // - observer commands to know when the image is deleted (no further action then, perhaps even remove the operations - // from the undo stack) - // - Image::ConstPointer input = ImageToImageFilter::GetInput(0); - Image::Pointer input3D = ImageToImageFilter::GetInput(0); - - Image::ConstPointer slice = m_SliceImage; - - if (input.IsNull() || slice.IsNull()) - return; - - switch (m_SliceDimension) - { - default: - case 2: - m_Dimension0 = 0; - m_Dimension1 = 1; - break; - case 1: - m_Dimension0 = 0; - m_Dimension1 = 2; - break; - case 0: - m_Dimension0 = 1; - m_Dimension1 = 2; - break; - } - - if (slice->GetDimension() < 2 || input->GetDimension() > 4 || - slice->GetDimension(0) != input->GetDimension(m_Dimension0) || - slice->GetDimension(1) != input->GetDimension(m_Dimension1) || - m_SliceIndex >= input->GetDimension(m_SliceDimension)) - { - itkExceptionMacro("Slice and image dimensions differ or slice index is too large. Sorry, cannot work like this."); - return; - } - - if (input->GetDimension() == 4) - { - ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); - timeSelector->SetInput(input); - timeSelector->SetTimeNr(m_TimeStep); - timeSelector->UpdateLargestPossibleRegion(); - input3D = timeSelector->GetOutput(); - } - - if (m_SliceDifferenceImage.IsNull() || m_SliceDifferenceImage->GetDimension(0) != m_SliceImage->GetDimension(0) || - m_SliceDifferenceImage->GetDimension(1) != m_SliceImage->GetDimension(1)) - { - m_SliceDifferenceImage = mitk::Image::New(); - mitk::PixelType pixelType(mitk::MakeScalarPixelType()); - m_SliceDifferenceImage->Initialize(pixelType, 2, m_SliceImage->GetDimensions()); - } - - // MITK_INFO << "Overwriting slice " << m_SliceIndex << " in dimension " << m_SliceDimension << " at time step " << - // m_TimeStep << std::endl; - // this will do a long long if/else to find out both pixel types - AccessFixedDimensionByItk(input3D, ItkImageSwitch, 3); - - SegmentationInterpolationController *interpolator = SegmentationInterpolationController::InterpolatorForImage(input); - if (interpolator) - { - interpolator->BlockModified(true); - interpolator->SetChangedSlice(m_SliceDifferenceImage, m_SliceDimension, m_SliceIndex, m_TimeStep); - } - - if (m_CreateUndoInformation) - { - // create do/undo operations (we don't execute the doOp here, because it has already been executed during - // calculation of the diff image - auto doOp = new ApplyDiffImageOperation(OpTEST, - const_cast(input.GetPointer()), - m_SliceDifferenceImage, - m_TimeStep, - m_SliceDimension, - m_SliceIndex); - auto undoOp = new ApplyDiffImageOperation(OpTEST, - const_cast(input.GetPointer()), - m_SliceDifferenceImage, - m_TimeStep, - m_SliceDimension, - m_SliceIndex); - undoOp->SetFactor(-1.0); - OperationEvent *undoStackItem = - new OperationEvent(DiffImageApplier::GetInstanceForUndo(), - doOp, - undoOp, - this->EventDescription(m_SliceDimension, m_SliceIndex, m_TimeStep)); - OperationEvent::IncCurrObjectEventId(); - UndoController::GetCurrentUndoModel()->SetOperationEvent(undoStackItem); - } - - // this image is modified (good to know for the renderer) - input->Modified(); - - if (interpolator) - { - interpolator->BlockModified(false); - } -} - -// basically copied from mitk/Core/Algorithms/mitkImageAccessByItk.h -#define myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, itkImageTypeFunction, pixeltype, dimension, itkimage2) \ - if (typeId == MapPixelComponentType::value) \ - \ -{ \ - typedef itk::Image ImageType; \ - typedef mitk::ImageToItk ImageToItkType; \ - itk::SmartPointer imagetoitk = ImageToItkType::New(); \ - const mitk::Image *constImage = mitkImage; \ - mitk::Image *nonConstImage = const_cast(constImage); \ - nonConstImage->Update(); \ - imagetoitk->SetInput(nonConstImage); \ - imagetoitk->Update(); \ - itkImageTypeFunction(imagetoitk->GetOutput(), itkimage2); \ - \ -} - -#define myMITKOverwriteSliceImageFilterAccessAllTypesByItk(mitkImage, itkImageTypeFunction, dimension, itkimage2) \ - \ -{ \ - myMITKOverwriteSliceImageFilterAccessByItk( \ - mitkImage, \ - itkImageTypeFunction, \ - double, \ - dimension, \ - itkimage2) else myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, \ - itkImageTypeFunction, \ - float, \ - dimension, \ - itkimage2) else myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, itkImageTypeFunction, int, dimension, itkimage2) else myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, itkImageTypeFunction, unsigned int, dimension, itkimage2) else myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, \ - itkImageTypeFunction, \ - short, \ - dimension, \ - itkimage2) else myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, itkImageTypeFunction, unsigned short, dimension, itkimage2) else myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, \ - itkImageTypeFunction, \ - char, \ - dimension, \ - itkimage2) else myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, \ - itkImageTypeFunction, \ - unsigned char, \ - dimension, \ - itkimage2) \ - \ -} - -template -void mitk::OverwriteSliceImageFilter::ItkImageSwitch(itk::Image *itkImage) -{ - const int typeId = m_SliceImage->GetPixelType().GetComponentType(); - - myMITKOverwriteSliceImageFilterAccessAllTypesByItk(m_SliceImage, ItkImageProcessing, 2, itkImage); -} - -template -void mitk::OverwriteSliceImageFilter::ItkImageProcessing(const itk::Image *inputImage, - itk::Image *outputImage) -{ - typedef itk::Image SliceImageType; - typedef itk::Image DiffImageType; - typedef itk::Image VolumeImageType; - - typedef itk::ImageSliceIteratorWithIndex OutputSliceIteratorType; - typedef itk::ImageRegionConstIterator InputSliceIteratorType; - typedef itk::ImageRegionIterator DiffSliceIteratorType; - - typename VolumeImageType::RegionType sliceInVolumeRegion; - - sliceInVolumeRegion = outputImage->GetLargestPossibleRegion(); - sliceInVolumeRegion.SetSize(m_SliceDimension, 1); // just one slice - sliceInVolumeRegion.SetIndex(m_SliceDimension, m_SliceIndex); // exactly this slice, please - - OutputSliceIteratorType outputIterator(outputImage, sliceInVolumeRegion); - outputIterator.SetFirstDirection(m_Dimension0); - outputIterator.SetSecondDirection(m_Dimension1); - - InputSliceIteratorType inputIterator(inputImage, inputImage->GetLargestPossibleRegion()); - - typename DiffImageType::Pointer diffImage; - CastToItkImage(m_SliceDifferenceImage, diffImage); - DiffSliceIteratorType diffIterator(diffImage, diffImage->GetLargestPossibleRegion()); - - // iterate over output slice (and over input slice simultaneously) - outputIterator.GoToBegin(); - inputIterator.GoToBegin(); - diffIterator.GoToBegin(); - while (!outputIterator.IsAtEnd()) - { - while (!outputIterator.IsAtEndOfSlice()) - { - while (!outputIterator.IsAtEndOfLine()) - { - diffIterator.Set(static_cast(inputIterator.Get() - - outputIterator.Get())); // oh oh, not good for bigger values - outputIterator.Set((TPixel2)inputIterator.Get()); - ++outputIterator; - ++inputIterator; - ++diffIterator; - } - outputIterator.NextLine(); - } - outputIterator.NextSlice(); - } -} - -std::string mitk::OverwriteSliceImageFilter::EventDescription(unsigned int sliceDimension, - unsigned int sliceIndex, - unsigned int timeStep) -{ - std::stringstream s; - - s << "Changed slice ("; - - switch (sliceDimension) - { - default: - case 2: - s << "T"; - break; - case 1: - s << "C"; - break; - case 0: - s << "S"; - break; - } - - s << " " << sliceIndex << " " << timeStep << ")"; - - return s.str(); -} diff --git a/Modules/Segmentation/Algorithms/mitkOverwriteSliceImageFilter.h b/Modules/Segmentation/Algorithms/mitkOverwriteSliceImageFilter.h deleted file mode 100644 index 97db8915ef..0000000000 --- a/Modules/Segmentation/Algorithms/mitkOverwriteSliceImageFilter.h +++ /dev/null @@ -1,121 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ - -#ifndef mitkOverwriteSliceImageFilter_h_Included -#define mitkOverwriteSliceImageFilter_h_Included - -#include "mitkCommon.h" -#include "mitkImageToImageFilter.h" -#include - -#include - -namespace mitk -{ - /** - \deprecated This class is deprecated. Use mitkVtkImageOverwrite instead. - \sa mitkVtkImageOverwrite - - \brief Writes a 2D slice into a 3D image. - - \sa SegTool2D - \sa ContourTool - \sa ExtractImageFilter - - \ingroup Process - \ingroup ToolManagerEtAl - - This class takes a 3D mitk::Image as input and tries to replace one slice in it with the second input image, which - is specified - by calling SetSliceImage with a 2D mitk::Image. - - Two parameters determine which slice is replaced: the "slice dimension" is that one, which is constant for all - points in the plane, e.g. axial would mean 2. - The "slice index" is the slice index in the image direction you specified with "affected dimension". Indices count - from zero. - - This class works with all kind of image types, the only restrictions being that the input is 3D, and the slice image - is 2D. - - If requested by SetCreateUndoInformation(true), this class will create instances of ApplyDiffImageOperation for the - undo stack. - These operations will (on user request) be executed by DiffImageApplier to perform undo. - - Last contributor: $Author$ - */ - class MITKSEGMENTATION_EXPORT OverwriteSliceImageFilter : public ImageToImageFilter - { - public: - mitkClassMacro(OverwriteSliceImageFilter, ImageToImageFilter); - itkFactorylessNewMacro(Self); - itkCloneMacro(Self); - - /** - \brief Which slice to overwrite (first one has index 0). - */ - itkSetMacro(SliceIndex, unsigned int); - itkGetConstMacro(SliceIndex, unsigned int); - - /** - \brief The orientation of the slice to overwrite. - - \a Parameter \a SliceDimension Number of the dimension which is constant for all pixels of the desired slices - (e.g. 0 for axial) - */ - itkSetMacro(SliceDimension, unsigned int); - itkGetConstMacro(SliceDimension, unsigned int); - - /** - \brief Time step of the slice to overwrite - */ - itkSetMacro(TimeStep, unsigned int); - itkGetConstMacro(TimeStep, unsigned int); - - /** - \brief Whether to create undo operation in the MITK undo stack - */ - itkSetMacro(CreateUndoInformation, bool); - itkGetConstMacro(CreateUndoInformation, bool); - - itkSetObjectMacro(SliceImage, Image); - const Image *GetSliceImage() { return m_SliceImage.GetPointer(); } - const Image *GetLastDifferenceImage() { return m_SliceDifferenceImage.GetPointer(); } - protected: - OverwriteSliceImageFilter(); // purposely hidden - ~OverwriteSliceImageFilter() override; - - void GenerateData() override; - - template - void ItkImageSwitch(itk::Image *image); - - template - void ItkImageProcessing(const itk::Image *itkImage1, - itk::Image *itkImage2); - - std::string EventDescription(unsigned int sliceDimension, unsigned int sliceIndex, unsigned int timeStep); - - Image::ConstPointer m_SliceImage; - Image::Pointer m_SliceDifferenceImage; - - unsigned int m_SliceIndex; - unsigned int m_SliceDimension; - unsigned int m_TimeStep; - unsigned int m_Dimension0; - unsigned int m_Dimension1; - - bool m_CreateUndoInformation; - }; - -} // namespace - -#endif diff --git a/Modules/Segmentation/Interactions/mitkContourTool.h b/Modules/Segmentation/Interactions/mitkContourTool.h index 23e7d7a79c..601aa226d0 100644 --- a/Modules/Segmentation/Interactions/mitkContourTool.h +++ b/Modules/Segmentation/Interactions/mitkContourTool.h @@ -1,71 +1,70 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkContourTool_h_Included #define mitkContourTool_h_Included #include "mitkCommon.h" #include "mitkFeedbackContourTool.h" #include namespace mitk { class Image; class StateMachineAction; class InteractionEvent; /** \brief Simple contour filling tool. \sa FeedbackContourTool \sa ExtractImageFilter - \sa OverwriteSliceImageFilter \ingroup Interaction \ingroup ToolManagerEtAl Fills a visible contour (from FeedbackContourTool) during mouse dragging. When the mouse button is released, ContourTool tries to extract a slice from the working image and fill in the (filled) contour as a binary image. The painting "color" is defined by m_PaintingPixelValue, which is set in the constructor (by sub-classes) or during some event (e.g. in OnInvertLogic - when CTRL is pressed). \warning Only to be instantiated by mitk::ToolManager. $Author$ */ class MITKSEGMENTATION_EXPORT ContourTool : public FeedbackContourTool { public: mitkClassMacro(ContourTool, FeedbackContourTool); protected: ContourTool(int paintingPixelValue = 1); // purposely hidden ~ContourTool() override; void Activated() override; void Deactivated() override; virtual void OnMousePressed(StateMachineAction *, InteractionEvent *interactionEvent); virtual void OnMouseMoved(StateMachineAction *, InteractionEvent *interactionEvent); virtual void OnMouseReleased(StateMachineAction *, InteractionEvent *interactionEvent); virtual void OnInvertLogic(StateMachineAction *, InteractionEvent *interactionEvent); void ConnectActionsAndFunctions() override; int m_PaintingPixelValue; }; } // namespace #endif diff --git a/Modules/Segmentation/Interactions/mitkDrawPaintbrushTool.h b/Modules/Segmentation/Interactions/mitkDrawPaintbrushTool.h index b86a9a3613..441d02480c 100644 --- a/Modules/Segmentation/Interactions/mitkDrawPaintbrushTool.h +++ b/Modules/Segmentation/Interactions/mitkDrawPaintbrushTool.h @@ -1,63 +1,62 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkPaintContourTool_h_Included #define mitkPaintContourTool_h_Included #include "mitkPaintbrushTool.h" #include namespace us { class ModuleResource; } namespace mitk { /** \brief Paintbrush tool for InteractiveSegmentation \sa FeedbackContourTool \sa ExtractImageFilter - \sa OverwriteSliceImageFilter \ingroup Interaction \ingroup ToolManagerEtAl Simple paintbrush drawing tool. Right now there are only circular pens of varying size. This class specified only the drawing "color" for the super class PaintbrushTool. \warning Only to be instantiated by mitk::ToolManager. $Author: maleike $ */ class MITKSEGMENTATION_EXPORT DrawPaintbrushTool : public PaintbrushTool { public: mitkClassMacro(DrawPaintbrushTool, PaintbrushTool); itkFactorylessNewMacro(Self); itkCloneMacro(Self); const char **GetXPM() const override; us::ModuleResource GetCursorIconResource() const override; us::ModuleResource GetIconResource() const override; const char *GetName() const override; protected: DrawPaintbrushTool(); // purposely hidden ~DrawPaintbrushTool() override; }; } // namespace #endif diff --git a/Modules/Segmentation/Interactions/mitkErasePaintbrushTool.h b/Modules/Segmentation/Interactions/mitkErasePaintbrushTool.h index 0111688c0b..3f99fdd22c 100644 --- a/Modules/Segmentation/Interactions/mitkErasePaintbrushTool.h +++ b/Modules/Segmentation/Interactions/mitkErasePaintbrushTool.h @@ -1,63 +1,62 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkErasePaintbrushTool_h_Included #define mitkErasePaintbrushTool_h_Included #include "mitkPaintbrushTool.h" #include namespace us { class ModuleResource; } namespace mitk { /** \brief Paintbrush tool for InteractiveSegmentation \sa FeedbackContourTool \sa ExtractImageFilter - \sa OverwriteSliceImageFilter \ingroup Interaction \ingroup ToolManagerEtAl Simple paintbrush drawing tool. Right now there are only circular pens of varying size. This class specified only the drawing "color" for the super class PaintbrushTool. \warning Only to be instantiated by mitk::ToolManager. $Author: maleike $ */ class MITKSEGMENTATION_EXPORT ErasePaintbrushTool : public PaintbrushTool { public: mitkClassMacro(ErasePaintbrushTool, PaintbrushTool); itkFactorylessNewMacro(Self); itkCloneMacro(Self); const char **GetXPM() const override; us::ModuleResource GetCursorIconResource() const override; us::ModuleResource GetIconResource() const override; const char *GetName() const override; protected: ErasePaintbrushTool(); // purposely hidden ~ErasePaintbrushTool() override; }; } // namespace #endif diff --git a/Modules/Segmentation/Interactions/mitkPaintbrushTool.h b/Modules/Segmentation/Interactions/mitkPaintbrushTool.h index b8c4074376..d0d5731aae 100644 --- a/Modules/Segmentation/Interactions/mitkPaintbrushTool.h +++ b/Modules/Segmentation/Interactions/mitkPaintbrushTool.h @@ -1,101 +1,100 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkPaintbrushTool_h_Included #define mitkPaintbrushTool_h_Included #include "mitkCommon.h" #include "mitkFeedbackContourTool.h" #include namespace mitk { class StateMachineAction; class InteractionEvent; class InteractionPositionEvent; /** \brief Paintbrush tool for InteractiveSegmentation \sa FeedbackContourTool \sa ExtractImageFilter - \sa OverwriteSliceImageFilter \ingroup Interaction \ingroup ToolManagerEtAl Simple paintbrush drawing tool. Right now there are only circular pens of varying size. \warning Only to be instantiated by mitk::ToolManager. $Author: maleike $ */ class MITKSEGMENTATION_EXPORT PaintbrushTool : public FeedbackContourTool { public: // sent when the pen size is changed or should be updated in a GUI. Message1 SizeChanged; mitkClassMacro(PaintbrushTool, FeedbackContourTool); void SetSize(int value); protected: PaintbrushTool(int paintingPixelValue = 1); // purposely hidden ~PaintbrushTool() override; void ConnectActionsAndFunctions() override; void Activated() override; void Deactivated() override; virtual void OnMousePressed(StateMachineAction *, InteractionEvent *); virtual void OnMouseMoved(StateMachineAction *, InteractionEvent *); virtual void OnPrimaryButtonPressedMoved(StateMachineAction *, InteractionEvent *); virtual void MouseMoved(mitk::InteractionEvent *interactionEvent, bool leftMouseButtonPressed); virtual void OnMouseReleased(StateMachineAction *, InteractionEvent *); virtual void OnInvertLogic(StateMachineAction *, InteractionEvent *); /** * \todo This is a possible place where to introduce * different types of pens */ void UpdateContour(const InteractionPositionEvent *); /** * Little helper function. Returns the upper left corner of the given pixel. */ mitk::Point2D upperLeft(mitk::Point2D p); /** * Checks if the current slice has changed */ void CheckIfCurrentSliceHasChanged(const InteractionPositionEvent *event); void OnToolManagerWorkingDataModified(); int m_PaintingPixelValue; static int m_Size; ContourModel::Pointer m_MasterContour; int m_LastContourSize; Image::Pointer m_WorkingSlice; PlaneGeometry::ConstPointer m_CurrentPlane; DataNode::Pointer m_WorkingNode; mitk::Point3D m_LastPosition; }; } // namespace #endif diff --git a/Modules/Segmentation/Interactions/mitkSetRegionTool.h b/Modules/Segmentation/Interactions/mitkSetRegionTool.h index b1fc705dab..fbaa1c2ecb 100644 --- a/Modules/Segmentation/Interactions/mitkSetRegionTool.h +++ b/Modules/Segmentation/Interactions/mitkSetRegionTool.h @@ -1,64 +1,63 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkSetRegionTool_h_Included #define mitkSetRegionTool_h_Included #include "mitkCommon.h" #include "mitkFeedbackContourTool.h" #include namespace mitk { class Image; class StateMachineAction; class InteractionEvent; /** \brief Fills or erases a 2D region \sa FeedbackContourTool \sa ExtractImageFilter - \sa OverwriteSliceImageFilter \ingroup Interaction \ingroup ToolManagerEtAl Finds the outer contour of a shape in 2D (possibly including holes) and sets all the inside pixels to a specified value. This might fill holes or erase segmentations. \warning Only to be instantiated by mitk::ToolManager. $Author$ */ class MITKSEGMENTATION_EXPORT SetRegionTool : public FeedbackContourTool { public: mitkClassMacro(SetRegionTool, FeedbackContourTool); protected: SetRegionTool(int paintingPixelValue = 1); // purposely hidden ~SetRegionTool() override; void ConnectActionsAndFunctions() override; void Activated() override; void Deactivated() override; virtual void OnMousePressed(StateMachineAction *, InteractionEvent *); virtual void OnMouseReleased(StateMachineAction *, InteractionEvent *); virtual void OnMouseMoved(StateMachineAction *, InteractionEvent *); int m_PaintingPixelValue; }; } // namespace #endif diff --git a/Modules/Segmentation/Testing/files.cmake b/Modules/Segmentation/Testing/files.cmake index 9330f21eb2..c707e4775d 100644 --- a/Modules/Segmentation/Testing/files.cmake +++ b/Modules/Segmentation/Testing/files.cmake @@ -1,29 +1,26 @@ set(MODULE_TESTS mitkContourMapper2DTest.cpp mitkContourTest.cpp mitkContourModelSetToImageFilterTest.cpp mitkDataNodeSegmentationTest.cpp mitkFeatureBasedEdgeDetectionFilterTest.cpp mitkImageToContourFilterTest.cpp mitkSegmentationInterpolationTest.cpp mitkOverwriteSliceFilterTest.cpp mitkOverwriteSliceFilterObliquePlaneTest.cpp # mitkToolManagerTest.cpp mitkToolManagerProviderTest.cpp mitkManualSegmentationToSurfaceFilterTest.cpp #new cpp unit style mitkToolInteractionTest.cpp ) -set(MODULE_IMAGE_TESTS - mitkOverwriteSliceImageFilterTest.cpp #only runs on images -) set(MODULE_CUSTOM_TESTS ) set(MODULE_TESTIMAGE US4DCyl.nrrd Pic3D.nrrd Pic2DplusT.nrrd BallBinary30x30x30.nrrd Png2D-bw.png ) diff --git a/Modules/Segmentation/Testing/mitkOverwriteSliceImageFilterTest.cpp b/Modules/Segmentation/Testing/mitkOverwriteSliceImageFilterTest.cpp deleted file mode 100644 index 604d647f6f..0000000000 --- a/Modules/Segmentation/Testing/mitkOverwriteSliceImageFilterTest.cpp +++ /dev/null @@ -1,366 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ - -#include "mitkCompareImageSliceTestHelper.h" -#include "mitkCoreObjectFactory.h" -#include "mitkExtractImageFilter.h" -#include "mitkOverwriteSliceImageFilter.h" - -#include - -unsigned int CompareImageSliceTestHelper::m_Dimension0 = 0; -unsigned int CompareImageSliceTestHelper::m_Dimension1 = 0; -unsigned int CompareImageSliceTestHelper::m_SliceDimension = 0; -unsigned int CompareImageSliceTestHelper::m_SliceIndex = 0; -bool CompareImageSliceTestHelper::m_ComparisonResult = false; -mitk::Image *CompareImageSliceTestHelper::m_SliceImage = nullptr; - -class mitkOverwriteSliceImageFilterTestClass -{ -public: - static void Test3D(mitk::OverwriteSliceImageFilter *filter, mitk::Image *image, unsigned int &numberFailed) - { - assert(filter); - assert(image); - - filter->SetInput(image); - - unsigned int initialNumberFailed = numberFailed; - bool exception = false; - // first extract slices and rewrite them - for (unsigned int sliceDimension = 0; sliceDimension < 3; ++sliceDimension) - { - mitk::ExtractImageFilter::Pointer extractor = mitk::ExtractImageFilter::New(); - extractor->SetInput(image); - extractor->SetSliceDimension(sliceDimension); - extractor->SetSliceIndex(2); // third slice in that direction - - try - { - extractor->Update(); - } - catch (...) - { - if (sliceDimension < 3) - { - // probably no sliceindex 2 there or extractor just doesn't work (check the corresponding test) - std::cout << " (WW) Couldn't extract slice number 3 from a 3D image. This could be a problem if the image " - "is not only two slices big." - << std::endl; - continue; - } - else - { - continue; // good - } - } - - mitk::Image::Pointer slice = extractor->GetOutput()->Clone(); - - filter->SetSliceDimension(sliceDimension); - filter->SetSliceIndex(1); // second slice in that direction - filter->SetSliceImage(slice); - - try - { - filter->Update(); // try to overwrite - } - catch (...) - { - if (sliceDimension < 3) - { - ++numberFailed; - std::cerr << " (EE) Couln't overwrite a slice with data from a neigbor in a " << image->GetDimension() - << "-dimensional image, sliceDimension " << sliceDimension << " sliceIndex 1-2." - << "(l. " << __LINE__ << ")" << std::endl; - } - else - { - // this was expected and is nice to see - continue; - } - } - - mitk::Image::Pointer output = filter->GetOutput(); - - if (output.IsNull()) - { - ++numberFailed; - std::cerr << " (EE) Overwrite filter has output nullptr and gave no exception for an " << image->GetDimension() - << "-dimensional image, sliceDimension " << sliceDimension << " sliceIndex 1-2." - << "(l. " << __LINE__ << ")" << std::endl; - continue; - } - - if (!CompareImageSliceTestHelper::CompareSlice(image, sliceDimension, 1, slice)) - { - ++numberFailed; - std::cerr << " (EE) Overwriting a slice seemed to work, but the pixels are not correct for an " - << image->GetDimension() << "-dimensional image, sliceDimension " << sliceDimension - << " sliceIndex 1-2." - << "(l. " << __LINE__ << ")" << std::endl; - } - - // try inserting at a position outside the image - filter->SetSliceDimension(sliceDimension); - filter->SetSliceIndex(image->GetDimension(sliceDimension)); // last possible slice index + 1 - filter->SetSliceImage(slice); - - exception = false; - try - { - filter->Update(); // try to overwrite - } - catch (...) - { - exception = true; - } - - if (!exception) - { - ++numberFailed; - std::cerr << " (EE) Inserting a slice outside the 3D volume did NOT throw an exception for an " - << image->GetDimension() << "-dimensional image, sliceDimension " << sliceDimension - << " sliceIndex 1-2." - << "(l. " << __LINE__ << ")" << std::endl; - } - - mitk::Image::Pointer originalSlice = slice; - - // now test slices that just don't fit (slice too big) - { - unsigned int dim[] = {slice->GetDimension(0) + 2, slice->GetDimension(1) + 2}; - slice = mitk::Image::New(); - slice->Initialize(mitk::MakeScalarPixelType(), 2, dim); - unsigned int i; - mitk::ImageWriteAccessor accessor(slice); - auto *p = (signed int *)accessor.GetData(); - unsigned int size = dim[0] * dim[1]; - for (i = 0; i < size; ++i, ++p) - *p = (signed int)i; - - // try to insert this bad slice - filter->SetSliceImage(slice); - exception = false; - try - { - filter->Update(); // try to overwrite - } - catch (...) - { - exception = true; - } - - if (!exception) - { - ++numberFailed; - std::cerr << " (EE) Trying to insert a slice of bad dimensions (larger) did NOT throw an exception in an " - << image->GetDimension() << "-dimensional image, sliceDimension " << sliceDimension - << " sliceIndex 1-2." - << "(l. " << __LINE__ << ")" << std::endl; - } - } - - // now test slices that just don't fit (slice too small) - { - slice = originalSlice; - if ((slice->GetDimension(0) < 3) || (slice->GetDimension(1) < 3)) - continue; // not possible shrink the image much further - unsigned int dim[] = {slice->GetDimension(0) - 2, slice->GetDimension(1) - 2}; - slice = mitk::Image::New(); - slice->Initialize(mitk::MakeScalarPixelType(), 2, dim); - unsigned int i; - mitk::ImageWriteAccessor accessor(slice); - auto *p = (signed int *)accessor.GetData(); - unsigned int size = dim[0] * dim[1]; - for (i = 0; i < size; ++i, ++p) - *p = (signed int)i; - - // try to insert this bad slice - filter->SetSliceImage(slice); - exception = false; - try - { - filter->Update(); // try to overwrite - } - catch (...) - { - exception = true; - } - - if (!exception) - { - ++numberFailed; - std::cerr << " (EE) Trying to insert a slice of bad dimensions (smaller) did NOT throw an exception in an " - << image->GetDimension() << "-dimensional image, sliceDimension " << sliceDimension - << " sliceIndex 1-2." - << "(l. " << __LINE__ << ")" << std::endl; - } - } - } - - if (numberFailed == initialNumberFailed) - { - std::cout << " (II) Overwriting works nicely (gives result, pixels are good) " << image->GetDimension() - << "-dimensional image." - << "(l. " << __LINE__ << ")" << std::endl; - } - } - - static void Test2D(mitk::OverwriteSliceImageFilter *filter, mitk::Image *image, unsigned int &numberFailed) - { - assert(filter); - assert(image); - - filter->SetInput(image); - filter->SetSliceImage(image); - bool exception = false; - try - { - filter->Update(); - } - catch (...) - { - exception = true; - } - - if (!exception) - { - std::cerr << " (EE) Using OverwriteImageFilter for 2D -> 2D did not throw an exception " - << "(l. " << __LINE__ << ")" << std::endl; - } - - unsigned int initialNumberFailed = numberFailed; - if (numberFailed == initialNumberFailed) - { - std::cout << " (II) Overwriting works nicely (gives result, pixels are good) " << image->GetDimension() - << "-dimensional image." - << "(l. " << __LINE__ << ")" << std::endl; - } - } - - static void TestOtherD(mitk::OverwriteSliceImageFilter *filter, mitk::Image *image, unsigned int &numberFailed) - { - assert(filter); - assert(image); - - filter->SetInput(image); - filter->SetSliceImage(image); - bool exception = false; - try - { - filter->Update(); - } - catch (...) - { - exception = true; - } - - if (!exception) - { - std::cerr << " (EE) Using OverwriteImageFilter did not throw an exception " - << "(l. " << __LINE__ << ")" << std::endl; - } - - unsigned int initialNumberFailed = numberFailed; - if (numberFailed == initialNumberFailed) - { - std::cout << " (II) Overwriting works nicely (gives result, pixels are good) " << image->GetDimension() - << "-dimensional image." - << "(l. " << __LINE__ << ")" << std::endl; - } - } -}; - -/// ctest entry point -int mitkOverwriteSliceImageFilterTest(int argc, char *argv[]) -{ - // one big variable to tell if anything went wrong - unsigned int numberFailed(0); - - // need one parameter (image filename) - if (argc == 0) - { - std::cerr << "No file specified [FAILED]" << std::endl; - return EXIT_FAILURE; - } - - // load the image - - mitk::Image::Pointer image = nullptr; - try - { - MITK_INFO << "Testing with parameter '" << argv[1] << "'"; - - std::string pathToImage(argv[1]); - image = mitk::IOUtil::Load(pathToImage); - if (image.IsNull()) - { - MITK_INFO << "File not an image - test will not be applied"; - return EXIT_FAILURE; - } - } - catch (itk::ExceptionObject &ex) - { - ++numberFailed; - std::cerr << "Exception: " << ex << "[FAILED]" << std::endl; - return EXIT_FAILURE; - } - - std::cout << " (II) Could load image." << std::endl; - std::cout << "Testing filter instantiation" << std::endl; - - // instantiation - mitk::OverwriteSliceImageFilter::Pointer filter = mitk::OverwriteSliceImageFilter::New(); - if (filter.IsNotNull()) - { - std::cout << " (II) Instantiation works." << std::endl; - } - else - { - ++numberFailed; - std::cout << "Test failed, and it's the ugliest one!" << std::endl; - return EXIT_FAILURE; - } - - // some real work - if (image->GetDimension() == 2) - { - mitkOverwriteSliceImageFilterTestClass::Test2D(filter, image, numberFailed); - } - else if (image->GetDimension() == 3) - { - mitkOverwriteSliceImageFilterTestClass::Test3D(filter, image, numberFailed); - } - else - { - mitkOverwriteSliceImageFilterTestClass::TestOtherD(filter, image, numberFailed); - } - - std::cout << "Testing filter destruction" << std::endl; - - // freeing - filter = nullptr; - - std::cout << " (II) Freeing works." << std::endl; - - if (numberFailed > 0) - { - std::cerr << numberFailed << " tests failed." << std::endl; - return EXIT_FAILURE; - } - else - { - std::cout << "PASSED all tests." << std::endl; - return EXIT_SUCCESS; - } -} diff --git a/Modules/Segmentation/files.cmake b/Modules/Segmentation/files.cmake index cb3c19d915..c4c3643e85 100644 --- a/Modules/Segmentation/files.cmake +++ b/Modules/Segmentation/files.cmake @@ -1,117 +1,115 @@ 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/mitkFeatureBasedEdgeDetectionFilter.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/mitkContourSet.cpp DataManagement/mitkExtrudedContour.cpp Interactions/mitkAdaptiveRegionGrowingTool.cpp Interactions/mitkAddContourTool.cpp Interactions/mitkAutoCropTool.cpp Interactions/mitkAutoSegmentationTool.cpp Interactions/mitkAutoSegmentationWithPreviewTool.cpp Interactions/mitkAutoMLSegmentationWithPreviewTool.cpp Interactions/mitkBinaryThresholdBaseTool.cpp Interactions/mitkBinaryThresholdTool.cpp Interactions/mitkBinaryThresholdULTool.cpp Interactions/mitkCalculateGrayValueStatisticsTool.cpp Interactions/mitkCalculateVolumetryTool.cpp Interactions/mitkContourModelInteractor.cpp Interactions/mitkContourModelLiveWireInteractor.cpp Interactions/mitkLiveWireTool2D.cpp Interactions/mitkContourTool.cpp Interactions/mitkCreateSurfaceTool.cpp Interactions/mitkDrawPaintbrushTool.cpp Interactions/mitkErasePaintbrushTool.cpp Interactions/mitkEraseRegionTool.cpp Interactions/mitkFastMarchingBaseTool.cpp Interactions/mitkFastMarchingTool.cpp Interactions/mitkFastMarchingTool3D.cpp Interactions/mitkFeedbackContourTool.cpp Interactions/mitkFillRegionTool.cpp Interactions/mitkOtsuTool3D.cpp Interactions/mitkPaintbrushTool.cpp Interactions/mitkPixelManipulationTool.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 Rendering/mitkContourMapper2D.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 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/FastMarchingTool.xml Interactions/PickingTool.xml Interactions/PressMoveRelease.xml Interactions/PressMoveReleaseAndPointSetting.xml Interactions/PressMoveReleaseWithCTRLInversion.xml Interactions/PressMoveReleaseWithCTRLInversionAllMouseMoves.xml Interactions/SegmentationToolsConfig.xml Interactions/ContourModelModificationConfig.xml Interactions/ContourModelModificationInteractor.xml ) diff --git a/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp b/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp index 99403aa8b2..0090146b9c 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp @@ -1,1443 +1,1442 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkSlicesInterpolator.h" #include "QmitkSelectableGLWidget.h" #include "QmitkStdMultiWidget.h" #include "mitkApplyDiffImageOperation.h" #include "mitkColorProperty.h" #include "mitkCoreObjectFactory.h" #include "mitkDiffImageApplier.h" #include "mitkInteractionConst.h" #include "mitkLevelWindowProperty.h" #include "mitkOperationEvent.h" -#include "mitkOverwriteSliceImageFilter.h" #include "mitkProgressBar.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkSegTool2D.h" #include "mitkSliceNavigationController.h" #include "mitkSurfaceToImageFilter.h" #include "mitkToolManager.h" #include "mitkUndoController.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { template itk::SmartPointer GetData(const mitk::DataNode* dataNode) { return nullptr != dataNode ? dynamic_cast(dataNode->GetData()) : nullptr; } } float SURFACE_COLOR_RGB[3] = {0.49f, 1.0f, 0.16f}; const std::map QmitkSlicesInterpolator::createActionToSliceDimension() { std::map actionToSliceDimension; foreach (mitk::SliceNavigationController *slicer, m_ControllerToDeleteObserverTag.keys()) { actionToSliceDimension[new QAction(QString::fromStdString(slicer->GetViewDirectionAsString()), nullptr)] = slicer; } return actionToSliceDimension; } QmitkSlicesInterpolator::QmitkSlicesInterpolator(QWidget *parent, const char * /*name*/) : QWidget(parent), // ACTION_TO_SLICEDIMENSION( createActionToSliceDimension() ), m_Interpolator(mitk::SegmentationInterpolationController::New()), m_SurfaceInterpolator(mitk::SurfaceInterpolationController::GetInstance()), m_ToolManager(nullptr), m_Initialized(false), m_LastSNC(nullptr), m_LastSliceIndex(0), m_2DInterpolationEnabled(false), m_3DInterpolationEnabled(false), m_FirstRun(true) { m_GroupBoxEnableExclusiveInterpolationMode = new QGroupBox("Interpolation", this); QVBoxLayout *vboxLayout = new QVBoxLayout(m_GroupBoxEnableExclusiveInterpolationMode); m_EdgeDetector = mitk::FeatureBasedEdgeDetectionFilter::New(); m_PointScorer = mitk::PointCloudScoringFilter::New(); m_CmbInterpolation = new QComboBox(m_GroupBoxEnableExclusiveInterpolationMode); m_CmbInterpolation->addItem("Disabled"); m_CmbInterpolation->addItem("2-Dimensional"); m_CmbInterpolation->addItem("3-Dimensional"); vboxLayout->addWidget(m_CmbInterpolation); m_BtnApply2D = new QPushButton("Confirm for single slice", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnApply2D); m_BtnApplyForAllSlices2D = new QPushButton("Confirm for all slices", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnApplyForAllSlices2D); m_BtnApply3D = new QPushButton("Confirm", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnApply3D); // T28261 // m_BtnSuggestPlane = new QPushButton("Suggest a plane", m_GroupBoxEnableExclusiveInterpolationMode); // vboxLayout->addWidget(m_BtnSuggestPlane); m_BtnReinit3DInterpolation = new QPushButton("Reinit Interpolation", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnReinit3DInterpolation); m_ChkShowPositionNodes = new QCheckBox("Show Position Nodes", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_ChkShowPositionNodes); this->HideAllInterpolationControls(); connect(m_CmbInterpolation, SIGNAL(currentIndexChanged(int)), this, SLOT(OnInterpolationMethodChanged(int))); connect(m_BtnApply2D, SIGNAL(clicked()), this, SLOT(OnAcceptInterpolationClicked())); connect(m_BtnApplyForAllSlices2D, SIGNAL(clicked()), this, SLOT(OnAcceptAllInterpolationsClicked())); connect(m_BtnApply3D, SIGNAL(clicked()), this, SLOT(OnAccept3DInterpolationClicked())); // T28261 // connect(m_BtnSuggestPlane, SIGNAL(clicked()), this, SLOT(OnSuggestPlaneClicked())); connect(m_BtnReinit3DInterpolation, SIGNAL(clicked()), this, SLOT(OnReinit3DInterpolation())); connect(m_ChkShowPositionNodes, SIGNAL(toggled(bool)), this, SLOT(OnShowMarkers(bool))); connect(m_ChkShowPositionNodes, SIGNAL(toggled(bool)), this, SIGNAL(SignalShowMarkerNodes(bool))); QHBoxLayout *layout = new QHBoxLayout(this); layout->addWidget(m_GroupBoxEnableExclusiveInterpolationMode); this->setLayout(layout); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnInterpolationInfoChanged); InterpolationInfoChangedObserverTag = m_Interpolator->AddObserver(itk::ModifiedEvent(), command); itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnSurfaceInterpolationInfoChanged); SurfaceInterpolationInfoChangedObserverTag = m_SurfaceInterpolator->AddObserver(itk::ModifiedEvent(), command2); auto command3 = itk::ReceptorMemberCommand::New(); command3->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnInterpolationAborted); InterpolationAbortedObserverTag = m_Interpolator->AddObserver(itk::AbortEvent(), command3); // feedback node and its visualization properties m_FeedbackNode = mitk::DataNode::New(); mitk::CoreObjectFactory::GetInstance()->SetDefaultProperties(m_FeedbackNode); m_FeedbackNode->SetProperty("binary", mitk::BoolProperty::New(true)); m_FeedbackNode->SetProperty("outline binary", mitk::BoolProperty::New(true)); m_FeedbackNode->SetProperty("color", mitk::ColorProperty::New(255.0, 255.0, 0.0)); m_FeedbackNode->SetProperty("texture interpolation", mitk::BoolProperty::New(false)); m_FeedbackNode->SetProperty("layer", mitk::IntProperty::New(20)); m_FeedbackNode->SetProperty("levelwindow", mitk::LevelWindowProperty::New(mitk::LevelWindow(0, 1))); m_FeedbackNode->SetProperty("name", mitk::StringProperty::New("Interpolation feedback")); m_FeedbackNode->SetProperty("opacity", mitk::FloatProperty::New(0.8)); m_FeedbackNode->SetProperty("helper object", mitk::BoolProperty::New(true)); m_InterpolatedSurfaceNode = mitk::DataNode::New(); m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(SURFACE_COLOR_RGB)); m_InterpolatedSurfaceNode->SetProperty("name", mitk::StringProperty::New("Surface Interpolation feedback")); m_InterpolatedSurfaceNode->SetProperty("opacity", mitk::FloatProperty::New(0.5)); m_InterpolatedSurfaceNode->SetProperty("line width", mitk::FloatProperty::New(4.0f)); 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->SetProperty("color", mitk::ColorProperty::New(0.0, 0.0, 0.0)); m_3DContourNode->SetProperty("hidden object", mitk::BoolProperty::New(true)); m_3DContourNode->SetProperty("name", mitk::StringProperty::New("Drawn Contours")); m_3DContourNode->SetProperty("material.representation", mitk::VtkRepresentationProperty::New(VTK_WIREFRAME)); m_3DContourNode->SetProperty("material.wireframeLineWidth", mitk::FloatProperty::New(2.0f)); m_3DContourNode->SetProperty("3DContourContainer", mitk::BoolProperty::New(true)); m_3DContourNode->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_3DContourNode->SetVisibility( false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget0"))); 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"))); QWidget::setContentsMargins(0, 0, 0, 0); if (QWidget::layout() != nullptr) { QWidget::layout()->setContentsMargins(0, 0, 0, 0); } // For running 3D Interpolation in background // create a QFuture and a QFutureWatcher 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())); } void QmitkSlicesInterpolator::SetDataStorage(mitk::DataStorage::Pointer storage) { if (m_DataStorage == storage) { return; } if (m_DataStorage.IsNotNull()) { m_DataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkSlicesInterpolator::NodeRemoved) ); } m_DataStorage = storage; m_SurfaceInterpolator->SetDataStorage(storage); if (m_DataStorage.IsNotNull()) { m_DataStorage->RemoveNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkSlicesInterpolator::NodeRemoved) ); } } mitk::DataStorage *QmitkSlicesInterpolator::GetDataStorage() { if (m_DataStorage.IsNotNull()) { return m_DataStorage; } else { return nullptr; } } void QmitkSlicesInterpolator::Initialize(mitk::ToolManager *toolManager, const QList &controllers) { Q_ASSERT(!controllers.empty()); if (m_Initialized) { // remove old observers Uninitialize(); } m_ToolManager = toolManager; if (m_ToolManager) { // set enabled only if a segmentation is selected mitk::DataNode *node = m_ToolManager->GetWorkingData(0); QWidget::setEnabled(node != nullptr); // react whenever the set of selected segmentation changes m_ToolManager->WorkingDataChanged += mitk::MessageDelegate(this, &QmitkSlicesInterpolator::OnToolManagerWorkingDataModified); m_ToolManager->ReferenceDataChanged += mitk::MessageDelegate( this, &QmitkSlicesInterpolator::OnToolManagerReferenceDataModified); // 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_TimePoints.insert(slicer, slicer->GetSelectedTimePoint()); itk::MemberCommand::Pointer deleteCommand = itk::MemberCommand::New(); deleteCommand->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnSliceNavigationControllerDeleted); m_ControllerToDeleteObserverTag.insert(slicer, slicer->AddObserver(itk::DeleteEvent(), deleteCommand)); itk::MemberCommand::Pointer timeChangedCommand = itk::MemberCommand::New(); timeChangedCommand->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnTimeChanged); m_ControllerToTimeObserverTag.insert( slicer, slicer->AddObserver(mitk::SliceNavigationController::TimeGeometryEvent(nullptr, 0), timeChangedCommand)); itk::MemberCommand::Pointer sliceChangedCommand = itk::MemberCommand::New(); sliceChangedCommand->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnSliceChanged); m_ControllerToSliceObserverTag.insert( slicer, slicer->AddObserver(mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), sliceChangedCommand)); } ACTION_TO_SLICEDIMENSION = createActionToSliceDimension(); } m_Initialized = true; } void QmitkSlicesInterpolator::Uninitialize() { if (m_ToolManager.IsNotNull()) { m_ToolManager->WorkingDataChanged -= mitk::MessageDelegate(this, &QmitkSlicesInterpolator::OnToolManagerWorkingDataModified); m_ToolManager->ReferenceDataChanged -= mitk::MessageDelegate( this, &QmitkSlicesInterpolator::OnToolManagerReferenceDataModified); } 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)); } ACTION_TO_SLICEDIMENSION.clear(); m_ToolManager = nullptr; m_Initialized = false; } QmitkSlicesInterpolator::~QmitkSlicesInterpolator() { if (m_Initialized) { // remove old observers Uninitialize(); } WaitForFutures(); if (m_DataStorage.IsNotNull()) { m_DataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkSlicesInterpolator::NodeRemoved) ); 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_Interpolator->RemoveObserver(InterpolationAbortedObserverTag); m_Interpolator->RemoveObserver(InterpolationInfoChangedObserverTag); m_SurfaceInterpolator->RemoveObserver(SurfaceInterpolationInfoChangedObserverTag); delete m_Timer; } /** External enableization... */ void QmitkSlicesInterpolator::setEnabled(bool enable) { QWidget::setEnabled(enable); // Set the gui elements of the different interpolation modi enabled if (enable) { if (m_2DInterpolationEnabled) { this->Show2DInterpolationControls(true); m_Interpolator->Activate2DInterpolation(true); } else if (m_3DInterpolationEnabled) { this->Show3DInterpolationControls(true); this->Show3DInterpolationResult(true); } } // Set all gui elements of the interpolation disabled else { this->HideAllInterpolationControls(); this->Show3DInterpolationResult(false); } } void QmitkSlicesInterpolator::On2DInterpolationEnabled(bool status) { OnInterpolationActivated(status); m_Interpolator->Activate2DInterpolation(status); } void QmitkSlicesInterpolator::On3DInterpolationEnabled(bool status) { On3DInterpolationActivated(status); } void QmitkSlicesInterpolator::OnInterpolationDisabled(bool status) { if (status) { OnInterpolationActivated(!status); On3DInterpolationActivated(!status); this->Show3DInterpolationResult(false); } } void QmitkSlicesInterpolator::HideAllInterpolationControls() { this->Show2DInterpolationControls(false); this->Show3DInterpolationControls(false); } void QmitkSlicesInterpolator::Show2DInterpolationControls(bool show) { m_BtnApply2D->setVisible(show); m_BtnApplyForAllSlices2D->setVisible(show); } void QmitkSlicesInterpolator::Show3DInterpolationControls(bool show) { m_BtnApply3D->setVisible(show); // T28261 // m_BtnSuggestPlane->setVisible(show); m_ChkShowPositionNodes->setVisible(show); m_BtnReinit3DInterpolation->setVisible(show); } void QmitkSlicesInterpolator::OnInterpolationMethodChanged(int index) { switch (index) { case 0: // Disabled m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation"); this->HideAllInterpolationControls(); this->OnInterpolationActivated(false); this->On3DInterpolationActivated(false); this->Show3DInterpolationResult(false); m_Interpolator->Activate2DInterpolation(false); break; case 1: // 2D m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation (Enabled)"); this->HideAllInterpolationControls(); this->Show2DInterpolationControls(true); this->OnInterpolationActivated(true); this->On3DInterpolationActivated(false); m_Interpolator->Activate2DInterpolation(true); break; case 2: // 3D m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation (Enabled)"); this->HideAllInterpolationControls(); this->Show3DInterpolationControls(true); this->OnInterpolationActivated(false); this->On3DInterpolationActivated(true); m_Interpolator->Activate2DInterpolation(false); break; default: MITK_ERROR << "Unknown interpolation method!"; m_CmbInterpolation->setCurrentIndex(0); break; } } void QmitkSlicesInterpolator::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)); } } void QmitkSlicesInterpolator::OnToolManagerWorkingDataModified() { if (m_ToolManager->GetWorkingData(0) != nullptr) { m_Segmentation = dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); m_BtnReinit3DInterpolation->setEnabled(true); } else { // If no workingdata is set, remove the interpolation feedback this->GetDataStorage()->Remove(m_FeedbackNode); m_FeedbackNode->SetData(nullptr); this->GetDataStorage()->Remove(m_3DContourNode); m_3DContourNode->SetData(nullptr); this->GetDataStorage()->Remove(m_InterpolatedSurfaceNode); m_InterpolatedSurfaceNode->SetData(nullptr); m_BtnReinit3DInterpolation->setEnabled(false); return; } // Updating the current selected segmentation for the 3D interpolation SetCurrentContourListID(); if (m_2DInterpolationEnabled) { OnInterpolationActivated(true); // re-initialize if needed } this->CheckSupportedImageDimension(); } void QmitkSlicesInterpolator::OnToolManagerReferenceDataModified() { } void QmitkSlicesInterpolator::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); const auto timePoint = slicer->GetSelectedTimePoint(); m_TimePoints[slicer] = timePoint; m_SurfaceInterpolator->SetCurrentTimePoint(timePoint); if (m_LastSNC == slicer) { slicer->SendSlice(); // will trigger a new interpolation } } void QmitkSlicesInterpolator::OnSliceChanged(itk::Object *sender, const itk::EventObject &e) { // Check whether we really have a GeometrySliceEvent if (!dynamic_cast(&e)) return; mitk::SliceNavigationController *slicer = dynamic_cast(sender); if (TranslateAndInterpolateChangedSlice(e, slicer)) { slicer->GetRenderer()->RequestUpdate(); } } bool QmitkSlicesInterpolator::TranslateAndInterpolateChangedSlice(const itk::EventObject &e, mitk::SliceNavigationController *slicer) { if (!m_2DInterpolationEnabled) return false; try { const mitk::SliceNavigationController::GeometrySliceEvent &event = dynamic_cast(e); mitk::TimeGeometry *tsg = event.GetTimeGeometry(); if (tsg && m_TimePoints.contains(slicer) && tsg->IsValidTimePoint(m_TimePoints[slicer])) { mitk::SlicedGeometry3D *slicedGeometry = dynamic_cast(tsg->GetGeometryForTimePoint(m_TimePoints[slicer]).GetPointer()); if (slicedGeometry) { m_LastSNC = slicer; mitk::PlaneGeometry *plane = dynamic_cast(slicedGeometry->GetPlaneGeometry(event.GetPos())); if (plane) Interpolate(plane, m_TimePoints[slicer], slicer); return true; } } } catch (const std::bad_cast &) { return false; // so what } return false; } void QmitkSlicesInterpolator::Interpolate(mitk::PlaneGeometry *plane, mitk::TimePointType timePoint, mitk::SliceNavigationController *slicer) { if (m_ToolManager) { mitk::DataNode *node = m_ToolManager->GetWorkingData(0); if (node) { m_Segmentation = dynamic_cast(node->GetData()); if (m_Segmentation) { if (!m_Segmentation->GetTimeGeometry()->IsValidTimePoint(timePoint)) { MITK_WARN << "Cannot interpolate segmentation. Passed time point is not within the time bounds of WorkingImage. Time point: " << timePoint; return; } const auto timeStep = m_Segmentation->GetTimeGeometry()->TimePointToTimeStep(timePoint); int clickedSliceDimension(-1); int clickedSliceIndex(-1); // calculate real slice position, i.e. slice of the image mitk::SegTool2D::DetermineAffectedImageSlice(m_Segmentation, plane, clickedSliceDimension, clickedSliceIndex); mitk::Image::Pointer interpolation = m_Interpolator->Interpolate(clickedSliceDimension, clickedSliceIndex, plane, timeStep); m_FeedbackNode->SetData(interpolation); m_LastSNC = slicer; m_LastSliceIndex = clickedSliceIndex; } } } } void QmitkSlicesInterpolator::OnSurfaceInterpolationFinished() { mitk::Surface::Pointer interpolatedSurface = m_SurfaceInterpolator->GetInterpolationResult(); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); if (interpolatedSurface.IsNotNull() && workingNode && workingNode->IsVisible( mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget2")))) { m_BtnApply3D->setEnabled(true); // T28261 // m_BtnSuggestPlane->setEnabled(true); m_InterpolatedSurfaceNode->SetData(interpolatedSurface); m_3DContourNode->SetData(m_SurfaceInterpolator->GetContoursAsSurface()); this->Show3DInterpolationResult(true); if (!m_DataStorage->Exists(m_InterpolatedSurfaceNode)) { m_DataStorage->Add(m_InterpolatedSurfaceNode); } if (!m_DataStorage->Exists(m_3DContourNode)) { m_DataStorage->Add(m_3DContourNode, workingNode); } } else if (interpolatedSurface.IsNull()) { m_BtnApply3D->setEnabled(false); // T28261 // m_BtnSuggestPlane->setEnabled(false); if (m_DataStorage->Exists(m_InterpolatedSurfaceNode)) { this->Show3DInterpolationResult(false); } } m_BtnReinit3DInterpolation->setEnabled(true); foreach (mitk::SliceNavigationController *slicer, m_ControllerToTimeObserverTag.keys()) { slicer->GetRenderer()->RequestUpdate(); } } void QmitkSlicesInterpolator::OnAcceptInterpolationClicked() { if (m_Segmentation && m_FeedbackNode->GetData()) { // 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 slice as input mitk::Image::Pointer slice = dynamic_cast(m_FeedbackNode->GetData()); reslice->SetInputSlice(slice->GetSliceData()->GetVtkImageAccessor(slice)->GetVtkImageData()); // set overwrite mode to true to write back to the image volume reslice->SetOverwriteMode(true); reslice->Modified(); const auto timePoint = m_LastSNC->GetSelectedTimePoint(); if (!m_Segmentation->GetTimeGeometry()->IsValidTimePoint(timePoint)) { MITK_WARN << "Cannot accept interpolation. Time point selected by SliceNavigationController is not within the time bounds of segmentation. Time point: " << timePoint; return; } mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); extractor->SetInput(m_Segmentation); const auto timeStep = m_Segmentation->GetTimeGeometry()->TimePointToTimeStep(timePoint); extractor->SetTimeStep(timeStep); extractor->SetWorldGeometry(m_LastSNC->GetCurrentPlaneGeometry()); extractor->SetVtkOutputRequest(true); extractor->SetResliceTransformByGeometry(m_Segmentation->GetTimeGeometry()->GetGeometryForTimeStep(timeStep)); extractor->Modified(); extractor->Update(); // the image was modified within the pipeline, but not marked so m_Segmentation->Modified(); m_Segmentation->GetVtkImageData()->Modified(); m_FeedbackNode->SetData(nullptr); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSlicesInterpolator::AcceptAllInterpolations(mitk::SliceNavigationController *slicer) { /* * What exactly is done here: * 1. We create an empty diff image for the current segmentation * 2. All interpolated slices are written into the diff image * 3. Then the diffimage is applied to the original segmentation */ if (m_Segmentation) { mitk::Image::Pointer segmentation3D = m_Segmentation; unsigned int timeStep = 0; const auto timePoint = slicer->GetSelectedTimePoint(); if (4 == m_Segmentation->GetDimension()) { const auto* geometry = m_Segmentation->GetTimeGeometry(); if (!geometry->IsValidTimePoint(timePoint)) { MITK_WARN << "Cannot accept all interpolations. Time point selected by passed SliceNavigationController is not within the time bounds of segmentation. Time point: " << timePoint; return; } timeStep = geometry->TimePointToTimeStep(timePoint); auto timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(m_Segmentation); timeSelector->SetTimeNr(timeStep); timeSelector->Update(); segmentation3D = timeSelector->GetOutput(); } // Create an empty diff image for the undo operation auto diffImage = mitk::Image::New(); diffImage->Initialize(segmentation3D); // Create scope for ImageWriteAccessor so that the accessor is destroyed right after use { mitk::ImageWriteAccessor accessor(diffImage); // Set all pixels to zero auto pixelType = mitk::MakeScalarPixelType(); // For legacy purpose support former pixel type of segmentations (before multilabel) if (itk::ImageIOBase::UCHAR == m_Segmentation->GetImageDescriptor()->GetChannelDescriptor().GetPixelType().GetComponentType()) pixelType = mitk::MakeScalarPixelType(); memset(accessor.GetData(), 0, pixelType.GetSize() * diffImage->GetDimension(0) * diffImage->GetDimension(1) * diffImage->GetDimension(2)); } // Since we need to shift the plane it must be clone so that the original plane isn't altered auto slicedGeometry = m_Segmentation->GetSlicedGeometry(); auto planeGeometry = slicer->GetCurrentPlaneGeometry()->Clone(); int sliceDimension = -1; int sliceIndex = -1; mitk::SegTool2D::DetermineAffectedImageSlice(m_Segmentation, planeGeometry, sliceDimension, sliceIndex); const auto numSlices = m_Segmentation->GetDimension(sliceDimension); mitk::ProgressBar::GetInstance()->AddStepsToDo(numSlices); std::atomic_uint totalChangedSlices; // Reuse interpolation algorithm instance for each slice to cache boundary calculations auto algorithm = mitk::ShapeBasedInterpolationAlgorithm::New(); // Distribute slice interpolations to multiple threads const auto numThreads = std::min(std::thread::hardware_concurrency(), numSlices); std::vector> sliceIndices(numThreads); for (std::remove_const_t sliceIndex = 0; sliceIndex < numSlices; ++sliceIndex) sliceIndices[sliceIndex % numThreads].push_back(sliceIndex); std::vector threads; threads.reserve(numThreads); // This lambda will be executed by the threads auto interpolate = [=, &interpolator = m_Interpolator, &totalChangedSlices](unsigned int threadIndex) { auto clonedPlaneGeometry = planeGeometry->Clone(); auto origin = clonedPlaneGeometry->GetOrigin(); for (auto sliceIndex : sliceIndices[threadIndex]) { slicedGeometry->WorldToIndex(origin, origin); origin[sliceDimension] = sliceIndex; slicedGeometry->IndexToWorld(origin, origin); clonedPlaneGeometry->SetOrigin(origin); auto interpolation = interpolator->Interpolate(sliceDimension, sliceIndex, clonedPlaneGeometry, timeStep, algorithm); if (interpolation.IsNotNull()) { // Setting up the reslicing pipeline which allows us to write the interpolation results back into the image volume auto reslicer = vtkSmartPointer::New(); // Set overwrite mode to true to write back to the image volume reslicer->SetInputSlice(interpolation->GetSliceData()->GetVtkImageAccessor(interpolation)->GetVtkImageData()); reslicer->SetOverwriteMode(true); reslicer->Modified(); auto diffSliceWriter = mitk::ExtractSliceFilter::New(reslicer); diffSliceWriter->SetInput(diffImage); diffSliceWriter->SetTimeStep(0); diffSliceWriter->SetWorldGeometry(clonedPlaneGeometry); diffSliceWriter->SetVtkOutputRequest(true); diffSliceWriter->SetResliceTransformByGeometry(diffImage->GetTimeGeometry()->GetGeometryForTimeStep(0)); diffSliceWriter->Modified(); diffSliceWriter->Update(); ++totalChangedSlices; } mitk::ProgressBar::GetInstance()->Progress(); } }; m_Interpolator->EnableSliceImageCache(); for (std::remove_const_t threadIndex = 0; threadIndex < numThreads; ++threadIndex) threads.emplace_back(interpolate, threadIndex); // Run the interpolation for (auto& thread : threads) thread.join(); m_Interpolator->DisableSliceImageCache(); if (totalChangedSlices > 0) { // Create do/undo operations auto* doOp = new mitk::ApplyDiffImageOperation(mitk::OpTEST, m_Segmentation, diffImage, timeStep); auto* undoOp = new mitk::ApplyDiffImageOperation(mitk::OpTEST, m_Segmentation, diffImage, timeStep); undoOp->SetFactor(-1.0); auto comment = "Confirm all interpolations (" + std::to_string(totalChangedSlices) + ")"; auto* undoStackItem = new mitk::OperationEvent(mitk::DiffImageApplier::GetInstanceForUndo(), doOp, undoOp, comment); mitk::OperationEvent::IncCurrGroupEventId(); mitk::OperationEvent::IncCurrObjectEventId(); mitk::UndoController::GetCurrentUndoModel()->SetOperationEvent(undoStackItem); // Apply the changes to the original image mitk::DiffImageApplier::GetInstanceForUndo()->ExecuteOperation(doOp); } m_FeedbackNode->SetData(nullptr); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::FinishInterpolation(mitk::SliceNavigationController *slicer) { // this redirect is for calling from outside if (slicer == nullptr) OnAcceptAllInterpolationsClicked(); else AcceptAllInterpolations(slicer); } void QmitkSlicesInterpolator::OnAcceptAllInterpolationsClicked() { QMenu orientationPopup(this); std::map::const_iterator it; for (it = ACTION_TO_SLICEDIMENSION.begin(); it != ACTION_TO_SLICEDIMENSION.end(); it++) orientationPopup.addAction(it->first); connect(&orientationPopup, SIGNAL(triggered(QAction *)), this, SLOT(OnAcceptAllPopupActivated(QAction *))); orientationPopup.exec(QCursor::pos()); } void QmitkSlicesInterpolator::OnAccept3DInterpolationClicked() { auto referenceImage = GetData(m_ToolManager->GetReferenceData(0)); auto* segmentationDataNode = m_ToolManager->GetWorkingData(0); auto segmentation = GetData(segmentationDataNode); if (referenceImage.IsNull() || segmentation.IsNull()) return; const auto* segmentationGeometry = segmentation->GetTimeGeometry(); const auto timePoint = m_LastSNC->GetSelectedTimePoint(); if (!referenceImage->GetTimeGeometry()->IsValidTimePoint(timePoint) || !segmentationGeometry->IsValidTimePoint(timePoint)) { MITK_WARN << "Cannot accept interpolation. Current time point is not within the time bounds of the patient image and segmentation."; return; } auto interpolatedSurface = GetData(m_InterpolatedSurfaceNode); if (interpolatedSurface.IsNull()) return; auto surfaceToImageFilter = mitk::SurfaceToImageFilter::New(); surfaceToImageFilter->SetImage(referenceImage); surfaceToImageFilter->SetMakeOutputBinary(true); surfaceToImageFilter->SetUShortBinaryPixelType(itk::ImageIOBase::USHORT == segmentation->GetPixelType().GetComponentType()); surfaceToImageFilter->SetInput(interpolatedSurface); surfaceToImageFilter->Update(); mitk::Image::Pointer interpolatedSegmentation = surfaceToImageFilter->GetOutput(); auto timeStep = interpolatedSegmentation->GetTimeGeometry()->TimePointToTimeStep(timePoint); mitk::ImageReadAccessor readAccessor(interpolatedSegmentation, interpolatedSegmentation->GetVolumeData(timeStep)); const auto* dataPointer = readAccessor.GetData(); if (nullptr == dataPointer) return; timeStep = segmentationGeometry->TimePointToTimeStep(timePoint); segmentation->SetVolume(dataPointer, timeStep, 0); m_CmbInterpolation->setCurrentIndex(0); this->Show3DInterpolationResult(false); std::string name = segmentationDataNode->GetName() + "_3D-interpolation"; mitk::TimeBounds timeBounds; if (1 < interpolatedSurface->GetTimeSteps()) { name += "_t" + std::to_string(timeStep); auto* polyData = vtkPolyData::New(); polyData->DeepCopy(interpolatedSurface->GetVtkPolyData(timeStep)); auto surface = mitk::Surface::New(); surface->SetVtkPolyData(polyData); interpolatedSurface = surface; timeBounds = segmentationGeometry->GetTimeBounds(timeStep); } else { timeBounds = segmentationGeometry->GetTimeBounds(0); } auto* surfaceGeometry = static_cast(interpolatedSurface->GetTimeGeometry()); surfaceGeometry->SetFirstTimePoint(timeBounds[0]); surfaceGeometry->SetStepDuration(timeBounds[1] - timeBounds[0]); // Typical file formats for surfaces do not save any time-related information. As a workaround at least for MITK scene files, we have the // possibility to seralize this information as properties. interpolatedSurface->SetProperty("ProportionalTimeGeometry.FirstTimePoint", mitk::FloatProperty::New(surfaceGeometry->GetFirstTimePoint())); interpolatedSurface->SetProperty("ProportionalTimeGeometry.StepDuration", mitk::FloatProperty::New(surfaceGeometry->GetStepDuration())); auto interpolatedSurfaceDataNode = mitk::DataNode::New(); interpolatedSurfaceDataNode->SetData(interpolatedSurface); interpolatedSurfaceDataNode->SetName(name); interpolatedSurfaceDataNode->SetOpacity(0.7f); std::array rgb; segmentationDataNode->GetColor(rgb.data()); interpolatedSurfaceDataNode->SetColor(rgb.data()); m_DataStorage->Add(interpolatedSurfaceDataNode, segmentationDataNode); } void ::QmitkSlicesInterpolator::OnSuggestPlaneClicked() { if (m_PlaneWatcher.isRunning()) m_PlaneWatcher.waitForFinished(); m_PlaneFuture = QtConcurrent::run(this, &QmitkSlicesInterpolator::RunPlaneSuggestion); m_PlaneWatcher.setFuture(m_PlaneFuture); } void ::QmitkSlicesInterpolator::RunPlaneSuggestion() { if (m_FirstRun) mitk::ProgressBar::GetInstance()->AddStepsToDo(7); else mitk::ProgressBar::GetInstance()->AddStepsToDo(3); m_EdgeDetector->SetSegmentationMask(m_Segmentation); m_EdgeDetector->SetInput(dynamic_cast(m_ToolManager->GetReferenceData(0)->GetData())); m_EdgeDetector->Update(); mitk::UnstructuredGrid::Pointer uGrid = mitk::UnstructuredGrid::New(); uGrid->SetVtkUnstructuredGrid(m_EdgeDetector->GetOutput()->GetVtkUnstructuredGrid()); mitk::ProgressBar::GetInstance()->Progress(); mitk::Surface::Pointer surface = dynamic_cast(m_InterpolatedSurfaceNode->GetData()); vtkSmartPointer vtkpoly = surface->GetVtkPolyData(); vtkSmartPointer vtkpoints = vtkpoly->GetPoints(); vtkSmartPointer vGrid = vtkSmartPointer::New(); vtkSmartPointer verts = vtkSmartPointer::New(); verts->GetPointIds()->SetNumberOfIds(vtkpoints->GetNumberOfPoints()); for (int i = 0; i < vtkpoints->GetNumberOfPoints(); i++) { verts->GetPointIds()->SetId(i, i); } vGrid->Allocate(1); vGrid->InsertNextCell(verts->GetCellType(), verts->GetPointIds()); vGrid->SetPoints(vtkpoints); mitk::UnstructuredGrid::Pointer interpolationGrid = mitk::UnstructuredGrid::New(); interpolationGrid->SetVtkUnstructuredGrid(vGrid); m_PointScorer->SetInput(0, uGrid); m_PointScorer->SetInput(1, interpolationGrid); m_PointScorer->Update(); mitk::UnstructuredGrid::Pointer scoredGrid = mitk::UnstructuredGrid::New(); scoredGrid = m_PointScorer->GetOutput(); mitk::ProgressBar::GetInstance()->Progress(); double spacing = mitk::SurfaceInterpolationController::GetInstance()->GetDistanceImageSpacing(); mitk::UnstructuredGridClusteringFilter::Pointer clusterFilter = mitk::UnstructuredGridClusteringFilter::New(); clusterFilter->SetInput(scoredGrid); clusterFilter->SetMeshing(false); clusterFilter->SetMinPts(4); clusterFilter->Seteps(spacing); clusterFilter->Update(); mitk::ProgressBar::GetInstance()->Progress(); // Create plane suggestion mitk::BaseRenderer::Pointer br = mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget0")); mitk::PlaneProposer planeProposer; std::vector grids = clusterFilter->GetAllClusters(); planeProposer.SetUnstructuredGrids(grids); mitk::SliceNavigationController::Pointer snc = br->GetSliceNavigationController(); planeProposer.SetSliceNavigationController(snc); planeProposer.SetUseDistances(true); try { planeProposer.CreatePlaneInfo(); } catch (const mitk::Exception &e) { MITK_ERROR << e.what(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_FirstRun = false; } void QmitkSlicesInterpolator::OnReinit3DInterpolation() { mitk::NodePredicateProperty::Pointer pred = mitk::NodePredicateProperty::New("3DContourContainer", mitk::BoolProperty::New(true)); mitk::DataStorage::SetOfObjects::ConstPointer contourNodes = m_DataStorage->GetDerivations(m_ToolManager->GetWorkingData(0), pred); if (contourNodes->Size() != 0) { m_BtnApply3D->setEnabled(true); m_3DContourNode = contourNodes->at(0); mitk::Surface::Pointer contours = dynamic_cast(m_3DContourNode->GetData()); if (contours) mitk::SurfaceInterpolationController::GetInstance()->ReinitializeInterpolation(contours); m_BtnReinit3DInterpolation->setEnabled(false); } else { m_BtnApply3D->setEnabled(false); QMessageBox errorInfo; errorInfo.setWindowTitle("Reinitialize surface interpolation"); errorInfo.setIcon(QMessageBox::Information); errorInfo.setText("No contours available for the selected segmentation!"); errorInfo.exec(); } } void QmitkSlicesInterpolator::OnAcceptAllPopupActivated(QAction *action) { try { std::map::const_iterator iter = ACTION_TO_SLICEDIMENSION.find(action); if (iter != ACTION_TO_SLICEDIMENSION.end()) { mitk::SliceNavigationController *slicer = iter->second; AcceptAllInterpolations(slicer); } } catch (...) { /* Showing message box with possible memory error */ QMessageBox errorInfo; errorInfo.setWindowTitle("Interpolation Process"); errorInfo.setIcon(QMessageBox::Critical); errorInfo.setText("An error occurred during interpolation. Possible cause: Not enough memory!"); errorInfo.exec(); // additional error message on std::cerr std::cerr << "Ill construction in " __FILE__ " l. " << __LINE__ << std::endl; } } void QmitkSlicesInterpolator::OnInterpolationActivated(bool on) { m_2DInterpolationEnabled = on; try { if (m_DataStorage.IsNotNull()) { if (on && !m_DataStorage->Exists(m_FeedbackNode)) { m_DataStorage->Add(m_FeedbackNode); } } } catch (...) { // don't care (double add/remove) } if (m_ToolManager) { mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); mitk::DataNode *referenceNode = m_ToolManager->GetReferenceData(0); QWidget::setEnabled(workingNode != nullptr); m_BtnApply2D->setEnabled(on); m_FeedbackNode->SetVisibility(on); if (!on) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return; } if (workingNode) { mitk::Image *segmentation = dynamic_cast(workingNode->GetData()); if (segmentation) { m_Interpolator->SetSegmentationVolume(segmentation); if (referenceNode) { mitk::Image *referenceImage = dynamic_cast(referenceNode->GetData()); m_Interpolator->SetReferenceVolume(referenceImage); // may be nullptr } } } } UpdateVisibleSuggestion(); } void QmitkSlicesInterpolator::Run3DInterpolation() { m_SurfaceInterpolator->Interpolate(); } void QmitkSlicesInterpolator::StartUpdateInterpolationTimer() { m_Timer->start(500); } void QmitkSlicesInterpolator::StopUpdateInterpolationTimer() { m_Timer->stop(); m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(SURFACE_COLOR_RGB)); mitk::RenderingManager::GetInstance()->RequestUpdate( mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))->GetRenderWindow()); } void QmitkSlicesInterpolator::ChangeSurfaceColor() { float currentColor[3]; m_InterpolatedSurfaceNode->GetColor(currentColor); if (currentColor[2] == SURFACE_COLOR_RGB[2]) { m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(1.0f, 1.0f, 1.0f)); } else { m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(SURFACE_COLOR_RGB)); } m_InterpolatedSurfaceNode->Update(); mitk::RenderingManager::GetInstance()->RequestUpdate( mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))->GetRenderWindow()); } void QmitkSlicesInterpolator::On3DInterpolationActivated(bool on) { m_3DInterpolationEnabled = on; this->CheckSupportedImageDimension(); try { if (m_DataStorage.IsNotNull() && m_ToolManager && m_3DInterpolationEnabled) { mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); if (workingNode) { if ((workingNode->IsVisible(mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget2"))))) { int ret = QMessageBox::Yes; if (m_SurfaceInterpolator->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, &QmitkSlicesInterpolator::Run3DInterpolation); m_Watcher.setFuture(m_Future); } else { m_CmbInterpolation->setCurrentIndex(0); } } } else { QWidget::setEnabled(false); m_ChkShowPositionNodes->setEnabled(m_3DInterpolationEnabled); } } if (!m_3DInterpolationEnabled) { this->Show3DInterpolationResult(false); m_BtnApply3D->setEnabled(m_3DInterpolationEnabled); // T28261 // m_BtnSuggestPlane->setEnabled(m_3DInterpolationEnabled); } } catch (...) { MITK_ERROR << "Error with 3D surface interpolation!"; } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::EnableInterpolation(bool on) { // only to be called from the outside world // just a redirection to OnInterpolationActivated OnInterpolationActivated(on); } void QmitkSlicesInterpolator::Enable3DInterpolation(bool on) { // only to be called from the outside world // just a redirection to OnInterpolationActivated On3DInterpolationActivated(on); } void QmitkSlicesInterpolator::UpdateVisibleSuggestion() { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::OnInterpolationInfoChanged(const itk::EventObject & /*e*/) { // something (e.g. undo) changed the interpolation info, we should refresh our display UpdateVisibleSuggestion(); } void QmitkSlicesInterpolator::OnInterpolationAborted(const itk::EventObject& /*e*/) { m_CmbInterpolation->setCurrentIndex(0); m_FeedbackNode->SetData(nullptr); } void QmitkSlicesInterpolator::OnSurfaceInterpolationInfoChanged(const itk::EventObject & /*e*/) { if (m_3DInterpolationEnabled) { if (m_Watcher.isRunning()) m_Watcher.waitForFinished(); m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation); m_Watcher.setFuture(m_Future); } } void QmitkSlicesInterpolator::SetCurrentContourListID() { // New ContourList = hide current interpolation Show3DInterpolationResult(false); if (m_DataStorage.IsNotNull() && m_ToolManager && m_LastSNC) { mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); if (workingNode) { QWidget::setEnabled(true); const auto timePoint = m_LastSNC->GetSelectedTimePoint(); // In case the time is not valid use 0 to access the time geometry of the working node unsigned int time_position = 0; if (!workingNode->GetData()->GetTimeGeometry()->IsValidTimePoint(timePoint)) { MITK_WARN << "Cannot accept interpolation. Time point selected by SliceNavigationController is not within the time bounds of WorkingImage. Time point: " << timePoint; return; } time_position = workingNode->GetData()->GetTimeGeometry()->TimePointToTimeStep(timePoint); mitk::Vector3D spacing = workingNode->GetData()->GetGeometry(time_position)->GetSpacing(); double minSpacing(100); double maxSpacing(0); for (int i = 0; i < 3; i++) { if (spacing[i] < minSpacing) { minSpacing = spacing[i]; } if (spacing[i] > maxSpacing) { maxSpacing = spacing[i]; } } m_SurfaceInterpolator->SetMaxSpacing(maxSpacing); m_SurfaceInterpolator->SetMinSpacing(minSpacing); m_SurfaceInterpolator->SetDistanceImageVolume(50000); mitk::Image *segmentationImage = dynamic_cast(workingNode->GetData()); m_SurfaceInterpolator->SetCurrentInterpolationSession(segmentationImage); m_SurfaceInterpolator->SetCurrentTimePoint(timePoint); if (m_3DInterpolationEnabled) { if (m_Watcher.isRunning()) m_Watcher.waitForFinished(); m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation); m_Watcher.setFuture(m_Future); } } else { QWidget::setEnabled(false); } } } void QmitkSlicesInterpolator::Show3DInterpolationResult(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.widget3"))); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::CheckSupportedImageDimension() { if (m_ToolManager->GetWorkingData(0)) m_Segmentation = dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); /*if (m_3DInterpolationEnabled && m_Segmentation && m_Segmentation->GetDimension() != 3) { QMessageBox info; info.setWindowTitle("3D Interpolation Process"); info.setIcon(QMessageBox::Information); info.setText("3D Interpolation is only supported for 3D images at the moment!"); info.exec(); m_CmbInterpolation->setCurrentIndex(0); }*/ } void QmitkSlicesInterpolator::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 QmitkSlicesInterpolator::WaitForFutures() { if (m_Watcher.isRunning()) { m_Watcher.waitForFinished(); } if (m_PlaneWatcher.isRunning()) { m_PlaneWatcher.waitForFinished(); } } void QmitkSlicesInterpolator::NodeRemoved(const mitk::DataNode* node) { if ((m_ToolManager && m_ToolManager->GetWorkingData(0) == node) || node == m_3DContourNode || node == m_FeedbackNode || node == m_InterpolatedSurfaceNode) { WaitForFutures(); } } diff --git a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation_Technical.dox b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation_Technical.dox index c3a27ea842..346754a8f0 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation_Technical.dox +++ b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation_Technical.dox @@ -1,100 +1,98 @@ /** \page QmitkSegmentationTechnicalPage Technical design of QmitkSegmentation \li \ref QmitkSegmentationTechnicalPage2 \li \ref QmitkSegmentationTechnicalPage3 \li \ref QmitkSegmentationTechnicalPage4 \section QmitkSegmentationTechnicalPage2 Introduction QmitkSegmentation was designed for the liver resection planning project "ReLiver". The goal was a stable, well-documented, extensible, and testable re-implementation of a functionality called "ERIS", which was used for manual segmentation in 2D slices of 3D or 3D+t images. Re-implementation was chosen because it seemed to be easier to write documentation and tests for newly developed code. In addition, the old code had some design weaknesses (e.g. a monolithic class), which would be hard to maintain in the future. By now Segmentation is a well tested and easily extensible vehicle for all kinds of interactive segmentation applications. A separate page describes how you can extend Segmentation with new tools in a shared object (DLL): \ref toolextensions. \section QmitkSegmentationTechnicalPage3 Overview of tasks We identified the following major tasks:
  1. Management of images: what is the original patient image, what images are the active segmentations?
  2. Management of drawing tools: there is a set of drawing tools, one at a time is active, that is, someone has to decide which tool will receive mouse (and other) events.
  3. Drawing tools: each tool can modify a segmentation in reaction to user interaction. To do so, the tools have to know about the relevant images.
  4. Slice manipulation: drawing tools need to have means to extract a single slice from an image volume and to write a single slice back into an image volume.
  5. Interpolation of unsegmented slices: some class has to keep track of all the segmentations in a volume and generate suggestions for missing slices. This should be possible in all three orthogonal slice direction.
  6. Undo: Slice manipulations should be undoable, no matter whether a tool or the interpolation mechanism changed something.
  7. GUI: Integration of everything.
\section QmitkSegmentationTechnicalPage4 Classes involved The above blocks correspond to a number of classes. Here is an overview of all related classes with their responsibilities and relations: \imageMacro{QmitkSegmentation_InteractiveSegmentationClasses.png,"",16.00}
  1. Management of images: mitk::ToolManager has a set of reference data (original images) and a second set of working data (segmentations). mitk::Tool objects know a ToolManager and can ask the manager for the currently relevant images. GUI and non-GUI classes are coupled by itk::Events (non-GUI to GUI) and direct method calls (GUI to non-GUI).
  2. Management of drawing tools: As a second task, ToolManager manages all available tools and makes sure that one at a time is able to receive MITK events. The GUI for selecting tools is implemented in QmitkToolSelectionBox.
  3. Drawing tools: Drawing tools all inherit from mitk::Tool, which is a mitk::StateMachine. There is a number of derivations from Tool, each offering some helper methods for specific sub-classes, like manipulation of 2D slices. Tools are instantiated through the itk::ObjectFactory, which means that there is also one factory for each tool (e.g. mitk::AddContourToolFactory). For the GUI representation, each tool has an identification, consisting of a name and an icon (XPM). The actual drawing methods are mainly implemented in mitk::SegTool2D (helper methods) and its sub-classes for region growing, freehand drawing, etc. -
  4. Slice manipulation: There are two filters for manipulation of slices +
  5. Slice manipulation: There are two ways to manipulate slices inside a 3D image volume. mitk::ExtractImageFilter retrieves a single 2D slice -from a 3D volume. mitk::OverwriteSliceImageFilter replaces a slice inside a 3D -volume with a second slice which is a parameter to the filter. These classes are -used extensively by most of the tools to fulfill their task. -mitk::OverwriteSliceImageFilter cooperates with the interpolation classes to -inform them of single slice modifications. +from a 3D volume. mitkVtkImageOverwrite replaces a slice inside a 3D +volume with a second slice. These classes are used extensively by most of the tools +to fulfill their task.
  6. Interpolation of unsegmented slices: There are two classes involved in interpolation: mitk::SegmentationInterpolationController knows a mitk::Image (the segmentation) and scans its contents for slices with non-zero pixels. It keeps track of changes in the image and is always able to tell, which neighbors of a slice (in the three orthogonal slice directions) contain segmentations. The class also performs this interpolation for single slices on demand. Again, we have a second class responsible for the GUI: QmitkSlicesInterpolator enables/disables interpolation and offers to accept interpolations for one or all slices. -
  7. Undo: Undo functionality is implemented in mitk::OverwriteSliceImageFilter, -since this is the central place where all image modifications are made. The filter stores a binary difference image -to the undo stack as a mitk::ApplyDiffImageOperation. When the user requests undo, this ApplyDiffImageOperation -will be executed by a singleton class DiffImageApplier. The operation itself observes the image, which it refers to, -for itk::DeleteEvent, so no undo operation will be executed on/for images that have already been destroyed. +
  8. Undo: Undo functionality is implemented using mitk::DiffSliceOperation. +mitk::SegTool2D::WriteSliceToVolume stores the original image and the modified slice to the undo stack as an +mitk::DiffSliceOperation. When the user requests undo, this mitk::DiffSliceOperation will be executed by a singleton +class DiffSliceOperationApplier. The operation itself observes the image, which it refers to, for itk::DeleteEvent, +so no undo operation will be executed on/for images that have already been destroyed.
  9. GUI: The top-level GUI is the view QmitkSegmentation, which is very thin in comparison to ERIS. There are separate widgets for image and tool selection, for interpolation. Additionaly, there are some methods to create, delete, crop, load and save segmentations.
**/ diff --git a/Plugins/org.mitk.gui.qt.segmentation/files.cmake b/Plugins/org.mitk.gui.qt.segmentation/files.cmake index dd452ef63f..a9b25997b4 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/files.cmake +++ b/Plugins/org.mitk.gui.qt.segmentation/files.cmake @@ -1,74 +1,70 @@ set(SRC_CPP_FILES QmitkSegmentationPreferencePage.cpp ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkSegmentationView.cpp - QmitkThresholdAction.cpp QmitkCreatePolygonModelAction.cpp - #QmitkStatisticsAction.cpp QmitkAutocropAction.cpp QmitkAutocropLabelSetImageAction.cpp Common/QmitkDataSelectionWidget.cpp SegmentationUtilities/QmitkSegmentationUtilitiesView.cpp SegmentationUtilities/QmitkSegmentationUtilityWidget.cpp SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.cpp SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.cpp SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp ) set(UI_FILES src/internal/QmitkSegmentationControls.ui src/internal/Common/QmitkDataSelectionWidgetControls.ui src/internal/SegmentationUtilities/QmitkSegmentationUtilitiesViewControls.ui src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidgetControls.ui src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidgetControls.ui src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidgetControls.ui src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidgetControls.ui src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidgetControls.ui ) set(MOC_H_FILES src/QmitkSegmentationPreferencePage.h src/internal/mitkPluginActivator.h src/internal/QmitkSegmentationView.h - src/internal/QmitkThresholdAction.h src/internal/QmitkCreatePolygonModelAction.h - #src/internal/QmitkStatisticsAction.h src/internal/QmitkAutocropAction.h src/internal/QmitkAutocropLabelSetImageAction.h src/internal/Common/QmitkDataSelectionWidget.h src/internal/SegmentationUtilities/QmitkSegmentationUtilitiesView.h src/internal/SegmentationUtilities/QmitkSegmentationUtilityWidget.h src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.h src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.h src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.h src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.h src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.h ) set(CACHED_RESOURCE_FILES resources/segmentation.svg resources/segmentation_utilities.svg plugin.xml ) set(QRC_FILES resources/segmentation.qrc resources/SegmentationUtilities.qrc resources/BooleanOperationsWidget.qrc resources/MorphologicalOperationsWidget.qrc ) set(CPP_FILES) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) 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.segmentation/src/internal/QmitkOtsuAction.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkOtsuAction.cpp deleted file mode 100644 index 4cec41b4c0..0000000000 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkOtsuAction.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ -#include "QmitkOtsuAction.h" - -// MITK -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -// ITK -#include - -// Qt -#include -#include -#include -#include -#include -#include - -using namespace berry; -using namespace mitk; -using namespace std; - -QmitkOtsuAction::QmitkOtsuAction() -: m_OtsuSegmentationDialog(nullptr) -{ -} - -QmitkOtsuAction::~QmitkOtsuAction() -{ -} - -void QmitkOtsuAction::Run(const QList &selectedNodes) -{ - this->m_DataNode = selectedNodes[0]; - //this->m_selectedNodes = selectedNodes; - - m_OtsuSegmentationDialog = new QDialog(QApplication::activeWindow(),Qt::WindowTitleHint | Qt::WindowSystemMenuHint); - - - QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins(0, 0, 0, 0); - QHBoxLayout* spinBoxLayout = new QHBoxLayout; - QHBoxLayout* buttonLayout = new QHBoxLayout; - - m_OtsuSpinBox = new QSpinBox; - m_OtsuSpinBox->setRange(2, 32); - m_OtsuSpinBox->setValue(2); - - m_OtsuPushButton = new QPushButton("OK"); - QPushButton* CancelButton = new QPushButton("Cancel"); - - connect(m_OtsuPushButton, SIGNAL(clicked()), this, SLOT(OtsuSegmentationDone())); - connect(CancelButton, SIGNAL(clicked()), m_OtsuSegmentationDialog, SLOT(reject())); - - QLabel* numberOfThresholdsLabel = new QLabel("Select number of Regions of Interest:"); - numberOfThresholdsLabel->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter); - layout->addWidget(numberOfThresholdsLabel); - layout->addLayout(spinBoxLayout); - spinBoxLayout->addSpacing(50); - spinBoxLayout->addWidget(m_OtsuSpinBox); - spinBoxLayout->addSpacing(50); - layout->addLayout(buttonLayout); - buttonLayout->addWidget(m_OtsuPushButton); - buttonLayout->addWidget(CancelButton); - - m_OtsuSegmentationDialog->setLayout(layout); - m_OtsuSegmentationDialog->setFixedSize(300, 80); - - m_OtsuSegmentationDialog->open(); -} - -void QmitkOtsuAction::OtsuSegmentationDone() -{ - this->PerformOtsuSegmentation(); - - m_OtsuSegmentationDialog->deleteLater(); - m_OtsuSegmentationDialog = nullptr; - - RenderingManager::GetInstance()->RequestUpdateAll(); -} - -void QmitkOtsuAction::SetDataStorage(DataStorage *dataStorage) -{ - m_DataStorage = dataStorage; -} - -void QmitkOtsuAction::SetFunctionality(QtViewPart* /*view*/) -{ -} - -void QmitkOtsuAction::PerformOtsuSegmentation() -{ - this->m_OtsuSegmentationDialog->setCursor(Qt::WaitCursor); - - int numberOfThresholds = this->m_OtsuSpinBox->value() - 1; - int proceed; - - QMessageBox* messageBox = new QMessageBox(QMessageBox::Question, nullptr, "The otsu segmentation computation may take several minutes depending on the number of Regions you selected. Proceed anyway?", QMessageBox::Ok | QMessageBox::Cancel); - if (numberOfThresholds >= 5) - { - proceed = messageBox->exec(); - if (proceed != QMessageBox::Ok) return; - } - - mitk::Image::Pointer mitkImage = 0; - - mitkImage = dynamic_cast( this->m_DataNode->GetData() ); - - try - { - // get selected mitk image - const unsigned short dim = 3; - typedef short InputPixelType; - typedef unsigned char OutputPixelType; - - typedef itk::Image< InputPixelType, dim > InputImageType; - typedef itk::Image< OutputPixelType, dim > OutputImageType; - - typedef itk::OtsuMultipleThresholdsImageFilter< InputImageType, OutputImageType > FilterType; - - FilterType::Pointer filter = FilterType::New(); - - filter->SetNumberOfThresholds(numberOfThresholds); - - InputImageType::Pointer itkImage; - mitk::CastToItkImage(mitkImage, itkImage); - - filter->SetInput( itkImage ); - - filter->Update(); - - mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); - std::string nameOfResultImage = this->m_DataNode->GetName(); - nameOfResultImage.append("Otsu"); - resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) ); - resultNode->SetProperty("binary", mitk::BoolProperty::New(false) ); - mitk::RenderingModeProperty::Pointer renderingMode = mitk::RenderingModeProperty::New(); - renderingMode->SetValue( mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR ); - resultNode->SetProperty("Image Rendering.Mode", renderingMode); - - mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); - - mitk::LookupTableProperty::Pointer prop = mitk::LookupTableProperty::New(lut); - - vtkLookupTable *lookupTable = vtkLookupTable::New(); - lookupTable->SetHueRange(1.0, 0.0); - lookupTable->SetSaturationRange(1.0, 1.0); - lookupTable->SetValueRange(1.0, 1.0); - lookupTable->SetTableRange(-1.0, 1.0); - lookupTable->Build(); - - lut->SetVtkLookupTable(lookupTable); - - prop->SetLookupTable(lut); - resultNode->SetProperty("LookupTable",prop); - - mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); - mitk::LevelWindow levelwindow; - levelwindow.SetRangeMinMax(0, numberOfThresholds+1); - levWinProp->SetLevelWindow( levelwindow ); - resultNode->SetProperty( "levelwindow", levWinProp ); - - resultNode->SetData( mitk::GrabItkImageMemory( filter->GetOutput() ) ); - - - this->m_DataStorage->Add(resultNode, this->m_DataNode); - - this->m_OtsuSegmentationDialog->setCursor(Qt::ArrowCursor); - - } - catch( std::exception& err ) - { - MITK_ERROR(this->GetClassName()) << err.what(); - } -} diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkOtsuAction.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkOtsuAction.h deleted file mode 100644 index 143fd164f2..0000000000 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkOtsuAction.h +++ /dev/null @@ -1,66 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ -#ifndef QMITKOTSUACTION_H -#define QMITKOTSUACTION_H - -#include - -// Parent classes -#include -#include - -// Data members -#include -#include -#include - -// Mitk classes -#include - -class QDialog; - -/** \deprecatedSince{2013_09} The interaction for the Otsu image filter was revised and moved to the segmentation plugin view. */ -class DEPRECATED() MITK_QT_SEGMENTATION QmitkOtsuAction : public QObject, public mitk::IContextMenuAction -{ - Q_OBJECT - Q_INTERFACES(mitk::IContextMenuAction) - -public: - QmitkOtsuAction(); - ~QmitkOtsuAction(); - - // IContextMenuAction - void Run(const QList &selectedNodes); - void SetDataStorage(mitk::DataStorage *dataStorage); - void SetFunctionality(berry::QtViewPart* view); - void SetSmoothed(bool smoothed){} - void SetDecimated(bool decimated){} - -private slots: - void OtsuSegmentationDone(); - -private: - QmitkOtsuAction(const QmitkOtsuAction &); - QmitkOtsuAction & operator=(const QmitkOtsuAction &); - - void PerformOtsuSegmentation(); - - mitk::DataStorage::Pointer m_DataStorage; - QDialog *m_OtsuSegmentationDialog; - - QSpinBox* m_OtsuSpinBox; - QPushButton* m_OtsuPushButton; - - mitk::DataNode::Pointer m_DataNode; -}; - -#endif diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkThresholdAction.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkThresholdAction.cpp deleted file mode 100644 index 01413c81a0..0000000000 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkThresholdAction.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ -#include "QmitkThresholdAction.h" - -// MITK -#include -#include -#include - -// Qt -#include -#include -#include -#include - -using namespace berry; -using namespace mitk; -using namespace std; - -QmitkThresholdAction::QmitkThresholdAction() -{ -} - -QmitkThresholdAction::~QmitkThresholdAction() -{ -} - -void QmitkThresholdAction::Run(const QList &selectedNodes) -{ - m_ThresholdingToolManager = ToolManager::New(m_DataStorage); - - m_ThresholdingToolManager->RegisterClient(); - - Tool *binaryThresholdTool = m_ThresholdingToolManager->GetToolById(m_ThresholdingToolManager->GetToolIdByToolType()); - if (binaryThresholdTool != nullptr) - { - QmitkBinaryThresholdToolGUI *gui = dynamic_cast(binaryThresholdTool->GetGUI("Qmitk", "GUI").GetPointer()); - if (gui != nullptr) - { - QDialog thresholdingDialog(QApplication::activeWindow(), Qt::Window | Qt::WindowStaysOnTopHint); - - thresholdingDialog.setWindowFlags(thresholdingDialog.windowFlags() & ~Qt::WindowMinimizeButtonHint); - - QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel); - connect(buttonBox, SIGNAL(rejected()), &thresholdingDialog, SLOT(reject())); - connect(gui, SIGNAL(thresholdAccepted()), &thresholdingDialog, SLOT(reject())); - - QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins(3, 3, 3, 3); - - gui->SetTool(binaryThresholdTool); - gui->setParent(&thresholdingDialog); - - layout->addWidget(gui); - layout->addWidget(buttonBox); - - thresholdingDialog.setLayout(layout); - thresholdingDialog.setMinimumWidth(350); - - m_SelectedNode = selectedNodes[0]; - m_ThresholdingToolManager->SetReferenceData(selectedNodes[0]); - m_ThresholdingToolManager->ActivateTool(m_ThresholdingToolManager->GetToolIdByToolType()); - - m_ThresholdingToolManager->ActiveToolChanged += mitk::MessageDelegate(this, &QmitkThresholdAction::OnThresholdingToolManagerToolModified); - thresholdingDialog.exec(); - m_ThresholdingToolManager->ActiveToolChanged -= mitk::MessageDelegate(this, &QmitkThresholdAction::OnThresholdingToolManagerToolModified); - - m_ThresholdingToolManager->SetReferenceData(nullptr); - m_ThresholdingToolManager->ActivateTool(-1); - m_SelectedNode = nullptr; - } - } - - m_ThresholdingToolManager->UnregisterClient(); -} - -void QmitkThresholdAction::OnThresholdingToolManagerToolModified() -{ - if (m_ThresholdingToolManager.IsNotNull()) - { - if (m_ThresholdingToolManager->GetActiveToolID() < 0) - { - m_ThresholdingToolManager->SetReferenceData(m_SelectedNode); - m_ThresholdingToolManager->ActivateTool(m_ThresholdingToolManager->GetToolIdByToolType()); - } - } -} - -void QmitkThresholdAction::SetDataStorage(DataStorage *dataStorage) -{ - m_DataStorage = dataStorage; -} - -void QmitkThresholdAction::SetSmoothed(bool) -{ -} - -void QmitkThresholdAction::SetDecimated(bool) -{ -} - -void QmitkThresholdAction::SetFunctionality(QtViewPart* /*view*/) -{ -} diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkThresholdAction.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkThresholdAction.h deleted file mode 100644 index 99e6cab6d1..0000000000 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkThresholdAction.h +++ /dev/null @@ -1,53 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ -#ifndef QMITKTHRESHOLDACTION_H -#define QMITKTHRESHOLDACTION_H - -#include - -// Parent classes -#include -#include - -// Data members -#include -#include - - -class MITK_QT_SEGMENTATION QmitkThresholdAction : public QObject, public mitk::IContextMenuAction -{ - Q_OBJECT - Q_INTERFACES(mitk::IContextMenuAction) - -public: - QmitkThresholdAction(); - ~QmitkThresholdAction() override; - - // IContextMenuAction - void Run(const QList &selectedNodes) override; - void SetDataStorage(mitk::DataStorage *dataStorage) override; - void SetSmoothed(bool smoothed) override; - void SetDecimated(bool decimated) override; - void SetFunctionality(berry::QtViewPart* view) override; - - void OnThresholdingToolManagerToolModified(); - -private: - QmitkThresholdAction(const QmitkThresholdAction &); - QmitkThresholdAction & operator=(const QmitkThresholdAction &); - - mitk::DataNode::Pointer m_SelectedNode; - mitk::DataStorage::Pointer m_DataStorage; - mitk::ToolManager::Pointer m_ThresholdingToolManager; -}; - -#endif diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/mitkPluginActivator.cpp index 75912cd1a5..6d27f32fde 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/mitkPluginActivator.cpp @@ -1,63 +1,61 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkPluginActivator.h" #include "QmitkSegmentationView.h" -#include "QmitkThresholdAction.h" #include "QmitkCreatePolygonModelAction.h" #include "QmitkAutocropAction.h" #include "QmitkAutocropLabelSetImageAction.h" #include "QmitkSegmentationPreferencePage.h" #include "SegmentationUtilities/QmitkSegmentationUtilitiesView.h" using namespace mitk; ctkPluginContext* PluginActivator::m_context = nullptr; PluginActivator* PluginActivator::m_Instance = nullptr; PluginActivator::PluginActivator() { m_Instance = this; } PluginActivator::~PluginActivator() { m_Instance = nullptr; } void PluginActivator::start(ctkPluginContext *context) { BERRY_REGISTER_EXTENSION_CLASS(QmitkSegmentationView, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkThresholdAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkCreatePolygonModelAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkAutocropAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkAutocropLabelSetImageAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkSegmentationPreferencePage, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkSegmentationUtilitiesView, context) this->m_context = context; } void PluginActivator::stop(ctkPluginContext *) { this->m_context = nullptr; } PluginActivator* PluginActivator::getDefault() { return m_Instance; } ctkPluginContext*PluginActivator::getContext() { return m_context; }