diff --git a/Modules/Core/TestingHelper/src/mitkTestDynamicImageGenerator.cpp b/Modules/Core/TestingHelper/src/mitkTestDynamicImageGenerator.cpp index 73a8af779d..bca01c2eeb 100644 --- a/Modules/Core/TestingHelper/src/mitkTestDynamicImageGenerator.cpp +++ b/Modules/Core/TestingHelper/src/mitkTestDynamicImageGenerator.cpp @@ -1,253 +1,212 @@ /*============================================================================ 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 "mitkTestDynamicImageGenerator.h" #include "mitkArbitraryTimeGeometry.h" #include "mitkImageCast.h" +#include "mitkTemporalJoinImagesFilter.h" namespace mitk { typedef itk::Image FrameITKImageType; typedef itk::Image DynamicITKImageType; typedef itk::Image MaskITKImageType; TestImageType::Pointer GenerateTestImage(int factor) { TestImageType::Pointer image = TestImageType::New(); TestImageType::IndexType start; start[0] = 0; // first index on X start[1] = 0; // first index on Y TestImageType::SizeType size; size[0] = 3; // size along X size[1] = 3; // size along Y TestImageType::RegionType region; region.SetSize(size); region.SetIndex(start); image->SetRegions(region); image->Allocate(); itk::ImageRegionIterator it = itk::ImageRegionIterator(image, image->GetLargestPossibleRegion()); int count = 1; while (!it.IsAtEnd()) { it.Set(count * factor); ++it; ++count; } return image; } TestMaskType::Pointer GenerateTestMask() { TestMaskType::Pointer image = TestMaskType::New(); TestMaskType::IndexType start; start[0] = 0; // first index on X start[1] = 0; // first index on Y TestMaskType::SizeType size; size[0] = 3; // size along X size[1] = 3; // size along Y TestMaskType::RegionType region; region.SetSize(size); region.SetIndex(start); image->SetRegions(region); image->Allocate(); itk::ImageRegionIterator it = itk::ImageRegionIterator(image, image->GetLargestPossibleRegion()); int count = 1; while (!it.IsAtEnd()) { if (count > 1 && count < 5) { it.Set(1); } else { it.Set(0); } ++it; ++count; } return image; } Image::Pointer GenerateTestFrame(double timePoint) { FrameITKImageType::Pointer image = FrameITKImageType::New(); FrameITKImageType::IndexType start; start[0] = 0; // first index on X start[1] = 0; // first index on Y start[2] = 0; // first index on Z FrameITKImageType::SizeType size; size[0] = 3; // size along X size[1] = 3; // size along Y size[2] = 3; // size along Z FrameITKImageType::RegionType region; region.SetSize(size); region.SetIndex(start); image->SetRegions(region); image->Allocate(); itk::ImageRegionIterator it = itk::ImageRegionIterator(image, image->GetLargestPossibleRegion()); int count = 0; while (!it.IsAtEnd()) { double slope = count % (size[0] * size[1]); double offset = itk::Math::Floor(count / (size[0] * size[1])) * 10; it.Set(slope * timePoint + offset); ++it; ++count; } mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk(image.GetPointer()); mitkImage->SetVolume(image->GetBufferPointer()); return mitkImage; } Image::Pointer GenerateTestMaskMITK() { MaskITKImageType::Pointer image = MaskITKImageType::New(); MaskITKImageType::IndexType start; start[0] = 0; // first index on X start[1] = 0; // first index on Y start[2] = 0; // first index on Z MaskITKImageType::SizeType size; size[0] = 3; // size along X size[1] = 3; // size along Y size[2] = 3; // size along Z MaskITKImageType::RegionType region; region.SetSize(size); region.SetIndex(start); image->SetRegions(region); image->Allocate(); itk::ImageRegionIterator it = itk::ImageRegionIterator(image, image->GetLargestPossibleRegion()); int count = 0; while (!it.IsAtEnd()) { if (count < 14) { it.Set(1); } else { it.Set(0); } ++it; ++count; } mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk(image.GetPointer()); mitkImage->SetVolume(image->GetBufferPointer()); return mitkImage; } Image::Pointer GenerateDynamicTestImageMITK() { + auto filter = mitk::TemporalJoinImagesFilter::New(); - mitk::Image::Pointer tempImage = GenerateTestFrame(1); - mitk::Image::Pointer dynamicImage = mitk::Image::New(); - - DynamicITKImageType::Pointer dynamicITKImage = DynamicITKImageType::New(); - DynamicITKImageType::RegionType dynamicITKRegion; - DynamicITKImageType::PointType dynamicITKOrigin; - DynamicITKImageType::IndexType dynamicITKIndex; - DynamicITKImageType::SpacingType dynamicITKSpacing; - - dynamicITKSpacing[0] = tempImage->GetGeometry()->GetSpacing()[0]; - dynamicITKSpacing[1] = tempImage->GetGeometry()->GetSpacing()[1]; - dynamicITKSpacing[2] = tempImage->GetGeometry()->GetSpacing()[2]; - dynamicITKSpacing[3] = 5.0; - - dynamicITKIndex[0] = 0; // The first pixel of the REGION - dynamicITKIndex[1] = 0; - dynamicITKIndex[2] = 0; - dynamicITKIndex[3] = 0; - - dynamicITKRegion.SetSize(0, tempImage->GetDimension(0)); - dynamicITKRegion.SetSize(1, tempImage->GetDimension(1)); - dynamicITKRegion.SetSize(2, tempImage->GetDimension(2)); - dynamicITKRegion.SetSize(3, 10); - - dynamicITKRegion.SetIndex(dynamicITKIndex); - - dynamicITKOrigin[0] = tempImage->GetGeometry()->GetOrigin()[0]; - dynamicITKOrigin[1] = tempImage->GetGeometry()->GetOrigin()[1]; - dynamicITKOrigin[2] = tempImage->GetGeometry()->GetOrigin()[2]; - - dynamicITKImage->SetOrigin(dynamicITKOrigin); - dynamicITKImage->SetSpacing(dynamicITKSpacing); - dynamicITKImage->SetRegions(dynamicITKRegion); - dynamicITKImage->Allocate(); - dynamicITKImage->FillBuffer(0); //not sure if this is necessary - - // Convert - mitk::CastToMitkImage(dynamicITKImage, dynamicImage); - - ArbitraryTimeGeometry::Pointer timeGeometry = ArbitraryTimeGeometry::New(); - timeGeometry->ClearAllGeometries(); - - + mitk::TemporalJoinImagesFilter::TimeBoundsVectorType bounds; for (int i = 0; i < 10; ++i) { - mitk::Image::Pointer frameImage = GenerateTestFrame(1 + (dynamicITKSpacing[3] * i)); - mitk::ImageReadAccessor accessor(frameImage); - dynamicImage->SetVolume(accessor.GetData(), i); - - timeGeometry->AppendNewTimeStepClone(frameImage->GetGeometry(), 1 + (dynamicITKSpacing[3] * i), - 1 + (dynamicITKSpacing[3]*(i+1))); + filter->SetInput(i, GenerateTestFrame(1 + (5.0 * i))); + bounds.push_back(1 + (5.0 * (i + 1))); } - dynamicImage->SetTimeGeometry(timeGeometry); + filter->SetFirstMinTimeBound(1.); + filter->SetMaxTimeBounds(bounds); + + filter->Update(); - return dynamicImage; + return filter->GetOutput(); } } diff --git a/Modules/Core/files.cmake b/Modules/Core/files.cmake index e13405173c..78ae1b7ad2 100644 --- a/Modules/Core/files.cmake +++ b/Modules/Core/files.cmake @@ -1,323 +1,324 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkCoreActivator.cpp mitkCoreObjectFactoryBase.cpp mitkCoreObjectFactory.cpp mitkCoreServices.cpp mitkException.cpp Algorithms/mitkBaseDataSource.cpp Algorithms/mitkClippedSurfaceBoundsCalculator.cpp Algorithms/mitkCompareImageDataFilter.cpp Algorithms/mitkCompositePixelValueToString.cpp Algorithms/mitkConvert2Dto3DImageFilter.cpp Algorithms/mitkDataNodeSource.cpp Algorithms/mitkExtractSliceFilter.cpp Algorithms/mitkExtractSliceFilter2.cpp Algorithms/mitkHistogramGenerator.cpp Algorithms/mitkImageChannelSelector.cpp Algorithms/mitkImageSliceSelector.cpp Algorithms/mitkImageSource.cpp Algorithms/mitkImageTimeSelector.cpp Algorithms/mitkImageToImageFilter.cpp Algorithms/mitkImageToSurfaceFilter.cpp Algorithms/mitkMultiComponentImageDataComparisonFilter.cpp Algorithms/mitkPlaneGeometryDataToSurfaceFilter.cpp Algorithms/mitkPointSetSource.cpp Algorithms/mitkPointSetToPointSetFilter.cpp Algorithms/mitkRGBToRGBACastImageFilter.cpp Algorithms/mitkSubImageSelector.cpp Algorithms/mitkSurfaceSource.cpp Algorithms/mitkSurfaceToImageFilter.cpp Algorithms/mitkSurfaceToSurfaceFilter.cpp Algorithms/mitkUIDGenerator.cpp Algorithms/mitkVolumeCalculator.cpp + Algorithms/mitkTemporalJoinImagesFilter.cpp Controllers/mitkBaseController.cpp Controllers/mitkCallbackFromGUIThread.cpp Controllers/mitkCameraController.cpp Controllers/mitkCameraRotationController.cpp Controllers/mitkLimitedLinearUndo.cpp Controllers/mitkOperationEvent.cpp Controllers/mitkPlanePositionManager.cpp Controllers/mitkProgressBar.cpp Controllers/mitkRenderingManager.cpp Controllers/mitkSliceNavigationController.cpp Controllers/mitkSlicesCoordinator.cpp Controllers/mitkStatusBar.cpp Controllers/mitkStepper.cpp Controllers/mitkTestManager.cpp Controllers/mitkUndoController.cpp Controllers/mitkVerboseLimitedLinearUndo.cpp Controllers/mitkVtkLayerController.cpp DataManagement/mitkAnatomicalStructureColorPresets.cpp DataManagement/mitkArbitraryTimeGeometry.cpp DataManagement/mitkAbstractTransformGeometry.cpp DataManagement/mitkAnnotationProperty.cpp DataManagement/mitkApplicationCursor.cpp DataManagement/mitkApplyTransformMatrixOperation.cpp DataManagement/mitkBaseData.cpp DataManagement/mitkBaseGeometry.cpp DataManagement/mitkBaseProperty.cpp DataManagement/mitkChannelDescriptor.cpp DataManagement/mitkClippingProperty.cpp DataManagement/mitkColorProperty.cpp DataManagement/mitkDataNode.cpp DataManagement/mitkDataStorage.cpp DataManagement/mitkEnumerationProperty.cpp DataManagement/mitkFloatPropertyExtension.cpp DataManagement/mitkGeometry3D.cpp DataManagement/mitkGeometryData.cpp DataManagement/mitkGeometryTransformHolder.cpp DataManagement/mitkGroupTagProperty.cpp DataManagement/mitkGenericIDRelationRule.cpp DataManagement/mitkIdentifiable.cpp DataManagement/mitkImageAccessorBase.cpp DataManagement/mitkImageCaster.cpp DataManagement/mitkImageCastPart1.cpp DataManagement/mitkImageCastPart2.cpp DataManagement/mitkImageCastPart3.cpp DataManagement/mitkImageCastPart4.cpp DataManagement/mitkImage.cpp DataManagement/mitkImageDataItem.cpp DataManagement/mitkImageDescriptor.cpp DataManagement/mitkImageReadAccessor.cpp DataManagement/mitkImageStatisticsHolder.cpp DataManagement/mitkImageVtkAccessor.cpp DataManagement/mitkImageVtkReadAccessor.cpp DataManagement/mitkImageVtkWriteAccessor.cpp DataManagement/mitkImageWriteAccessor.cpp DataManagement/mitkIntPropertyExtension.cpp DataManagement/mitkIPersistenceService.cpp DataManagement/mitkIPropertyAliases.cpp DataManagement/mitkIPropertyDescriptions.cpp DataManagement/mitkIPropertyExtensions.cpp DataManagement/mitkIPropertyFilters.cpp DataManagement/mitkIPropertyOwner.cpp DataManagement/mitkIPropertyPersistence.cpp DataManagement/mitkIPropertyProvider.cpp DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp DataManagement/mitkLandmarkProjector.cpp DataManagement/mitkLevelWindow.cpp DataManagement/mitkLevelWindowManager.cpp DataManagement/mitkLevelWindowPreset.cpp DataManagement/mitkLevelWindowProperty.cpp DataManagement/mitkLine.cpp DataManagement/mitkLookupTable.cpp DataManagement/mitkLookupTableProperty.cpp DataManagement/mitkLookupTables.cpp # specializations of GenericLookupTable DataManagement/mitkMaterial.cpp DataManagement/mitkMemoryUtilities.cpp DataManagement/mitkModalityProperty.cpp DataManagement/mitkModifiedLock.cpp DataManagement/mitkNodePredicateAnd.cpp DataManagement/mitkNodePredicateBase.cpp DataManagement/mitkNodePredicateCompositeBase.cpp DataManagement/mitkNodePredicateData.cpp DataManagement/mitkNodePredicateDataType.cpp DataManagement/mitkNodePredicateDataUID.cpp DataManagement/mitkNodePredicateDimension.cpp DataManagement/mitkNodePredicateFirstLevel.cpp DataManagement/mitkNodePredicateFunction.cpp DataManagement/mitkNodePredicateGeometry.cpp DataManagement/mitkNodePredicateNot.cpp DataManagement/mitkNodePredicateOr.cpp DataManagement/mitkNodePredicateProperty.cpp DataManagement/mitkNodePredicateDataProperty.cpp DataManagement/mitkNodePredicateSource.cpp DataManagement/mitkNumericConstants.cpp DataManagement/mitkPlaneGeometry.cpp DataManagement/mitkPlaneGeometryData.cpp DataManagement/mitkPlaneOperation.cpp DataManagement/mitkPlaneOrientationProperty.cpp DataManagement/mitkPointOperation.cpp DataManagement/mitkPointSet.cpp DataManagement/mitkPointSetShapeProperty.cpp DataManagement/mitkProperties.cpp DataManagement/mitkPropertyAliases.cpp DataManagement/mitkPropertyDescriptions.cpp DataManagement/mitkPropertyExtension.cpp DataManagement/mitkPropertyExtensions.cpp DataManagement/mitkPropertyFilter.cpp DataManagement/mitkPropertyFilters.cpp DataManagement/mitkPropertyKeyPath.cpp DataManagement/mitkPropertyList.cpp DataManagement/mitkPropertyListReplacedObserver.cpp DataManagement/mitkPropertyNameHelper.cpp DataManagement/mitkPropertyObserver.cpp DataManagement/mitkPropertyPersistence.cpp DataManagement/mitkPropertyPersistenceInfo.cpp DataManagement/mitkPropertyRelationRuleBase.cpp DataManagement/mitkProportionalTimeGeometry.cpp DataManagement/mitkRenderingModeProperty.cpp DataManagement/mitkResliceMethodProperty.cpp DataManagement/mitkRestorePlanePositionOperation.cpp DataManagement/mitkRotationOperation.cpp DataManagement/mitkScaleOperation.cpp DataManagement/mitkSlicedData.cpp DataManagement/mitkSlicedGeometry3D.cpp DataManagement/mitkSmartPointerProperty.cpp DataManagement/mitkStandaloneDataStorage.cpp DataManagement/mitkStringProperty.cpp DataManagement/mitkSurface.cpp DataManagement/mitkSurfaceOperation.cpp DataManagement/mitkSourceImageRelationRule.cpp DataManagement/mitkThinPlateSplineCurvedGeometry.cpp DataManagement/mitkTimeGeometry.cpp DataManagement/mitkTransferFunction.cpp DataManagement/mitkTransferFunctionInitializer.cpp DataManagement/mitkTransferFunctionProperty.cpp DataManagement/mitkTemporoSpatialStringProperty.cpp DataManagement/mitkUIDManipulator.cpp DataManagement/mitkVector.cpp DataManagement/mitkVectorProperty.cpp DataManagement/mitkVtkInterpolationProperty.cpp DataManagement/mitkVtkRepresentationProperty.cpp DataManagement/mitkVtkResliceInterpolationProperty.cpp DataManagement/mitkVtkScalarModeProperty.cpp DataManagement/mitkVtkVolumeRenderingProperty.cpp DataManagement/mitkWeakPointerProperty.cpp DataManagement/mitkIPropertyRelations.cpp DataManagement/mitkPropertyRelations.cpp Interactions/mitkAction.cpp Interactions/mitkBindDispatcherInteractor.cpp Interactions/mitkCrosshairPositionEvent.cpp Interactions/mitkDataInteractor.cpp Interactions/mitkDispatcher.cpp Interactions/mitkDisplayActionEventBroadcast.cpp Interactions/mitkDisplayActionEventFunctions.cpp Interactions/mitkDisplayActionEventHandler.cpp Interactions/mitkDisplayActionEventHandlerDesynchronized.cpp Interactions/mitkDisplayActionEventHandlerStd.cpp Interactions/mitkDisplayActionEventHandlerSynchronized.cpp Interactions/mitkDisplayCoordinateOperation.cpp Interactions/mitkDisplayInteractor.cpp Interactions/mitkEventConfig.cpp Interactions/mitkEventFactory.cpp Interactions/mitkEventRecorder.cpp Interactions/mitkEventStateMachine.cpp Interactions/mitkInteractionEventConst.cpp Interactions/mitkInteractionEvent.cpp Interactions/mitkInteractionEventHandler.cpp Interactions/mitkInteractionEventObserver.cpp Interactions/mitkInteractionKeyEvent.cpp Interactions/mitkInteractionPositionEvent.cpp Interactions/mitkInteractionSchemeSwitcher.cpp Interactions/mitkInternalEvent.cpp Interactions/mitkMouseDoubleClickEvent.cpp Interactions/mitkMouseModeSwitcher.cpp Interactions/mitkMouseMoveEvent.cpp Interactions/mitkMousePressEvent.cpp Interactions/mitkMouseReleaseEvent.cpp Interactions/mitkMouseWheelEvent.cpp Interactions/mitkPointSetDataInteractor.cpp Interactions/mitkSinglePointDataInteractor.cpp Interactions/mitkStateMachineAction.cpp Interactions/mitkStateMachineCondition.cpp Interactions/mitkStateMachineContainer.cpp Interactions/mitkStateMachineState.cpp Interactions/mitkStateMachineTransition.cpp Interactions/mitkVtkEventAdapter.cpp Interactions/mitkVtkInteractorStyle.cxx Interactions/mitkXML2EventParser.cpp IO/mitkAbstractFileIO.cpp IO/mitkAbstractFileReader.cpp IO/mitkAbstractFileWriter.cpp IO/mitkCustomMimeType.cpp IO/mitkFileReader.cpp IO/mitkFileReaderRegistry.cpp IO/mitkFileReaderSelector.cpp IO/mitkFileReaderWriterBase.cpp IO/mitkFileWriter.cpp IO/mitkFileWriterRegistry.cpp IO/mitkFileWriterSelector.cpp IO/mitkGeometry3DToXML.cpp IO/mitkIFileIO.cpp IO/mitkIFileReader.cpp IO/mitkIFileWriter.cpp IO/mitkGeometryDataReaderService.cpp IO/mitkGeometryDataWriterService.cpp IO/mitkImageGenerator.cpp IO/mitkImageVtkLegacyIO.cpp IO/mitkImageVtkXmlIO.cpp IO/mitkIMimeTypeProvider.cpp IO/mitkIOConstants.cpp IO/mitkIOMimeTypes.cpp IO/mitkIOUtil.cpp IO/mitkItkImageIO.cpp IO/mitkItkLoggingAdapter.cpp IO/mitkLegacyFileReaderService.cpp IO/mitkLegacyFileWriterService.cpp IO/mitkLocaleSwitch.cpp IO/mitkLog.cpp IO/mitkMimeType.cpp IO/mitkMimeTypeProvider.cpp IO/mitkOperation.cpp IO/mitkPixelType.cpp IO/mitkPointSetReaderService.cpp IO/mitkPointSetWriterService.cpp IO/mitkProportionalTimeGeometryToXML.cpp IO/mitkRawImageFileReader.cpp IO/mitkStandardFileLocations.cpp IO/mitkSurfaceStlIO.cpp IO/mitkSurfaceVtkIO.cpp IO/mitkSurfaceVtkLegacyIO.cpp IO/mitkSurfaceVtkXmlIO.cpp IO/mitkVtkLoggingAdapter.cpp IO/mitkPreferenceListReaderOptionsFunctor.cpp Rendering/mitkAbstractAnnotationRenderer.cpp Rendering/mitkAnnotationUtils.cpp Rendering/mitkBaseRenderer.cpp #Rendering/mitkGLMapper.cpp Moved to deprecated LegacyGL Module Rendering/mitkGradientBackground.cpp Rendering/mitkImageVtkMapper2D.cpp Rendering/mitkMapper.cpp Rendering/mitkAnnotation.cpp Rendering/mitkPlaneGeometryDataMapper2D.cpp Rendering/mitkPlaneGeometryDataVtkMapper3D.cpp Rendering/mitkPointSetVtkMapper2D.cpp Rendering/mitkPointSetVtkMapper3D.cpp Rendering/mitkRenderWindowBase.cpp Rendering/mitkRenderWindow.cpp Rendering/mitkRenderWindowFrame.cpp #Rendering/mitkSurfaceGLMapper2D.cpp Moved to deprecated LegacyGL Module Rendering/mitkSurfaceVtkMapper2D.cpp Rendering/mitkSurfaceVtkMapper3D.cpp Rendering/mitkVtkEventProvider.cpp Rendering/mitkVtkMapper.cpp Rendering/mitkVtkPropRenderer.cpp Rendering/mitkVtkWidgetRendering.cpp Rendering/vtkMitkLevelWindowFilter.cpp Rendering/vtkMitkRectangleProp.cpp Rendering/vtkMitkRenderProp.cpp Rendering/vtkMitkThickSlicesFilter.cpp Rendering/vtkNeverTranslucentTexture.cpp ) set(RESOURCE_FILES Interactions/globalConfig.xml Interactions/DisplayInteraction.xml Interactions/DisplayConfig.xml Interactions/DisplayConfigPACS.xml Interactions/DisplayConfigPACSPan.xml Interactions/DisplayConfigPACSScroll.xml Interactions/DisplayConfigPACSZoom.xml Interactions/DisplayConfigPACSLevelWindow.xml Interactions/DisplayConfigMITK.xml Interactions/DisplayConfigMITKNoCrosshair.xml Interactions/DisplayConfigMITKRotation.xml Interactions/DisplayConfigMITKRotationUnCoupled.xml Interactions/DisplayConfigMITKSwivel.xml Interactions/DisplayConfigMITKLimited.xml Interactions/PointSet.xml Interactions/Legacy/StateMachine.xml Interactions/Legacy/DisplayConfigMITKTools.xml Interactions/PointSetConfig.xml mitkLevelWindowPresets.xml mitkAnatomicalStructureColorPresets.xml ) diff --git a/Modules/Core/include/mitkLocaleSwitch.h b/Modules/Core/include/mitkLocaleSwitch.h index 96af6c09b6..601ac02d63 100644 --- a/Modules/Core/include/mitkLocaleSwitch.h +++ b/Modules/Core/include/mitkLocaleSwitch.h @@ -1,61 +1,72 @@ /*============================================================================ 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 __mitkLocaleSwitch_h #define __mitkLocaleSwitch_h #include "MitkCoreExports.h" namespace mitk { /** \brief Convenience class to temporarily change the current locale. This helper class can be used to switch to a specific locale for a couple of operations. Once the class is destroyed, the previous locale will be restored. This avoids calling or forgetting to call setlocale() in multiple return locations. Typically this is used to switch to a "C" locale when parsing or printing numbers, in order to consistently get "." and not "," as a decimal separator. + WARNING: Please be aware that using setlocale and there for is not thread + safe. So use this class with care (see tast T24295 for more information. + This switch is especially use full if you have to deal with third party code + where you have to controll the locale via set locale \code - - std::string toString(int number) { mitk::LocaleSwitch localeSwitch("C");// installs C locale until the end of the function - std::stringstream parser; - parser << number; + ExternalLibraryCall(); //that might throw or what ever. + } + \endcode + If you just want to control you own stringstream operations use imbue instead, as it is + threadsafe. E.G.: + \code + std::string toString(int number) + { + std::ostringstream parser; + parser.imbue(std::locale("C")); + parser << number; return parser.str(); } \endcode */ struct MITKCORE_EXPORT LocaleSwitch { explicit LocaleSwitch(const char *newLocale); ~LocaleSwitch(); LocaleSwitch(LocaleSwitch &) = delete; LocaleSwitch operator=(LocaleSwitch &) = delete; private: struct Impl; Impl *m_LocaleSwitchImpl; }; } #endif // __mitkLocaleSwitch_h diff --git a/Modules/Core/include/mitkTemporalJoinImagesFilter.h b/Modules/Core/include/mitkTemporalJoinImagesFilter.h new file mode 100644 index 0000000000..b03f905221 --- /dev/null +++ b/Modules/Core/include/mitkTemporalJoinImagesFilter.h @@ -0,0 +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 TEMPORALJOINIMAGESFILTER_H +#define TEMPORALJOINIMAGESFILTER_H + + +#include "mitkImageToImageFilter.h" +#include "mitkCommon.h" + +#include "MitkCoreExports.h" + +namespace mitk +{ + /** Filter that takes n mitk images as inputs and fuse them to a new image (with n time points). + Preconditions of this filter are, that all input images have the same pixel type and geometry. + The sequence of frames in the output image is the same then the sequence of inputs. + It no time bounds are defined the dynamic image will start at 0 ms and each time step has a duration + of 1 ms.*/ + class MITKCORE_EXPORT TemporalJoinImagesFilter : public ImageToImageFilter + { + public: + mitkClassMacro(TemporalJoinImagesFilter, ImageToImageFilter); + itkFactorylessNewMacro(TemporalJoinImagesFilter); + + typedef std::vector TimeBoundsVectorType; + + itkGetConstMacro(FirstMinTimeBound, mitk::TimePointType); + /**Set custom min time bound for the first time step.*/ + itkSetMacro(FirstMinTimeBound, mitk::TimePointType); + + itkGetConstMacro(MaxTimeBounds, TimeBoundsVectorType); + /**Set custom max time bounds for all time steps.*/ + void SetMaxTimeBounds(const TimeBoundsVectorType &bounds); + + protected: + TemporalJoinImagesFilter(){}; + ~TemporalJoinImagesFilter() override{}; + + void GenerateInputRequestedRegion() override; + + void GenerateOutputInformation() override; + + void GenerateData() override; + + private: + TimeBoundsVectorType m_MaxTimeBounds; + mitk::TimePointType m_FirstMinTimeBound = 0.0; + }; +} + + +#endif // MODELSIGNALIMAGEGENERATOR_H diff --git a/Modules/Core/src/Algorithms/mitkTemporalJoinImagesFilter.cpp b/Modules/Core/src/Algorithms/mitkTemporalJoinImagesFilter.cpp new file mode 100644 index 0000000000..7b22a3760f --- /dev/null +++ b/Modules/Core/src/Algorithms/mitkTemporalJoinImagesFilter.cpp @@ -0,0 +1,122 @@ +/*============================================================================ + +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 "mitkTemporalJoinImagesFilter.h" + +#include + +#include "mitkArbitraryTimeGeometry.h" +#include "mitkImageReadAccessor.h" +#include "mitkTemporoSpatialStringProperty.h" + +void mitk::TemporalJoinImagesFilter::SetMaxTimeBounds(const TimeBoundsVectorType& timeBounds) +{ + m_MaxTimeBounds = timeBounds; + this->Modified(); +} + +void mitk::TemporalJoinImagesFilter::GenerateInputRequestedRegion() +{ + Superclass::GenerateInputRequestedRegion(); + const auto nrOfInputs = this->GetNumberOfInputs(); + for (DataObjectPointerArraySizeType pos = 0; pos < nrOfInputs; ++pos) + { + this->GetInput(pos)->SetRequestedRegionToLargestPossibleRegion(); + } +} + +void mitk::TemporalJoinImagesFilter::GenerateOutputInformation() +{ + mitk::Image::ConstPointer input = this->GetInput(); + mitk::Image::Pointer output = this->GetOutput(); + + const auto nrOfInputs = this->GetNumberOfInputs(); + auto timeBounds = m_MaxTimeBounds; + + if (timeBounds.empty()) + { + timeBounds.resize(nrOfInputs); + std::iota(timeBounds.begin(), timeBounds.end(), 1.0); + } + else if(timeBounds.size() != nrOfInputs) + { + mitkThrow() << "User defined max time bounds do not match the number if inputs (" << nrOfInputs << "). Size of max timebounds is " << timeBounds.size() << ", but it should be " << nrOfInputs << "."; + } + + timeBounds.insert(timeBounds.begin(), m_FirstMinTimeBound); + + auto timeGeo = mitk::ArbitraryTimeGeometry::New(); + timeGeo->ReserveSpaceForGeometries(nrOfInputs); + + for (DataObjectPointerArraySizeType pos = 0; pos < nrOfInputs; ++pos) + { + timeGeo->AppendNewTimeStepClone(this->GetInput(pos)->GetGeometry(), timeBounds[pos], timeBounds[pos + 1]); + } + output->Initialize(input->GetPixelType(), *timeGeo); + + auto newPropList = input->GetPropertyList()->Clone(); + for (DataObjectPointerArraySizeType pos = 1; pos < nrOfInputs; ++pos) + { + const auto otherList = this->GetInput(pos)->GetPropertyList(); + for (const auto& key : otherList->GetPropertyKeys()) + { + auto prop = newPropList->GetProperty(key); + if (prop == nullptr) + { + newPropList->SetProperty(key, otherList->GetProperty(key)->Clone()); + } + else + { + auto tempoSpatialProp = dynamic_cast(prop); + auto oTempoSpatialProp = dynamic_cast(otherList->GetProperty(key)); + if (prop != nullptr && oTempoSpatialProp != nullptr) + { + auto availabelSlices = oTempoSpatialProp->GetAvailableSlices(0); + + for (const auto& sliceID : availabelSlices) + { + tempoSpatialProp->SetValue(pos, sliceID, oTempoSpatialProp->GetValueBySlice(sliceID)); + } + } + //other prop types can be ignored, we only use the values of the first frame. + } + } + } + + output->SetPropertyList(newPropList); +} + + +void mitk::TemporalJoinImagesFilter::GenerateData() +{ + mitk::Image::Pointer output = this->GetOutput(); + mitk::Image::ConstPointer refInput = this->GetInput(); + const auto nrOfInputs = this->GetNumberOfInputs(); + + for (DataObjectPointerArraySizeType pos = 0; pos < nrOfInputs; ++pos) + { + if (!Equal(*(refInput->GetGeometry()), *(this->GetInput(pos)->GetGeometry()), mitk::eps, false)) + { + mitkThrow() << "Cannot fuse images. At least image #" << pos << " has another geometry than the first image."; + } + if (refInput->GetPixelType() != this->GetInput(pos)->GetPixelType()) + { + mitkThrow() << "Cannot fuse images. At least image #" << pos << " has another pixeltype than the first image."; + } + } + + for (DataObjectPointerArraySizeType pos = 0; pos < nrOfInputs; ++pos) + { + mitk::ImageReadAccessor accessor(this->GetInput(pos)); + output->SetVolume(accessor.GetData(), pos); + } +} diff --git a/Modules/Core/test/files.cmake b/Modules/Core/test/files.cmake index f98fb8a5df..5efc282bfa 100644 --- a/Modules/Core/test/files.cmake +++ b/Modules/Core/test/files.cmake @@ -1,193 +1,194 @@ # tests with no extra command line parameter set(MODULE_TESTS # IMPORTANT: If you plan to deactivate / comment out a test please write a bug number to the commented out line of code. # # Example: #mitkMyTest #this test is commented out because of bug 12345 # # It is important that the bug is open and that the test will be activated again before the bug is closed. This assures that # no test is forgotten after it was commented out. If there is no bug for your current problem, please add a new one and # mark it as critical. ################## DISABLED TESTS ################################################# #mitkAbstractTransformGeometryTest.cpp #seems as tested class mitkExternAbstractTransformGeometry doesnt exist any more #mitkStateMachineContainerTest.cpp #rewrite test, indirect since no longer exported Bug 14529 #mitkRegistrationBaseTest.cpp #tested class mitkRegistrationBase doesn't exist any more #mitkSegmentationInterpolationTest.cpp #file doesn't exist! #mitkPipelineSmartPointerCorrectnessTest.cpp #file doesn't exist! #mitkITKThreadingTest.cpp #test outdated because itk::Semaphore was removed from ITK #mitkAbstractTransformPlaneGeometryTest.cpp #mitkVtkAbstractTransformPlaneGeometry doesn't exist any more #mitkTestUtilSharedLibrary.cpp #Linker problem with this test... #mitkTextOverlay2DSymbolsRenderingTest.cpp #Implementation of the tested feature is not finished yet. Ask Christoph or see bug 15104 for details. ################# RUNNING TESTS ################################################### mitkAccessByItkTest.cpp mitkCoreObjectFactoryTest.cpp mitkDataNodeTest.cpp mitkMaterialTest.cpp mitkActionTest.cpp mitkDispatcherTest.cpp mitkEnumerationPropertyTest.cpp mitkFileReaderRegistryTest.cpp #mitkFileWriterRegistryTest.cpp mitkFloatToStringTest.cpp mitkGenericPropertyTest.cpp mitkGeometry3DTest.cpp mitkGeometry3DEqualTest.cpp mitkGeometryDataIOTest.cpp mitkGeometryDataToSurfaceFilterTest.cpp mitkImageCastTest.cpp mitkImageDataItemTest.cpp mitkImageGeneratorTest.cpp mitkIOUtilTest.cpp mitkBaseDataTest.cpp mitkImportItkImageTest.cpp mitkGrabItkImageMemoryTest.cpp mitkInstantiateAccessFunctionTest.cpp mitkLevelWindowTest.cpp mitkMessageTest.cpp mitkPixelTypeTest.cpp mitkPlaneGeometryTest.cpp mitkPointSetTest.cpp mitkPointSetEqualTest.cpp mitkPointSetFileIOTest.cpp mitkPointSetOnEmptyTest.cpp mitkPointSetLocaleTest.cpp mitkPointSetWriterTest.cpp mitkPointSetPointOperationsTest.cpp mitkProgressBarTest.cpp mitkPropertyTest.cpp mitkPropertyListTest.cpp mitkPropertyPersistenceTest.cpp mitkPropertyPersistenceInfoTest.cpp mitkPropertyRelationRuleBaseTest.cpp mitkPropertyRelationsTest.cpp mitkSlicedGeometry3DTest.cpp mitkSliceNavigationControllerTest.cpp mitkSurfaceTest.cpp mitkSurfaceEqualTest.cpp mitkSurfaceToSurfaceFilterTest.cpp mitkTimeGeometryTest.cpp mitkProportionalTimeGeometryTest.cpp mitkUndoControllerTest.cpp mitkVtkWidgetRenderingTest.cpp mitkVerboseLimitedLinearUndoTest.cpp mitkWeakPointerTest.cpp mitkTransferFunctionTest.cpp mitkStepperTest.cpp mitkRenderingManagerTest.cpp mitkCompositePixelValueToStringTest.cpp vtkMitkThickSlicesFilterTest.cpp mitkNodePredicateSourceTest.cpp mitkNodePredicateDataPropertyTest.cpp mitkNodePredicateFunctionTest.cpp mitkVectorTest.cpp mitkClippedSurfaceBoundsCalculatorTest.cpp mitkExceptionTest.cpp mitkExtractSliceFilterTest.cpp mitkLogTest.cpp mitkImageDimensionConverterTest.cpp mitkLoggingAdapterTest.cpp mitkUIDGeneratorTest.cpp mitkPlanePositionManagerTest.cpp mitkAffineTransformBaseTest.cpp mitkPropertyAliasesTest.cpp mitkPropertyDescriptionsTest.cpp mitkPropertyExtensionsTest.cpp mitkPropertyFiltersTest.cpp mitkPropertyKeyPathTest.cpp mitkTinyXMLTest.cpp mitkRawImageFileReaderTest.cpp mitkInteractionEventTest.cpp mitkLookupTableTest.cpp mitkSTLFileReaderTest.cpp mitkPointTypeConversionTest.cpp mitkVectorTypeConversionTest.cpp mitkMatrixTypeConversionTest.cpp mitkArrayTypeConversionTest.cpp mitkSurfaceToImageFilterTest.cpp mitkBaseGeometryTest.cpp mitkImageToSurfaceFilterTest.cpp mitkEqualTest.cpp mitkLineTest.cpp mitkArbitraryTimeGeometryTest.cpp mitkItkImageIOTest.cpp mitkLevelWindowManagerCppUnitTest.cpp mitkVectorPropertyTest.cpp mitkTemporoSpatialStringPropertyTest.cpp mitkPropertyNameHelperTest.cpp mitkNodePredicateGeometryTest.cpp mitkPreferenceListReaderOptionsFunctorTest.cpp mitkGenericIDRelationRuleTest.cpp mitkSourceImageRelationRuleTest.cpp mitkPointSetDataInteractorTest.cpp #since mitkInteractionTestHelper is currently creating a vtkRenderWindow mitkSurfaceVtkMapper2DTest.cpp #new rendering test in CppUnit style mitkSurfaceVtkMapper2D3DTest.cpp # comparisons/consistency 2D/3D + mitkTemporalJoinImagesFilterTest.cpp ) # test with image filename as an extra command line parameter set(MODULE_IMAGE_TESTS mitkImageTimeSelectorTest.cpp #only runs on images mitkImageAccessorTest.cpp #only runs on images ) set(MODULE_SURFACE_TESTS mitkSurfaceVtkWriterTest.cpp #only runs on surfaces ) # list of images for which the tests are run set(MODULE_TESTIMAGE US4DCyl.nrrd Pic3D.nrrd Pic2DplusT.nrrd BallBinary30x30x30.nrrd Png2D-bw.png ) set(MODULE_TESTSURFACE binary.stl ball.stl ) set(MODULE_CUSTOM_TESTS mitkDataStorageTest.cpp mitkDataNodeTest.cpp mitkEventConfigTest.cpp mitkPointSetLocaleTest.cpp mitkImageTest.cpp mitkImageVtkMapper2DTest.cpp mitkImageVtkMapper2DLevelWindowTest.cpp mitkImageVtkMapper2DOpacityTest.cpp mitkImageVtkMapper2DResliceInterpolationPropertyTest.cpp mitkImageVtkMapper2DColorTest.cpp mitkImageVtkMapper2DSwivelTest.cpp mitkImageVtkMapper2DTransferFunctionTest.cpp mitkImageVtkMapper2DOpacityTransferFunctionTest.cpp mitkImageVtkMapper2DLookupTableTest.cpp mitkSurfaceVtkMapper3DTest.cpp mitkVolumeCalculatorTest.cpp mitkLevelWindowManagerTest.cpp mitkPointSetVtkMapper2DTest.cpp mitkPointSetVtkMapper2DImageTest.cpp mitkPointSetVtkMapper2DGlyphTypeTest.cpp mitkPointSetVtkMapper2DTransformedPointsTest.cpp mitkVTKRenderWindowSizeTest.cpp mitkMultiComponentImageDataComparisonFilterTest.cpp mitkImageToItkTest.cpp mitkImageSliceSelectorTest.cpp mitkPointSetReaderTest.cpp mitkImageEqualTest.cpp mitkRotatedSlice4DTest.cpp mitkPlaneGeometryDataMapper2DTest.cpp ) # Currently not working on windows because of a rendering timing issue # see bug 18083 for details if(NOT WIN32) set(MODULE_CUSTOM_TESTS ${MODULE_CUSTOM_TESTS} mitkSurfaceDepthSortingTest.cpp) endif() set(RESOURCE_FILES Interactions/AddAndRemovePoints.xml Interactions/globalConfig.xml Interactions/StatemachineTest.xml Interactions/StatemachineConfigTest.xml ) diff --git a/Modules/Core/test/mitkTemporalJoinImagesFilterTest.cpp b/Modules/Core/test/mitkTemporalJoinImagesFilterTest.cpp new file mode 100644 index 0000000000..4f2035ef7e --- /dev/null +++ b/Modules/Core/test/mitkTemporalJoinImagesFilterTest.cpp @@ -0,0 +1,188 @@ +/*============================================================================ + +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 "mitkImagePixelReadAccessor.h" + +#include "mitkTemporalJoinImagesFilter.h" +#include "mitkTestFixture.h" +#include "mitkTestingMacros.h" + +#include +#include "mitkTestDynamicImageGenerator.h" +#include "mitkStringProperty.h" +#include "mitkTemporoSpatialStringProperty.h" + +class mitkTemporalJoinImagesFilterTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkTemporalJoinImagesFilterTestSuite); + + MITK_TEST(InvalidUsage); + MITK_TEST(FuseDefault); + MITK_TEST(FuseUseDefinedTimeBounds); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::Image::Pointer t0; + mitk::Image::Pointer t1; + mitk::Image::Pointer t2; + + mitk::Image::Pointer invalidPixel; + mitk::Image::Pointer invalidGeometry; + +public: + void setUp() override + { + t0 = mitk::GenerateTestFrame(1); + t0->SetProperty("all", mitk::StringProperty::New("all_0")); + t0->SetProperty("ts", mitk::TemporoSpatialStringProperty::New("ts_0")); + + t1 = mitk::GenerateTestFrame(20); + t1->SetProperty("all", mitk::StringProperty::New("all_1")); + t1->SetProperty("ts", mitk::TemporoSpatialStringProperty::New("ts_1")); + t1->SetProperty("special", mitk::StringProperty::New("special_1")); + + t2 = mitk::GenerateTestFrame(300); + t2->SetProperty("all", mitk::StringProperty::New("all_2")); + t2->SetProperty("ts", mitk::TemporoSpatialStringProperty::New("ts_2")); + + invalidPixel = mitk::Image::New(); + invalidPixel->Initialize(mitk::MakePixelType(), *(t0->GetTimeGeometry())); + + invalidGeometry = mitk::Image::New(); + invalidGeometry->Initialize(t0); + invalidGeometry->SetGeometry(mitk::Geometry3D::New()); + } + + void tearDown() override {} + + void InvalidUsage() + { + auto filter = mitk::TemporalJoinImagesFilter::New(); + + filter->SetInput(0, t0); + filter->SetInput(1, invalidPixel); + + CPPUNIT_ASSERT_THROW(filter->Update(), mitk::Exception); + + filter = mitk::TemporalJoinImagesFilter::New(); + + filter->SetInput(0, t0); + filter->SetInput(1, invalidGeometry); + + CPPUNIT_ASSERT_THROW(filter->Update(), mitk::Exception); + + filter = mitk::TemporalJoinImagesFilter::New(); + + filter->SetInput(0, t0); + filter->SetInput(1, t1); + filter->SetMaxTimeBounds({ 3 }); + + CPPUNIT_ASSERT_THROW(filter->Update(), mitk::Exception); + } + + void FuseDefault() + { + auto filter = mitk::TemporalJoinImagesFilter::New(); + + filter->SetInput(0, t0); + filter->SetInput(1, t1); + filter->SetInput(2, t2); + + filter->Update(); + auto output = filter->GetOutput(); + + CPPUNIT_ASSERT(output->GetTimeSteps() == 3); + auto allProp = output->GetProperty("all"); + CPPUNIT_ASSERT(allProp->GetValueAsString() == "all_0"); + auto specialProp = output->GetProperty("special"); + CPPUNIT_ASSERT(specialProp->GetValueAsString() == "special_1"); + auto tsProp = dynamic_cast(output->GetProperty("ts").GetPointer()); + CPPUNIT_ASSERT(tsProp->GetValueByTimeStep(0) == "ts_0"); + CPPUNIT_ASSERT(tsProp->GetValueByTimeStep(1) == "ts_1"); + CPPUNIT_ASSERT(tsProp->GetValueByTimeStep(2) == "ts_2"); + + CPPUNIT_ASSERT(mitk::Equal(*(t0->GetGeometry()), *(output->GetGeometry()), mitk::eps, true)); + CPPUNIT_ASSERT(output->GetTimeGeometry()->GetMinimumTimePoint(0) == 0.); + CPPUNIT_ASSERT(output->GetTimeGeometry()->GetMaximumTimePoint(0) == 1.); + CPPUNIT_ASSERT(output->GetTimeGeometry()->GetMinimumTimePoint(1) == 1.); + CPPUNIT_ASSERT(output->GetTimeGeometry()->GetMaximumTimePoint(1) == 2.); + CPPUNIT_ASSERT(output->GetTimeGeometry()->GetMinimumTimePoint(2) == 2.); + CPPUNIT_ASSERT(output->GetTimeGeometry()->GetMaximumTimePoint(2) == 3.); + + mitk::ImagePixelReadAccessor accessor(output); + itk::Index<4> testIndex0; + testIndex0.Fill(2); + testIndex0[3] = 0; + itk::Index<4> testIndex1; + testIndex1.Fill(2); + testIndex1[3] = 1; + itk::Index<4> testIndex2; + testIndex2.Fill(2); + testIndex2[3] = 2; + + CPPUNIT_ASSERT_EQUAL(28., accessor.GetPixelByIndex(testIndex0)); + CPPUNIT_ASSERT_EQUAL(180., accessor.GetPixelByIndex(testIndex1)); + CPPUNIT_ASSERT_EQUAL(2420., accessor.GetPixelByIndex(testIndex2)); + } + + void FuseUseDefinedTimeBounds() + { + auto filter = mitk::TemporalJoinImagesFilter::New(); + + filter->SetInput(0, t0); + filter->SetInput(1, t1); + filter->SetInput(2, t2); + + filter->SetFirstMinTimeBound(10); + filter->SetMaxTimeBounds({ 20,30,40 }); + + filter->Update(); + auto output = filter->GetOutput(); + + CPPUNIT_ASSERT(output->GetTimeSteps() == 3); + auto allProp = output->GetProperty("all"); + CPPUNIT_ASSERT(allProp->GetValueAsString() == "all_0"); + auto specialProp = output->GetProperty("special"); + CPPUNIT_ASSERT(specialProp->GetValueAsString() == "special_1"); + auto tsProp = dynamic_cast(output->GetProperty("ts").GetPointer()); + CPPUNIT_ASSERT(tsProp->GetValueByTimeStep(0) == "ts_0"); + CPPUNIT_ASSERT(tsProp->GetValueByTimeStep(1) == "ts_1"); + CPPUNIT_ASSERT(tsProp->GetValueByTimeStep(2) == "ts_2"); + + CPPUNIT_ASSERT(mitk::Equal(*(t0->GetGeometry()), *(output->GetGeometry()), mitk::eps, true)); + CPPUNIT_ASSERT(output->GetTimeGeometry()->GetMinimumTimePoint(0) == 10.); + CPPUNIT_ASSERT(output->GetTimeGeometry()->GetMaximumTimePoint(0) == 20.); + CPPUNIT_ASSERT(output->GetTimeGeometry()->GetMinimumTimePoint(1) == 20.); + CPPUNIT_ASSERT(output->GetTimeGeometry()->GetMaximumTimePoint(1) == 30.); + CPPUNIT_ASSERT(output->GetTimeGeometry()->GetMinimumTimePoint(2) == 30.); + CPPUNIT_ASSERT(output->GetTimeGeometry()->GetMaximumTimePoint(2) == 40.); + + mitk::ImagePixelReadAccessor accessor(output); + itk::Index<4> testIndex0; + testIndex0.Fill(2); + testIndex0[3] = 0; + itk::Index<4> testIndex1; + testIndex1.Fill(2); + testIndex1[3] = 1; + itk::Index<4> testIndex2; + testIndex2.Fill(2); + testIndex2[3] = 2; + + CPPUNIT_ASSERT_EQUAL(28., accessor.GetPixelByIndex(testIndex0)); + CPPUNIT_ASSERT_EQUAL(180., accessor.GetPixelByIndex(testIndex1)); + CPPUNIT_ASSERT_EQUAL(2420., accessor.GetPixelByIndex(testIndex2)); + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkTemporalJoinImagesFilter) diff --git a/Modules/ModelFit/cmdapps/CMakeLists.txt b/Modules/ModelFit/cmdapps/CMakeLists.txt index f78ad56dda..cda6e31973 100644 --- a/Modules/ModelFit/cmdapps/CMakeLists.txt +++ b/Modules/ModelFit/cmdapps/CMakeLists.txt @@ -1,34 +1,35 @@ option(BUILD_ModelFitMiniApps "Build commandline tools for the ModelFit module" OFF) if(BUILD_ModelFitMiniApps OR MITK_BUILD_ALL_APPS) # needed include directories include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( miniapps GenericFittingMiniApp^^ PixelDumpMiniApp^^ + Fuse3Dto4DImageMiniApp^^ ) foreach(miniapp ${miniapps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${miniapp}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitkFunctionCreateCommandLineApp( NAME ${appname} DEPENDS MitkCore MitkModelFit ${dependencies_list} PACKAGE_DEPENDS ITK ) endforeach() endif(BUILD_ModelFitMiniApps OR MITK_BUILD_ALL_APPS) diff --git a/Modules/ModelFit/cmdapps/Fuse3Dto4DImageMiniApp.cpp b/Modules/ModelFit/cmdapps/Fuse3Dto4DImageMiniApp.cpp new file mode 100644 index 0000000000..a2cd40129f --- /dev/null +++ b/Modules/ModelFit/cmdapps/Fuse3Dto4DImageMiniApp.cpp @@ -0,0 +1,167 @@ +/*============================================================================ + +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. + +============================================================================*/ + +// std includes +#include +#include + +// itk includes +#include "itksys/SystemTools.hxx" + +// CTK includes +#include "mitkCommandLineParser.h" + +// MITK includes +#include +#include +#include + +mitkCommandLineParser::StringContainerType inFilenames; +std::string outFileName; + +std::vector images; +std::vector timebounds; + +void setupParser(mitkCommandLineParser& parser) +{ + // set general information about your MiniApp + parser.setCategory("Dynamic Data Analysis Tools"); + parser.setTitle("Fuse 3D to 4D Image"); + parser.setDescription("MiniApp that allows to fuse several 3D images (with same geometry) into a 3D+t (4D) image that can be processed as dynamic data."); + parser.setContributor("DKFZ MIC"); + //! [create parser] + + //! [add arguments] + // how should arguments be prefixed + parser.setArgumentPrefix("--", "-"); + // add each argument, unless specified otherwise each argument is optional + // see mitkCommandLineParser::addArgument for more information + parser.beginGroup("Required I/O parameters"); + parser.addArgument( + "inputs", "i", mitkCommandLineParser::StringList, "Input files", "Pathes to the input images that should be fused", us::Any(), false, false, false, mitkCommandLineParser::Input); + parser.addArgument("output", + "o", + mitkCommandLineParser::File, + "Output file path", + "Path to the fused 3D+t image.", + us::Any(), + false, false, false, mitkCommandLineParser::Output); + parser.endGroup(); + + parser.beginGroup("Optional parameters"); + parser.addArgument( + "time", "t", mitkCommandLineParser::StringList, "Time bounds", "Defines the time geometry of the resulting dynamic image in [ms]. The first number is the start time point of the first time step. All other numbers are the max bound of a time step. So the structure is [minBound0 maxBound1 [maxBound2 [... maxBoundN]]]; e.g. \"2 3.5 10\" encodes a time geometry with two time steps and that starts at 2 ms and the second time step starts at 3.5 ms and ends at 10 ms. If not set e propertional time geometry with 1 ms duration will be generated!", us::Any(), true, false, false, mitkCommandLineParser::Input); + parser.addArgument("help", "h", mitkCommandLineParser::Bool, "Help:", "Show this help text"); + parser.endGroup(); + //! [add arguments] +} + +bool configureApplicationSettings(std::map parsedArgs) +{ + if (parsedArgs.size() == 0) + return false; + + inFilenames = us::any_cast(parsedArgs["inputs"]); + outFileName = us::any_cast(parsedArgs["output"]); + + if (parsedArgs.count("time")) + { + auto timeBoundsStr = us::any_cast(parsedArgs["time"]); + for (const auto& timeBoundStr : timeBoundsStr) + { + std::istringstream stream; + stream.imbue(std::locale("C")); + stream.str(timeBoundStr); + mitk::TimePointType time = 0 ; + stream >> time; + timebounds.emplace_back(time); + } + } + + return true; +} + +int main(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + setupParser(parser); + + mitk::PreferenceListReaderOptionsFunctor readerFilterFunctor = mitk::PreferenceListReaderOptionsFunctor({ "MITK DICOM Reader v2 (classic config)" }, { "MITK DICOM Reader" }); + + const std::map& parsedArgs = parser.parseArguments(argc, argv); + if (!configureApplicationSettings(parsedArgs)) + { + return EXIT_FAILURE; + }; + + // Show a help message + if (parsedArgs.count("help") || parsedArgs.count("h")) + { + std::cout << parser.helpText(); + return EXIT_SUCCESS; + } + + if (timebounds.empty()) + { + timebounds.resize(inFilenames.size()+1); + std::iota(timebounds.begin(), timebounds.end(), 0.0); + } + else if (inFilenames.size() + 1 != timebounds.size()) + { + std::cerr << "Cannot fuse images. Explicitly specified time bounds do not match. Use --help for more information on how to specify time bounds correctly."; + return EXIT_FAILURE; + }; + + //! [do processing] + try + { + std::cout << "Load images:" << std::endl; + + auto filter = mitk::TemporalJoinImagesFilter::New(); + + unsigned int step = 0; + for (auto path : inFilenames) + { + std::cout << "Time step #"<(path, &readerFilterFunctor); + images.push_back(image); + filter->SetInput(step, image); + ++step; + } + + filter->SetFirstMinTimeBound(timebounds[0]); + filter->SetMaxTimeBounds({ timebounds.begin() + 1, timebounds.end() }); + + std::cout << "Fuse the images ..." << std::endl; + + filter->Update(); + auto output = filter->GetOutput(); + + std::cout << "Save output image: " << outFileName << std::endl; + + mitk::IOUtil::Save(output, outFileName); + + std::cout << "Processing finished." << std::endl; + + return EXIT_SUCCESS; + } + catch (const std::exception& e) + { + MITK_ERROR << e.what(); + return EXIT_FAILURE; + } + catch (...) + { + MITK_ERROR << "Unexpected error encountered."; + return EXIT_FAILURE; + } +}