diff --git a/Modules/MitkExt/Algorithms/mitkExtractDirectedPlaneImageFilter.cpp.orig b/Modules/MitkExt/Algorithms/mitkExtractDirectedPlaneImageFilter.cpp.orig deleted file mode 100644 index fdc10a7bf1..0000000000 --- a/Modules/MitkExt/Algorithms/mitkExtractDirectedPlaneImageFilter.cpp.orig +++ /dev/null @@ -1,504 +0,0 @@ -/*========================================================================= - -Program: Medical Imaging & Interaction Toolkit -Language: C++ -Date: $Date$ -Version: $Revision: $ - -Copyright (c) German Cancer Research Center, Division of Medical and -Biological Informatics. All rights reserved. -See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. - -This software is distributed WITHOUT ANY WARRANTY; without even -the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -PURPOSE. See the above copyright notices for more information. - -=========================================================================*/ - - -#include "mitkExtractDirectedPlaneImageFilter.h" -#include "mitkAbstractTransformGeometry.h" - -#include -#include -#include -#include -#include - -#include "pic2vtk.h" -#include "picimage.h" - - - -mitk::ExtractDirectedPlaneImageFilter::ExtractDirectedPlaneImageFilter() -: m_WorldGeometry(NULL) -{ - m_Reslicer = vtkImageReslice::New(); - m_TargetTimestep = 0; - m_InPlaneResampleExtentByGeometry = false; -} - -mitk::ExtractDirectedPlaneImageFilter::~ExtractDirectedPlaneImageFilter() -{ - m_WorldGeometry = NULL; - m_Reslicer->Delete(); -} - -void mitk::ExtractDirectedPlaneImageFilter::GenerateData() -{ - // A world geometry must be set... - if ( m_WorldGeometry == NULL ) - { - itkWarningMacro(<<"No world geometry has been set. Returning."); - return; - } - - Image *input = const_cast< ImageToImageFilter::InputImageType* >( this->GetInput() ); - input->Update(); - - if ( input == NULL ) - { - itkWarningMacro(<<"No input set."); - return; - } - - const TimeSlicedGeometry *inputTimeGeometry = input->GetTimeSlicedGeometry(); - if ( ( inputTimeGeometry == NULL ) - || ( inputTimeGeometry->GetTimeSteps() == 0 ) ) - { - itkWarningMacro(<<"Error reading input image geometry."); - return; - } - - // Get the target timestep; if none is set, use the lowest given. - unsigned int timestep = 0; - if ( ! m_TargetTimestep ) - { - ScalarType time = m_WorldGeometry->GetTimeBounds()[0]; - if ( time > ScalarTypeNumericTraits::NonpositiveMin() ) - { - timestep = inputTimeGeometry->MSToTimeStep( time ); - } - } - else timestep = m_TargetTimestep; - - if ( inputTimeGeometry->IsValidTime( timestep ) == false ) - { - itkWarningMacro(<<"This is not a valid timestep: "<IsVolumeSet( timestep ) ) - { - itkWarningMacro(<<"No volume data existent at given timestep "<GetLargestPossibleRegion(); - requestedRegion.SetIndex( 3, timestep ); - requestedRegion.SetSize( 3, 1 ); - requestedRegion.SetSize( 4, 1 ); - input->SetRequestedRegion( &requestedRegion ); - input->Update(); - - vtkImageData* inputData = input->GetVtkImageData( timestep ); - - if ( inputData == NULL ) - { - itkWarningMacro(<<"Could not extract vtk image data for given timestep"<GetSpacing( spacing ); - - // how big the area is in physical coordinates: widthInMM x heightInMM pixels - mitk::ScalarType widthInMM, heightInMM; - - // where we want to sample - Point3D origin; - Vector3D right, bottom, normal; - Vector3D rightInIndex, bottomInIndex; - - assert( input->GetTimeSlicedGeometry() == inputTimeGeometry ); - - // take transform of input image into account - Geometry3D* inputGeometry = inputTimeGeometry->GetGeometry3D( timestep ); - if ( inputGeometry == NULL ) - { - itkWarningMacro(<<"There is no Geometry3D at given timestep "<( m_WorldGeometry ) != NULL ) - { - const PlaneGeometry *planeGeometry = - static_cast< const PlaneGeometry * >( m_WorldGeometry ); - origin = planeGeometry->GetOrigin(); - right = planeGeometry->GetAxisVector( 0 ); - bottom = planeGeometry->GetAxisVector( 1 ); - normal = planeGeometry->GetNormal(); - - if ( m_InPlaneResampleExtentByGeometry ) - { - // Resampling grid corresponds to the current world geometry. This - // means that the spacing of the output 2D image depends on the - // currently selected world geometry, and *not* on the image itself. - - extent[0] = m_WorldGeometry->GetExtent( 0 ); - extent[1] = m_WorldGeometry->GetExtent( 1 ); - } - else - { - // Resampling grid corresponds to the input geometry. This means that - // the spacing of the output 2D image is directly derived from the - // associated input image, regardless of the currently selected world - // geometry. - inputGeometry->WorldToIndex( origin, right, rightInIndex ); - inputGeometry->WorldToIndex( origin, bottom, bottomInIndex ); - extent[0] = rightInIndex.GetNorm(); - extent[1] = bottomInIndex.GetNorm(); - } - - // Get the extent of the current world geometry and calculate resampling - // spacing therefrom. - widthInMM = m_WorldGeometry->GetExtentInMM( 0 ); - heightInMM = m_WorldGeometry->GetExtentInMM( 1 ); - - mmPerPixel[0] = widthInMM / extent[0]; - mmPerPixel[1] = heightInMM / extent[1]; - - right.Normalize(); - bottom.Normalize(); - normal.Normalize(); - - //origin += right * ( mmPerPixel[0] * 0.5 ); - //origin += bottom * ( mmPerPixel[1] * 0.5 ); - - //widthInMM -= mmPerPixel[0]; - //heightInMM -= mmPerPixel[1]; - - // Use inverse transform of the input geometry for reslicing the 3D image - m_Reslicer->SetResliceTransform( - inputGeometry->GetVtkTransform()->GetLinearInverse() ); - - // Set background level to TRANSLUCENT (see Geometry2DDataVtkMapper3D) - m_Reslicer->SetBackgroundLevel( -32768 ); - - // Check if a reference geometry does exist (as would usually be the case for - // PlaneGeometry). - // Note: this is currently not strictly required, but could facilitate - // correct plane clipping. - if ( m_WorldGeometry->GetReferenceGeometry() ) - { - // Calculate the actual bounds of the transformed plane clipped by the - // dataset bounding box; this is required for drawing the texture at the - // correct position during 3D mapping. - boundsInitialized = this->CalculateClippedPlaneBounds( - m_WorldGeometry->GetReferenceGeometry(), planeGeometry, bounds ); - } - } - - // Do we have an AbstractTransformGeometry? - else if ( dynamic_cast< const AbstractTransformGeometry * >( m_WorldGeometry ) ) - { - const mitk::AbstractTransformGeometry* abstractGeometry = - dynamic_cast< const AbstractTransformGeometry * >(m_WorldGeometry); - - extent[0] = abstractGeometry->GetParametricExtent(0); - extent[1] = abstractGeometry->GetParametricExtent(1); - - widthInMM = abstractGeometry->GetParametricExtentInMM(0); - heightInMM = abstractGeometry->GetParametricExtentInMM(1); - - mmPerPixel[0] = widthInMM / extent[0]; - mmPerPixel[1] = heightInMM / extent[1]; - - origin = abstractGeometry->GetPlane()->GetOrigin(); - - right = abstractGeometry->GetPlane()->GetAxisVector(0); - right.Normalize(); - - bottom = abstractGeometry->GetPlane()->GetAxisVector(1); - bottom.Normalize(); - - normal = abstractGeometry->GetPlane()->GetNormal(); - normal.Normalize(); - - // Use a combination of the InputGeometry *and* the possible non-rigid - // AbstractTransformGeometry for reslicing the 3D Image - vtkGeneralTransform *composedResliceTransform = vtkGeneralTransform::New(); - composedResliceTransform->Identity(); - composedResliceTransform->Concatenate( - inputGeometry->GetVtkTransform()->GetLinearInverse() ); - composedResliceTransform->Concatenate( - abstractGeometry->GetVtkAbstractTransform() - ); - - m_Reslicer->SetResliceTransform( composedResliceTransform ); - - // Set background level to BLACK instead of translucent, to avoid - // boundary artifacts (see Geometry2DDataVtkMapper3D) - m_Reslicer->SetBackgroundLevel( -1023 ); - composedResliceTransform->Delete(); - } - else - { - itkWarningMacro(<<"World Geometry has to be a PlaneGeometry or an AbstractTransformGeometry."); - return; - } - - // Make sure that the image to be resliced has a certain minimum size. - if ( (extent[0] <= 2) && (extent[1] <= 2) ) - { - itkWarningMacro(<<"Image is too small to be resliced..."); - return; - } - - vtkImageChangeInformation * unitSpacingImageFilter = vtkImageChangeInformation::New() ; - unitSpacingImageFilter->SetOutputSpacing( 1.0, 1.0, 1.0 ); - unitSpacingImageFilter->SetInput( inputData ); - - m_Reslicer->SetInput( unitSpacingImageFilter->GetOutput() ); - unitSpacingImageFilter->Delete(); - - //m_Reslicer->SetInput( inputData ); - - m_Reslicer->SetOutputDimensionality( 2 ); - m_Reslicer->SetOutputOrigin( 0.0, 0.0, 0.0 ); - - Vector2D pixelsPerMM; - pixelsPerMM[0] = 1.0 / mmPerPixel[0]; - pixelsPerMM[1] = 1.0 / mmPerPixel[1]; - - //calulate the originArray and the orientations for the reslice-filter - double originArray[3]; - itk2vtk( origin, originArray ); - - m_Reslicer->SetResliceAxesOrigin( originArray ); - - double cosines[9]; - - // direction of the X-axis of the sampled result - vnl2vtk( right.Get_vnl_vector(), cosines ); - - // direction of the Y-axis of the sampled result - vnl2vtk( bottom.Get_vnl_vector(), cosines + 3 ); - - // normal of the plane - vnl2vtk( normal.Get_vnl_vector(), cosines + 6 ); - - m_Reslicer->SetResliceAxesDirectionCosines( cosines ); - - // Determine output extent for reslicing - ScalarType size[2]; - size[0] = (bounds[1] - bounds[0]) / mmPerPixel[0]; - size[1] = (bounds[3] - bounds[2]) / mmPerPixel[1]; - - int xMin, xMax, yMin, yMax; - if ( boundsInitialized ) - { - xMin = static_cast< int >( bounds[0] / mmPerPixel[0] );//+ 0.5 ); - xMax = static_cast< int >( bounds[1] / mmPerPixel[0] );//+ 0.5 ); - yMin = static_cast< int >( bounds[2] / mmPerPixel[1] );//+ 0.5); - yMax = static_cast< int >( bounds[3] / mmPerPixel[1] );//+ 0.5 ); - } - else - { - // If no reference geometry is available, we also don't know about the - // maximum plane size; so the overlap is just ignored - - xMin = yMin = 0; - xMax = static_cast< int >( extent[0] - pixelsPerMM[0] );//+ 0.5 ); - yMax = static_cast< int >( extent[1] - pixelsPerMM[1] );//+ 0.5 ); - } - - m_Reslicer->SetOutputSpacing( mmPerPixel[0], mmPerPixel[1], 1.0 ); - // xMax and yMax are meant exclusive until now, whereas - // SetOutputExtent wants an inclusive bound. Thus, we need - // to subtract 1. - m_Reslicer->SetOutputExtent( xMin, xMax-1, yMin, yMax-1, 0, 1 ); - - // Do the reslicing. Modified() is called to make sure that the reslicer is - // executed even though the input geometry information did not change; this - // is necessary when the input /em data, but not the /em geometry changes. - m_Reslicer->Modified(); - m_Reslicer->ReleaseDataFlagOn(); - - m_Reslicer->Update(); - - // 1. Check the result - vtkImageData* reslicedImage = m_Reslicer->GetOutput(); - - mitkIpPicDescriptor *pic = Pic2vtk::convert( reslicedImage ); - - if((reslicedImage == NULL) || (reslicedImage->GetDataDimension() < 1)) - { - itkWarningMacro(<<"Reslicer returned empty image"); - return; - } - - unsigned int dimensions[2]; - dimensions[0] = (unsigned int)extent[0]; dimensions[1] = (unsigned int)extent[1]; - Vector3D spacingVector; - FillVector3D(spacingVector, mmPerPixel[0], mmPerPixel[1], 1.0); - - mitk::Image::Pointer resultImage = this->GetOutput(); - resultImage->Initialize( pic ); - resultImage->SetSpacing( spacingVector ); - resultImage->SetPicVolume( pic ); - - mitkIpPicFree(pic); - - /*unsigned int dimensions[2]; - dimensions[0] = (unsigned int)extent[0]; dimensions[1] = (unsigned int)extent[1]; - Vector3D spacingVector; - FillVector3D(spacingVector, mmPerPixel[0], mmPerPixel[1], 1.0); - - mitk::Image::Pointer resultImage = this->GetOutput(); - resultImage->Initialize(m_Reslicer->GetOutput()); - resultImage->Initialize(inputImage->GetPixelType(), 2, dimensions); - resultImage->SetSpacing(spacingVector); - resultImage->SetSlice(m_Reslicer->GetOutput());*/ -} - - -void mitk::ExtractDirectedPlaneImageFilter::GenerateOutputInformation() -{ - Superclass::GenerateOutputInformation(); -} - - -bool mitk::ExtractDirectedPlaneImageFilter -::CalculateClippedPlaneBounds( const Geometry3D *boundingGeometry, - const PlaneGeometry *planeGeometry, vtkFloatingPointType *bounds ) -{ - // Clip the plane with the bounding geometry. To do so, the corner points - // of the bounding box are transformed by the inverse transformation - // matrix, and the transformed bounding box edges derived therefrom are - // clipped with the plane z=0. The resulting min/max values are taken as - // bounds for the image reslicer. - const BoundingBox *boundingBox = boundingGeometry->GetBoundingBox(); - - BoundingBox::PointType bbMin = boundingBox->GetMinimum(); - BoundingBox::PointType bbMax = boundingBox->GetMaximum(); - BoundingBox::PointType bbCenter = boundingBox->GetCenter(); - - vtkPoints *points = vtkPoints::New(); - if(boundingGeometry->GetImageGeometry()) - { - points->InsertPoint( 0, bbMin[0]-0.5, bbMin[1]-0.5, bbMin[2]-0.5 ); - points->InsertPoint( 1, bbMin[0]-0.5, bbMin[1]-0.5, bbMax[2]-0.5 ); - points->InsertPoint( 2, bbMin[0]-0.5, bbMax[1]-0.5, bbMax[2]-0.5 ); - points->InsertPoint( 3, bbMin[0]-0.5, bbMax[1]-0.5, bbMin[2]-0.5 ); - points->InsertPoint( 4, bbMax[0]-0.5, bbMin[1]-0.5, bbMin[2]-0.5 ); - points->InsertPoint( 5, bbMax[0]-0.5, bbMin[1]-0.5, bbMax[2]-0.5 ); - points->InsertPoint( 6, bbMax[0]-0.5, bbMax[1]-0.5, bbMax[2]-0.5 ); - points->InsertPoint( 7, bbMax[0]-0.5, bbMax[1]-0.5, bbMin[2]-0.5 ); - } - else - { - points->InsertPoint( 0, bbMin[0], bbMin[1], bbMin[2] ); - points->InsertPoint( 1, bbMin[0], bbMin[1], bbMax[2] ); - points->InsertPoint( 2, bbMin[0], bbMax[1], bbMax[2] ); - points->InsertPoint( 3, bbMin[0], bbMax[1], bbMin[2] ); - points->InsertPoint( 4, bbMax[0], bbMin[1], bbMin[2] ); - points->InsertPoint( 5, bbMax[0], bbMin[1], bbMax[2] ); - points->InsertPoint( 6, bbMax[0], bbMax[1], bbMax[2] ); - points->InsertPoint( 7, bbMax[0], bbMax[1], bbMin[2] ); - } - - vtkPoints *newPoints = vtkPoints::New(); - - vtkTransform *transform = vtkTransform::New(); - transform->Identity(); - transform->Concatenate( - planeGeometry->GetVtkTransform()->GetLinearInverse() - ); - - transform->Concatenate( boundingGeometry->GetVtkTransform() ); - - transform->TransformPoints( points, newPoints ); - transform->Delete(); - - bounds[0] = bounds[2] = 10000000.0; - bounds[1] = bounds[3] = -10000000.0; - bounds[4] = bounds[5] = 0.0; - - this->LineIntersectZero( newPoints, 0, 1, bounds ); - this->LineIntersectZero( newPoints, 1, 2, bounds ); - this->LineIntersectZero( newPoints, 2, 3, bounds ); - this->LineIntersectZero( newPoints, 3, 0, bounds ); - this->LineIntersectZero( newPoints, 0, 4, bounds ); - this->LineIntersectZero( newPoints, 1, 5, bounds ); - this->LineIntersectZero( newPoints, 2, 6, bounds ); - this->LineIntersectZero( newPoints, 3, 7, bounds ); - this->LineIntersectZero( newPoints, 4, 5, bounds ); - this->LineIntersectZero( newPoints, 5, 6, bounds ); - this->LineIntersectZero( newPoints, 6, 7, bounds ); - this->LineIntersectZero( newPoints, 7, 4, bounds ); - - // clean up vtk data - points->Delete(); - newPoints->Delete(); - - if ( (bounds[0] > 9999999.0) || (bounds[2] > 9999999.0) - || (bounds[1] < -9999999.0) || (bounds[3] < -9999999.0) ) - { - return false; - } - else - { - // The resulting bounds must be adjusted by the plane spacing, since we - // we have so far dealt with index coordinates - const float *planeSpacing = planeGeometry->GetFloatSpacing(); - bounds[0] *= planeSpacing[0]; - bounds[1] *= planeSpacing[0]; - bounds[2] *= planeSpacing[1]; - bounds[3] *= planeSpacing[1]; - bounds[4] *= planeSpacing[2]; - bounds[5] *= planeSpacing[2]; - return true; - } -} - -bool mitk::ExtractDirectedPlaneImageFilter -::LineIntersectZero( vtkPoints *points, int p1, int p2, - vtkFloatingPointType *bounds ) -{ - vtkFloatingPointType point1[3]; - vtkFloatingPointType point2[3]; - points->GetPoint( p1, point1 ); - points->GetPoint( p2, point2 ); - - if ( (point1[2] * point2[2] <= 0.0) && (point1[2] != point2[2]) ) - { - double x, y; - x = ( point1[0] * point2[2] - point1[2] * point2[0] ) / ( point2[2] - point1[2] ); - y = ( point1[1] * point2[2] - point1[2] * point2[1] ) / ( point2[2] - point1[2] ); - - if ( x < bounds[0] ) { bounds[0] = x; } - if ( x > bounds[1] ) { bounds[1] = x; } - if ( y < bounds[2] ) { bounds[2] = y; } - if ( y > bounds[3] ) { bounds[3] = y; } - bounds[4] = bounds[5] = 0.0; - return true; - } - return false; -} diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.cpp index fdcf725c3f..52114cd27b 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.cpp @@ -1,755 +1,737 @@ /*========================================================================= Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "QmitkDiffusionDicomImportView.h" // qt includes #include // itk includes #include "itkTimeProbesCollectorBase.h" #include "itkGDCMSeriesFileNames.h" #include "itksys/SystemTools.hxx" // mitk includes #include "mitkProgressBar.h" #include "mitkStatusBar.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkMemoryUtilities.h" // diffusion module includes #include "mitkDicomDiffusionImageHeaderReader.h" #include "mitkGroupDiffusionHeadersFilter.h" #include "mitkDicomDiffusionImageReader.h" #include "mitkDiffusionImage.h" #include "mitkNrrdDiffusionImageWriter.h" #include "gdcmDirectory.h" #include "gdcmScanner.h" #include "gdcmSorter.h" #include "gdcmIPPSorter.h" #include "gdcmAttribute.h" #include "gdcmVersion.h" #include const std::string QmitkDiffusionDicomImport::VIEW_ID = "org.mitk.views.diffusiondicomimport"; QmitkDiffusionDicomImport::QmitkDiffusionDicomImport(QObject* /*parent*/, const char* /*name*/) : QmitkFunctionality(), m_Controls(NULL), m_MultiWidget(NULL), m_OutputFolderName(""), m_OutputFolderNameSet(false) { } QmitkDiffusionDicomImport::QmitkDiffusionDicomImport(const QmitkDiffusionDicomImport& other) { Q_UNUSED(other) throw std::runtime_error("Copy constructor not implemented"); } QmitkDiffusionDicomImport::~QmitkDiffusionDicomImport() {} void QmitkDiffusionDicomImport::CreateQtPartControl(QWidget *parent) { m_Parent = parent; if (m_Controls == NULL) { m_Controls = new Ui::QmitkDiffusionDicomImportControls; m_Controls->setupUi(parent); this->CreateConnections(); m_Controls->m_DicomLoadRecursiveCheckbox->setChecked(true); m_Controls->m_DicomLoadAverageDuplicatesCheckbox->setChecked(false); m_Controls->m_DicomLoadRecursiveCheckbox->setVisible(false); AverageClicked(); - AdvancedCheckboxClicked(); } } void QmitkDiffusionDicomImport::CreateConnections() { if ( m_Controls ) { connect( m_Controls->m_AddFoldersButton, SIGNAL(clicked()), this, SLOT(DicomLoadAddFolderNames()) ); connect( m_Controls->m_DeleteFoldersButton, SIGNAL(clicked()), this, SLOT(DicomLoadDeleteFolderNames()) ); connect( m_Controls->m_DicomLoadStartLoadButton, SIGNAL(clicked()), this, SLOT(DicomLoadStartLoad()) ); connect( m_Controls->m_DicomLoadAverageDuplicatesCheckbox, SIGNAL(clicked()), this, SLOT(AverageClicked()) ); connect( m_Controls->m_OutputSetButton, SIGNAL(clicked()), this, SLOT(OutputSet()) ); connect( m_Controls->m_OutputClearButton, SIGNAL(clicked()), this, SLOT(OutputClear()) ); - connect( m_Controls->m_Advanced, SIGNAL(clicked()), this, SLOT(AdvancedCheckboxClicked()) ); connect( m_Controls->m_Remove, SIGNAL(clicked()), this, SLOT(Remove()) ); } } void QmitkDiffusionDicomImport::Remove() { int i = m_Controls->listWidget->currentRow(); m_Controls->listWidget->takeItem(i); } -void QmitkDiffusionDicomImport::AdvancedCheckboxClicked() -{ - bool check = m_Controls-> - m_Advanced->isChecked(); - - m_Controls->m_AdvancedFrame->setVisible(check); -} - void QmitkDiffusionDicomImport::OutputSet() { // SELECT FOLDER DIALOG QFileDialog* w = new QFileDialog( m_Parent, QString("Select folders containing DWI data") ); w->setFileMode( QFileDialog::Directory ); // RETRIEVE SELECTION if ( w->exec() != QDialog::Accepted ) return; m_OutputFolderName = w->selectedFiles()[0]; m_OutputFolderNameSet = true; m_Controls->m_OutputLabel->setText(m_OutputFolderName); } void QmitkDiffusionDicomImport::OutputClear() { m_OutputFolderName = ""; m_OutputFolderNameSet = false; m_Controls->m_OutputLabel->setText("... optional out-folder ..."); } void QmitkDiffusionDicomImport::AverageClicked() { m_Controls->m_Blur->setEnabled(m_Controls->m_DicomLoadAverageDuplicatesCheckbox->isChecked()); } void QmitkDiffusionDicomImport::Activated() { QmitkFunctionality::Activated(); } void QmitkDiffusionDicomImport::DicomLoadDeleteFolderNames() { m_Controls->listWidget->clear(); } void QmitkDiffusionDicomImport::DicomLoadAddFolderNames() { // SELECT FOLDER DIALOG QFileDialog* w = new QFileDialog( m_Parent, QString("Select folders containing DWI data") ); w->setFileMode( QFileDialog::Directory ); // RETRIEVE SELECTION if ( w->exec() != QDialog::Accepted ) return; m_Controls->listWidget->addItems(w->selectedFiles()); } bool SortBySeriesUID(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) { gdcm::Attribute<0x0020,0x000e> at1; at1.Set( ds1 ); gdcm::Attribute<0x0020,0x000e> at2; at2.Set( ds2 ); return at1 < at2; } bool SortByAcquisitionNumber(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) { gdcm::Attribute<0x0020,0x0012> at1; at1.Set( ds1 ); gdcm::Attribute<0x0020,0x0012> at2; at2.Set( ds2 ); return at1 < at2; } bool SortBySeqName(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) { gdcm::Attribute<0x0018, 0x0024> at1; at1.Set( ds1 ); gdcm::Attribute<0x0018, 0x0024> at2; at2.Set( ds2 ); std::string str1 = at1.GetValue().Trim(); std::string str2 = at2.GetValue().Trim(); return std::lexicographical_compare(str1.begin(), str1.end(), str2.begin(), str2.end() ); } void QmitkDiffusionDicomImport::Status(QString status) { mitk::StatusBar::GetInstance()->DisplayText(status.toAscii()); MITK_INFO << status.toStdString().c_str(); } void QmitkDiffusionDicomImport::Status(std::string status) { mitk::StatusBar::GetInstance()->DisplayText(status.c_str()); MITK_INFO << status.c_str(); } void QmitkDiffusionDicomImport::Status(const char* status) { mitk::StatusBar::GetInstance()->DisplayText(status); MITK_INFO << status; } void QmitkDiffusionDicomImport::Error(QString status) { mitk::StatusBar::GetInstance()->DisplayErrorText(status.toAscii()); MITK_ERROR << status.toStdString().c_str(); } void QmitkDiffusionDicomImport::Error(std::string status) { mitk::StatusBar::GetInstance()->DisplayErrorText(status.c_str()); MITK_ERROR << status.c_str(); } void QmitkDiffusionDicomImport::Error(const char* status) { mitk::StatusBar::GetInstance()->DisplayErrorText(status); MITK_ERROR << status; } void QmitkDiffusionDicomImport::PrintMemoryUsage() { size_t processSize = mitk::MemoryUtilities::GetProcessMemoryUsage(); size_t totalSize = mitk::MemoryUtilities::GetTotalSizeOfPhysicalRam(); float percentage = ( (float) processSize / (float) totalSize ) * 100.0; MITK_INFO << "Current memory usage: " << GetMemoryDescription( processSize, percentage ); } std::string QmitkDiffusionDicomImport::FormatMemorySize( size_t size ) { double val = size; std::string descriptor("B"); if ( val >= 1000.0 ) { val /= 1024.0; descriptor = "KB"; } if ( val >= 1000.0 ) { val /= 1024.0; descriptor = "MB"; } if ( val >= 1000.0 ) { val /= 1024.0; descriptor = "GB"; } std::ostringstream str; str << std::fixed << std::setprecision(2) << val << " " << descriptor; return str.str(); } std::string QmitkDiffusionDicomImport::FormatPercentage( double val ) { std::ostringstream str; str << std::fixed << std::setprecision(2) << val << " " << "%"; return str.str(); } std::string QmitkDiffusionDicomImport::GetMemoryDescription( size_t processSize, float percentage ) { std::ostringstream str; str << FormatMemorySize(processSize) << " (" << FormatPercentage( percentage ) <<")" ; return str.str(); } void QmitkDiffusionDicomImport::DicomLoadStartLoad() { itk::TimeProbesCollectorBase clock; bool imageSuccessfullySaved = true; try { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, NULL ); if ( locale.compare(currLocale)!=0 ) { try { MITK_INFO << " ** Changing locale from " << setlocale(LC_ALL, NULL) << " to '" << locale << "'"; setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } int nrFolders = m_Controls->listWidget->count(); if(!nrFolders) { Error(QString("No input folders were selected. ABORTING.")); return; } Status(QString("GDCM %1 used for DICOM parsing and sorting!").arg(gdcm::Version::GetVersion())); PrintMemoryUsage(); QString status; mitk::DataNode::Pointer node; mitk::ProgressBar::GetInstance()->AddStepsToDo(2*nrFolders); std::string folder = m_Controls->m_OutputLabel->text().toStdString(); if(berry::Platform::IsWindows()) { folder.append("\\import.log"); } else { folder.append("/import.log"); } ofstream logfile; if(m_OutputFolderNameSet) logfile.open(folder.c_str()); while(m_Controls->listWidget->count()) { // RETREIVE FOLDERNAME QListWidgetItem * item = m_Controls->listWidget->takeItem(0); QString folderName = item->text(); if(m_OutputFolderNameSet) logfile << "Reading " << folderName.toStdString() << '\n'; // PARSING DIRECTORY PrintMemoryUsage(); clock.Start(folderName.toAscii()); std::vector seriesUIDs(0); std::vector > seriesFilenames(0); Status("== Initial Directory Scan =="); if(m_OutputFolderNameSet) logfile << "== Initial Directory Scan ==\n"; gdcm::Directory d; d.Load( folderName.toStdString().c_str(), true ); // recursive ! const gdcm::Directory::FilenamesType &l1 = d.GetFilenames(); const unsigned int ntotalfiles = l1.size(); Status(QString(" ... found %1 different files").arg(ntotalfiles)); if(m_OutputFolderNameSet)logfile << "...found " << ntotalfiles << " different files\n"; Status("Scanning Headers"); if(m_OutputFolderNameSet) logfile << "Scanning Headers\n"; gdcm::Scanner s; const gdcm::Tag t1(0x0020,0x000d); // Study Instance UID const gdcm::Tag t2(0x0020,0x000e); // Series Instance UID const gdcm::Tag t5(0x0028, 0x0010); // number rows const gdcm::Tag t6(0x0028, 0x0011); // number cols s.AddTag( t1 ); s.AddTag( t2 ); s.AddTag( t5 ); s.AddTag( t6 ); bool b = s.Scan( d.GetFilenames() ); if( !b ) { Error("Scanner failed"); if(m_OutputFolderNameSet )logfile << "ERROR: scanner failed\n"; continue; } // Only get the DICOM files: gdcm::Directory::FilenamesType l2 = s.GetKeys(); const int nfiles = l2.size(); if(nfiles < 1) { Error("No DICOM files found"); if(m_OutputFolderNameSet)logfile << "ERROR: No DICOM files found\n"; continue; } Status(QString(" ... successfully scanned %1 headers.").arg(nfiles)); if(m_OutputFolderNameSet) logfile << "...succesfully scanned " << nfiles << " headers\n"; Status("Sorting"); if(m_OutputFolderNameSet) logfile << "Sorting\n"; const gdcm::Scanner::ValuesType &values1 = s.GetValues(t1); int nvalues; if(m_Controls->m_DuplicateID->isChecked()) { nvalues = 1; } else { nvalues = values1.size(); } if(nvalues>1) { Error("Multiple sSeries tudies found. Please limit to 1 study per folder"); if(m_OutputFolderNameSet) logfile << "Multiple series found. Limit to one. If you are convinced this is an error use the merge duplicate study IDs option \n"; continue; } const gdcm::Scanner::ValuesType &values5 = s.GetValues(t5); const gdcm::Scanner::ValuesType &values6 = s.GetValues(t6); if(values5.size()>1 || values6.size()>1) { Error("Folder contains images of unequal dimensions that cannot be combined in one 3d volume. ABORTING."); if(m_OutputFolderNameSet) logfile << "Folder contains images of unequal dimensions that cannot be combined in one 3d volume. ABORTING\n."; continue; } const gdcm::Scanner::ValuesType &values2 = s.GetValues(t2); int nSeries; if(m_Controls->m_DuplicateID->isChecked()) { nSeries = 1; } else { nSeries = values2.size(); } gdcm::Directory::FilenamesType files; if(nSeries > 1) { gdcm::Sorter sorter; sorter.SetSortFunction( SortBySeriesUID ); sorter.StableSort( l2 ); files = sorter.GetFilenames(); } else { files = l2; } unsigned int nTotalAcquis = 0; if(nfiles % nSeries != 0) { Error("Number of files in series not equal, ABORTING"); if(m_OutputFolderNameSet) logfile << "Number of files in series not equal, Some volumes are probably incomplete. ABORTING \n"; continue; } int filesPerSeries = nfiles / nSeries; gdcm::Scanner::ValuesType::const_iterator it2 = values2.begin(); for(int i=0; i & list = ippsorter.GetFilenames(); seriesFilenames.push_back(list); seriesUIDs.push_back(identifier.c_str()); } ++it2; } if(nfiles % nTotalAcquis != 0) { Error("Number of files per acquisition differs between series, ABORTING"); if(m_OutputFolderNameSet) logfile << "Number of files per acquisition differs between series, ABORTING \n"; continue; } int slices = nfiles/nTotalAcquis; Status(QString("Series is composed of %1 different 3D volumes with %2 slices.").arg(nTotalAcquis).arg(slices)); if(m_OutputFolderNameSet) logfile << "Series is composed of " << nTotalAcquis << " different 3D volumes with " << slices << " slices\n"; // READING HEADER-INFOS PrintMemoryUsage(); Status(QString("Reading Headers %1").arg(folderName)); if(m_OutputFolderNameSet) logfile << "Reading Headers "<< folderName.toStdString() << "\n"; mitk::DicomDiffusionImageHeaderReader::Pointer headerReader; mitk::GroupDiffusionHeadersFilter::InputType inHeaders; unsigned int size2 = seriesUIDs.size(); for ( unsigned int i = 0 ; i < size2 ; ++i ) { Status(QString("Reading header image #%1/%2").arg(i+1).arg(size2)); headerReader = mitk::DicomDiffusionImageHeaderReader::New(); headerReader->SetSeriesDicomFilenames(seriesFilenames[i]); headerReader->Update(); inHeaders.push_back(headerReader->GetOutput()); //Status(std::endl; } mitk::ProgressBar::GetInstance()->Progress(); // // GROUP HEADERS // mitk::GroupDiffusionHeadersFilter::Pointer grouper // = mitk::GroupDiffusionHeadersFilter::New(); // mitk::GroupDiffusionHeadersFilter::OutputType outHeaders; // grouper->SetInput(inHeaders); // grouper->Update(); // outHeaders = grouper->GetOutput(); // READ VOLUMES PrintMemoryUsage(); if(m_OutputFolderNameSet) logfile << "Loading volumes\n"; Status(QString("Loading Volumes %1").arg(folderName)); typedef short PixelValueType; typedef mitk::DicomDiffusionImageReader< PixelValueType, 3 > VolumesReader; VolumesReader::Pointer vReader = VolumesReader::New(); VolumesReader::HeaderContainer hc = inHeaders; // hc.insert(hc.end(), outHeaders[1].begin(), outHeaders[1].end() ); // hc.insert(hc.end(), outHeaders[2].begin(), outHeaders[2].end() ); if(hc.size()>1) { vReader->SetHeaders(hc); vReader->Update(); VolumesReader::OutputImageType::Pointer vecImage; vecImage = vReader->GetOutput(); Status(QString("Volumes Loaded (%1)").arg(folderName)); // CONSTRUCT CONTAINER WITH DIRECTIONS typedef vnl_vector_fixed< double, 3 > GradientDirectionType; typedef itk::VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; GradientDirectionContainerType::Pointer directions = GradientDirectionContainerType::New(); std::vector b_vals; double maxb = 0; for(unsigned int i=0; ibValue; if(maxb vect = hc[i]->DiffusionVector; vect.normalize(); vect *= sqrt(b_vals[i]/maxb); directions->push_back(vect); } // DWI TO DATATREE PrintMemoryUsage(); Status(QString("Initializing Diffusion Image")); if(m_OutputFolderNameSet) logfile << "Initializing Diffusion Image\n"; typedef mitk::DiffusionImage DiffVolumesType; DiffVolumesType::Pointer diffImage = DiffVolumesType::New(); diffImage->SetDirections(directions); diffImage->SetOriginalDirections(directions); - if(m_Controls->m_DicomLoadDKFZ->isChecked()) - { - diffImage->CorrectDKFZBrokenGradientScheme(m_Controls->m_Blur->value()); - } diffImage->SetVectorImage(vecImage); diffImage->SetB_Value(maxb); diffImage->InitializeFromVectorImage(); Status(QString("Diffusion Image initialized")); if(m_OutputFolderNameSet) logfile << "Diffusion Image initialized\n"; if(m_Controls->m_DicomLoadAverageDuplicatesCheckbox->isChecked()) { PrintMemoryUsage(); Status(QString("Averaging gradient directions")); logfile << "Averaging gradient directions\n"; diffImage->AverageRedundantGradients(m_Controls->m_Blur->value()); } - //if(m_Controls->m_DicomLoadDuplicateIfSingleSliceCheckbox->isChecked()) - // diffVolumes->DuplicateIfSingleSlice(); - QString descr = QString("%1_%2_%3") .arg(((inHeaders)[0])->seriesDescription.c_str()) .arg(((inHeaders)[0])->seriesNumber) .arg(((inHeaders)[0])->patientName.c_str()); descr = descr.trimmed(); descr = descr.replace(" ", "_"); if(!m_OutputFolderNameSet) { node=mitk::DataNode::New(); node->SetData( diffImage ); GetDefaultDataStorage()->Add(node); SetDwiNodeProperties(node, descr.toStdString().c_str()); Status(QString("Image %1 added to datastorage").arg(descr)); } else { typedef mitk::NrrdDiffusionImageWriter WriterType; WriterType::Pointer writer = WriterType::New(); QString fullpath = QString("%1/%2.dwi") .arg(m_OutputFolderName) .arg(descr); - //std::string pathstring = itksys::SystemTools::ConvertToOutputPath(fullpath.toStdString().c_str()); writer->SetFileName(fullpath.toStdString()); writer->SetInput(diffImage); try { writer->Update(); } catch (itk::ExceptionObject &ex) { imageSuccessfullySaved = false; Error(QString("%1\n%2\n%3\n%4\n%5\n%6").arg(ex.GetNameOfClass()).arg(ex.GetFile()).arg(ex.GetLine()).arg(ex.GetLocation()).arg(ex.what()).arg(ex.GetDescription())); logfile << QString("%1\n%2\n%3\n%4\n%5\n%6").arg(ex.GetNameOfClass()).arg(ex.GetFile()).arg(ex.GetLine()).arg(ex.GetLocation()).arg(ex.what()).arg(ex.GetDescription()).toStdString() << "\n"; node=mitk::DataNode::New(); node->SetData( diffImage ); GetDefaultDataStorage()->Add(node); SetDwiNodeProperties(node, descr.toStdString().c_str()); Status(QString("Image %1 added to datastorage").arg(descr)); logfile << "Image " << descr.toStdString() << " added to datastorage\n"; continue ; } Status(QString("Image %1 written to disc (%1)").arg(fullpath.toStdString().c_str())); logfile << "Image " << fullpath.toStdString() << "\n"; } } else { Status(QString("No diffusion information found (%1)").arg(folderName)); if(m_OutputFolderNameSet) logfile << "No diffusion information found "<< folderName.toStdString(); } Status(QString("Finished processing %1 with memory:").arg(folderName)); if(m_OutputFolderNameSet) logfile << "Finished processing " << folderName.toStdString() << "\n"; PrintMemoryUsage(); clock.Stop(folderName.toAscii()); mitk::ProgressBar::GetInstance()->Progress(); int lwidget = m_Controls->listWidget->count(); std::cout << lwidget <GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); try { MITK_INFO << " ** Changing locale back from " << setlocale(LC_ALL, NULL) << " to '" << currLocale << "'"; setlocale(LC_ALL, currLocale.c_str()); } catch(...) { MITK_INFO << "Could not reset locale " << currLocale; } } catch (itk::ExceptionObject &ex) { Error(QString("%1\n%2\n%3\n%4\n%5\n%6").arg(ex.GetNameOfClass()).arg(ex.GetFile()).arg(ex.GetLine()).arg(ex.GetLocation()).arg(ex.what()).arg(ex.GetDescription())); return ; } if (!imageSuccessfullySaved) QMessageBox::warning(NULL,"WARNING","One or more files could not be saved! The according files where moved to the datastorage."); Status(QString("Finished import with memory:")); PrintMemoryUsage(); } void QmitkDiffusionDicomImport::SetDwiNodeProperties(mitk::DataNode::Pointer node, std::string name) { node->SetProperty( "IsDWIRawVolume", mitk::BoolProperty::New( true ) ); // set foldername as string property mitk::StringProperty::Pointer nameProp = mitk::StringProperty::New( name ); node->SetProperty( "name", nameProp ); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.h index b7dcb07d03..87aceb3cab 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.h @@ -1,119 +1,112 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Module: $RCSfile$ Language: C++ Date: $Date: 2009-05-05 11:31:02 +0200 (Di, 05 Mai 2009) $ Version: $Revision: 10185 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef QmitkDiffusionDicomImportView_H__INCLUDED #define QmitkDiffusionDicomImportView_H__INCLUDED #include "QmitkFunctionality.h" #include "ui_QmitkDiffusionDicomImportViewControls.h" /*! -\brief QmitkDiffusionDicomImport +\brief QmitkDiffusionDicomImport \sa QmitkFunctionality \ingroup Functionalities */ class QmitkDiffusionDicomImport : public QmitkFunctionality -{ +{ Q_OBJECT -public: +public: static const std::string VIEW_ID; - /*! + /*! \ Convenient typedefs */ typedef mitk::DataStorage::SetOfObjects ConstVector; typedef ConstVector::ConstPointer ConstVectorPointer; typedef ConstVector::ConstIterator ConstVectorIterator; - /*! - \brief default constructor - */ + /*! + \brief default constructor + */ QmitkDiffusionDicomImport(QObject *parent=0, const char *name=0); QmitkDiffusionDicomImport(const QmitkDiffusionDicomImport& other); - /*! - \brief default destructor - */ + /*! + \brief default destructor + */ virtual ~QmitkDiffusionDicomImport(); - /*! - \brief method for creating the widget containing the application controls, like sliders, buttons etc. - */ + /*! + \brief method for creating the widget containing the application controls, like sliders, buttons etc. + */ virtual void CreateQtPartControl(QWidget *parent); - /*! - \brief method for creating the connections of main and control widget - */ + /*! + \brief method for creating the connections of main and control widget + */ virtual void CreateConnections(); virtual void Activated(); void SetDwiNodeProperties(mitk::DataNode::Pointer node, std::string name); protected slots: void DicomLoadAddFolderNames(); - void DicomLoadDeleteFolderNames(); - void DicomLoadStartLoad() ; - void AverageClicked(); - void OutputSet(); void OutputClear(); - - void AdvancedCheckboxClicked(); - void Remove(); -protected: +protected: void Status(QString status); void Status(std::string status); void Status(const char* status); void Error(QString status); void Error(std::string status); void Error(const char* status); void PrintMemoryUsage(); std::string FormatMemorySize( size_t size ); std::string FormatPercentage( double val ); std::string GetMemoryDescription( size_t processSize, float percentage ); - /*! - * controls containing sliders for scrolling through the slices - */ + /*! + * controls containing sliders for scrolling through the slices + */ Ui::QmitkDiffusionDicomImportControls *m_Controls; QmitkStdMultiWidget* m_MultiWidget; QWidget *m_Parent; QString m_OutputFolderName; bool m_OutputFolderNameSet; }; #endif // !defined(QmitkDiffusionDicomImport_H__INCLUDED) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui index 3e096d8494..02cbb86b1e 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui @@ -1,330 +1,313 @@ QmitkDiffusionDicomImportControls 0 0 - 313 + 338 498 0 0 true QmitkDiffusionDicomImport 16777215 70 QFrame::NoFrame QFrame::Plain 0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> <tr> <td style="border: none;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">Each input folder must only contain DICOM-images that can be combined into one vector-valued 3D output volume. Different patients must be loaded from different input-folders. The folders must not contain other acquisitions (e.g. T1,T2,localizer).</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;"></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">In case many imports are performed at once, it is recommended to set the the optional output folder argument. This prevents the images from being kept in memory.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;"></p></td></tr></table></body></html> 0 0 QFrame::NoFrame QFrame::Raised 0 0 Add Input Folders Remove Clear 0 0 0 70 QFrame::Box QFrame::Plain 1 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAlwaysOn QListView::Adjust true QFrame::StyledPanel QFrame::Raised Recursive + + Multiple acquistions of one gradient direction can be averaged. Due to rounding errors, similar gradients often differ in the last decimal positions. The Merge radius allows to average them anyway by taking into account all directions within a certain radius. + QFrame::NoFrame QFrame::Raised 0 - Avg. dupl. grad., blur= + Merge duplicate gradients: false + + + - 6 + 4 2.000000000000000 0.000100000000000 0.001000000000000 - + + + Select this option if you are sure that your DICOM dataset contains multiple Study Instance UID or Series Instance UID. It will ignore that fact and attempt to import all images as one. + - Advanced + Merge duplicate study IDs - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - Correct DKFZ Gradient Scheme - - - - - - - Select this option if you are sure that your DICOM dataset contains multiple Study Instance UID or Series Instance UID. It will ignore that fact and attempt to import all images as one. - - - merge duplicate study IDs - - - - - - QFrame::NoFrame QFrame::Raised 0 40 25 30 16777215 + + Files are automaticall saved to disc. If the files can not be written, they are added to the data manager. + Set ... optional out-folder ... false true 50 25 30 16777215 Clear Import DICOM as *.dwi Qt::Vertical 20 0