diff --git a/Modules/DiffusionImaging/DiffusionCore/Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.cpp b/Modules/DiffusionImaging/DiffusionCore/Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.cpp index d55b2ca14a..1c661d6a62 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.cpp @@ -1,290 +1,311 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKDIFFUSIONIMAGETODIFFUSIONIMAGEFILTER_CPP #define MITKDIFFUSIONIMAGETODIFFUSIONIMAGEFILTER_CPP #include "mitkDWIHeadMotionCorrectionFilter.h" #include "itkSplitDWImageFilter.h" #include "itkB0ImageExtractionToSeparateImageFilter.h" #include "mitkImageTimeSelector.h" #include "mitkPyramidImageRegistrationMethod.h" #include "mitkImageToDiffusionImageSource.h" #include "mitkDiffusionImageCorrectionFilter.h" - - #include #include "mitkIOUtil.h" #include template< typename DiffusionPixelType> mitk::DWIHeadMotionCorrectionFilter -::DWIHeadMotionCorrectionFilter() + ::DWIHeadMotionCorrectionFilter(): +m_CurrentStep(0), + m_Steps(100), + m_IsInValidState(true), + m_AbortRegistration(false) { } template< typename DiffusionPixelType> void mitk::DWIHeadMotionCorrectionFilter -::GenerateData() + ::GenerateData() { typedef itk::SplitDWImageFilter< DiffusionPixelType, DiffusionPixelType> SplitFilterType; DiffusionImageType* input = const_cast(this->GetInput(0)); + unsigned int numberOfSteps = input->GetVectorImage()->GetNumberOfComponentsPerPixel () ; + m_Steps = numberOfSteps; // // (1) Extract the b-zero images to a 3d+t image, register them by NCorr metric and // rigid registration : they will then be used are reference image for registering // the gradient images // typedef itk::B0ImageExtractionToSeparateImageFilter< DiffusionPixelType, DiffusionPixelType> B0ExtractorType; typename B0ExtractorType::Pointer b0_extractor = B0ExtractorType::New(); b0_extractor->SetInput( input->GetVectorImage() ); b0_extractor->SetDirections( input->GetDirections() ); b0_extractor->Update(); mitk::Image::Pointer b0Image = mitk::Image::New(); b0Image->InitializeByItk( b0_extractor->GetOutput() ); b0Image->SetImportChannel( b0_extractor->GetOutput()->GetBufferPointer(), - mitk::Image::CopyMemory ); + mitk::Image::CopyMemory ); // (2.1) Use the extractor to access the extracted b0 volumes mitk::ImageTimeSelector::Pointer t_selector = - mitk::ImageTimeSelector::New(); + mitk::ImageTimeSelector::New(); t_selector->SetInput( b0Image ); t_selector->SetTimeNr(0); t_selector->Update(); // first unweighted image as reference space for the registration mitk::Image::Pointer b0referenceImage = t_selector->GetOutput(); mitk::PyramidImageRegistrationMethod::Pointer registrationMethod = mitk::PyramidImageRegistrationMethod::New(); registrationMethod->SetFixedImage( b0referenceImage ); registrationMethod->SetTransformToRigid(); // the unweighted images are of same modality registrationMethod->SetCrossModalityOff(); // use the advanced (windowed sinc) interpolation registrationMethod->SetUseAdvancedInterpolation(true); // Initialize the temporary output image mitk::Image::Pointer registeredB0Image = b0Image->Clone(); const unsigned int numberOfb0Images = b0Image->GetTimeSteps(); if( numberOfb0Images > 1) { - mitk::ImageTimeSelector::Pointer t_selector2 = - mitk::ImageTimeSelector::New(); + mitk::ImageTimeSelector::New(); t_selector2->SetInput( b0Image ); for( unsigned int i=1; iSetTimeNr(i); t_selector2->Update(); registrationMethod->SetMovingImage( t_selector2->GetOutput() ); try { MITK_INFO << " === (" << i <<"/"<< numberOfb0Images-1 << ") :: Starting registration"; registrationMethod->Update(); } catch( const itk::ExceptionObject& e) { + m_IsInValidState = false; mitkThrow() << "Failed to register the b0 images, the PyramidRegistration threw an exception: \n" << e.what(); } // import volume to the inter-results registeredB0Image->SetImportVolume( registrationMethod->GetResampledMovingImage()->GetData(), - i, 0, mitk::Image::ReferenceMemory ); + i, 0, mitk::Image::ReferenceMemory ); } // use the accumulateImageFilter as provided by the ItkAccumulateFilter method in the header file AccessFixedDimensionByItk_1(registeredB0Image, ItkAccumulateFilter, (4), b0referenceImage ); } // // (2) Split the diffusion image into a 3d+t regular image, extract only the weighted images // typename SplitFilterType::Pointer split_filter = SplitFilterType::New(); split_filter->SetInput (input->GetVectorImage() ); split_filter->SetExtractAllAboveThreshold(20, input->GetB_ValueMap() ); try { split_filter->Update(); } catch( const itk::ExceptionObject &e) { + m_IsInValidState = false; mitkThrow() << " Caught exception from SplitImageFilter : " << e.what(); } mitk::Image::Pointer splittedImage = mitk::Image::New(); splittedImage->InitializeByItk( split_filter->GetOutput() ); splittedImage->SetImportChannel( split_filter->GetOutput()->GetBufferPointer(), - mitk::Image::CopyMemory ); + mitk::Image::CopyMemory ); // // (3) Use again the time-selector to access the components separately in order // to perform the registration of Image -> unweighted reference // mitk::PyramidImageRegistrationMethod::Pointer weightedRegistrationMethod - = mitk::PyramidImageRegistrationMethod::New(); + = mitk::PyramidImageRegistrationMethod::New(); weightedRegistrationMethod->SetTransformToAffine(); weightedRegistrationMethod->SetCrossModalityOn(); // // - (3.1) Set the reference image // - a single b0 image // - average over the registered b0 images if multiple present // weightedRegistrationMethod->SetFixedImage( b0referenceImage ); // use the advanced (windowed sinc) interpolation weightedRegistrationMethod->SetUseAdvancedInterpolation(true); // // - (3.2) Register all timesteps in the splitted image onto the first reference // unsigned int maxImageIdx = splittedImage->GetTimeSteps(); mitk::TimeSlicedGeometry* tsg = splittedImage->GetTimeSlicedGeometry(); tsg->ExpandToNumberOfTimeSteps( maxImageIdx+1 ); mitk::Image::Pointer registeredWeighted = mitk::Image::New(); registeredWeighted->Initialize( splittedImage->GetPixelType(0), *tsg ); // insert the first unweighted reference as the first volume registeredWeighted->SetImportVolume( b0referenceImage->GetData(), - 0,0, mitk::Image::CopyMemory ); + 0,0, mitk::Image::CopyMemory ); // mitk::Image::Pointer registeredWeighted = splittedImage->Clone(); // this time start at 0, we have only gradient images in the 3d+t file // the reference image comes form an other image mitk::ImageTimeSelector::Pointer t_selector_w = - mitk::ImageTimeSelector::New(); + mitk::ImageTimeSelector::New(); t_selector_w->SetInput( splittedImage ); // store the rotation parts of the transformations in a vector typedef mitk::PyramidImageRegistrationMethod::TransformMatrixType MatrixType; std::vector< MatrixType > estimated_transforms; + for( unsigned int i=0; iSetTimeNr(i); t_selector_w->Update(); weightedRegistrationMethod->SetMovingImage( t_selector_w->GetOutput() ); try { MITK_INFO << " === (" << i+1 <<"/"<< maxImageIdx << ") :: Starting registration"; weightedRegistrationMethod->Update(); } catch( const itk::ExceptionObject& e) { + m_IsInValidState = false; mitkThrow() << "Failed to register the b0 images, the PyramidRegistration threw an exception: \n" << e.what(); } // allow expansion registeredWeighted->SetImportVolume( weightedRegistrationMethod->GetResampledMovingImage()->GetData(), - i+1, 0, mitk::Image::CopyMemory); + i+1, 0, mitk::Image::CopyMemory); estimated_transforms.push_back( weightedRegistrationMethod->GetLastRotationMatrix() ); } // // (4) Cast the resulting image back to an diffusion weighted image // typename DiffusionImageType::GradientDirectionContainerType *gradients = input->GetDirections(); typename DiffusionImageType::GradientDirectionContainerType::Pointer gradients_new = - DiffusionImageType::GradientDirectionContainerType::New(); + DiffusionImageType::GradientDirectionContainerType::New(); typename DiffusionImageType::GradientDirectionType bzero_vector; bzero_vector.fill(0); // compose the direction vector // - no direction for the first image // - correct ordering of the directions based on the index list gradients_new->push_back( bzero_vector ); typename SplitFilterType::IndexListType index_list = split_filter->GetIndexList(); typename SplitFilterType::IndexListType::const_iterator lIter = index_list.begin(); while( lIter != index_list.end() ) { gradients_new->push_back( gradients->at( *lIter ) ); ++lIter; } typename mitk::ImageToDiffusionImageSource< DiffusionPixelType >::Pointer caster = - mitk::ImageToDiffusionImageSource< DiffusionPixelType >::New(); + mitk::ImageToDiffusionImageSource< DiffusionPixelType >::New(); caster->SetImage( registeredWeighted ); caster->SetBValue( input->GetB_Value() ); caster->SetGradientDirections( gradients_new.GetPointer() ); try { caster->Update(); } catch( const itk::ExceptionObject& e) { + m_IsInValidState = false; MITK_ERROR << "Casting back to diffusion image failed: "; mitkThrow() << "Subprocess failed with exception: " << e.what(); } // // (5) Adapt the gradient directions according to the estimated transforms // typedef mitk::DiffusionImageCorrectionFilter< DiffusionPixelType > CorrectionFilterType; typename CorrectionFilterType::Pointer corrector = CorrectionFilterType::New(); OutputImagePointerType output = caster->GetOutput(); corrector->SetImage( output ); corrector->CorrectDirections( estimated_transforms ); // // (6) Pass the corrected image to the filters output port // + m_CurrentStep += 1; this->GetOutput()->SetVectorImage(output->GetVectorImage()); this->GetOutput()->SetB_Value(output->GetB_Value()); this->GetOutput()->SetDirections(output->GetDirections()); this->GetOutput()->SetMeasurementFrame(output->GetMeasurementFrame()); this->GetOutput()->InitializeFromVectorImage(); this->GetOutput()->Modified(); } -#endif // MITKDIFFUSIONIMAGETODIFFUSIONIMAGEFILTER_CPP +#endif // MITKDIFFUSIONIMAGETODIFFUSIONIMAGEFILTER_CPP \ No newline at end of file diff --git a/Modules/DiffusionImaging/DiffusionCore/Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.h b/Modules/DiffusionImaging/DiffusionCore/Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.h index 196383c65f..69d9bc0ce5 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.h +++ b/Modules/DiffusionImaging/DiffusionCore/Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.h @@ -1,119 +1,129 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKDWIHEADMOTIONCORRECTIONFILTER_H #define MITKDWIHEADMOTIONCORRECTIONFILTER_H #include "mitkDiffusionImageToDiffusionImageFilter.h" #include #include #include "mitkITKImageImport.h" namespace mitk { /** * @class DWIHeadMotionCorrectionFilter * * @brief Performs standard head-motion correction by using affine registration of the gradient images. * * (Head) motion correction is a essential pre-processing step before performing any further analysis of a diffusion-weighted * images since all model fits ( tensor, QBI ) rely on an aligned diffusion-weighted dataset. The correction is done in two steps. First the * unweighted images ( if multiple present ) are separately registered on the first one by means of rigid registration and normalized correlation * as error metric. Second, the weighted gradient images are registered to the unweighted reference ( computed as average from the aligned images from first step ) * by an affine transformation using the MattesMutualInformation metric as optimizer guidance. * */ template< typename DiffusionPixelType> class DWIHeadMotionCorrectionFilter : public DiffusionImageToDiffusionImageFilter< DiffusionPixelType > { public: // class macros mitkClassMacro( DWIHeadMotionCorrectionFilter, DiffusionImageToDiffusionImageFilter ) itkNewMacro(Self) + itkGetMacro( Steps, unsigned long ) + itkGetMacro( CurrentStep, unsigned long ) + itkGetMacro( IsInValidState, bool) + itkSetMacro( AbortRegistration, bool ) + // public typedefs typedef typename Superclass::InputImageType DiffusionImageType; typedef typename Superclass::InputImagePointerType DiffusionImagePointerType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImagePointerType OutputImagePointerType; protected: DWIHeadMotionCorrectionFilter(); virtual ~DWIHeadMotionCorrectionFilter() {} virtual void GenerateData(); + unsigned long m_Steps; + unsigned long m_CurrentStep; + bool m_IsInValidState; ///< Whether the filter is in a valid state, false if error occured + bool m_AbortRegistration; ///< set flag to abort + /** * @brief Averages an 3d+t image along the time axis. * * The method uses the AccumulateImageFilter as provided by ITK and collapses the given 3d+t image * to an 3d image while computing the average over the time axis for each of the spatial voxels. */ template< typename TPixel, unsigned int VDimensions> static void ItkAccumulateFilter( const itk::Image< TPixel, VDimensions>* image, mitk::Image::Pointer& output) { // input 3d+t --> output 3d typedef itk::Image< TPixel, 4> InputItkType; typedef itk::Image< TPixel, 3> OutputItkType; // the accumulate filter requires the same dimension in output and input image typedef typename itk::AccumulateImageFilter< InputItkType, InputItkType > FilterType; typename FilterType::Pointer filter = FilterType::New(); filter->SetInput( image ); filter->SetAccumulateDimension( 3 ); filter->SetAverage( true ); // we need to extract the volume to reduce the size from 4 to 3 for further processing typedef typename itk::ExtractImageFilter< InputItkType, OutputItkType > ExtractFilterType; typename ExtractFilterType::Pointer extractor = ExtractFilterType::New(); extractor->SetInput( filter->GetOutput() ); extractor->SetDirectionCollapseToIdentity(); typename InputItkType::RegionType extractRegion = image->GetLargestPossibleRegion(); // crop out the time axis extractRegion.SetSize( 3, 0); extractor->SetExtractionRegion( extractRegion ); try { extractor->Update(); } catch( const itk::ExceptionObject& e) { mitkThrow() << " Exception while averaging: " << e.what(); } output = mitk::GrabItkImageMemory( extractor->GetOutput() ); } }; } //end namespace mitk #include "mitkDWIHeadMotionCorrectionFilter.cpp" #endif // MITKDWIHEADMOTIONCORRECTIONFILTER_H diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake index 0c3fa25393..4778152042 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake @@ -1,173 +1,178 @@ set(SRC_CPP_FILES QmitkODFDetailsWidget.cpp QmitkODFRenderWidget.cpp QmitkPartialVolumeAnalysisWidget.cpp QmitkIVIMWidget.cpp QmitkTbssRoiAnalysisWidget.cpp QmitkResidualAnalysisWidget.cpp QmitkResidualViewWidget.cpp QmitkTensorModelParametersWidget.cpp QmitkZeppelinModelParametersWidget.cpp QmitkStickModelParametersWidget.cpp QmitkDotModelParametersWidget.cpp QmitkBallModelParametersWidget.cpp QmitkAstrosticksModelParametersWidget.cpp ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkQBallReconstructionView.cpp QmitkPreprocessingView.cpp QmitkDiffusionDicomImportView.cpp QmitkDiffusionQuantificationView.cpp QmitkTensorReconstructionView.cpp QmitkDiffusionImagingPublicPerspective.cpp QmitkControlVisualizationPropertiesView.cpp QmitkODFDetailsView.cpp QmitkGibbsTrackingView.cpp QmitkStochasticFiberTrackingView.cpp QmitkStreamlineTrackingView.cpp QmitkFiberProcessingView.cpp # QmitkFiberBundleDeveloperView.cpp QmitkPartialVolumeAnalysisView.cpp QmitkIVIMView.cpp QmitkTractbasedSpatialStatisticsView.cpp QmitkTbssTableModel.cpp QmitkTbssMetaTableModel.cpp QmitkTbssSkeletonizationView.cpp Connectomics/QmitkConnectomicsDataView.cpp Connectomics/QmitkConnectomicsNetworkOperationsView.cpp Connectomics/QmitkConnectomicsStatisticsView.cpp Connectomics/QmitkNetworkHistogramCanvas.cpp QmitkDwiSoftwarePhantomView.cpp QmitkOdfMaximaExtractionView.cpp QmitkFiberfoxView.cpp QmitkFiberExtractionView.cpp QmitkFieldmapGeneratorView.cpp + QmitkDiffusionRegistrationView.cpp ) set(UI_FILES src/internal/QmitkQBallReconstructionViewControls.ui src/internal/QmitkPreprocessingViewControls.ui src/internal/QmitkDiffusionDicomImportViewControls.ui src/internal/QmitkDiffusionQuantificationViewControls.ui src/internal/QmitkTensorReconstructionViewControls.ui src/internal/QmitkControlVisualizationPropertiesViewControls.ui src/internal/QmitkODFDetailsViewControls.ui src/internal/QmitkGibbsTrackingViewControls.ui src/internal/QmitkStochasticFiberTrackingViewControls.ui src/internal/QmitkStreamlineTrackingViewControls.ui src/internal/QmitkFiberProcessingViewControls.ui # src/internal/QmitkFiberBundleDeveloperViewControls.ui src/internal/QmitkPartialVolumeAnalysisViewControls.ui src/internal/QmitkIVIMViewControls.ui src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui src/internal/QmitkTbssSkeletonizationViewControls.ui src/internal/Connectomics/QmitkConnectomicsDataViewControls.ui src/internal/Connectomics/QmitkConnectomicsNetworkOperationsViewControls.ui src/internal/Connectomics/QmitkConnectomicsStatisticsViewControls.ui src/internal/QmitkDwiSoftwarePhantomViewControls.ui src/internal/QmitkOdfMaximaExtractionViewControls.ui src/internal/QmitkFiberfoxViewControls.ui src/internal/QmitkFiberExtractionViewControls.ui src/QmitkTensorModelParametersWidgetControls.ui src/QmitkZeppelinModelParametersWidgetControls.ui src/QmitkStickModelParametersWidgetControls.ui src/QmitkDotModelParametersWidgetControls.ui src/QmitkBallModelParametersWidgetControls.ui src/QmitkAstrosticksModelParametersWidgetControls.ui src/internal/QmitkFieldmapGeneratorViewControls.ui + src/internal/QmitkDiffusionRegistrationViewControls.ui + ) set(MOC_H_FILES src/internal/mitkPluginActivator.h src/internal/QmitkQBallReconstructionView.h src/internal/QmitkPreprocessingView.h src/internal/QmitkDiffusionDicomImportView.h src/internal/QmitkDiffusionImagingPublicPerspective.h src/internal/QmitkDiffusionQuantificationView.h src/internal/QmitkTensorReconstructionView.h src/internal/QmitkControlVisualizationPropertiesView.h src/internal/QmitkODFDetailsView.h src/QmitkODFRenderWidget.h src/QmitkODFDetailsWidget.h src/internal/QmitkGibbsTrackingView.h src/internal/QmitkStochasticFiberTrackingView.h src/internal/QmitkStreamlineTrackingView.h src/internal/QmitkFiberProcessingView.h # src/internal/QmitkFiberBundleDeveloperView.h src/internal/QmitkPartialVolumeAnalysisView.h src/QmitkPartialVolumeAnalysisWidget.h src/internal/QmitkIVIMView.h src/internal/QmitkTractbasedSpatialStatisticsView.h src/internal/QmitkTbssSkeletonizationView.h src/QmitkTbssRoiAnalysisWidget.h src/QmitkResidualAnalysisWidget.h src/QmitkResidualViewWidget.h src/internal/Connectomics/QmitkConnectomicsDataView.h src/internal/Connectomics/QmitkConnectomicsNetworkOperationsView.h src/internal/Connectomics/QmitkConnectomicsStatisticsView.h src/internal/Connectomics/QmitkNetworkHistogramCanvas.h src/internal/QmitkDwiSoftwarePhantomView.h src/internal/QmitkOdfMaximaExtractionView.h src/internal/QmitkFiberfoxView.h src/internal/QmitkFiberExtractionView.h src/QmitkTensorModelParametersWidget.h src/QmitkZeppelinModelParametersWidget.h src/QmitkStickModelParametersWidget.h src/QmitkDotModelParametersWidget.h src/QmitkBallModelParametersWidget.h src/QmitkAstrosticksModelParametersWidget.h src/internal/QmitkFieldmapGeneratorView.h + src/internal/QmitkDiffusionRegistrationView.h ) set(CACHED_RESOURCE_FILES # list of resource files which can be used by the plug-in # system without loading the plug-ins shared library, # for example the icon used in the menu and tabs for the # plug-in views in the workbench plugin.xml resources/preprocessing.png resources/dwiimport.png resources/quantification.png resources/reconodf.png resources/recontensor.png resources/vizControls.png resources/OdfDetails.png resources/GibbsTracking.png resources/FiberBundleOperations.png resources/PartialVolumeAnalysis_24.png resources/IVIM_48.png resources/stochFB.png resources/tbss.png resources/connectomics/QmitkConnectomicsDataViewIcon_48.png resources/connectomics/QmitkConnectomicsNetworkOperationsViewIcon_48.png resources/connectomics/QmitkConnectomicsStatisticsViewIcon_48.png resources/arrow.png resources/qball_peaks.png resources/phantom.png resources/tensor.png resources/qball.png resources/StreamlineTracking.png resources/dwi2.png resources/odf.png resources/refresh.xpm -) + resources/diffusionregistration.png + ) set(QRC_FILES # uncomment the following line if you want to use Qt resources resources/QmitkDiffusionImaging.qrc #resources/QmitkTractbasedSpatialStatisticsView.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.diffusionimaging/plugin.xml b/Plugins/org.mitk.gui.qt.diffusionimaging/plugin.xml index 7e20b5b89c..38c63b5d05 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/plugin.xml +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/plugin.xml @@ -1,176 +1,181 @@ - + + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/resources/diffusionregistration.png b/Plugins/org.mitk.gui.qt.diffusionimaging/resources/diffusionregistration.png new file mode 100644 index 0000000000..968fa2b167 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.diffusionimaging/resources/diffusionregistration.png differ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionRegistrationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionRegistrationView.cpp new file mode 100644 index 0000000000..2b97833cb6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionRegistrationView.cpp @@ -0,0 +1,342 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +//misc +#define _USE_MATH_DEFINES +#include + +// Blueberry +#include +#include + +// Qmitk +#include "QmitkDiffusionRegistrationView.h" +#include + +// MITK +#include +#include +#include +#include +#include + +// Qt +#include +#include +#include + +#include + + +QmitkRegistrationWorker::QmitkRegistrationWorker(QmitkDiffusionRegistrationView* view) + : m_View(view) +{ + +} + +void QmitkRegistrationWorker::run() +{ + + typedef mitk::DiffusionImage DiffusionImageType; + typedef DiffusionImageType::BValueMap BValueMap; + + for( int i=0; i< m_View->m_SelectedDiffusionNodes.size(); i++) + { + m_View->m_GlobalRegisterer = QmitkDiffusionRegistrationView::DWIHeadMotionCorrectionFilterType::New(); + + mitk::DataNode::Pointer node = m_View->m_SelectedDiffusionNodes.at(i); + DiffusionImageType::Pointer inImage = dynamic_cast*>(node->GetData()); + if(inImage.IsNull()) + { + MITK_ERROR << "Error occured: can't get input image. \nAborting"; + return; + } + + + m_View->m_GlobalRegisterer->SetInput(inImage); + + try{ + m_View->m_GlobalRegisterer->Update(); + } + catch( mitk::Exception e ) + { + MITK_ERROR << "Internal error occured: " << e.what() << "\nAborting"; + } + + if( m_View->m_GlobalRegisterer->GetIsInValidState() ) + { + DiffusionImageType::Pointer image = m_View->m_GlobalRegisterer->GetOutput(); + mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); + imageNode->SetData( image ); + QString name = node->GetName().c_str(); + imageNode->SetName((name+"_MC").toStdString().c_str()); + m_View->GetDataStorage()->Add(imageNode); + } + + + } + + + m_View->m_RegistrationThread.quit(); +} + + +const std::string QmitkDiffusionRegistrationView::VIEW_ID = "org.mitk.views.diffusionregistrationview"; + +QmitkDiffusionRegistrationView::QmitkDiffusionRegistrationView() + : QmitkAbstractView() + , m_Controls( 0 ) + , m_DiffusionImage( NULL ) + + , m_ThreadIsRunning(false) + , m_GlobalRegisterer(NULL) + , m_RegistrationWorker(this) + , m_Steps(100) + , m_LastStep(0) + +{ + + m_RegistrationWorker.moveToThread(&m_RegistrationThread); + connect(&m_RegistrationThread, SIGNAL(started()), this, SLOT(BeforeThread())); + connect(&m_RegistrationThread, SIGNAL(started()), &m_RegistrationWorker, SLOT(run())); + connect(&m_RegistrationThread, SIGNAL(finished()), this, SLOT(AfterThread())); + connect(&m_RegistrationThread, SIGNAL(terminated()), this, SLOT(AfterThread())); + m_RegistrationTimer = new QTimer(this); + +} + +// Destructor +QmitkDiffusionRegistrationView::~QmitkDiffusionRegistrationView() +{ + delete m_RegistrationTimer; +} + +// update Registration status and generate fiber bundle +void QmitkDiffusionRegistrationView::TimerUpdate() +{ + int currentStep = m_GlobalRegisterer->GetCurrentStep(); + + mitk::ProgressBar::GetInstance()->Progress(currentStep-m_LastStep); + UpdateRegistrationStatus(); + + m_LastStep = currentStep; +} + +// update gui elements after registration is finished +void QmitkDiffusionRegistrationView::AfterThread() +{ + + m_ThreadIsRunning = false; + m_RegistrationTimer->stop(); + + mitk::ProgressBar::GetInstance()->Progress(m_GlobalRegisterer->GetSteps()-m_LastStep+1); + UpdateGUI(); + + + if( !m_GlobalRegisterer->GetIsInValidState() ) + { + QMessageBox::critical( NULL, "Registration", "An internal error occured, or user canceled the Registration.\n Please check the log for details." ); + return; + } + + UpdateRegistrationStatus(); + + + m_GlobalRegisterer = 0; + +} + +// start Registration timer and update gui elements before Registration is started +void QmitkDiffusionRegistrationView::BeforeThread() +{ + m_ThreadIsRunning = true; + m_RegistrationTime = QTime::currentTime(); + m_ElapsedTime = 0; + m_RegistrationTimer->start(1000); + m_LastStep = 0; + + UpdateGUI(); +} + + +void QmitkDiffusionRegistrationView::CreateQtPartControl( QWidget *parent ) +{ + // build up qt view, unless already done + if ( !m_Controls ) + { + // create GUI widgets from the Qt Designer's .ui file + m_Controls = new Ui::QmitkDiffusionRegistrationViewControls; + m_Controls->setupUi( parent ); + + AdvancedSettings(); + + connect( m_RegistrationTimer, SIGNAL(timeout()), this, SLOT(TimerUpdate()) ); + connect( m_Controls->m_RegistrationStopButton, SIGNAL(clicked()), this, SLOT(StopRegistration()) ); + connect( m_Controls->m_RegistrationStartButton, SIGNAL(clicked()), this, SLOT(StartRegistration()) ); + connect( m_Controls->m_AdvancedSettingsCheckbox, SIGNAL(clicked()), this, SLOT(AdvancedSettings()) ); + + } +} + +// show/hide advanced settings frame +void QmitkDiffusionRegistrationView::AdvancedSettings() +{ + //m_Controls->m_AdvancedFrame->setVisible(m_Controls->m_AdvancedSettingsCheckbox->isChecked()); + m_Controls->m_AdvancedFrame->setVisible(false); + m_Controls->m_AdvancedSettingsCheckbox->setVisible(false); +} + + +void QmitkDiffusionRegistrationView::OnSelectionChanged( berry::IWorkbenchPart::Pointer, const QList& nodes ) +{ + + if (m_ThreadIsRunning) + return; + + bool foundDwiVolume = false; + QString tempSelectedNames = ""; + m_DiffusionImage = NULL; + m_SelectedDiffusionNodes.clear(); + + // iterate selection + for( int i=0; i*>(node->GetData()) ) + { + foundDwiVolume = true; + m_SelectedDiffusionNodes.push_back(node); + + if(m_SelectedDiffusionNodes.size() > 0){tempSelectedNames += "\n";} + tempSelectedNames += (node->GetName().c_str()); + } + + } + + + m_Controls->m_RegistrationStartButton->setEnabled(foundDwiVolume); + + if (foundDwiVolume) + { + m_Controls->m_DiffusionImageLabel->setText(tempSelectedNames); + m_Controls->m_InputData->setTitle("Input Data"); + } + else + { + m_Controls->m_DiffusionImageLabel->setText("mandatory"); + m_Controls->m_InputData->setTitle("Please Select Input Data"); + } + + UpdateGUI(); + +} + + +// update gui elements displaying Registrations status +void QmitkDiffusionRegistrationView::UpdateRegistrationStatus() +{ + if (m_GlobalRegisterer.IsNull()) + return; + + m_ElapsedTime += m_RegistrationTime.elapsed()/1000; + m_RegistrationTime.restart(); + unsigned long hours = m_ElapsedTime/3600; + unsigned long minutes = (m_ElapsedTime%3600)/60; + unsigned long seconds = m_ElapsedTime%60; + + m_Controls->m_RegistrationTimeLabel->setText( QString::number(hours)+QString("h ")+QString::number(minutes)+QString("m ")+QString::number(seconds)+QString("s") ); + m_Controls->m_CurrentStepLabel->setText( QString::number((int)(100*(float)(m_GlobalRegisterer->GetCurrentStep()-1)/m_GlobalRegisterer->GetSteps()))+"%" ); + +} + +void QmitkDiffusionRegistrationView::UpdateGUI() +{ + + if (!m_ThreadIsRunning && (m_SelectedDiffusionNodes.size() > 0) ) + { + m_Controls->m_RegistrationStopButton->setEnabled(false); + m_Controls->m_RegistrationStartButton->setEnabled(true); + m_Controls->m_AdvancedFrame->setEnabled(true); + m_Controls->m_RegistrationStopButton->setText("Stop"); + m_Controls->m_RegistrationStartButton->setToolTip("Start Registration"); + m_Controls->m_RegistrationStopButton->setToolTip(""); + } + else if (!m_ThreadIsRunning) + { + m_Controls->m_RegistrationStopButton->setEnabled(false); + m_Controls->m_RegistrationStartButton->setEnabled(false); + m_Controls->m_AdvancedFrame->setEnabled(true); + m_Controls->m_RegistrationStopButton->setText("Stop"); + m_Controls->m_RegistrationStartButton->setToolTip("No Diffusion image selected."); + m_Controls->m_RegistrationStopButton->setToolTip(""); + } + else + { + m_Controls->m_RegistrationStopButton->setEnabled(true); + m_Controls->m_RegistrationStartButton->setEnabled(false); + m_Controls->m_AdvancedFrame->setEnabled(false); + m_Controls->m_AdvancedFrame->setVisible(false); + m_Controls->m_AdvancedSettingsCheckbox->setChecked(false); + m_Controls->m_RegistrationStartButton->setToolTip("Registration in progress."); + m_Controls->m_RegistrationStopButton->setToolTip("Cancel Registration"); + } + +} + +void QmitkDiffusionRegistrationView::SetFocus() +{ + m_Controls->m_RegistrationStartButton->setFocus(); +} + + +void QmitkDiffusionRegistrationView::StartRegistration() +{ + + if(m_ThreadIsRunning) + { + MITK_WARN("QmitkDiffusionRegistrationView")<<"Thread already running!"; + return; + } + m_GlobalRegisterer = NULL; + + if (m_SelectedDiffusionNodes.size()<1) + { + QMessageBox::information( NULL, "Warning", "Please load and select a diffusion image before starting image processing."); + return; + } + + + m_Controls->m_RegistrationStartButton->setEnabled(false); + + // start worker thread + m_RegistrationThread.start(QThread::NormalPriority); + + return; +} + +void QmitkDiffusionRegistrationView::StopRegistration() +{ + + if (m_GlobalRegisterer.IsNull()) + return; + + m_GlobalRegisterer->SetAbortRegistration(true); + m_Controls->m_RegistrationStopButton->setEnabled(false); + m_Controls->m_RegistrationStopButton->setText("Stopping ..."); + + return; +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionRegistrationView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionRegistrationView.h new file mode 100644 index 0000000000..67dbca81f4 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionRegistrationView.h @@ -0,0 +1,124 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + + +#include +#include + +#include +#include "ui_QmitkDiffusionRegistrationViewControls.h" + +#include "mitkDiffusionImage.h" +#include + +#include +#include + +typedef short DiffusionPixelType; + +/*! +\brief View for diffusion image registration / head motion correction + +\sa QmitkFunctionality +\ingroup Functionalities +*/ + +// Forward Qt class declarations + +using namespace std; + +class QmitkDiffusionRegistrationView; + +class QmitkRegistrationWorker : public QObject +{ + Q_OBJECT + +public: + + QmitkRegistrationWorker(QmitkDiffusionRegistrationView* view); + + public slots: + + void run(); + +private: + + QmitkDiffusionRegistrationView* m_View; +}; + + +class QmitkDiffusionRegistrationView : public QmitkAbstractView +{ + + // this is needed for all Qt objects that should have a Qt meta-object + // (everything that derives from QObject and wants to have signal/slots) + Q_OBJECT + +public: + + static const string VIEW_ID; + + QmitkDiffusionRegistrationView(); + virtual ~QmitkDiffusionRegistrationView(); + + virtual void CreateQtPartControl(QWidget *parent); + void SetFocus(); + + typedef mitk::DWIHeadMotionCorrectionFilter< DiffusionPixelType > DWIHeadMotionCorrectionFilterType; + +protected slots: + + void StartRegistration(); + void StopRegistration(); + + void AfterThread(); ///< update gui etc. after registrations has finished + void BeforeThread(); ///< start timer etc. + void TimerUpdate(); + + void AdvancedSettings(); + + +protected: + + /// \brief called by QmitkFunctionality when DataManager's selection has changed + virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList&); + + Ui::QmitkDiffusionRegistrationViewControls* m_Controls; + + mitk::DiffusionImage::Pointer m_DiffusionImage; + std::vector< mitk::DataNode::Pointer > m_SelectedDiffusionNodes; + +private: + + void UpdateRegistrationStatus(); ///< update textual status display of the Registration process + void UpdateGUI(); ///< update button activity etc. dpending on current datamanager selection + + /** flags etc. */ + bool m_ThreadIsRunning; + QTimer* m_RegistrationTimer; + QTime m_RegistrationTime; + unsigned long m_ElapsedTime; + unsigned long m_Steps; + int m_LastStep; + + /** global Registerer and friends */ + itk::SmartPointer m_GlobalRegisterer; + QmitkRegistrationWorker m_RegistrationWorker; + QThread m_RegistrationThread; + friend class QmitkRegistrationWorker; + +}; diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionRegistrationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionRegistrationViewControls.ui new file mode 100644 index 0000000000..b7489b33c7 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionRegistrationViewControls.ui @@ -0,0 +1,226 @@ + + + QmitkDiffusionRegistrationViewControls + + + + 0 + 0 + 435 + 744 + + + + Form + + + + + + + 0 + 0 + + + + DWI Head Motion Correction + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + false + + + Start DWI registration/Head Motion Correction + + + Start Head Motion Correction + + + + + + + Please Select Input Data + + + + + + Diffusion Image + + + + + + + <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> + + + true + + + + + + + + + + Monitor + + + + + + + + + + + + + + + Process Time: + + + + + + + + + + + + + + + + Progress: + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + - + + + + + + + + + + false + + + + + + Qt::LeftToRight + + + Stop + + + + :/qmitk/stop.xpm:/qmitk/stop.xpm + + + + + + + true + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 9 + + + 0 + + + 9 + + + 0 + + + 4 + + + + + Advanced settings + + + + + + + + + + Advanced Settings + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp index df007f0f3d..9c69c931d3 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp @@ -1,85 +1,87 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPluginActivator.h" #include #include "src/internal/QmitkDiffusionImagingPublicPerspective.h" #include "src/internal/QmitkQBallReconstructionView.h" #include "src/internal/QmitkPreprocessingView.h" #include "src/internal/QmitkDiffusionDicomImportView.h" #include "src/internal/QmitkDiffusionQuantificationView.h" #include "src/internal/QmitkTensorReconstructionView.h" #include "src/internal/QmitkControlVisualizationPropertiesView.h" #include "src/internal/QmitkODFDetailsView.h" #include "src/internal/QmitkGibbsTrackingView.h" #include "src/internal/QmitkStochasticFiberTrackingView.h" #include "src/internal/QmitkFiberProcessingView.h" //#include "src/internal/QmitkFiberBundleDeveloperView.h" #include "src/internal/QmitkPartialVolumeAnalysisView.h" #include "src/internal/QmitkIVIMView.h" #include "src/internal/QmitkTractbasedSpatialStatisticsView.h" #include "src/internal/QmitkTbssSkeletonizationView.h" #include "src/internal/QmitkStreamlineTrackingView.h" #include "src/internal/Connectomics/QmitkConnectomicsDataView.h" #include "src/internal/Connectomics/QmitkConnectomicsNetworkOperationsView.h" #include "src/internal/Connectomics/QmitkConnectomicsStatisticsView.h" #include "src/internal/QmitkOdfMaximaExtractionView.h" #include "src/internal/QmitkFiberfoxView.h" #include "src/internal/QmitkFiberExtractionView.h" #include "src/internal/QmitkFieldmapGeneratorView.h" +#include "src/internal/QmitkDiffusionRegistrationView.h" namespace mitk { void PluginActivator::start(ctkPluginContext* context) { BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionImagingPublicPerspective, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkQBallReconstructionView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkPreprocessingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionDicomImport, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionQuantificationView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkTensorReconstructionView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkControlVisualizationPropertiesView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkODFDetailsView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkGibbsTrackingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkStochasticFiberTrackingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkFiberProcessingView, context) // BERRY_REGISTER_EXTENSION_CLASS(QmitkFiberBundleDeveloperView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkPartialVolumeAnalysisView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkIVIMView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkTractbasedSpatialStatisticsView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkTbssSkeletonizationView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConnectomicsDataView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConnectomicsNetworkOperationsView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConnectomicsStatisticsView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkStreamlineTrackingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkOdfMaximaExtractionView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkFiberfoxView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkFiberExtractionView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkFieldmapGeneratorView, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionRegistrationView, context) } void PluginActivator::stop(ctkPluginContext* context) { Q_UNUSED(context) } } Q_EXPORT_PLUGIN2(org_mitk_gui_qt_diffusionimaging, mitk::PluginActivator)