diff --git a/Examples/Tutorial/QtTesting.cpp b/Examples/Tutorial/QtTesting.cpp index 053df8a3ca..2abb81db78 100644 --- a/Examples/Tutorial/QtTesting.cpp +++ b/Examples/Tutorial/QtTesting.cpp @@ -1,32 +1,32 @@ /*=================================================================== 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 -int QtTesting() +int QtTesting(void) { // QtTestingClass *qttestingclass = new QtTestingClass; std::cout << "Testing ... " << std::endl; auto timer = new QTimer(QApplication::instance()); timer->setSingleShot(true); QObject::connect(timer, SIGNAL(timeout()), QApplication::instance(), SLOT(quit())); timer->start(2000); // 2 seconds single-shot timer QApplication::instance()->exec(); return EXIT_SUCCESS; } diff --git a/Examples/Tutorial/QtTesting.h b/Examples/Tutorial/QtTesting.h index e48ab07d56..e6d2ef3b7b 100644 --- a/Examples/Tutorial/QtTesting.h +++ b/Examples/Tutorial/QtTesting.h @@ -1,27 +1,27 @@ /*=================================================================== 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 -int QtTesting(); +int QtTesting(void); // class QtTestingClass : public QObject //{ // Q_OBJECT // public: // QtTestingClass( QObject * parent = 0, const char * name = 0 ); // //} diff --git a/Modules/Classification/CLLibSVM/test/mitkLibSVMClassifierTest.cpp b/Modules/Classification/CLLibSVM/test/mitkLibSVMClassifierTest.cpp index 424174dadf..eec7e4b335 100644 --- a/Modules/Classification/CLLibSVM/test/mitkLibSVMClassifierTest.cpp +++ b/Modules/Classification/CLLibSVM/test/mitkLibSVMClassifierTest.cpp @@ -1,314 +1,314 @@ /*=================================================================== 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 "mitkIOUtil.h" #include "itkArray2D.h" #include #include #include #include #include #include #include //#include class mitkLibSVMClassifierTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkLibSVMClassifierTestSuite); MITK_TEST(TrainSVMClassifier_MatlabDataSet_shouldReturnTrue); MITK_TEST(TrainSVMClassifier_BreastCancerDataSet_shouldReturnTrue); CPPUNIT_TEST_SUITE_END(); private: typedef Eigen::Matrix MatrixDoubleType; typedef Eigen::Matrix MatrixIntType; Eigen::MatrixXd m_TrainingMatrixX; Eigen::MatrixXi m_TrainingLabelMatrixY; Eigen::MatrixXd m_TestXPredict; Eigen::MatrixXi m_TestYPredict; mitk::LibSVMClassifier::Pointer classifier; public: /*Reading an file, which includes the trainingdataset and the testdataset, and convert the content of the file into an 2dim matrixpair. There are an delimiter, which separates the matrix into an trainingmatrix and testmatrix */ template std::pair,Eigen::Matrix >convertCSVToMatrix(const std::string &path, char delimiter,double range, bool isXMatrix) { typename itk::CSVArray2DFileReader::Pointer fr = itk::CSVArray2DFileReader::New(); fr->SetFileName(path); fr->SetFieldDelimiterCharacter(delimiter); fr->HasColumnHeadersOff(); fr->HasRowHeadersOff(); fr->Parse(); try{ fr->Update(); }catch(itk::ExceptionObject& ex){ cout << "Exception caught!" << std::endl; cout << ex << std::endl; } typename itk::CSVArray2DDataObject::Pointer p = fr->GetOutput(); unsigned int maxrowrange = p->GetMatrix().rows(); unsigned int c = p->GetMatrix().cols(); unsigned int percentRange = (unsigned int)(maxrowrange*range); if(isXMatrix == true) { Eigen::Matrix trainMatrixX(percentRange,c); Eigen::Matrix testMatrixXPredict(maxrowrange-percentRange,c); for(unsigned int row = 0; row < percentRange; row++){ for(unsigned int col = 0; col < c; col++){ trainMatrixX(row,col) = p->GetData(row,col); } } for(unsigned int row = percentRange; row < maxrowrange; row++){ for(unsigned int col = 0; col < c; col++){ testMatrixXPredict(row-percentRange,col) = p->GetData(row,col); } } return std::make_pair(trainMatrixX,testMatrixXPredict); } else { Eigen::Matrix trainLabelMatrixY(percentRange,c); Eigen::Matrix testMatrixYPredict(maxrowrange-percentRange,c); for(unsigned int row = 0; row < percentRange; row++){ for(unsigned int col = 0; col < c; col++){ trainLabelMatrixY(row,col) = p->GetData(row,col); } } for(unsigned int row = percentRange; row < maxrowrange; row++){ for(unsigned int col = 0; col < c; col++){ testMatrixYPredict(row-percentRange,col) = p->GetData(row,col); } } return std::make_pair(trainLabelMatrixY,testMatrixYPredict); } } /* Reading an csv-data and transfer the included datas into an matrix. */ template Eigen::Matrix readCsvData(const std::string &path, char delimiter) { typename itk::CSVArray2DFileReader::Pointer fr = itk::CSVArray2DFileReader::New(); fr->SetFileName(path); fr->SetFieldDelimiterCharacter(delimiter); fr->HasColumnHeadersOff(); fr->HasRowHeadersOff(); fr->Parse(); try{ fr->Update(); }catch(itk::ExceptionObject& ex){ cout << "Exception caught!" << std::endl; cout << ex << std::endl; } typename itk::CSVArray2DDataObject::Pointer p = fr->GetOutput(); unsigned int maxrowrange = p->GetMatrix().rows(); unsigned int maxcols = p->GetMatrix().cols(); Eigen::Matrix matrix(maxrowrange,maxcols); - for(int rows = 0; rows < maxrowrange; rows++){ - for(int cols = 0; cols < maxcols; cols++ ){ + for(unsigned int rows = 0; rows < maxrowrange; rows++){ + for(unsigned int cols = 0; cols < maxcols; cols++ ){ matrix(rows,cols) = p->GetData(rows,cols); } } return matrix; } /* Write the content of the array into an own csv-data in the following sequence: root.csv: 1 2 3 0 0 4 writen.csv: 1 1:2 2:3 3:0 4:0 5:4 */ template void writeMatrixToCsv(Eigen::Matrix paramMatrix,const std::string &path) { std::ofstream outputstream (path,std::ofstream::out); // 682 if(outputstream.is_open()){ for(int i = 0; i < paramMatrix.rows(); i++){ outputstream << paramMatrix(i,0); for(int j = 1; j < 11; j++){ outputstream << " " << j << ":" << paramMatrix(i,j); } outputstream << endl; } outputstream.close(); } else{ cout << "Unable to write into CSV" << endl; } } /* Train the classifier with an exampledataset of mattlab. Note: The included data are gaußan normaldistributed. */ void TrainSVMClassifier_MatlabDataSet_shouldReturnTrue() { /* Declarating an featurematrixdataset, the first matrix of the matrixpair is the trainingmatrix and the second one is the testmatrix.*/ std::pair matrixDouble; matrixDouble = convertCSVToMatrix(GetTestDataFilePath("Classification/FeaturematrixMatlab.csv"),';',0.5,true); m_TrainingMatrixX = matrixDouble.first; m_TestXPredict = matrixDouble.second; /* The declaration of the labelmatrixdataset is equivalent to the declaration of the featurematrixdataset.*/ std::pair matrixInt; matrixInt = convertCSVToMatrix(GetTestDataFilePath("Classification/LabelmatrixMatlab.csv"),';',0.5,false); m_TrainingLabelMatrixY = matrixInt.first; m_TestYPredict = matrixInt.second; classifier = mitk::LibSVMClassifier::New(); /* Setting of the SVM-Parameters*/ classifier->SetGamma(1/(double)(m_TrainingMatrixX.cols())); classifier->SetSvmType(0); classifier->SetKernelType(0); /* Train the classifier, by giving trainingdataset for the labels and features. The result in an colunmvector of the labels.*/ classifier->Train(m_TrainingMatrixX,m_TrainingLabelMatrixY); Eigen::MatrixXi classes = classifier->Predict(m_TestXPredict); /* Testing the matching between the calculated colunmvector and the result of the SVM */ unsigned int maxrows = classes.rows(); int count = 0; for (unsigned int i = 0; i < maxrows; i++) { if(classes(i, 0) == m_TestYPredict(i, 0)) ++count; } MITK_INFO << 100*count/(double)(maxrows) << "%"; MITK_TEST_CONDITION(isEqual(m_TestYPredict,classes),"Expected vector and occured vector match."); } // Method of testing for assertions. template bool isEqual(Eigen::Matrix expected, Eigen::Matrix actual) { bool isSimilar = true; unsigned int mrow = expected.rows(); unsigned int mcol = expected.cols(); for(unsigned int i = 0; i < mrow; i++){ for(unsigned int j = 0; j < mcol; j++){ if(expected(i,j) != actual(i,j)){ isSimilar = false; } } } return isSimilar; } // Method of intervalltesting template bool isIntervall(Eigen::Matrix expected, Eigen::Matrix actual, double lowrange, double toprange) { bool isInIntervall = false; int count = 0; unsigned int rowRange = expected.rows(); unsigned int colRange = expected.cols(); for(unsigned int i = 0; i < rowRange; i++){ for(unsigned int j = 0; j < colRange; j++){ if(expected(i,j) == actual(i,j)){ count++; } } double valueOfMatch = 100*count/(double)(rowRange); if((lowrange <= valueOfMatch) && (toprange >= valueOfMatch)){ isInIntervall = true; } } return isInIntervall; } /* Train the classifier with the dataset of breastcancer patients from the LibSVM Libary */ void TrainSVMClassifier_BreastCancerDataSet_shouldReturnTrue() { /* Declarating an featurematrixdataset, the first matrix of the matrixpair is the trainingmatrix and the second one is the testmatrix.*/ std::pair matrixDouble; matrixDouble = convertCSVToMatrix(GetTestDataFilePath("Classification/FeaturematrixBreastcancer.csv"),';',0.5,true); m_TrainingMatrixX = matrixDouble.first; m_TestXPredict = matrixDouble.second; /* The declaration of the labelmatrixdataset is equivalent to the declaration of the featurematrixdataset.*/ std::pair matrixInt; matrixInt = convertCSVToMatrix(GetTestDataFilePath("Classification/LabelmatrixBreastcancer.csv"),';',0.5,false); m_TrainingLabelMatrixY = matrixInt.first; m_TestYPredict = matrixInt.second; /* Setting of the SVM-Parameters*/ classifier = mitk::LibSVMClassifier::New(); classifier->SetGamma(1/(double)(m_TrainingMatrixX.cols())); classifier->SetSvmType(0); classifier->SetKernelType(2); /* Train the classifier, by giving trainingdataset for the labels and features. The result in an colunmvector of the labels.*/ classifier->Train(m_TrainingMatrixX,m_TrainingLabelMatrixY); Eigen::MatrixXi classes = classifier->Predict(m_TestXPredict); /* Testing the matching between the calculated colunmvector and the result of the SVM */ unsigned int maxrows = classes.rows(); int count = 0; for (unsigned int i = 0; i < maxrows; i++) { if (classes(i, 0) == m_TestYPredict(i, 0)) ++count; } MITK_INFO << 100*count/(double)(maxrows) << "%"; MITK_TEST_CONDITION(isIntervall(m_TestYPredict,classes,75,100),"Testvalue is in range."); } void TestThreadedDecisionForest() { } }; MITK_TEST_SUITE_REGISTRATION(mitkLibSVMClassifier) diff --git a/Modules/DICOMReader/include/mitkITKDICOMSeriesReaderHelper.txx b/Modules/DICOMReader/include/mitkITKDICOMSeriesReaderHelper.txx index 341b5ed0b4..b3d2ec91f0 100644 --- a/Modules/DICOMReader/include/mitkITKDICOMSeriesReaderHelper.txx +++ b/Modules/DICOMReader/include/mitkITKDICOMSeriesReaderHelper.txx @@ -1,305 +1,305 @@ /*=================================================================== 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 "mitkITKDICOMSeriesReaderHelper.h" #include #include //#include //#include //#include -#include +#include "dcmtk/ofstd/ofdatime.h" template mitk::Image::Pointer mitk::ITKDICOMSeriesReaderHelper ::LoadDICOMByITK( const StringContainer& filenames, bool correctTilt, const GantryTiltInformation& tiltInfo, itk::GDCMImageIO::Pointer& io) { /******** Normal Case, 3D (also for GDCM < 2 usable) ***************/ mitk::Image::Pointer image = mitk::Image::New(); typedef itk::Image ImageType; typedef itk::ImageSeriesReader ReaderType; io = itk::GDCMImageIO::New(); typename ReaderType::Pointer reader = ReaderType::New(); reader->SetImageIO(io); reader->ReverseOrderOff(); // at this point we require an order of input images so that // the direction between the origin of the first and the last slice // is the same direction as the image normals! Otherwise we might // see images upside down. Unclear whether this is a bug in MITK, // see NormalDirectionConsistencySorter. reader->SetFileNames(filenames); reader->Update(); typename ImageType::Pointer readVolume = reader->GetOutput(); // if we detected that the images are from a tilted gantry acquisition, we need to push some pixels into the right position if (correctTilt) { readVolume = FixUpTiltedGeometry( reader->GetOutput(), tiltInfo ); } image->InitializeByItk(readVolume.GetPointer()); image->SetImportVolume(readVolume->GetBufferPointer()); #ifdef MBILOG_ENABLE_DEBUG MITK_DEBUG << "Volume dimension: [" << image->GetDimension(0) << ", " << image->GetDimension(1) << ", " << image->GetDimension(2) << "]"; MITK_DEBUG << "Volume spacing: [" << image->GetGeometry()->GetSpacing()[0] << ", " << image->GetGeometry()->GetSpacing()[1] << ", " << image->GetGeometry()->GetSpacing()[2] << "]"; #endif //MBILOG_ENABLE_DEBUG return image; } #define MITK_DEBUG_OUTPUT_FILELIST(list)\ MITK_DEBUG << "-------------------------------------------"; \ for (StringContainer::const_iterator _iter = (list).cbegin(); _iter!=(list).cend(); ++_iter) \ { \ MITK_DEBUG <<" file '" << *_iter<< "'"; \ } \ MITK_DEBUG << "-------------------------------------------"; template mitk::Image::Pointer mitk::ITKDICOMSeriesReaderHelper ::LoadDICOMByITK3DnT( const StringContainerList& filenamesForTimeSteps, bool correctTilt, const GantryTiltInformation& tiltInfo, itk::GDCMImageIO::Pointer& io) { unsigned int numberOfTimeSteps = filenamesForTimeSteps.size(); MITK_DEBUG << "Start extracting time bounds of time steps"; const TimeBoundsList timeBoundsList = ExtractTimeBoundsOfTimeSteps(filenamesForTimeSteps); if (numberOfTimeSteps!=timeBoundsList.size()) { mitkThrow() << "Error while loading 3D+t. Inconsistent size of generated time bounds list. List size: "<< timeBoundsList.size() << "; number of steps: "< ImageType; typedef itk::ImageSeriesReader ReaderType; io = itk::GDCMImageIO::New(); typename ReaderType::Pointer reader = ReaderType::New(); reader->SetImageIO(io); reader->ReverseOrderOff(); // at this point we require an order of input images so that // the direction between the origin of the first and the last slice // is the same direction as the image normals! Otherwise we might // see images upside down. Unclear whether this is a bug in MITK, // see NormalDirectionConsistencySorter. unsigned int currentTimeStep = 0; #ifdef MBILOG_ENABLE_DEBUG MITK_DEBUG << "Start loading timestep " << currentTimeStep; MITK_DEBUG_OUTPUT_FILELIST( filenamesForTimeSteps.front() ) #endif // MBILOG_ENABLE_DEBUG reader->SetFileNames(filenamesForTimeSteps.front()); reader->Update(); typename ImageType::Pointer readVolume = reader->GetOutput(); // if we detected that the images are from a tilted gantry acquisition, we need to push some pixels into the right position if (correctTilt) { readVolume = FixUpTiltedGeometry( reader->GetOutput(), tiltInfo ); } image->InitializeByItk(readVolume.GetPointer(), 1, numberOfTimeSteps); image->SetImportVolume(readVolume->GetBufferPointer(), currentTimeStep++); // timestep 0 // for other time-steps for (auto timestepsIter = ++(filenamesForTimeSteps.cbegin()); // start with SECOND entry timestepsIter != filenamesForTimeSteps.cend(); ++currentTimeStep, ++timestepsIter) { #ifdef MBILOG_ENABLE_DEBUG MITK_DEBUG << "Start loading timestep " << currentTimeStep; MITK_DEBUG_OUTPUT_FILELIST( *timestepsIter ) #endif // MBILOG_ENABLE_DEBUG reader->SetFileNames( *timestepsIter ); reader->Update(); readVolume = reader->GetOutput(); if (correctTilt) { readVolume = FixUpTiltedGeometry( reader->GetOutput(), tiltInfo ); } image->SetImportVolume(readVolume->GetBufferPointer(), currentTimeStep); } #ifdef MBILOG_ENABLE_DEBUG MITK_DEBUG << "Volume dimension: [" << image->GetDimension(0) << ", " << image->GetDimension(1) << ", " << image->GetDimension(2) << "]"; MITK_DEBUG << "Volume spacing: [" << image->GetGeometry()->GetSpacing()[0] << ", " << image->GetGeometry()->GetSpacing()[1] << ", " << image->GetGeometry()->GetSpacing()[2] << "]"; #endif // MBILOG_ENABLE_DEBUG //construct timegeometry TimeGeometry::Pointer timeGeometry = GenerateTimeGeometry(image->GetGeometry(),timeBoundsList); image->SetTimeGeometry(timeGeometry); return image; } template typename ImageType::Pointer mitk::ITKDICOMSeriesReaderHelper ::FixUpTiltedGeometry( ImageType* input, const GantryTiltInformation& tiltInfo ) { typedef itk::ResampleImageFilter ResampleFilterType; typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); resampler->SetInput( input ); /* Transform for a point is - transform from actual position to index coordinates - apply a shear that undoes the gantry tilt - transform back into world coordinates Anybody who does this in a simpler way: don't forget to write up how and why your solution works */ typedef itk::ScalableAffineTransform< double, ImageType::ImageDimension > TransformType; typename TransformType::Pointer transformShear = TransformType::New(); /** - apply a shear and spacing correction to the image block that corrects the ITK reader's error - ITK ignores the shear and loads slices into an orthogonal volume - ITK calculates the spacing from the origin distance, which is more than the actual spacing with gantry tilt images - to undo the effect - we have calculated some information in tiltInfo: - the shift in Y direction that is added with each additional slice is the most important information - the Y-shift is calculated in mm world coordinates - we apply a shearing transformation to the ITK-read image volume - to do this locally, - we transform the image volume back to origin and "normal" orientation by applying the inverse of its transform (this brings us into the image's "index coordinate" system) - we apply a shear with the Y-shift factor put into a unit transform at row 1, col 2 - we transform the image volume back to its actual position (from index to world coordinates) - we lastly apply modify the image spacing in z direction by replacing this number with the correctly calulcated inter-slice distance */ const ScalarType factor = tiltInfo.GetMatrixCoefficientForCorrectionInWorldCoordinates() / input->GetSpacing()[1]; // row 1, column 2 corrects shear in parallel to Y axis, proportional to distance in Z direction transformShear->Shear( 1, 2, factor ); typename TransformType::Pointer imageIndexToWorld = TransformType::New(); imageIndexToWorld->SetOffset( input->GetOrigin().GetVectorFromOrigin() ); typename TransformType::MatrixType indexToWorldMatrix; indexToWorldMatrix = input->GetDirection(); typename ImageType::DirectionType scale; for ( unsigned int i = 0; i < ImageType::ImageDimension; i++ ) { scale[i][i] = input->GetSpacing()[i]; } indexToWorldMatrix *= scale; imageIndexToWorld->SetMatrix( indexToWorldMatrix ); typename TransformType::Pointer imageWorldToIndex = TransformType::New(); imageIndexToWorld->GetInverse( imageWorldToIndex ); typename TransformType::Pointer gantryTiltCorrection = TransformType::New(); gantryTiltCorrection->Compose( imageWorldToIndex ); gantryTiltCorrection->Compose( transformShear ); gantryTiltCorrection->Compose( imageIndexToWorld ); resampler->SetTransform( gantryTiltCorrection ); typedef itk::LinearInterpolateImageFunction< ImageType, double > InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); resampler->SetInterpolator( interpolator ); /* This would be the right place to invent a meaningful value for positions outside of the image. For CT, HU -1000 might be meaningful, but a general solution seems not possible. Even for CT, -1000 would only look natural for many not all images. */ // TODO use (0028,0120) Pixel Padding Value if present resampler->SetDefaultPixelValue( itk::NumericTraits< typename ImageType::PixelType >::min() ); // adjust size in Y direction! (maybe just transform the outer last pixel to see how much space we would need resampler->SetOutputParametersFromImage( input ); // we basically need the same image again, just sheared // if tilt positive, then we need additional pixels BELOW origin, otherwise we need pixels behind the end of the block // in any case we need more size to accomodate shifted slices typename ImageType::SizeType largerSize = resampler->GetSize(); // now the resampler already holds the input image's size. const double imageSizeZ = largerSize[2]; //MITK_DEBUG <<"Calculate lager size = " << largerSize[1] << " + " << tiltInfo.GetTiltCorrectedAdditionalSize(imageSizeZ) << " / " << input->GetSpacing()[1] << "+ 2.0"; largerSize[1] += static_cast(tiltInfo.GetTiltCorrectedAdditionalSize(imageSizeZ) / input->GetSpacing()[1]+ 2.0); resampler->SetSize( largerSize ); //MITK_DEBUG << "Fix Y size of image w/ spacing " << input->GetSpacing()[1] << " from " << input->GetLargestPossibleRegion().GetSize()[1] << " to " << largerSize[1]; // in SOME cases this additional size is below/behind origin if ( tiltInfo.GetMatrixCoefficientForCorrectionInWorldCoordinates() > 0.0 ) { typename ImageType::DirectionType imageDirection = input->GetDirection(); Vector3D yDirection; yDirection[0] = imageDirection[0][1]; yDirection[1] = imageDirection[1][1]; yDirection[2] = imageDirection[2][1]; yDirection.Normalize(); typename ImageType::PointType shiftedOrigin; shiftedOrigin = input->GetOrigin(); // add some pixels to make everything fit shiftedOrigin[0] -= yDirection[0] * (tiltInfo.GetTiltCorrectedAdditionalSize(imageSizeZ) + 1.0 * input->GetSpacing()[1]); shiftedOrigin[1] -= yDirection[1] * (tiltInfo.GetTiltCorrectedAdditionalSize(imageSizeZ) + 1.0 * input->GetSpacing()[1]); shiftedOrigin[2] -= yDirection[2] * (tiltInfo.GetTiltCorrectedAdditionalSize(imageSizeZ) + 1.0 * input->GetSpacing()[1]); resampler->SetOutputOrigin( shiftedOrigin ); } resampler->Update(); typename ImageType::Pointer result = resampler->GetOutput(); // ImageSeriesReader calculates z spacing as the distance between the first two origins. // This is not correct in case of gantry tilt, so we set our calculated spacing. typename ImageType::SpacingType correctedSpacing = result->GetSpacing(); correctedSpacing[2] = tiltInfo.GetRealZSpacing(); result->SetSpacing( correctedSpacing ); return result; } diff --git a/Modules/DICOMReader/src/mitkDICOMDCMTKTagScanner.cpp b/Modules/DICOMReader/src/mitkDICOMDCMTKTagScanner.cpp index 222bd84c9a..88c4b1d8ed 100644 --- a/Modules/DICOMReader/src/mitkDICOMDCMTKTagScanner.cpp +++ b/Modules/DICOMReader/src/mitkDICOMDCMTKTagScanner.cpp @@ -1,188 +1,188 @@ /*=================================================================== 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 "mitkDICOMDCMTKTagScanner.h" #include "mitkDICOMGenericImageFrameInfo.h" -#include -#include +#include +#include mitk::DICOMDCMTKTagScanner::DICOMDCMTKTagScanner() { } mitk::DICOMDCMTKTagScanner::~DICOMDCMTKTagScanner() { } void mitk::DICOMDCMTKTagScanner::AddTag( const DICOMTag& tag ) { m_ScannedTags.insert( DICOMTagPath(tag) ); } void mitk::DICOMDCMTKTagScanner::AddTags( const DICOMTagList& tags ) { for ( auto tagIter = tags.cbegin(); tagIter != tags.cend(); ++tagIter ) { this->AddTag( *tagIter ); } } void mitk::DICOMDCMTKTagScanner::AddTagPath(const DICOMTagPath& path) { m_ScannedTags.insert(path); } void mitk::DICOMDCMTKTagScanner::AddTagPaths(const DICOMTagPathList& paths) { for (const auto& path : paths) { this->AddTagPath(path); } } void mitk::DICOMDCMTKTagScanner::SetInputFiles( const StringList& filenames ) { m_InputFilenames = filenames; } mitk::DICOMTagPath DcmPathToTagPath(DcmPath * dcmpath) { mitk::DICOMTagPath result; OFListConstIterator(DcmPathNode*) it = dcmpath->begin(); OFListConstIterator(DcmPathNode*) endOfList = dcmpath->end(); OFString pathStr; DcmEVR vr; DcmObject* obj; while (it != endOfList) { if (((*it) == nullptr) || ((*it)->m_obj == nullptr)) { mitkThrow() << "Error in DcmPathToTagPath(). Invalid search result"; } obj = (*it)->m_obj; vr = obj->ident(); if ((vr == EVR_SQ) || (obj->isLeaf())) { result.AddElement(obj->getTag().getGroup(), obj->getTag().getElement()); } else if ((vr == EVR_item) || (vr == EVR_dataset)) { if (result.Size() > 0) { result.GetLastNode().type = mitk::DICOMTagPath::NodeInfo::NodeType::SequenceSelection; result.GetLastNode().selection = (*it)->m_itemNo; } else { mitkThrow() << "Error in DcmPathToTagPath(). DCMTK path is illegal due to toplevel sequence item."; } } else { result.AddNode(mitk::DICOMTagPath::NodeInfo()); } ++it; } return result; } void mitk::DICOMDCMTKTagScanner::Scan() { this->PushLocale(); try { DcmPathProcessor processor; processor.setItemWildcardSupport(true); DICOMGenericTagCache::Pointer newCache = DICOMGenericTagCache::New(); for (const auto& fileName : this->m_InputFilenames) { DcmFileFormat dfile; OFCondition cond = dfile.loadFile(fileName.c_str()); if (cond.bad()) { MITK_ERROR << "Error when scanning for tags. Cannot open given file. File: " << fileName; } else { DICOMGenericImageFrameInfo::Pointer info = DICOMGenericImageFrameInfo::New(fileName); for (const auto& path : this->m_ScannedTags) { std::string tagPath = DICOMTagPathToDCMTKSearchPath(path); cond = processor.findOrCreatePath(dfile.getDataset(), tagPath.c_str()); if (cond.good()) { OFList< DcmPath * > findings; processor.getResults(findings); for (const auto& finding : findings) { auto element = dynamic_cast(finding->back()->m_obj); if (!element) { auto item = dynamic_cast(finding->back()->m_obj); if (item) { element = item->getElement(finding->back()->m_itemNo); } } if (element) { OFString value; cond = element->getOFStringArray(value); if (cond.good()) { info->SetTagValue(DcmPathToTagPath(finding), std::string(value.c_str())); } } } } } newCache->AddFrameInfo(info); } } m_Cache = newCache; this->PopLocale(); } catch (...) { this->PopLocale(); throw; } } mitk::DICOMTagCache::Pointer mitk::DICOMDCMTKTagScanner::GetScanCache() const { return m_Cache.GetPointer(); } mitk::DICOMDatasetAccessingImageFrameList mitk::DICOMDCMTKTagScanner::GetFrameInfoList() const { if (m_Cache.IsNotNull()) { return m_Cache->GetFrameInfoList(); } return mitk::DICOMDatasetAccessingImageFrameList(); } diff --git a/Modules/DICOMReader/src/mitkDICOMSortByTag.cpp b/Modules/DICOMReader/src/mitkDICOMSortByTag.cpp index 441f20b647..e2a966f126 100644 --- a/Modules/DICOMReader/src/mitkDICOMSortByTag.cpp +++ b/Modules/DICOMReader/src/mitkDICOMSortByTag.cpp @@ -1,181 +1,181 @@ /*=================================================================== 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 "mitkDICOMSortByTag.h" -#include "ofstd.h" +#include "dcmtk/ofstd/ofstd.h" mitk::DICOMSortByTag ::DICOMSortByTag(const DICOMTag& tag, DICOMSortCriterion::Pointer secondaryCriterion) :DICOMSortCriterion(secondaryCriterion) ,m_Tag(tag) { } mitk::DICOMSortByTag ::~DICOMSortByTag() { } mitk::DICOMSortByTag ::DICOMSortByTag(const DICOMSortByTag& other ) :DICOMSortCriterion(other) ,m_Tag(other.m_Tag) { } mitk::DICOMSortByTag& mitk::DICOMSortByTag ::operator=(const DICOMSortByTag& other) { if (this != &other) { DICOMSortCriterion::operator=(other); m_Tag = other.m_Tag; } return *this; } bool mitk::DICOMSortByTag ::operator==(const DICOMSortCriterion& other) const { if (const DICOMSortByTag* otherSelf = dynamic_cast(&other)) { if (!(this->m_Tag == otherSelf->m_Tag)) return false; if (this->m_SecondaryCriterion.IsNull() && otherSelf->m_SecondaryCriterion.IsNull()) return true; if (this->m_SecondaryCriterion.IsNull() || otherSelf->m_SecondaryCriterion.IsNull()) return false; return *(this->m_SecondaryCriterion) == *(otherSelf->m_SecondaryCriterion); } else { return false; } } void mitk::DICOMSortByTag ::Print(std::ostream& os) const { m_Tag.Print(os); } mitk::DICOMTagList mitk::DICOMSortByTag ::GetTagsOfInterest() const { DICOMTagList list; list.push_back(m_Tag); return list; } bool mitk::DICOMSortByTag ::IsLeftBeforeRight(const mitk::DICOMDatasetAccess* left, const mitk::DICOMDatasetAccess* right) const { return this->NumericCompare(left, right, m_Tag); } bool mitk::DICOMSortByTag ::StringCompare(const mitk::DICOMDatasetAccess* left, const mitk::DICOMDatasetAccess* right, const DICOMTag& tag) const { assert(left); assert(right); DICOMDatasetFinding leftFinding = left->GetTagValueAsString(tag); DICOMDatasetFinding rightFinding = right->GetTagValueAsString(tag); //Doesn't care if findings are valid or not. If they are not valid, //value is empty, thats enough. if (leftFinding.value != rightFinding.value) { return leftFinding.value.compare(rightFinding.value) < 0; } else { return this->NextLevelIsLeftBeforeRight(left, right); } } bool mitk::DICOMSortByTag ::NumericCompare(const mitk::DICOMDatasetAccess* left, const mitk::DICOMDatasetAccess* right, const DICOMTag& tag) const { assert(left); assert(right); const DICOMDatasetFinding leftFinding = left->GetTagValueAsString(tag); const DICOMDatasetFinding rightFinding = right->GetTagValueAsString(tag); //Doesn't care if findings are valid or not. If they are not valid, //value is empty, thats enough. double leftDouble( 0 ); double rightDouble( 0 ); try { leftDouble = OFStandard::atof( leftFinding.value.c_str() ); rightDouble = OFStandard::atof(rightFinding.value.c_str()); } catch ( const std::exception& /*e*/ ) { return this->StringCompare(left,right, tag); // fallback to string compare } if ( leftDouble != rightDouble ) // can we decide? { return leftDouble < rightDouble; } else // ask secondary criterion { return this->NextLevelIsLeftBeforeRight( left, right ); } } double mitk::DICOMSortByTag ::NumericDistance(const mitk::DICOMDatasetAccess* from, const mitk::DICOMDatasetAccess* to) const { assert(from); assert(to); const DICOMDatasetFinding fromFinding = from->GetTagValueAsString(m_Tag); const DICOMDatasetFinding toFinding = to->GetTagValueAsString(m_Tag); //Doesn't care if findings are valid or not. If they are not valid, //value is empty, thats enough. double fromDouble(0); double toDouble(0); try { fromDouble = OFStandard::atof(fromFinding.value.c_str()); toDouble = OFStandard::atof(toFinding.value.c_str()); } catch ( const std::exception& /*e*/ ) { MITK_WARN << "NO NUMERIC DISTANCE between '" << fromFinding.value << "' and '" << toFinding.value << "'"; return 0; } return toDouble - fromDouble; // TODO second-level compare? } diff --git a/Modules/DICOMReader/src/mitkDICOMTag.cpp b/Modules/DICOMReader/src/mitkDICOMTag.cpp index f3a04522de..24b054b646 100644 --- a/Modules/DICOMReader/src/mitkDICOMTag.cpp +++ b/Modules/DICOMReader/src/mitkDICOMTag.cpp @@ -1,216 +1,216 @@ /*=================================================================== 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 "mitkDICOMTag.h" #include #include #include #include "mitkLogMacros.h" -#include "ofstd.h" +#include "dcmtk/ofstd/ofstd.h" mitk::DICOMTag ::DICOMTag(unsigned int group, unsigned int element) :m_Group(group) ,m_Element(element) { } mitk::DICOMTag ::DICOMTag(const DICOMTag& other) :m_Group(other.m_Group) ,m_Element(other.m_Element) { } bool mitk::DICOMTag ::operator==(const DICOMTag& other) const { return m_Group == other.m_Group && m_Element == other.m_Element ; } mitk::DICOMTag& mitk::DICOMTag ::operator=(const DICOMTag& other) { if (this != &other) { m_Group = other.m_Group; m_Element = other.m_Element; } return *this; } unsigned int mitk::DICOMTag ::GetGroup() const { return m_Group; } unsigned int mitk::DICOMTag ::GetElement() const { return m_Element; } bool mitk::DICOMTag ::operator<(const DICOMTag& other) const { return ( this->m_Group < other.m_Group ) || ( ( this->m_Group == other.m_Group ) && ( this->m_Element < other.m_Element ) ); } std::string mitk::DICOMTag ::GetName() const { gdcm::Tag t(m_Group, m_Element); const gdcm::Global& g = gdcm::Global::GetInstance(); // sum of all knowledge ! const gdcm::Dicts& dicts = g.GetDicts(); const gdcm::Dict& pub = dicts.GetPublicDict(); // Part 6 const gdcm::DictEntry& entry = pub.GetDictEntry(t); std::string name = entry.GetName(); if (name.empty()) { name = "Unknown Tag"; } return name; } std::string mitk::DICOMTag ::toHexString(unsigned int i) const { std::stringstream ss; ss << std::setfill ('0') << std::setw(4) << std::hex << i; return ss.str(); } void mitk::DICOMTag ::Print(std::ostream& os) const { os << "(" << toHexString(m_Group) << "," << toHexString(m_Element) << ") " << this->GetName(); } void mitk::DICOMStringToOrientationVectors( const std::string& s, Vector3D& right, Vector3D& up, bool& successful ) { successful = false; try { std::vector strs; boost::split( strs, s, boost::is_any_of( "\\" ) ); if ( strs.size() == 6 ) { int i = 0; for ( ; i < 3; ++i ) { right[i] = OFStandard::atof( strs[i].c_str() ); } for ( ; i < 6; ++i ) { up[i - 3] = OFStandard::atof( strs[i].c_str() ); } successful = true; } } catch ( const std::exception& /*e*/ ) { right.Fill( 0.0 ); right[0] = 1.0; up.Fill( 0.0 ); up[1] = 1.0; successful = false; } } bool mitk::DICOMStringToSpacing(const std::string& s, ScalarType& spacingX, ScalarType& spacingY) { bool successful = false; try { std::vector strs; boost::split( strs, s, boost::is_any_of( "\\" ) ); if ( strs.size() > 1 ) { spacingY = OFStandard::atof( strs[0].c_str() ); spacingX = OFStandard::atof( strs[1].c_str() ); successful = true; } } catch ( const std::exception& /*e*/ ) { } return successful; } mitk::Point3D mitk::DICOMStringToPoint3D( const std::string& s, bool& successful ) { Point3D p; successful = true; try { std::vector strs; boost::split( strs, s, boost::is_any_of( "\\" ) ); if ( strs.size() == 3 ) { for ( int i = 0; i < 3; ++i ) { p[i] = OFStandard::atof( strs[i].c_str() ); } } } catch ( const std::exception& /*e*/ ) { p.Fill( 0.0 ); } return p; } diff --git a/Modules/DICOMReader/src/mitkITKDICOMSeriesReaderHelper.cpp b/Modules/DICOMReader/src/mitkITKDICOMSeriesReaderHelper.cpp index 8390b79d90..995c1835ad 100644 --- a/Modules/DICOMReader/src/mitkITKDICOMSeriesReaderHelper.cpp +++ b/Modules/DICOMReader/src/mitkITKDICOMSeriesReaderHelper.cpp @@ -1,458 +1,458 @@ /*=================================================================== 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. ===================================================================*/ //#define MBILOG_ENABLE_DEBUG -#include +#include #define BOOST_DATE_TIME_NO_LIB //Prevent unnecessary/unwanted auto link in this compilation when activating boost libraries in the MITK superbuild //It is necessary because BOOST_ALL_DYN_LINK overwrites BOOST_DATE_TIME_NO_LIB #if defined(BOOST_ALL_DYN_LINK) #undef BOOST_ALL_DYN_LINK #endif #include #include "mitkITKDICOMSeriesReaderHelper.h" #include "mitkITKDICOMSeriesReaderHelper.txx" #include "mitkDICOMGDCMTagScanner.h" #include "mitkArbitraryTimeGeometry.h" -#include "dcvrda.h" +#include "dcmtk/dcmdata/dcvrda.h" const mitk::DICOMTag mitk::ITKDICOMSeriesReaderHelper::AcquisitionDateTag = mitk::DICOMTag( 0x0008, 0x0022 ); const mitk::DICOMTag mitk::ITKDICOMSeriesReaderHelper::AcquisitionTimeTag = mitk::DICOMTag( 0x0008, 0x0032 ); const mitk::DICOMTag mitk::ITKDICOMSeriesReaderHelper::TriggerTimeTag = mitk::DICOMTag( 0x0018, 0x1060 ); #define switch3DCase( IOType, T ) \ case IOType: \ return LoadDICOMByITK( filenames, correctTilt, tiltInfo, io ); bool mitk::ITKDICOMSeriesReaderHelper::CanHandleFile( const std::string& filename ) { MITK_DEBUG << "ITKDICOMSeriesReaderHelper::CanHandleFile " << filename; itk::GDCMImageIO::Pointer tester = itk::GDCMImageIO::New(); return tester->CanReadFile( filename.c_str() ); } mitk::Image::Pointer mitk::ITKDICOMSeriesReaderHelper::Load( const StringContainer& filenames, bool correctTilt, const GantryTiltInformation& tiltInfo ) { if ( filenames.empty() ) { MITK_DEBUG << "Calling LoadDicomSeries with empty filename string container. Probably invalid application logic."; return nullptr; // this is not actually an error but the result is very simple } typedef itk::GDCMImageIO DcmIoType; DcmIoType::Pointer io = DcmIoType::New(); try { if ( io->CanReadFile( filenames.front().c_str() ) ) { io->SetFileName( filenames.front().c_str() ); io->ReadImageInformation(); if ( io->GetPixelType() == itk::ImageIOBase::SCALAR ) { switch ( io->GetComponentType() ) { switch3DCase(DcmIoType::UCHAR, unsigned char) switch3DCase(DcmIoType::CHAR, char) switch3DCase( DcmIoType::USHORT, unsigned short) switch3DCase(DcmIoType::SHORT, short) switch3DCase(DcmIoType::UINT, unsigned int) switch3DCase(DcmIoType::INT, int) switch3DCase( DcmIoType::ULONG, long unsigned int) switch3DCase(DcmIoType::LONG, long int) switch3DCase(DcmIoType::FLOAT, float) switch3DCase(DcmIoType::DOUBLE, double) default : MITK_ERROR << "Found unsupported DICOM scalar pixel type: (enum value) " << io->GetComponentType(); } } else if ( io->GetPixelType() == itk::ImageIOBase::RGB ) { switch ( io->GetComponentType() ) { switch3DCase(DcmIoType::UCHAR, itk::RGBPixel) switch3DCase( DcmIoType::CHAR, itk::RGBPixel) switch3DCase(DcmIoType::USHORT, itk::RGBPixel) switch3DCase(DcmIoType::SHORT, itk::RGBPixel) switch3DCase( DcmIoType::UINT, itk::RGBPixel) switch3DCase(DcmIoType::INT, itk::RGBPixel) switch3DCase(DcmIoType::ULONG, itk::RGBPixel) switch3DCase(DcmIoType::LONG, itk::RGBPixel) switch3DCase( DcmIoType::FLOAT, itk::RGBPixel) switch3DCase(DcmIoType::DOUBLE, itk::RGBPixel) default : MITK_ERROR << "Found unsupported DICOM scalar pixel type: (enum value) " << io->GetComponentType(); } } MITK_ERROR << "Unsupported DICOM pixel type"; return nullptr; } } catch ( const itk::MemoryAllocationError& e ) { MITK_ERROR << "Out of memory. Cannot load DICOM series: " << e.what(); } catch ( const std::exception& e ) { MITK_ERROR << "Error encountered when loading DICOM series:" << e.what(); } catch ( ... ) { MITK_ERROR << "Unspecified error encountered when loading DICOM series."; } return nullptr; } #define switch3DnTCase( IOType, T ) \ case IOType: \ return LoadDICOMByITK3DnT( filenamesLists, correctTilt, tiltInfo, io ); mitk::Image::Pointer mitk::ITKDICOMSeriesReaderHelper::Load3DnT( const StringContainerList& filenamesLists, bool correctTilt, const GantryTiltInformation& tiltInfo ) { if ( filenamesLists.empty() || filenamesLists.front().empty() ) { MITK_DEBUG << "Calling LoadDicomSeries with empty filename string container. Probably invalid application logic."; return nullptr; // this is not actually an error but the result is very simple } typedef itk::GDCMImageIO DcmIoType; DcmIoType::Pointer io = DcmIoType::New(); try { if ( io->CanReadFile( filenamesLists.front().front().c_str() ) ) { io->SetFileName( filenamesLists.front().front().c_str() ); io->ReadImageInformation(); if ( io->GetPixelType() == itk::ImageIOBase::SCALAR ) { switch ( io->GetComponentType() ) { switch3DnTCase(DcmIoType::UCHAR, unsigned char) switch3DnTCase(DcmIoType::CHAR, char) switch3DnTCase(DcmIoType::USHORT, unsigned short) switch3DnTCase( DcmIoType::SHORT, short) switch3DnTCase(DcmIoType::UINT, unsigned int) switch3DnTCase(DcmIoType::INT, int) switch3DnTCase(DcmIoType::ULONG, long unsigned int) switch3DnTCase(DcmIoType::LONG, long int) switch3DnTCase(DcmIoType::FLOAT, float) switch3DnTCase(DcmIoType::DOUBLE, double) default : MITK_ERROR << "Found unsupported DICOM scalar pixel type: (enum value) " << io->GetComponentType(); } } else if ( io->GetPixelType() == itk::ImageIOBase::RGB ) { switch ( io->GetComponentType() ) { switch3DnTCase(DcmIoType::UCHAR, itk::RGBPixel) switch3DnTCase(DcmIoType::CHAR, itk::RGBPixel) switch3DnTCase( DcmIoType::USHORT, itk::RGBPixel) switch3DnTCase(DcmIoType::SHORT, itk::RGBPixel) switch3DnTCase(DcmIoType::UINT, itk::RGBPixel) switch3DnTCase( DcmIoType::INT, itk::RGBPixel) switch3DnTCase(DcmIoType::ULONG, itk::RGBPixel) switch3DnTCase(DcmIoType::LONG, itk::RGBPixel) switch3DnTCase( DcmIoType::FLOAT, itk::RGBPixel) switch3DnTCase(DcmIoType::DOUBLE, itk::RGBPixel) default : MITK_ERROR << "Found unsupported DICOM scalar pixel type: (enum value) " << io->GetComponentType(); } } MITK_ERROR << "Unsupported DICOM pixel type"; return nullptr; } } catch ( const itk::MemoryAllocationError& e ) { MITK_ERROR << "Out of memory. Cannot load DICOM series: " << e.what(); } catch ( const std::exception& e ) { MITK_ERROR << "Error encountered when loading DICOM series:" << e.what(); } catch ( ... ) { MITK_ERROR << "Unspecified error encountered when loading DICOM series."; } return nullptr; } bool ConvertDICOMDateTimeString( const std::string& dateString, const std::string& timeString, OFDateTime& time ) { OFString content( timeString.c_str() ); if ( !dateString.empty() ) { content = OFString( dateString.c_str() ).append( content ); } else { // This is a workaround for DICOM data that has an AquisitionTime but no AquisitionDate. // In this case, we use the current date. That's not really nice, but is absolutely OK // as we're only interested in the time anyways... OFString currentDate; DcmDate::getCurrentDate( currentDate ); content = currentDate.append( content ); } const OFCondition result = DcmDateTime::getOFDateTimeFromString( content, time ); return result.good(); } boost::posix_time::ptime ConvertOFDateTimeToPTime( const OFDateTime& time ) { const boost::gregorian::date boostDate( time.getDate().getYear(), time.getDate().getMonth(), time.getDate().getDay() ); const boost::posix_time::time_duration boostTime = boost::posix_time::hours( time.getTime().getHour() ) + boost::posix_time::minutes( time.getTime().getMinute() ) + boost::posix_time::seconds( time.getTime().getSecond() ) + boost::posix_time::milliseconds( time.getTime().getMilliSecond() ); boost::posix_time::ptime result( boostDate, boostTime ); return result; } OFDateTime GetLowerDateTime( const OFDateTime& time1, const OFDateTime& time2 ) { OFDateTime result = time1; if ( ( time2.getDate() < time1.getDate() ) || ( ( time2.getDate() == time1.getDate() ) && ( time2.getTime() < time1.getTime() ) ) ) { result = time2; } return result; } OFDateTime GetUpperDateTime( const OFDateTime& time1, const OFDateTime& time2 ) { OFDateTime result = time1; if ( ( time2.getDate() > time1.getDate() ) || ( ( time2.getDate() == time1.getDate() ) && ( time2.getTime() > time1.getTime() ) ) ) { result = time2; } return result; } double ComputeMiliSecDuration( const OFDateTime& start, const OFDateTime& stop ) { const boost::posix_time::ptime startTime = ConvertOFDateTimeToPTime( start ); const boost::posix_time::ptime stopTime = ConvertOFDateTimeToPTime( stop ); ::boost::posix_time::time_duration duration = stopTime - startTime; return duration.total_milliseconds(); } bool mitk::ITKDICOMSeriesReaderHelper::ExtractDateTimeBoundsAndTriggerOfTimeStep( const StringContainer& filenamesOfTimeStep, DateTimeBounds& bounds, TimeBounds& triggerBounds) { DICOMGDCMTagScanner::Pointer filescanner = DICOMGDCMTagScanner::New(); filescanner->SetInputFiles(filenamesOfTimeStep); filescanner->AddTag(AcquisitionDateTag); filescanner->AddTag(AcquisitionTimeTag); filescanner->AddTag(TriggerTimeTag); filescanner->Scan(); const DICOMDatasetAccessingImageFrameList frameList = filescanner->GetFrameInfoList(); bool result = false; bool firstAq = true; bool firstTr = true; triggerBounds = TimeBounds(0.0); for (DICOMDatasetAccessingImageFrameList::const_iterator pos = frameList.cbegin(); pos != frameList.cend(); ++pos) { const std::string aqDateStr = (*pos)->GetTagValueAsString(AcquisitionDateTag).value; const std::string aqTimeStr = (*pos)->GetTagValueAsString(AcquisitionTimeTag).value; const std::string triggerTimeStr = (*pos)->GetTagValueAsString(TriggerTimeTag).value; OFDateTime aqDateTime; const bool convertAqResult = ConvertDICOMDateTimeString(aqDateStr, aqTimeStr, aqDateTime); OFBool convertTriggerResult; mitk::ScalarType triggerTime = OFStandard::atof(triggerTimeStr.c_str(), &convertTriggerResult); if (convertAqResult) { if (firstAq) { bounds[0] = aqDateTime; bounds[1] = aqDateTime; firstAq = false; } else { bounds[0] = GetLowerDateTime(bounds[0], aqDateTime); bounds[1] = GetUpperDateTime(bounds[1], aqDateTime); } result = true; } if (convertTriggerResult) { if (firstTr) { triggerBounds[0] = triggerTime; triggerBounds[1] = triggerTime; firstTr = false; } else { triggerBounds[0] = std::min(triggerBounds[0], triggerTime); triggerBounds[1] = std::max(triggerBounds[1], triggerTime); } result = true; } } return result; }; bool mitk::ITKDICOMSeriesReaderHelper::ExtractTimeBoundsOfTimeStep( const StringContainer& filenamesOfTimeStep, TimeBounds& bounds, const OFDateTime& baselineDateTime ) { DateTimeBounds aqDTBounds; TimeBounds triggerBounds; bool result = ExtractDateTimeBoundsAndTriggerOfTimeStep(filenamesOfTimeStep, aqDTBounds, triggerBounds); mitk::ScalarType lowerBound = ComputeMiliSecDuration( baselineDateTime, aqDTBounds[0] ); mitk::ScalarType upperBound = ComputeMiliSecDuration( baselineDateTime, aqDTBounds[1] ); if ( lowerBound < mitk::eps || upperBound < mitk::eps ) { lowerBound = triggerBounds[0]; upperBound = triggerBounds[1]; } bounds[0] = lowerBound; bounds[1] = upperBound; return result; }; mitk::ITKDICOMSeriesReaderHelper::TimeBoundsList mitk::ITKDICOMSeriesReaderHelper::ExtractTimeBoundsOfTimeSteps( const StringContainerList& filenamesOfTimeSteps ) { TimeBoundsList result; OFDateTime baseLine; // extract the timebounds DateTimeBounds baselineDateTimeBounds; TimeBounds triggerBounds; StringContainerList::const_iterator pos = filenamesOfTimeSteps.cbegin(); ExtractDateTimeBoundsAndTriggerOfTimeStep(*pos, baselineDateTimeBounds, triggerBounds); baseLine = baselineDateTimeBounds[0]; // timebounds for baseline is 0 TimeBounds bounds( 0.0 ); result.push_back( bounds ); // iterate over the remaining timesteps for ( ++pos; pos != filenamesOfTimeSteps.cend(); ++pos ) { TimeBounds bounds( 0.0 ); TimeBounds dateTimeBounds; // extract the timebounds relative to the baseline if ( ExtractTimeBoundsOfTimeStep( *pos, dateTimeBounds, baseLine ) ) { bounds[0] = dateTimeBounds[0]; bounds[1] = dateTimeBounds[1]; } result.push_back( bounds ); } return result; }; mitk::TimeGeometry::Pointer mitk::ITKDICOMSeriesReaderHelper::GenerateTimeGeometry( const BaseGeometry* templateGeometry, const TimeBoundsList& boundsList ) { TimeGeometry::Pointer timeGeometry; double check = 0.0; const auto boundListSize = boundsList.size(); for ( std::size_t pos = 0; pos < boundListSize; ++pos ) { check += boundsList[pos][0]; check += boundsList[pos][1]; } if ( check < mitk::eps ) { // if all bounds are zero we assume that the bounds could not be correctly determined // and as a fallback generate a time geometry in the old mitk style ProportionalTimeGeometry::Pointer newTimeGeometry = ProportionalTimeGeometry::New(); newTimeGeometry->Initialize( templateGeometry, boundListSize ); timeGeometry = newTimeGeometry.GetPointer(); } else { ArbitraryTimeGeometry::Pointer newTimeGeometry = ArbitraryTimeGeometry::New(); newTimeGeometry->ClearAllGeometries(); newTimeGeometry->ReserveSpaceForGeometries( boundListSize ); for ( std::size_t pos = 0; pos < boundListSize; ++pos ) { TimeBounds bounds = boundsList[pos]; if ( pos + 1 < boundListSize ) { //Currently we do not explicitly support "gaps" in the time coverage //thus we set the max time bound of a time step to the min time bound //of its successor. bounds[1] = boundsList[pos + 1][0]; } newTimeGeometry->AppendNewTimeStepClone(templateGeometry, bounds[0], bounds[1]); } timeGeometry = newTimeGeometry.GetPointer(); } return timeGeometry; }; diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/BrainParcellation/mitkRandomParcellationGenerator.cpp b/Modules/DiffusionImaging/Connectomics/Algorithms/BrainParcellation/mitkRandomParcellationGenerator.cpp index d33e95a353..f6cfb9e35e 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/BrainParcellation/mitkRandomParcellationGenerator.cpp +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/BrainParcellation/mitkRandomParcellationGenerator.cpp @@ -1,1189 +1,1189 @@ /*=================================================================== 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 //To sort #include //To use sqrt #include //Itk Iterators #include #include //for the use of abs() #include template mitk::RandomParcellationGenerator::RandomParcellationGenerator() : m_RandGen(ItkRngType::New()) { } //Definition of the Set-Functions template void mitk::RandomParcellationGenerator::SetImage(itk::Image * image) { m_Image = image; } template void mitk::RandomParcellationGenerator::SetNumberNodes(int numberNodes) { m_NumberNodes = numberNodes; } template void mitk::RandomParcellationGenerator::SetVariablesForMerging (int givenSizeOfSmallestRegion, int desiredNumberOfParcels, int givenSizeOfSmallestRegionBeginning) { m_GivenSizeOfSmallestRegion = givenSizeOfSmallestRegion; m_DesiredNumberOfParcels = desiredNumberOfParcels; m_GivenSizeOfSmallestRegionBeginning = givenSizeOfSmallestRegionBeginning; } template void mitk::RandomParcellationGenerator::SetBoolsForMerging(bool mergingWithNumberParcels, bool mergingWithSmallestParcel, bool justMergeSmallParcels) { m_MergingWithNumberParcels = mergingWithNumberParcels; m_MergingWithSmallestParcel = mergingWithSmallestParcel; m_JustMergeSmallParcels = justMergeSmallParcels; } //Definition of other functions //Calculates the Center of mass (COM) and m_SizeOfRegions template std::vector mitk::RandomParcellationGenerator::GetCenterOfMass( itk::ImageRegionIterator it_region, int valueOfRegion, bool getSizeOfRegions) { //Counts all tagged voxels in this region typedef itk::Image< TPixel, VImageDimension > ImageType; int currentSizeOfRegion (0); std::vector indexVoxel; std::vector centerOfMass; double xValue(0); double yValue(0); double zValue(0); for (it_region.GoToBegin(); !it_region.IsAtEnd(); ++it_region) { if(it_region.Value() == valueOfRegion) { indexVoxel.push_back(it_region.GetIndex()); currentSizeOfRegion++; } } if (getSizeOfRegions == true) { m_SizeOfRegions.push_back(currentSizeOfRegion); } xValue = 0; yValue = 0; zValue = 0; for (int i = 0; i < currentSizeOfRegion; i++) { xValue += indexVoxel[i][0]; yValue += indexVoxel[i][1]; zValue += indexVoxel[i][2]; } centerOfMass.push_back(xValue/currentSizeOfRegion); centerOfMass.push_back(yValue/currentSizeOfRegion); centerOfMass.push_back(zValue/currentSizeOfRegion); return centerOfMass; } template double mitk::RandomParcellationGenerator::GetDistance( std::vector centerOfMass, typename itk::Image< TPixel, VImageDimension >::IndexType indexNewVoxel) { double distancetemp(0); for (int i = 0; i < 3; i++) { distancetemp += (centerOfMass[i] - indexNewVoxel[i])*(centerOfMass[i] - indexNewVoxel[i]); } return sqrt(distancetemp); } template double mitk::RandomParcellationGenerator::GetDistanceVector( std::vector centerOfMass, std::vector indexNewVoxel) { double distancetemp(0); for (int i = 0; i < 3; i++) { distancetemp += (centerOfMass[i] - indexNewVoxel[i])*(centerOfMass[i] - indexNewVoxel[i]); } return sqrt(distancetemp); } template < typename TPixel, unsigned int VImageDimension > int mitk::RandomParcellationGenerator::SmallestValue (std::vector distance) { int distancemin; distancemin = distance[0]; for (std::size_t i = 1; i < distance.size(); i++) { if (distance[i] < distancemin) { distancemin = distance[i]; } } return distancemin; } template < typename TPixel, unsigned int VImageDimension > double mitk::RandomParcellationGenerator::SmallestValue (std::vector distance) { double distancemin; distancemin = distance[0]; for (std::size_t i = 1; i < distance.size(); i++) { if (distance[i] < distancemin) { distancemin = distance[i]; } } return distancemin; } template < typename TPixel, unsigned int VImageDimension > void mitk::RandomParcellationGenerator::SetAppropriateValues() { typedef itk::Image< TPixel, VImageDimension > TemplateImageType; itk::ImageRegionIterator it_image(m_Image, m_Image->GetLargestPossibleRegion()); TPixel minimumValue, maximumValue; it_image.GoToBegin(); maximumValue = minimumValue = it_image.Value(); for(it_image.GoToBegin(); !it_image.IsAtEnd(); ++it_image) { if ( it_image.Value() < minimumValue ) { minimumValue = it_image.Value(); } else { if ( it_image.Value() > maximumValue ) { maximumValue = it_image.Value(); } } } int range = int ( maximumValue - minimumValue ); //needs to be castable to int int offset = int ( minimumValue ); if ( range < 0 ) //error { return; } std::vector< std::size_t > histogram; histogram.resize( range + 1, 0 ); for(it_image.GoToBegin(); !it_image.IsAtEnd(); ++it_image) { histogram[ int ( it_image.Value() ) - offset ] += 1; } int gapCounter = 0; //this variable will be used to count the empty labels //stores how much has to be subtracted from the image to remove gaps std::vector< TPixel > subtractionStorage; subtractionStorage.resize( range + 1, 0 ); for( int index = 0; index <= range; index++ ) { if( histogram[ index ] == 0 ) { gapCounter++; //if the label is empty, increase gapCounter } else { subtractionStorage[ index ] = TPixel ( gapCounter ); } } //remove gaps from label image for(it_image.GoToBegin(); !it_image.IsAtEnd(); ++it_image) { it_image.Value() = it_image.Value() - subtractionStorage[ int ( it_image.Value() ) ]; } } template < typename TPixel, unsigned int VImageDimension > typename itk::Image< TPixel, VImageDimension >::RegionType mitk::RandomParcellationGenerator::ExtendedRegion(typename itk::Image< TPixel, VImageDimension >::RegionType chosenRegion, typename ImageType::IndexType indexChosenVoxel) { itk::Size<3> size = chosenRegion.GetSize(); itk::Index<3> start = chosenRegion.GetIndex(); std::vector greatestValues; std::vector smallestValues; for(int i = 0; i < 3; i++) { greatestValues.push_back(start[i] + size[i]); smallestValues.push_back(start[i]); } for(int i = 0; i < 3; i++) { if (indexChosenVoxel[i] == greatestValues[i]) { size[i] += 1; } if (indexChosenVoxel[i] == smallestValues[i] - 1) { start[i] -= 1; size[i] += 1; } } chosenRegion.SetSize(size); chosenRegion.SetIndex(start); return chosenRegion; } template < typename TPixel, unsigned int VImageDimension > typename itk::Image< TPixel, VImageDimension >::RegionType mitk::RandomParcellationGenerator::ExtendedRegionNotNeighbor(typename itk::Image< TPixel, VImageDimension >::RegionType chosenRegion, typename itk::Image< TPixel, VImageDimension >::RegionType smallestRegion) { itk::Size<3> sizeChosenRegion = chosenRegion.GetSize(); itk::Index<3> startChosenRegion = chosenRegion.GetIndex(); itk::Size<3> sizeSmallestRegion = smallestRegion.GetSize(); itk::Index<3> startSmallestRegion = smallestRegion.GetIndex(); //size and start of the new merged region itk::Size<3> size; itk::Index<3> start; //Calculate the size of the merged region for (int i = 0; i < 3; i++) { //Overlapping (start of ChosenRegion before start of SmallestRegion) if ((startChosenRegion[i] + (itk::IndexValueType)sizeChosenRegion[i] > startSmallestRegion[i]) && (startChosenRegion[i] <= startSmallestRegion[i])) { //Not integrated if (startSmallestRegion[i] + sizeSmallestRegion[i] > startChosenRegion[i] + sizeChosenRegion[i]) { size[i] = abs(startSmallestRegion[i] - startChosenRegion[i]) + sizeSmallestRegion[i]; } //Integrated else { size[i] = std::max(sizeChosenRegion[i], sizeSmallestRegion[i]); } } //Overlapping (start of SmallestRegion before start of ChosenRegion) if ((startSmallestRegion[i] + (itk::IndexValueType)sizeSmallestRegion[i] > startChosenRegion[i]) && (startChosenRegion[i] >= startSmallestRegion[i])) { //Not integrated if (startChosenRegion[i] + sizeChosenRegion[i] > startSmallestRegion[i] + sizeSmallestRegion[i]) { size[i] = abs(startSmallestRegion[i] - startChosenRegion[i]) + sizeChosenRegion[i]; } //Integrated else { size[i] = std::max(sizeChosenRegion[i], sizeSmallestRegion[i]); } } //No overlapping (right next to each other) if ((startChosenRegion[i] + (itk::IndexValueType)sizeChosenRegion[i] == startSmallestRegion[i]) || (startSmallestRegion[i] + (itk::IndexValueType)sizeSmallestRegion[i] == startChosenRegion[i])) { size[i] = sizeChosenRegion[i] + sizeSmallestRegion[i]; } //Isolated if ((startChosenRegion[i] + (itk::IndexValueType)sizeChosenRegion[i] < startSmallestRegion[i]) || (startSmallestRegion[i] + (itk::IndexValueType)sizeSmallestRegion[i] < startChosenRegion[i])) { if(startChosenRegion[i] + (itk::IndexValueType)sizeChosenRegion[i] < startSmallestRegion[i]) { size[i] = abs(startChosenRegion[i] - startSmallestRegion[i]) +1; } if(startSmallestRegion[i] + (itk::IndexValueType)sizeSmallestRegion[i] < startChosenRegion[i]) { size[i] = abs(startChosenRegion[i] - startSmallestRegion[i]) + sizeChosenRegion[i]; } } } //Calculate the start point of the new region, choose the smallest value respectively for (int i = 0; i < 3; i++) { start[i] = std::min(startChosenRegion[i], startSmallestRegion[i]); } chosenRegion.SetSize(size); chosenRegion.SetIndex(start); return chosenRegion; } //checks if a number is already an element of the vector template < typename TPixel, unsigned int VImageDimension > bool mitk::RandomParcellationGenerator::IsUnique (int number, std::vector vec) { for (std::size_t i = 0; i < vec.size(); i++) { if (vec[i] == number) { return false; } } return true; } template < typename TPixel, unsigned int VImageDimension > void mitk::RandomParcellationGenerator::GetRandomSeedVoxels() { typedef itk::Image< TPixel, VImageDimension > ImageType; RegionVoxelCounter counter; counter.SetImage(m_Image); counter.SetRegion(m_Image->GetLargestPossibleRegion()); int numberVoxels = counter.VoxelWithValue(1); //Create vector with unique numbers std::vector randomvector; int randomnumber; //for-loop to get (m_NumberNodes) randomly chosen seed-points for (int j = 0; j < m_NumberNodes; j++) { //m_RandGen->GetIntegerVariate() is the same as rand() but with an extended range randomnumber = m_RandGen->GetIntegerVariate() % numberVoxels +1; //Bool-function (IsUnique) if (this->IsUnique(randomnumber, randomvector)) { randomvector.push_back(randomnumber); } else { j--; } } //sorts the numbers in randomvector according to their size sort (randomvector.begin(), randomvector.end()); //assign new values to the chosen voxels and build the regions itk::Size<3> originalSize; originalSize.Fill(1); itk::Index<3> originalStart; typename ImageType::IndexType currentIndex; int valueCounter(0); int regionNumber(0); typename ImageType::RegionType tempRegion; itk::ImageRegionIterator it_image(m_Image, m_Image->GetLargestPossibleRegion()); - for (it_image.GoToBegin(); !it_image.IsAtEnd(), regionNumber < m_NumberNodes; ++it_image) + for (it_image.GoToBegin(); !it_image.IsAtEnd() && regionNumber < m_NumberNodes; ++it_image) { if (it_image.Value() >= 1) { valueCounter++; if (valueCounter == randomvector[regionNumber]) { it_image.Value() = regionNumber+3; //Build the Regions currentIndex = it_image.GetIndex(); originalStart[0] = currentIndex[0]; originalStart[1] = currentIndex[1]; originalStart[2] = currentIndex[2]; tempRegion.SetSize(originalSize); tempRegion.SetIndex(originalStart); std::pair tempPair (tempRegion, regionNumber+3); m_OddRegions.push_back(tempPair); regionNumber++; } } } } template < typename TPixel, unsigned int VImageDimension > void mitk::RandomParcellationGenerator::ParcelGrowthOverFaces() { typedef itk::Image< int, VImageDimension > IntegerImageType; typedef itk::NeighborhoodIterator< IntegerImageType > NeighborhoodIteratorType; typename NeighborhoodIteratorType::RadiusType radius; radius.Fill(1); std::pair chosenRegion; int thisRegion; typename IntegerImageType::IndexType indexChosenVoxel; std::vector distance; std::vector possibleNeighbor; int thisNeighbor; std::vector centerOfMass; typename IntegerImageType::IndexType indexNewVoxel; std::vector indexNewVoxelVector; int numberAvailableVoxels(0); bool validVoxelNotYetFound; bool checkRegionsOfOddSize(true); std::vector > * possibleRegions = nullptr; int costValue; //As long as there are still non invalid regions (of even or odd size) add a voxel to them in each iteration step while(m_OddRegions.size() != 0 || m_EvenRegions.size() != 0) { //When we change from odd to even or vice versa if (m_OddRegions.size() == 0) { checkRegionsOfOddSize = false; possibleRegions = &m_EvenRegions; } if (m_EvenRegions.size() == 0) { checkRegionsOfOddSize = true; possibleRegions = &m_OddRegions; } //All our smallest regions are contained in possibleRegions, choose one randomly and check whether we can expand it thisRegion = m_RandGen->GetIntegerVariate() % possibleRegions->size(); chosenRegion = (*possibleRegions)[thisRegion]; //Calculate Center of mass (COM) centerOfMass.clear(); itk::ImageRegionIterator it_region(m_Image, chosenRegion.first); centerOfMass = this->GetCenterOfMass(it_region, chosenRegion.second, false); numberAvailableVoxels = 0; NeighborhoodIteratorType it_neighborhood(radius, m_Image, chosenRegion.first); //Check if there are any valid voxels which we can add to our chosen region for (it_neighborhood.GoToBegin(); !it_neighborhood.IsAtEnd(); ++it_neighborhood) { if (it_neighborhood.GetCenterPixel() == chosenRegion.second) { //Now the Neighborhood of a Parcel-Voxel is available //Check if there is a valid voxel for (int k = 0; k <27; k++) { if (it_neighborhood.GetPixel(k) == 1 && (k == 4 || k == 10 || k == 12 || k == 14 || k == 16 || k == 22) ) { // Calculate the distance btw. the centerOfMass and the NewVoxel indexNewVoxel = it_neighborhood.GetIndex(k); indexNewVoxelVector.push_back(indexNewVoxel); distance.push_back(this->GetDistance(centerOfMass, indexNewVoxel)); numberAvailableVoxels++; } } } } if (numberAvailableVoxels > 0) { validVoxelNotYetFound = true; while (validVoxelNotYetFound && distance.size() > 0) { possibleNeighbor.clear(); //Find the possible neighbors with the smallest distance to the COM of the region for (std::size_t i = 0; i < distance.size(); i++) { if (distance[i] == this->SmallestValue(distance)) { possibleNeighbor.push_back(i); } } //Choose a random voxel and check if it is valid //Get the index of this voxel thisNeighbor = m_RandGen->GetIntegerVariate() % possibleNeighbor.size(); indexChosenVoxel = indexNewVoxelVector[possibleNeighbor[thisNeighbor]]; //Check if we now have to expand the region due to the possible new voxel std::pair chosenRegionChanged; chosenRegionChanged.first = this->ExtendedRegion(chosenRegion.first, indexChosenVoxel); chosenRegionChanged.second = chosenRegion.second; //Constraints CostFunctionBase costCalculator; costCalculator.SetImage(m_Image); costCalculator.SetRegion(chosenRegionChanged); costValue = costCalculator.CalculateCost(); if(costValue >= costCalculator.MaximalValue())//Constraints are fulfilled { validVoxelNotYetFound = false; chosenRegion = chosenRegionChanged; } else //Constraints are not fulfilled { validVoxelNotYetFound = true; //So we are still in the while loop distance.erase(distance.begin() + possibleNeighbor[thisNeighbor]); indexNewVoxelVector.erase(indexNewVoxelVector.begin() + possibleNeighbor[thisNeighbor]); if (distance.size() == 0) { if (checkRegionsOfOddSize == true) { m_InvalidRegions.push_back(chosenRegion); m_OddRegions.erase(m_OddRegions.begin() + thisRegion); } else { m_InvalidRegions.push_back(chosenRegion); m_EvenRegions.erase(m_EvenRegions.begin() + thisRegion); } } } } if (distance.size() > 0) { //Change the value of the new voxel itk::ImageRegionIterator it_region(m_Image, m_Image->GetLargestPossibleRegion()); it_region.SetIndex(indexChosenVoxel); it_region.Value() = chosenRegion.second; //Change from even to odd or vice versa if (checkRegionsOfOddSize == true) { m_EvenRegions.push_back(chosenRegion); m_OddRegions.erase(m_OddRegions.begin() + thisRegion); } else { m_OddRegions.push_back(chosenRegion); m_EvenRegions.erase(m_EvenRegions.begin() + thisRegion); } distance.clear(); indexNewVoxelVector.clear(); } } else { //The region can't be extended, put it into the m_InvalidRegions vector m_InvalidRegions.push_back((*possibleRegions)[thisRegion]); possibleRegions->erase(possibleRegions->begin() + thisRegion); } } } template < typename TPixel, unsigned int VImageDimension > void mitk::RandomParcellationGenerator::FillOverEdgeOrVertex() { typedef itk::Image< int, VImageDimension > IntegerImageType; typedef itk::NeighborhoodIterator< IntegerImageType > NeighborhoodIteratorType; typename NeighborhoodIteratorType::RadiusType radius; radius.Fill(1); NeighborhoodIteratorType it_neighborhood(radius, m_Image, m_Image->GetLargestPossibleRegion()); std::vector valueOfRegions; std::vector sizeOfPossibleRegions; std::vector valueOfPossibleRegions; std::vector indexInvalidRegions; std::vector indexOfPossibleInvalidRegions; std::vector distance; std::vector possibleNeighbor; typename IntegerImageType::IndexType indexNewVoxel; std::vector centerOfMass; int thisNeighbor; std::pair chosenRegion; typename IntegerImageType::IndexType indexChosenVoxel; RegionVoxelCounter wholeImageCounter; wholeImageCounter.SetImage(m_Image); wholeImageCounter.SetRegion(m_Image->GetLargestPossibleRegion()); int voxelsWithValueOne = wholeImageCounter.VoxelWithValue(1); if (voxelsWithValueOne > 0) { std::stringstream message; message << "Edge " << voxelsWithValueOne << endl; MITK_DEBUG << message.str(); for (it_neighborhood.GoToBegin(); !it_neighborhood.IsAtEnd(); ++it_neighborhood) { if (it_neighborhood.GetCenterPixel() == 1) //Found Voxel with Value 1 { m_SizeOfRegions.clear(); distance.clear(); valueOfRegions.clear(); possibleNeighbor.clear(); indexInvalidRegions.clear(); indexOfPossibleInvalidRegions.clear(); indexNewVoxel = it_neighborhood.GetIndex(); //Add this voxel to a region //first check if it shares an edge or vertex with (at least) one region for (int k = 0; k <27; k++) { if (it_neighborhood.GetPixel(k) > 2) { for (std::size_t i = 0; i < m_InvalidRegions.size(); i++) { if (it_neighborhood.GetPixel(k) == m_InvalidRegions[i].second) { valueOfRegions.push_back(m_InvalidRegions[i].second); itk::ImageRegionIterator it_region(m_Image, m_InvalidRegions[i].first); //Gets center of mass and the m_SizeOfRegions centerOfMass = this->GetCenterOfMass(it_region, m_InvalidRegions[i].second, true); distance.push_back(this->GetDistance(centerOfMass, indexNewVoxel)); indexInvalidRegions.push_back(i); break; } } } } //Minimal distance if (distance.size() != 0) { for (std::size_t i = 0; i < distance.size(); i++) { if (distance[i] == this->SmallestValue(distance)) { possibleNeighbor.push_back(i); } } distance.clear(); //Check the Size of the Regions and get the smallest one! //First get the regions with the same distance to COM for (std::size_t i = 0; i < possibleNeighbor.size(); i++) { sizeOfPossibleRegions.push_back(m_SizeOfRegions[possibleNeighbor[i]]); valueOfPossibleRegions.push_back(valueOfRegions[possibleNeighbor[i]]); indexOfPossibleInvalidRegions.push_back(indexInvalidRegions[possibleNeighbor[i]]); } possibleNeighbor.clear(); indexInvalidRegions.clear(); for (std::size_t i = 0; i < sizeOfPossibleRegions.size(); i++) { if (sizeOfPossibleRegions[i] == this->SmallestValue(sizeOfPossibleRegions)) { possibleNeighbor.push_back(i); } } sizeOfPossibleRegions.clear(); thisNeighbor = m_RandGen->GetIntegerVariate() % possibleNeighbor.size(); it_neighborhood.SetCenterPixel(valueOfPossibleRegions[thisNeighbor]); valueOfPossibleRegions.clear(); //region extansion if necessary //first we need to get the right region chosenRegion = m_InvalidRegions[indexOfPossibleInvalidRegions[thisNeighbor]]; indexChosenVoxel = it_neighborhood.GetIndex(); m_InvalidRegions[indexOfPossibleInvalidRegions[thisNeighbor]].first = this->ExtendedRegion(chosenRegion.first, indexChosenVoxel); indexOfPossibleInvalidRegions.clear(); } } } } } template < typename TPixel, unsigned int VImageDimension > void mitk::RandomParcellationGenerator::AllocateIsolatedVoxels() { typedef itk::Image< int, VImageDimension > IntegerImageType; std::vector valueOfRegions; std::vector sizeOfPossibleRegions; std::vector valueOfPossibleRegions; std::vector indexInvalidRegions; std::vector indexOfPossibleInvalidRegions; std::vector distance; std::vector possibleNeighbor; typename IntegerImageType::IndexType indexNewVoxel; std::vector centerOfMass; int thisNeighbor; std::pair chosenRegion; typename IntegerImageType::IndexType indexChosenVoxel; RegionVoxelCounter wholeImageCounter; wholeImageCounter.SetImage(m_Image); wholeImageCounter.SetRegion(m_Image->GetLargestPossibleRegion()); int voxelsWithValueOne = wholeImageCounter.VoxelWithValue(1); if (voxelsWithValueOne > 0) { std::stringstream message; message << "Isolated " << voxelsWithValueOne << endl; MITK_DEBUG << message.str(); std::vector > comOfRegions; m_SizeOfRegions.clear(); //Calculate all center of mass for (std::size_t i = 0; i < m_InvalidRegions.size(); i++) { valueOfRegions.push_back(m_InvalidRegions[i].second); itk::ImageRegionIterator it_region(m_Image, m_InvalidRegions[i].first); centerOfMass = this->GetCenterOfMass(it_region, m_InvalidRegions[i].second, true); comOfRegions.push_back(centerOfMass); } itk::ImageRegionIterator it_region(m_Image, m_Image->GetLargestPossibleRegion()); for (it_region.GoToBegin(); !it_region.IsAtEnd(); ++it_region) { if (it_region.Value() == 1) //Found Voxel with Value 1 { indexNewVoxel = it_region.GetIndex(); //distance calculation for (std::size_t j = 0; j < m_InvalidRegions.size(); j++) { distance.push_back(this->GetDistance(comOfRegions[j], indexNewVoxel)); indexInvalidRegions.push_back(j); } //Minimal distance if (distance.size() != 0) { for (std::size_t i = 0; i < distance.size(); i++) { if (distance[i] == this->SmallestValue(distance)) { possibleNeighbor.push_back(i); } } distance.clear(); //Check the Size of the Regions and get the smallest one! //First get the regions with the same distance to COM for (std::size_t i = 0; i < possibleNeighbor.size(); i++) { sizeOfPossibleRegions.push_back(m_SizeOfRegions[possibleNeighbor[i]]); valueOfPossibleRegions.push_back(valueOfRegions[possibleNeighbor[i]]); indexOfPossibleInvalidRegions.push_back(indexInvalidRegions[possibleNeighbor[i]]); } possibleNeighbor.clear(); indexInvalidRegions.clear(); for (std::size_t i = 0; i < sizeOfPossibleRegions.size(); i++) { if (sizeOfPossibleRegions[i] == this->SmallestValue(sizeOfPossibleRegions)) { possibleNeighbor.push_back(i); } } sizeOfPossibleRegions.clear(); thisNeighbor = m_RandGen->GetIntegerVariate() % possibleNeighbor.size(); it_region.Value() = valueOfPossibleRegions[thisNeighbor]; valueOfPossibleRegions.clear(); possibleNeighbor.clear(); //region extansion if necessary //first we need to get the right region chosenRegion = m_InvalidRegions[indexOfPossibleInvalidRegions[thisNeighbor]]; indexChosenVoxel = it_region.GetIndex(); RegionType voxelRegion; voxelRegion.SetIndex(indexChosenVoxel); itk::Size<3> voxelSize; voxelSize.Fill(1); voxelRegion.SetSize(voxelSize); m_InvalidRegions[indexOfPossibleInvalidRegions[thisNeighbor]].first = this->ExtendedRegionNotNeighbor(chosenRegion.first, voxelRegion); indexOfPossibleInvalidRegions.clear(); } } } } } template < typename TPixel, unsigned int VImageDimension > int mitk::RandomParcellationGenerator::MergeParcels() { typedef itk::Image< int, VImageDimension > IntegerImageType; typedef itk::NeighborhoodIterator< IntegerImageType > NeighborhoodIteratorType; typename NeighborhoodIteratorType::RadiusType radius; radius.Fill(1); //Calculate the m_SizeOfRegions this->GetSizeOfRegions(); int sizeOfSmallestRegion = this->SmallestValue(m_SizeOfRegions); std::vector smallRegions; std::vector indexSmallRegions; int thisIndex = 0; int thisSmallRegion; bool mergingStillPossible(true); std::vector smallDistances; std::vector centerOfMassPossibleRegion; std::vector > comOfRegions; std::vector sizeSmallRegions; std::vector smallestRegions; bool tooManyParcels(true); int currentNumberOfParcels = m_NumberNodes; int sizeNewParcel; std::vector costFunctionValue; std::vector smallestCostFunctionValues; std::vector valueOfPossibleRegions; std::vector distance; std::pair chosenRegion; std::vector centerOfMass; bool smallRegionFound(false); bool hasNeighbors(false); while (sizeOfSmallestRegion < m_GivenSizeOfSmallestRegion && mergingStillPossible && tooManyParcels) { smallRegions.clear(); sizeSmallRegions.clear(); smallestRegions.clear(); //Find all small Regions for (std::size_t i = 0; i < m_SizeOfRegions.size(); i++) { if (m_SizeOfRegions[i] < m_GivenSizeOfSmallestRegion) { smallRegions.push_back(i); sizeSmallRegions.push_back(m_SizeOfRegions[i]); } } //Find one of the smallest regions for (std::size_t i = 0; i < sizeSmallRegions.size(); i++) { if (sizeSmallRegions[i] == this->SmallestValue(sizeSmallRegions)) { smallestRegions.push_back(smallRegions[i]); } } if (smallestRegions.size() > 0 && this->SmallestValue(sizeSmallRegions) < m_GivenSizeOfSmallestRegionBeginning) { thisSmallRegion = rand() % smallestRegions.size(); //Choose a random small region //First check if it has direct neighbors NeighborhoodIteratorType it_neighborhood(radius, m_Image, m_InvalidRegions[smallestRegions[thisSmallRegion]].first); valueOfPossibleRegions.clear(); smallRegionFound = false; hasNeighbors = false; for (it_neighborhood.GoToBegin(); !it_neighborhood.IsAtEnd(); ++it_neighborhood) { for (int k = 0; k <27; k++) { if ((k == 4 || k == 10 || k == 12 || k == 14 || k == 16 || k == 22) &&//over faces it_neighborhood.GetPixel(k) > 2 //found value which belongs to a region != the chosen region && it_neighborhood.GetPixel(k) != m_InvalidRegions[smallestRegions[thisSmallRegion]].second) { hasNeighbors = true; for (std::size_t i = 0; i < smallRegions.size(); i++) { if (it_neighborhood.GetPixel(k) == m_InvalidRegions[smallRegions[i]].second) //The value belongs to a small region { valueOfPossibleRegions.push_back(it_neighborhood.GetPixel(k)); smallRegionFound = true; break; } } } } } if (hasNeighbors == true) { if (smallRegionFound == true)//the region has direct neighbors { //valueOfPossibleRegions may contain some values, that are the same. Erase the duplicates and sort the vector. std::sort(valueOfPossibleRegions.begin(), valueOfPossibleRegions.end()); valueOfPossibleRegions.erase(std::unique(valueOfPossibleRegions.begin(), valueOfPossibleRegions.end()), valueOfPossibleRegions.end()); indexSmallRegions.clear(); //Get the values of the possible regions! for (std::size_t i = 0; i < valueOfPossibleRegions.size() ; i++) { for (std::size_t j = 0; j < m_InvalidRegions.size(); j++) { if (valueOfPossibleRegions[i] == m_InvalidRegions[j].second) { indexSmallRegions.push_back(j); break; } } } //take the region with the greatest value of the cost function //the cost function depends on the distance (btw the 2 COMs) and the size of the merged parcel //First get all the distances itk::ImageRegionIterator it_regionSmallest(m_Image, m_InvalidRegions[smallestRegions[thisSmallRegion]].first); std::vector centerOfMassCurrentRegion = this->GetCenterOfMass(it_regionSmallest, m_InvalidRegions[smallestRegions[thisSmallRegion]].second, false); distance.clear(); for (std::size_t i = 0; i < indexSmallRegions.size(); i++) { itk::ImageRegionIterator it_region(m_Image, m_InvalidRegions[indexSmallRegions[i]].first); centerOfMassPossibleRegion = this->GetCenterOfMass(it_region, m_InvalidRegions[indexSmallRegions[i]].second, false); distance.push_back(this->GetDistanceVector(centerOfMassCurrentRegion, centerOfMassPossibleRegion)); } smallDistances.clear(); if (m_MergingWithSmallestParcel && m_JustMergeSmallParcels) { //If there are small Regions with equal distance btw the COMs choose a random one for (std::size_t i = 0; i < distance.size(); i++) { if (distance[i] == this->SmallestValue(distance)) { smallDistances.push_back(indexSmallRegions[i]); } } thisIndex = smallDistances[rand() % smallDistances.size()]; } //Calculate the cost function values if (m_MergingWithNumberParcels || (m_MergingWithSmallestParcel && !m_JustMergeSmallParcels)) { costFunctionValue.clear(); for (std::size_t i = 0; i < indexSmallRegions.size(); i++) { if (distance[i] == 0) { distance[i] = 0.01; } sizeNewParcel = (m_SizeOfRegions[smallestRegions[thisSmallRegion]] + m_SizeOfRegions[indexSmallRegions[i]]); costFunctionValue.push_back(-(1.0/distance[i]) - (1.0/sizeNewParcel)); //1, 2 or 3 at sizeNewParcel } smallestCostFunctionValues.clear(); for (std::size_t i = 0; i < indexSmallRegions.size(); i++) { if (costFunctionValue[i] == this->SmallestValue(costFunctionValue)) { smallestCostFunctionValues.push_back(indexSmallRegions[i]); } } thisIndex = smallestCostFunctionValues[rand() % smallestCostFunctionValues.size()]; } //m_InvalidRegions[thisIndex].first is the region we want to merge with our current one //Colour the small parcel like the found one for (it_regionSmallest.GoToBegin(); !it_regionSmallest.IsAtEnd(); ++it_regionSmallest) { if (it_regionSmallest.Value() == m_InvalidRegions[smallestRegions[thisSmallRegion]].second) { it_regionSmallest.Value() = m_InvalidRegions[thisIndex].second; } } //Expand the region of the new parcel if necessary! chosenRegion = m_InvalidRegions[thisIndex]; chosenRegion.first = this->ExtendedRegionNotNeighbor(chosenRegion.first, m_InvalidRegions[smallestRegions[thisSmallRegion]].first); m_InvalidRegions[thisIndex] = chosenRegion; //Erase the smallest Region from m_InvalidRegions m_InvalidRegions.erase(m_InvalidRegions.begin() + smallestRegions[thisSmallRegion]); currentNumberOfParcels--; if (currentNumberOfParcels <= m_DesiredNumberOfParcels) { tooManyParcels = false; } //m_SizeOfRegions changed, get the new one this->GetSizeOfRegions(); } else //No merging possible, erase this small region from m_InvalidRegions and from m_SizeOfRegions { m_InvalidRegions.erase(m_InvalidRegions.begin() + smallestRegions[thisSmallRegion]); currentNumberOfParcels--; m_SizeOfFinishedRegions.push_back(m_SizeOfRegions[smallestRegions[thisSmallRegion]]); m_SizeOfRegions.erase(m_SizeOfRegions.begin() + smallestRegions[thisSmallRegion]); if (currentNumberOfParcels <= m_DesiredNumberOfParcels) { tooManyParcels = false; } } } else //There are no 6-connected neighborhood-regions. Try to merge this small region to a near region (according to the Center of Mass) { comOfRegions.clear(); //Calculate the center of mass of all small regions for (std::size_t i = 0; i < smallRegions.size(); i++) { itk::ImageRegionIterator it_region(m_Image, m_InvalidRegions[smallRegions[i]].first); centerOfMass = this->GetCenterOfMass(it_region, m_InvalidRegions[smallRegions[i]].second, false); comOfRegions.push_back(centerOfMass); } //Calculate the distance between the center of mass of our small region and all other regions itk::ImageRegionIterator it_regionSmallest(m_Image, m_InvalidRegions[smallestRegions[thisSmallRegion]].first); std::vector centerOfMassCurrentRegion = this->GetCenterOfMass(it_regionSmallest, m_InvalidRegions[smallestRegions[thisSmallRegion]].second, false); distance.clear(); for (std::size_t i = 0; i < smallRegions.size(); i++) { itk::ImageRegionIterator it_region(m_Image, m_InvalidRegions[smallRegions[i]].first); centerOfMassPossibleRegion = this->GetCenterOfMass(it_region, m_InvalidRegions[smallRegions[i]].second, false); distance.push_back(this->GetDistanceVector(centerOfMassCurrentRegion, centerOfMassPossibleRegion)); } smallDistances.clear(); std::vector distanceWithoutZero = distance; for (std::size_t i = 0; i < distanceWithoutZero.size(); i++) { if (distanceWithoutZero[i] == 0) { distanceWithoutZero.erase(distanceWithoutZero.begin() + i); //Our smallestRegion is calculated too, erase the zero entry break; } } if (distanceWithoutZero.size() > 0) { //If there are small Regions with equal distance btw the COM's choose a random one for (std::size_t i = 0; i < distance.size(); i++) { if (distance[i] == this->SmallestValue(distanceWithoutZero)) { smallDistances.push_back(smallRegions[i]); } } thisIndex = smallDistances[rand() % smallDistances.size()]; //Colour the small parcel like the found one for (it_regionSmallest.GoToBegin(); !it_regionSmallest.IsAtEnd(); ++it_regionSmallest) { if (it_regionSmallest.Value() == m_InvalidRegions[smallestRegions[thisSmallRegion]].second) { it_regionSmallest.Value() = m_InvalidRegions[thisIndex].second; } } //Expand the region of the new parcel if necessary! chosenRegion = m_InvalidRegions[thisIndex]; chosenRegion.first = this->ExtendedRegionNotNeighbor(chosenRegion.first , m_InvalidRegions[smallestRegions[thisSmallRegion]].first); m_InvalidRegions[thisIndex] = chosenRegion; //Erase the smallest Region from m_InvalidRegions m_InvalidRegions.erase(m_InvalidRegions.begin() + smallestRegions[thisSmallRegion]); currentNumberOfParcels--; if (currentNumberOfParcels <= m_DesiredNumberOfParcels) { tooManyParcels = false; } //m_SizeOfRegions changed, get the new one this->GetSizeOfRegions(); } else//No merging possible, erase this small region from m_InvalidRegions and from m_SizeOfRegions { m_InvalidRegions.erase(m_InvalidRegions.begin() + smallestRegions[thisSmallRegion]); currentNumberOfParcels--; m_SizeOfFinishedRegions.push_back(m_SizeOfRegions[smallestRegions[thisSmallRegion]]); m_SizeOfRegions.erase(m_SizeOfRegions.begin() + smallestRegions[thisSmallRegion]); if (currentNumberOfParcels <= m_DesiredNumberOfParcels) { tooManyParcels = false; } } } } else //there are no parcels left to merge with { mergingStillPossible = false; } } return (m_SizeOfFinishedRegions.size() + m_SizeOfRegions.size()); } template < typename TPixel, unsigned int VImageDimension > void mitk::RandomParcellationGenerator::GetSizeOfRegions() { m_SizeOfRegions.clear(); RegionVoxelCounter voxelCounter; voxelCounter.SetImage(m_Image); for (std::size_t i = 0; i < m_InvalidRegions.size(); i++) { voxelCounter.SetRegion(m_InvalidRegions[i].first); m_SizeOfRegions.push_back(voxelCounter.VoxelWithValue(m_InvalidRegions[i].second)); } } template < typename TPixel, unsigned int VImageDimension > void mitk::RandomParcellationGenerator::ShowSizeOfRegions() { RegionVoxelCounter voxelCounter; voxelCounter.SetImage(m_Image); std::stringstream message; for (std::size_t i = 0; i < m_InvalidRegions.size(); i++) { voxelCounter.SetRegion(m_InvalidRegions[i].first); m_SizeOfRegions.push_back(voxelCounter.VoxelWithValue(m_InvalidRegions[i].second)); message << voxelCounter.VoxelWithValue(m_InvalidRegions[i].second) << " , "; } MITK_DEBUG << message.str(); } diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx index 2ecd8e5cf2..cb988e355c 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx @@ -1,485 +1,484 @@ /*=================================================================== 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 DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_CXX #define DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_CXX #include "itkDiffusionKurtosisReconstructionImageFilter.h" #include #include #include #include #include #include #include template< class TInputPixelType> static void FitSingleVoxel( const itk::VariableLengthVector< TInputPixelType > &input, const vnl_vector& bvalues, vnl_vector& result, itk::KurtosisFitConfiguration kf_config) { // check for length assert( input.Size() == bvalues.size() ); // assembly data vectors for fitting auto bvalueIter = bvalues.begin(); unsigned int unused_values = 0; while( bvalueIter != bvalues.end() ) { if( *bvalueIter < vnl_math::eps && kf_config.omit_bzero ) { ++unused_values; } ++bvalueIter; } // initialize data vectors with the estimated size (after filtering) vnl_vector fit_measurements( input.Size() - unused_values, 0 ); vnl_vector fit_bvalues( input.Size() - unused_values, 0 ); bvalueIter = bvalues.begin(); unsigned int running_index = 0; unsigned int skip_count = 0; while( bvalueIter != bvalues.end() ) { // skip b=0 if the corresponding flag is set if( ( kf_config.omit_bzero && *bvalueIter < vnl_math::eps ) // skip bvalues higher than the limit provided, if the flag is activated || ( kf_config.exclude_high_b && *bvalueIter > kf_config.b_upper_threshold ) ) { ++skip_count; } else { fit_measurements[ running_index - skip_count ] = input.GetElement(running_index); fit_bvalues[ running_index - skip_count] = *bvalueIter; } ++running_index; ++bvalueIter; } MITK_DEBUG("KurtosisFilter.FitSingleVoxel.Meas") << fit_measurements; MITK_DEBUG("KurtosisFilter.FitSingleVoxel.Bval") << fit_bvalues; // perform fit on data vectors if( kf_config.omit_bzero ) { itk::kurtosis_fit_omit_unweighted kurtosis_cost_fn( fit_measurements.size() ); // configuration kurtosis_cost_fn.set_fit_logscale( static_cast(kf_config.fit_scale) ); kurtosis_cost_fn.initialize( fit_measurements, fit_bvalues ); if( kf_config.use_K_limits) { kurtosis_cost_fn.set_K_bounds( kf_config.K_limits ); } vnl_levenberg_marquardt nonlinear_fit( kurtosis_cost_fn ); nonlinear_fit.minimize( result ); } else { itk::kurtosis_fit_lsq_function kurtosis_cost_fn( fit_measurements.size() ); // configuration kurtosis_cost_fn.set_fit_logscale( static_cast(kf_config.fit_scale) ); kurtosis_cost_fn.initialize( fit_measurements, fit_bvalues ); if( kf_config.use_K_limits) { kurtosis_cost_fn.set_K_bounds( kf_config.K_limits ); } vnl_levenberg_marquardt nonlinear_fit( kurtosis_cost_fn ); nonlinear_fit.minimize(result); } MITK_DEBUG("KurtosisFilter.FitSingleVoxel.Rslt") << result; } template< class TInputPixelType, class TOutputPixelType> itk::DiffusionKurtosisReconstructionImageFilter ::DiffusionKurtosisReconstructionImageFilter() : m_ReferenceBValue(-1), m_OmitBZero(false), m_ApplyPriorSmoothing(false), m_SmoothingSigma(1.5), m_UseKBounds( false ), m_MaxFitBValue( 3000 ), m_ScaleForFitting( STRAIGHT ) { this->m_InitialPosition = vnl_vector(3, 0); this->m_InitialPosition[2] = 1000.0; // S_0 this->m_InitialPosition[0] = 0.001; // D this->m_InitialPosition[1] = 1; // K this->m_KurtosisBounds.fill(0); // single input image this->SetNumberOfRequiredInputs(1); // two output images (D, K) this->SetNumberOfRequiredOutputs(2); typename OutputImageType::Pointer outputPtr1 = OutputImageType::New(); typename OutputImageType::Pointer outputPtr2 = OutputImageType::New(); this->SetNthOutput(0, outputPtr1.GetPointer() ); this->SetNthOutput(1, outputPtr2.GetPointer() ); } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::GenerateOutputInformation() { // first call superclass Superclass::GenerateOutputInformation(); } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::SetImageMask(MaskImageType::Pointer mask) { this->m_MaskImage = mask; } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::BeforeThreadedGenerateData() { // if we have a region set, convert it to a mask image, which is to be used as default for telling // we need to set the image anyway, so by default the mask is overall 1 if( m_MaskImage.IsNull() ) { m_MaskImage = MaskImageType::New(); m_MaskImage->SetRegions( this->GetInput()->GetLargestPossibleRegion() ); m_MaskImage->CopyInformation( this->GetInput() ); m_MaskImage->Allocate(); if( this->m_MapOutputRegion.GetNumberOfPixels() > 0 ) { m_MaskImage->FillBuffer(0); typedef itk::ImageRegionIteratorWithIndex< MaskImageType > MaskIteratorType; MaskIteratorType maskIter( this->m_MaskImage, this->m_MapOutputRegion ); maskIter.GoToBegin(); while( !maskIter.IsAtEnd() ) { maskIter.Set( 1 ); ++maskIter; } } else { m_MaskImage->FillBuffer(1); } } // apply smoothing to the input image if( this->m_ApplyPriorSmoothing ) { // filter typedefs typedef itk::DiscreteGaussianImageFilter< itk::Image, itk::Image > GaussianFilterType; typedef itk::VectorIndexSelectionCastImageFilter< InputImageType, itk::Image > IndexSelectionType; typedef itk::ComposeImageFilter< itk::Image, InputImageType > ComposeFilterType; auto vectorImage = this->GetInput(); typename IndexSelectionType::Pointer indexSelectionFilter = IndexSelectionType::New(); indexSelectionFilter->SetInput( vectorImage ); typename ComposeFilterType::Pointer vec_composer = ComposeFilterType::New(); for( unsigned int i=0; iGetVectorLength(); ++i) { typename GaussianFilterType::Pointer gaussian_filter = GaussianFilterType::New(); indexSelectionFilter->SetIndex( i ); gaussian_filter->SetInput( indexSelectionFilter->GetOutput() ); gaussian_filter->SetVariance( m_SmoothingSigma ); vec_composer->SetInput(i, gaussian_filter->GetOutput() ); gaussian_filter->Update(); } try { vec_composer->Update(); } catch(const itk::ExceptionObject &e) { mitkThrow() << "[VectorImage.GaussianSmoothing] !! Failed with ITK Exception: " << e.what(); } this->m_ProcessedInputImage = vec_composer->GetOutput(); } else { this->m_ProcessedInputImage = const_cast( this->GetInput() ); } } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::AfterThreadedGenerateData() { /* // initialize buffer to zero overall, but don't forget the requested region pointer for( unsigned int i=0; iGetNumberOfOutputs(); ++i) { typename OutputImageType::Pointer output = this->GetOutput(i); // after generating, set the buffered region to max, we have taken care about filling it with valid data in // UpdateOutputInformation, if not set, a writer (or any filter using the LargestPossibleRegion() during update may // complain about not getting the requested region output->SetBufferedRegion( output->GetLargestPossibleRegion() ); std::cout << "[DiffusionKurtosisReconstructionImageFilter.After]" << output->GetLargestPossibleRegion() << std::endl; }*/ } template< class TInputPixelType, class TOutputPixelType> typename itk::DiffusionKurtosisReconstructionImageFilter::KurtosisSnapshot itk::DiffusionKurtosisReconstructionImageFilter ::GetSnapshot(const itk::VariableLengthVector &input, GradientDirectionContainerType::Pointer gradients, float bvalue, KurtosisFitConfiguration kf_conf) { // initialize bvalues from reference value and the gradients provided on input this->SetReferenceBValue(bvalue); this->SetGradientDirections( gradients ); // call the other method return this->GetSnapshot( input, this->m_BValues, kf_conf ); } template< class TInputPixelType, class TOutputPixelType> typename itk::DiffusionKurtosisReconstructionImageFilter::KurtosisSnapshot itk::DiffusionKurtosisReconstructionImageFilter ::GetSnapshot(const itk::VariableLengthVector &input, vnl_vector bvalues, KurtosisFitConfiguration kf_conf) { // initialize vnl_vector initial_position; bool omit_bzero = kf_conf.omit_bzero; if( !omit_bzero ) { initial_position.set_size(2); initial_position[0] = this->m_InitialPosition[0]; initial_position[1] = this->m_InitialPosition[1]; } else { initial_position.set_size(3); initial_position = this->m_InitialPosition; } // fit FitSingleVoxel( input, bvalues, initial_position, kf_conf ); // assembly result snapshot KurtosisSnapshot result; result.m_D = initial_position[0]; result.m_K = initial_position[1]; if( omit_bzero ) { result.m_f = 1 - initial_position[2] / std::fmax(0.01, input.GetElement(0)); result.m_BzeroFit = initial_position[2]; } else result.m_f = 1; // assembly data vectors for fitting auto bvalueIter = bvalues.begin(); unsigned int unused_values = 0; while( bvalueIter != bvalues.end() ) { if( *bvalueIter < vnl_math::eps && omit_bzero ) { ++unused_values; } ++bvalueIter; } // initialize data vectors with the estimated size (after filtering) vnl_vector fit_measurements( input.Size() - unused_values, 0 ); vnl_vector fit_bvalues( input.Size() - unused_values, 0 ); // original data vnl_vector orig_measurements( input.Size(), 0 ); bvalueIter = bvalues.begin(); unsigned int running_index = 0; unsigned int skip_count = 0; while( bvalueIter != bvalues.end() ) { if( *bvalueIter < vnl_math::eps && omit_bzero ) { ++skip_count; } else { fit_measurements[ running_index - skip_count ] = input.GetElement(running_index); fit_bvalues[ running_index - skip_count ] = *bvalueIter; } orig_measurements[ running_index ] = input.GetElement(running_index); ++running_index; ++bvalueIter; } result.fit_bvalues = fit_bvalues; result.fit_measurements = fit_measurements; result.bvalues = bvalues; result.measurements = orig_measurements; result.m_fittedBZero = omit_bzero; return result; } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::SetGradientDirections(GradientDirectionContainerType::Pointer gradients) { if( this->m_ReferenceBValue < 0) { itkExceptionMacro( << "Specify reference b-value prior to setting the gradient directions." ); } if( gradients->Size() == 0 ) { itkExceptionMacro( << "Empty gradient directions container retrieved" ); } vnl_vector vnl_bvalues( gradients->Size(), 0 ); // initialize the b-values auto grIter = gradients->Begin(); unsigned int index = 0; while( grIter != gradients->End() ) { const double twonorm = grIter.Value().two_norm(); vnl_bvalues( index++ ) = this->m_ReferenceBValue * twonorm * twonorm; ++grIter; } this->m_BValues = vnl_bvalues; } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::SetInitialSolution(const vnl_vector& x0 ) { - unsigned int param_size = 2 + static_cast( this->m_OmitBZero ); - assert( x0.size() == param_size ); + assert( x0.size() == (2 + static_cast( this->m_OmitBZero )) ); this->m_InitialPosition = x0; } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType /*threadId*/) { typename OutputImageType::Pointer dImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); itk::ImageRegionIteratorWithIndex< OutputImageType > dImageIt(dImage, outputRegionForThread); dImageIt.GoToBegin(); typename OutputImageType::Pointer kImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(1)); itk::ImageRegionIteratorWithIndex< OutputImageType > kImageIt(kImage, outputRegionForThread); kImageIt.GoToBegin(); typedef itk::ImageRegionConstIteratorWithIndex< InputImageType > InputIteratorType; InputIteratorType inputIter( m_ProcessedInputImage, outputRegionForThread ); inputIter.GoToBegin(); typedef itk::ImageRegionConstIteratorWithIndex< MaskImageType > MaskIteratorType; MaskIteratorType maskIter( this->m_MaskImage, outputRegionForThread ); maskIter.GoToBegin(); KurtosisFitConfiguration fit_config; fit_config.omit_bzero = this->m_OmitBZero; fit_config.fit_scale = this->m_ScaleForFitting; fit_config.use_K_limits = this->m_UseKBounds; fit_config.K_limits = this->m_KurtosisBounds; vnl_vector initial_position; if( !this->m_OmitBZero ) { initial_position.set_size(2); initial_position[0] = this->m_InitialPosition[0]; initial_position[1] = this->m_InitialPosition[1]; } else { initial_position.set_size(3); initial_position = this->m_InitialPosition; } while( !inputIter.IsAtEnd() ) { // set (reset) each iteration vnl_vector result = initial_position; // fit single voxel (if inside mask ) if( maskIter.Get() > 0 ) { FitSingleVoxel( inputIter.Get(), this->m_BValues, result, fit_config ); } else { result.fill(0); } // regardless the fit type, the parameters are always in the first two position // of the results vector dImageIt.Set( result[0] ); kImageIt.Set( result[1] ); //std::cout << "[Kurtosis.Fit]" << inputIter.GetIndex() << " --> " << dImageIt.GetIndex() << " result: " << result << std::endl; ++maskIter; ++inputIter; ++dImageIt; ++kImageIt; } } #endif // guards diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.cpp b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.cpp index b67e1c2420..96cfad8def 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.cpp @@ -1,1262 +1,1262 @@ /*=================================================================== 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 __itkDiffusionMultiShellQballReconstructionImageFilter_cpp #define __itkDiffusionMultiShellQballReconstructionImageFilter_cpp #include #include #include #include namespace itk { template< class T, class TG, class TO, int L, int NODF> DiffusionMultiShellQballReconstructionImageFilter ::DiffusionMultiShellQballReconstructionImageFilter() : m_ReconstructionType(Mode_Standard1Shell), m_Interpolation_Flag(false), m_Interpolation_SHT1_inv(nullptr), m_Interpolation_SHT2_inv(nullptr), m_Interpolation_SHT3_inv(nullptr), m_TARGET_SH_shell1(nullptr), m_TARGET_SH_shell2(nullptr), m_TARGET_SH_shell3(nullptr), m_MaxDirections(0), m_CoeffReconstructionMatrix(nullptr), m_ODFSphericalHarmonicBasisMatrix(nullptr), m_GradientDirectionContainer(nullptr), m_NumberOfGradientDirections(0), m_NumberOfBaselineImages(0), m_Threshold(0), m_BZeroImage(nullptr), m_CoefficientImage(nullptr), m_BValue(1.0), m_Lambda(0.0), m_IsHemisphericalArrangementOfGradientDirections(false), m_IsArithmeticProgession(false) { // At least 1 inputs is necessary for a vector image. // For images added one at a time we need at least six this->SetNumberOfRequiredInputs( 1 ); } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::SetGradientImage(const GradientDirectionContainerType *gradientDirection , const GradientImagesType *gradientImage , float bvalue) { m_BValue = bvalue; m_NumberOfBaselineImages = 0; this->m_GradientDirectionContainer = GradientDirectionContainerType::New(); for(GradientDirectionContainerType::ConstIterator it = gradientDirection->Begin(); it != gradientDirection->End(); it++) { this->m_GradientDirectionContainer->push_back(it.Value()); } if(m_BValueMap.size() == 0){ itkWarningMacro(<< "DiffusionMultiShellQballReconstructionImageFilter.cpp : no GradientIndexMapAvalible"); GradientDirectionContainerType::ConstIterator gdcit; for( gdcit = m_GradientDirectionContainer->Begin(); gdcit != m_GradientDirectionContainer->End(); ++gdcit) { double bValueKey = int(((m_BValue * gdcit.Value().two_norm() * gdcit.Value().two_norm())+7.5)/10)*10; MITK_INFO << bValueKey; m_BValueMap[bValueKey].push_back(gdcit.Index()); } } if(m_BValueMap.find(0) == m_BValueMap.end()) { itkExceptionMacro(<< "DiffusionMultiShellQballReconstructionImageFilter.cpp : GradientIndxMap with no b-Zero indecies found: check input BValueMap"); } m_NumberOfBaselineImages = m_BValueMap[0].size(); m_NumberOfGradientDirections = gradientDirection->Size() - m_NumberOfBaselineImages; // ensure that the gradient image we received has as many components as // the number of gradient directions if( gradientImage->GetVectorLength() != m_NumberOfBaselineImages + m_NumberOfGradientDirections ) { itkExceptionMacro( << m_NumberOfGradientDirections << " gradients + " << m_NumberOfBaselineImages << "baselines = " << m_NumberOfGradientDirections + m_NumberOfBaselineImages << " directions specified but image has " << gradientImage->GetVectorLength() << " components."); } ProcessObject::SetNthInput( 0, const_cast< GradientImagesType* >(gradientImage) ); std::string gradientImageClassName(ProcessObject::GetInput(0)->GetNameOfClass()); if ( strcmp(gradientImageClassName.c_str(),"VectorImage") != 0 ) itkExceptionMacro( << "There is only one Gradient image. I expect that to be a VectorImage. But its of type: " << gradientImageClassName ); m_BZeroImage = BZeroImageType::New(); typename GradientImagesType::Pointer img = static_cast< GradientImagesType * >( ProcessObject::GetInput(0) ); m_BZeroImage->SetSpacing( img->GetSpacing() ); // Set the image spacing m_BZeroImage->SetOrigin( img->GetOrigin() ); // Set the image origin m_BZeroImage->SetDirection( img->GetDirection() ); // Set the image direction m_BZeroImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion()); m_BZeroImage->SetBufferedRegion( img->GetLargestPossibleRegion() ); m_BZeroImage->Allocate(); m_CoefficientImage = CoefficientImageType::New(); m_CoefficientImage->SetSpacing( img->GetSpacing() ); // Set the image spacing m_CoefficientImage->SetOrigin( img->GetOrigin() ); // Set the image origin m_CoefficientImage->SetDirection( img->GetDirection() ); // Set the image direction m_CoefficientImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion()); m_CoefficientImage->SetBufferedRegion( img->GetLargestPossibleRegion() ); m_CoefficientImage->Allocate(); } template void DiffusionMultiShellQballReconstructionImageFilter ::Normalize( OdfPixelType & out) { for(int i=0; i void DiffusionMultiShellQballReconstructionImageFilter ::Projection1(vnl_vector & vec, double delta) { if (delta==0){ //Clip attenuation values. If att<0 => att=0, if att>1 => att=1 for (unsigned int i=0; i=0 && vec[i]<=1)*vec[i]+(vec[i]>1); } else{ //Use function from Aganj et al, MRM, 2010 for (unsigned int i=0; i< vec.size(); i++) vec[i]=CalculateThreashold(vec[i], delta); } } template double DiffusionMultiShellQballReconstructionImageFilter ::CalculateThreashold(const double value, const double delta) { return (value<0)*(0.5*delta) + (value>=0 && value=delta && value<1-delta)*value+(value>=1-delta && value<1)*(1-0.5*delta-0.5*((1-value)*(1-value))/delta) + (value>=1)*(1-0.5*delta); } template void DiffusionMultiShellQballReconstructionImageFilter ::Projection2( vnl_vector & E1,vnl_vector & E2, vnl_vector & E3, double delta ) { const double sF = sqrt(5.0); vnl_vector vOnes(m_MaxDirections); vOnes.fill(1.0); vnl_matrix T0(m_MaxDirections, 3); vnl_matrix C(m_MaxDirections, 7); vnl_matrix A(m_MaxDirections, 7); vnl_matrix B(m_MaxDirections, 7); vnl_vector s0(m_MaxDirections); vnl_vector a0(m_MaxDirections); vnl_vector b0(m_MaxDirections); vnl_vector ta(m_MaxDirections); vnl_vector tb(m_MaxDirections); vnl_vector e(m_MaxDirections); vnl_vector m(m_MaxDirections); vnl_vector a(m_MaxDirections); vnl_vector b(m_MaxDirections); // logarithmierung aller werte in E for(unsigned int i = 0 ; i < m_MaxDirections; i++) { T0(i,0) = -log(E1(i)); T0(i,1) = -log(E2(i)); T0(i,2) = -log(E3(i)); } //T0 = -T0.apply(std::log); // Summeiere Zeilenweise über alle Shells sum = E1+E2+E3 for(unsigned int i = 0 ; i < m_MaxDirections; i++) { s0[i] = T0(i,0) + T0(i,1) + T0(i,2); } for(unsigned int i = 0; i < m_MaxDirections; i ++) { // Alle Signal-Werte auf der Ersten shell E(N,0) normiert auf s0 a0[i] = T0(i,0) / s0[i]; // Alle Signal-Werte auf der Zweiten shell E(N,1) normiert auf s0 b0[i] = T0(i,1) / s0[i]; } ta = a0 * 3.0; tb = b0 * 3.0; e = tb - (ta * 2.0); m = (tb * 2.0 ) + ta; for(unsigned int i = 0; i =1-3*(sF+2)*delta); C(i,2) = (m[i] > 3-3*sF*delta) && (-1+3*(2*sF+5)*delta= 3-3*sF*delta && e[i] >= -3 *sF * delta); C(i,4) = (2.5 + 1.5*(5+sF)*delta < m[i] && m[i] < 3-3*sF*delta && e[i] > -3*sF*delta); C(i,5) = (ta[i] <= 0.5+1.5 *(sF+1)*delta && m[i] <= 2.5 + 1.5 *(5+sF) * delta); C(i,6) = !((bool) C(i,0) ||(bool) C(i,1) ||(bool) C(i,2) ||(bool) C(i,3) ||(bool) C(i,4) ||(bool) C(i,5) ); // ~ANY(C(i,[0-5] ),2) A(i,0)=(bool)C(i,0) * a0(i); A(i,1)=(bool)C(i,1) * (1.0/3.0-(sF+2)*delta); A(i,2)=(bool)C(i,2) * (0.2+0.8*a0(i)-0.4*b0(i)-delta/sF); A(i,3)=(bool)C(i,3) * (0.2+delta/sF); A(i,4)=(bool)C(i,4) * (0.2*a0(i)+0.4*b0(i)+2*delta/sF); A(i,5)=(bool)C(i,5) * (1.0/6.0+0.5*(sF+1)*delta); A(i,6)=(bool)C(i,6) * a0(i); B(i,0)=(bool)C(i,0) * (1.0/3.0+delta); B(i,1)=(bool)C(i,1) * (1.0/3.0+delta); B(i,2)=(bool)C(i,2) * (0.4-0.4*a0(i)+0.2*b0(i)-2*delta/sF); B(i,3)=(bool)C(i,3) * (0.4-3*delta/sF); B(i,4)=(bool)C(i,4) * (0.4*a0(i)+0.8*b0(i)-delta/sF); B(i,5)=(bool)C(i,5) * (1.0/3.0+delta); B(i,6)=(bool)C(i,6) * b0(i); } for(unsigned int i = 0 ; i < m_MaxDirections; i++) { double sumA = 0; double sumB = 0; for(int j = 0 ; j < 7; j++) { sumA += A(i,j); sumB += B(i,j); } a[i] = sumA; b[i] = sumB; } for(unsigned int i = 0; i < m_MaxDirections; i++) { E1(i) = exp(-(a[i]*s0[i])); E2(i) = exp(-(b[i]*s0[i])); E3(i) = exp(-((1-a[i]-b[i])*s0[i])); } } template void DiffusionMultiShellQballReconstructionImageFilter ::Projection3( vnl_vector & A, vnl_vector & a, vnl_vector & b, double delta0) { const double s6 = sqrt(6.0); const double s15 = s6/2.0; vnl_vector delta(a.size()); delta.fill(delta0); vnl_matrix AM(a.size(), 15); vnl_matrix aM(a.size(), 15); vnl_matrix bM(a.size(), 15); vnl_matrix B(a.size(), 15); AM.set_column(0, A); AM.set_column(1, A); AM.set_column(2, A); AM.set_column(3, delta); AM.set_column(4, (A+a-b - (delta*s6))/3.0); AM.set_column(5, delta); AM.set_column(6, delta); AM.set_column(7, delta); AM.set_column(8, A); AM.set_column(9, 0.2*(a*2+A-2*(s6+1)*delta)); AM.set_column(10,0.2*(b*(-2)+A+2-2*(s6+1)*delta)); AM.set_column(11, delta); AM.set_column(12, delta); AM.set_column(13, delta); AM.set_column(14, 0.5-(1+s15)*delta); aM.set_column(0, a); aM.set_column(1, a); aM.set_column(2, -delta + 1); aM.set_column(3, a); aM.set_column(4, (A*2+a*5+b+s6*delta)/6.0); aM.set_column(5, a); aM.set_column(6, -delta + 1); aM.set_column(7, 0.5*(a+b)+(1+s15)*delta); aM.set_column(8, -delta + 1); aM.set_column(9, 0.2*(a*4+A*2+(s6+1)*delta)); aM.set_column(10, -delta + 1); aM.set_column(11, (s6+3)*delta); aM.set_column(12, -delta + 1); aM.set_column(13, -delta + 1); aM.set_column(14, -delta + 1); bM.set_column(0, b); bM.set_column(1, delta); bM.set_column(2, b); bM.set_column(3, b); bM.set_column(4, (A*(-2)+a+b*5-s6*delta)/6.0); bM.set_column(5, delta); bM.set_column(6, b); bM.set_column(7, 0.5*(a+b)-(1+s15)*delta); bM.set_column(8, delta); bM.set_column(9, delta); bM.set_column(10, 0.2*(b*4-A*2+1-(s6+1)*delta)); bM.set_column(11, delta); bM.set_column(12, delta); bM.set_column(13, -delta*(s6+3) + 1); bM.set_column(14, delta); delta0 *= 0.99; vnl_matrix R2(a.size(), 15); std::vector I(a.size()); for (unsigned int i=0; idelta0 && aM(i,j)<1-delta0) R2(i,j) = (AM(i,j)-A(i))*(AM(i,j)-A(i))+ (aM(i,j)-a(i))*(aM(i,j)-a(i))+(bM(i,j)-b(i))*(bM(i,j)-b(i)); else R2(i,j) = 1e20; } unsigned int index = 0; double minvalue = 999; for(int j = 0 ; j < 15 ; j++) { if(R2(i,j) < minvalue){ minvalue = R2(i,j); index = j; } } I[i] = index; } for (unsigned int i=0; i < A.size(); i++){ A(i) = AM(i,(int)I[i]); a(i) = aM(i,(int)I[i]); b(i) = bM(i,(int)I[i]); } } template void DiffusionMultiShellQballReconstructionImageFilter ::S_S0Normalization( vnl_vector & vec, double S0 ) { for(unsigned int i = 0; i < vec.size(); i++) { if (S0==0) S0 = 0.01; vec[i] /= S0; } } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::DoubleLogarithm(vnl_vector & vec) { for(unsigned int i = 0; i < vec.size(); i++) { vec[i] = log(-log(vec[i])); } } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::BeforeThreadedGenerateData() { m_ReconstructionType = Mode_Standard1Shell; if(m_BValueMap.size() == 4 ){ BValueMapIteraotr it = m_BValueMap.begin(); it++; // skip b0 entry const unsigned int bValue_shell1 = it->first; const unsigned int size_shell1 = it->second.size(); IndiciesVector shell1 = it->second; it++; const unsigned int bValue_shell2 = it->first; const unsigned int size_shell2 = it->second.size(); IndiciesVector shell2 = it->second; it++; const unsigned int bValue_shell3 = it->first; const unsigned int size_shell3 = it->second.size(); IndiciesVector shell3 = it->second; // arithmetic progrssion if(bValue_shell2 - bValue_shell1 == bValue_shell1 && bValue_shell3 - bValue_shell2 == bValue_shell1 ) { // check if Interpolation is needed // if shells with different numbers of directions exist m_Interpolation_Flag = false; if(size_shell1 != size_shell2 || size_shell2 != size_shell3 || size_shell1 != size_shell3) { m_Interpolation_Flag = true; MITK_INFO << "Shell interpolation: shells with different numbers of directions"; } else { // else if each shell holds same numbers of directions, but the gradient direction differ more than one 1 degree m_Interpolation_Flag = CheckForDifferingShellDirections(); if(m_Interpolation_Flag) MITK_INFO << "Shell interpolation: gradient direction differ more than one 1 degree"; } m_ReconstructionType = Mode_Analytical3Shells; if(m_Interpolation_Flag) { unsigned int interp_SHOrder_shell1 = 12; while( ((interp_SHOrder_shell1+1)*(interp_SHOrder_shell1+2)/2) > size_shell1 && interp_SHOrder_shell1 > L ) interp_SHOrder_shell1 -= 2 ; const int number_coeffs_shell1 = (int)(interp_SHOrder_shell1*interp_SHOrder_shell1 + interp_SHOrder_shell1 + 2.0)/2.0 + interp_SHOrder_shell1; unsigned int interp_SHOrder_shell2 = 12; while( ((interp_SHOrder_shell2+1)*(interp_SHOrder_shell2+2)/2) > size_shell2 && interp_SHOrder_shell2 > L ) interp_SHOrder_shell2 -= 2 ; const int number_coeffs_shell2 = (int)(interp_SHOrder_shell2*interp_SHOrder_shell2 + interp_SHOrder_shell2 + 2.0)/2.0 + interp_SHOrder_shell2; unsigned int interp_SHOrder_shell3 = 12; while( ((interp_SHOrder_shell3+1)*(interp_SHOrder_shell3+2)/2) > size_shell3 && interp_SHOrder_shell3 > L ) interp_SHOrder_shell3 -= 2 ; const int number_coeffs_shell3 = (int)(interp_SHOrder_shell3*interp_SHOrder_shell3 + interp_SHOrder_shell3 + 2.0)/2.0 + interp_SHOrder_shell3; // Create direction container for all directions (no duplicates, different directions from all shells) IndiciesVector all_directions_container = GetAllDirections(); m_MaxDirections = all_directions_container.size(); // create target SH-Basis // initialize empty target matrix and set the wanted directions vnl_matrix * Q = new vnl_matrix(3, m_MaxDirections); ComputeSphericalFromCartesian(Q, all_directions_container); // initialize a SH Basis, neede to interpolate from oldDirs -> newDirs m_TARGET_SH_shell1 = new vnl_matrix(m_MaxDirections, number_coeffs_shell1); ComputeSphericalHarmonicsBasis(Q, m_TARGET_SH_shell1, interp_SHOrder_shell1); delete Q; Q = new vnl_matrix(3, m_MaxDirections); ComputeSphericalFromCartesian(Q, all_directions_container); m_TARGET_SH_shell2 = new vnl_matrix(m_MaxDirections, number_coeffs_shell2); ComputeSphericalHarmonicsBasis(Q, m_TARGET_SH_shell2, interp_SHOrder_shell2); delete Q; Q = new vnl_matrix(3, m_MaxDirections); ComputeSphericalFromCartesian(Q, all_directions_container); m_TARGET_SH_shell3 = new vnl_matrix(m_MaxDirections, number_coeffs_shell3); ComputeSphericalHarmonicsBasis(Q, m_TARGET_SH_shell3, interp_SHOrder_shell3); delete Q; // end creat target SH-Basis // create measured-SHBasis // Shell 1 vnl_matrix * tempSHBasis; vnl_matrix_inverse * temp; // initialize empty matrix and set the measured directions of shell1 Q = new vnl_matrix(3, shell1.size()); ComputeSphericalFromCartesian(Q, shell1); // initialize a SH Basis, need to get the coeffs from measuredShell tempSHBasis = new vnl_matrix(shell1.size(), number_coeffs_shell1); ComputeSphericalHarmonicsBasis(Q, tempSHBasis, interp_SHOrder_shell1); // inversion of the SH=Basis // c_s1 = B^-1 * shell1 // interp_Values = targetSHBasis * c_s1 // Values = m_TARGET_SH_shell1 * Interpolation_SHT1_inv * DataShell1; temp = new vnl_matrix_inverse((*tempSHBasis)); m_Interpolation_SHT1_inv = new vnl_matrix(temp->inverse()); delete Q; delete temp; delete tempSHBasis; // Shell 2 Q = new vnl_matrix(3, shell2.size()); ComputeSphericalFromCartesian(Q, shell2); tempSHBasis = new vnl_matrix(shell2.size(), number_coeffs_shell2); ComputeSphericalHarmonicsBasis(Q, tempSHBasis, interp_SHOrder_shell2); temp = new vnl_matrix_inverse((*tempSHBasis)); m_Interpolation_SHT2_inv = new vnl_matrix(temp->inverse()); delete Q; delete temp; delete tempSHBasis; // Shell 3 Q = new vnl_matrix(3, shell3.size()); ComputeSphericalFromCartesian(Q, shell3); tempSHBasis = new vnl_matrix(shell3.size(), number_coeffs_shell3); ComputeSphericalHarmonicsBasis(Q, tempSHBasis, interp_SHOrder_shell3); temp = new vnl_matrix_inverse((*tempSHBasis)); m_Interpolation_SHT3_inv = new vnl_matrix(temp->inverse()); delete Q; delete temp; delete tempSHBasis; ComputeReconstructionMatrix(all_directions_container); MITK_INFO << "Reconstruction information: Multishell Reconstruction filter - Interpolation"; MITK_INFO << "Shell 1"; MITK_INFO << " SHOrder: " << interp_SHOrder_shell1; MITK_INFO << " Number of Coeffs: " << number_coeffs_shell1; MITK_INFO << " Number of Gradientdirections: " << size_shell1; MITK_INFO << "Shell 2"; MITK_INFO << " SHOrder: " << interp_SHOrder_shell2; MITK_INFO << " Number of Coeffs: " << number_coeffs_shell2; MITK_INFO << " Number of Gradientdirections: " << size_shell2; MITK_INFO << "Shell 3"; MITK_INFO << " SHOrder: " << interp_SHOrder_shell3; MITK_INFO << " Number of Coeffs: " << number_coeffs_shell3; MITK_INFO << " Number of Gradientdirections: " << size_shell3; MITK_INFO << "Overall"; MITK_INFO << " SHOrder: " << L; MITK_INFO << " Number of Coeffs: " << (L+1)*(L+2)*0.5; MITK_INFO << " Number of Gradientdirections: " << m_MaxDirections; return; }else { ComputeReconstructionMatrix(shell1); } } } if(m_BValueMap.size() > 2 && m_ReconstructionType != Mode_Analytical3Shells) { m_ReconstructionType = Mode_NumericalNShells; } if(m_BValueMap.size() == 2){ BValueMapIteraotr it = m_BValueMap.begin(); it++; // skip b0 entry IndiciesVector shell = it->second; ComputeReconstructionMatrix(shell); } } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType /*NumberOfThreads*/) { itk::TimeProbe clock; clock.Start(); switch(m_ReconstructionType) { case Mode_Standard1Shell: StandardOneShellReconstruction(outputRegionForThread); break; case Mode_Analytical3Shells: AnalyticalThreeShellReconstruction(outputRegionForThread); break; case Mode_NumericalNShells: break; } clock.Stop(); MITK_INFO << "Reconstruction in : " << clock.GetTotal() << " s"; } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::StandardOneShellReconstruction(const OutputImageRegionType& outputRegionForThread) { // Get output image pointer typename OdfImageType::Pointer outputImage = static_cast< OdfImageType * >(ProcessObject::GetPrimaryOutput()); // Get input gradient image pointer typename GradientImagesType::Pointer gradientImagePointer = static_cast< GradientImagesType * >( ProcessObject::GetInput(0) ); // ImageRegionIterator for the output image ImageRegionIterator< OdfImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); // ImageRegionIterator for the BZero (output) image ImageRegionIterator< BZeroImageType > bzeroIterator(m_BZeroImage, outputRegionForThread); bzeroIterator.GoToBegin(); // Const ImageRegionIterator for input gradient image typedef ImageRegionConstIterator< GradientImagesType > GradientIteratorType; GradientIteratorType git(gradientImagePointer, outputRegionForThread ); git.GoToBegin(); BValueMapIteraotr it = m_BValueMap.begin(); it++; // skip b0 entry IndiciesVector SignalIndicies = it->second; IndiciesVector BZeroIndicies = m_BValueMap[0]; unsigned int NumbersOfGradientIndicies = SignalIndicies.size(); typedef typename GradientImagesType::PixelType GradientVectorType; // iterate overall voxels of the gradient image region while( ! git.IsAtEnd() ) { GradientVectorType b = git.Get(); // ODF Vector OdfPixelType odf(0.0); double b0average = 0; const unsigned int b0size = BZeroIndicies.size(); for(unsigned int i = 0; i < b0size ; ++i) { b0average += b[BZeroIndicies[i]]; } b0average /= b0size; bzeroIterator.Set(b0average); ++bzeroIterator; // Create the Signal Vector vnl_vector SignalVector(NumbersOfGradientIndicies); if( (b0average != 0) && (b0average >= m_Threshold) ) { for( unsigned int i = 0; i< SignalIndicies.size(); i++ ) { SignalVector[i] = static_cast(b[SignalIndicies[i]]); } // apply threashold an generate ln(-ln(E)) signal // Replace SignalVector with PreNormalized SignalVector S_S0Normalization(SignalVector, b0average); Projection1(SignalVector); DoubleLogarithm(SignalVector); // approximate ODF coeffs vnl_vector coeffs = ( (*m_CoeffReconstructionMatrix) * SignalVector ); coeffs[0] = 1.0/(2.0*sqrt(M_PI)); odf = element_cast(( (*m_ODFSphericalHarmonicBasisMatrix) * coeffs )).data_block(); odf *= (M_PI*4/NODF); } // set ODF to ODF-Image oit.Set( odf ); ++oit; ++git; } MITK_INFO << "One Thread finished reconstruction"; } //#include "itkLevenbergMarquardtOptimizer.h" template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter -::NumericalNShellReconstruction(const OutputImageRegionType& outputRegionForThread) +::NumericalNShellReconstruction(const OutputImageRegionType& /*outputRegionForThread*/) { /* itk::LevenbergMarquardtOptimizer::Pointer optimizer = itk::LevenbergMarquardtOptimizer::New(); optimizer->SetUseCostFunctionGradient(false); // Scale the translation components of the Transform in the Optimizer itk::LevenbergMarquardtOptimizer::ScalesType scales(transform->GetNumberOfParameters()); scales.Fill(0.01); unsigned long numberOfIterations = 80000; double gradientTolerance = 1e-10; // convergence criterion double valueTolerance = 1e-10; // convergence criterion double epsilonFunction = 1e-10; // convergence criterion optimizer->SetScales( scales ); optimizer->SetNumberOfIterations( numberOfIterations ); optimizer->SetValueTolerance( valueTolerance ); optimizer->SetGradientTolerance( gradientTolerance ); optimizer->SetEpsilonFunction( epsilonFunction );*/ } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::AnalyticalThreeShellReconstruction(const OutputImageRegionType& outputRegionForThread) { // Input Gradient Image and Output ODF Image typedef typename GradientImagesType::PixelType GradientVectorType; typename OdfImageType::Pointer outputImage = static_cast< OdfImageType * >(ProcessObject::GetPrimaryOutput()); typename GradientImagesType::Pointer gradientImagePointer = static_cast< GradientImagesType * >( ProcessObject::GetInput(0) ); // Define Image iterators ImageRegionIterator< OdfImageType > odfOutputImageIterator(outputImage, outputRegionForThread); ImageRegionConstIterator< GradientImagesType > gradientInputImageIterator(gradientImagePointer, outputRegionForThread ); ImageRegionIterator< BZeroImageType > bzeroIterator(m_BZeroImage, outputRegionForThread); ImageRegionIterator< CoefficientImageType > coefficientImageIterator(m_CoefficientImage, outputRegionForThread); // All iterators seht to Begin of the specific OutputRegion coefficientImageIterator.GoToBegin(); bzeroIterator.GoToBegin(); odfOutputImageIterator.GoToBegin(); gradientInputImageIterator.GoToBegin(); // Get Shell Indicies for all non-BZero Gradients // it MUST be a arithmetic progression eg.: 1000, 2000, 3000 BValueMapIteraotr it = m_BValueMap.begin(); it++; // it = b-value = 1000 IndiciesVector Shell1Indiecies = it->second; it++; // it = b-value = 2000 IndiciesVector Shell2Indiecies = it->second; it++; // it = b-value = 3000 IndiciesVector Shell3Indiecies = it->second; IndiciesVector BZeroIndicies = m_BValueMap[0]; if(!m_Interpolation_Flag) { m_MaxDirections = Shell1Indiecies.size(); }// else: m_MaxDirection is set in BeforeThreadedGenerateData // Nx3 Signal Matrix with E(0) = Shell 1, E(1) = Shell 2, E(2) = Shell 3 vnl_vector< double > E1(m_MaxDirections); vnl_vector< double > E2(m_MaxDirections); vnl_vector< double > E3(m_MaxDirections); vnl_vector AlphaValues(m_MaxDirections); vnl_vector BetaValues(m_MaxDirections); vnl_vector LAValues(m_MaxDirections); vnl_vector PValues(m_MaxDirections); vnl_vector DataShell1(Shell1Indiecies.size()); vnl_vector DataShell2(Shell2Indiecies.size()); vnl_vector DataShell3(Shell3Indiecies.size()); vnl_matrix tempInterpolationMatrixShell1,tempInterpolationMatrixShell2,tempInterpolationMatrixShell3; if(m_Interpolation_Flag) { tempInterpolationMatrixShell1 = (*m_TARGET_SH_shell1) * (*m_Interpolation_SHT1_inv); tempInterpolationMatrixShell2 = (*m_TARGET_SH_shell2) * (*m_Interpolation_SHT2_inv); tempInterpolationMatrixShell3 = (*m_TARGET_SH_shell3) * (*m_Interpolation_SHT3_inv); } OdfPixelType odf(0.0); typename CoefficientImageType::PixelType coeffPixel(0.0); double P2,A,B2,B,P,alpha,beta,lambda, ER1, ER2; // iterate overall voxels of the gradient image region while( ! gradientInputImageIterator.IsAtEnd() ) { odf = 0.0; coeffPixel = 0.0; GradientVectorType b = gradientInputImageIterator.Get(); // calculate for each shell the corresponding b0-averages double shell1b0Norm =0; double shell2b0Norm =0; double shell3b0Norm =0; double b0average = 0; const unsigned int b0size = BZeroIndicies.size(); if(b0size == 1) { shell1b0Norm = b[BZeroIndicies[0]]; shell2b0Norm = b[BZeroIndicies[0]]; shell3b0Norm = b[BZeroIndicies[0]]; b0average = b[BZeroIndicies[0]]; }else if(b0size % 3 ==0) { for(unsigned int i = 0; i < b0size ; ++i) { if(i < b0size / 3) shell1b0Norm += b[BZeroIndicies[i]]; if(i >= b0size / 3 && i < (b0size / 3)*2) shell2b0Norm += b[BZeroIndicies[i]]; if(i >= (b0size / 3) * 2) shell3b0Norm += b[BZeroIndicies[i]]; } shell1b0Norm /= (b0size/3); shell2b0Norm /= (b0size/3); shell3b0Norm /= (b0size/3); b0average = (shell1b0Norm + shell2b0Norm+ shell3b0Norm)/3; }else { for(unsigned int i = 0; i = m_Threshold) ) { // Get the Signal-Value for each Shell at each direction (specified in the ShellIndicies Vector .. this direction corresponse to this shell...) /*//fsl fix --------------------------------------------------- for(int i = 0 ; i < Shell1Indiecies.size(); i++) DataShell1[i] = static_cast(b[Shell1Indiecies[i]]); for(int i = 0 ; i < Shell2Indiecies.size(); i++) DataShell2[i] = static_cast(b[Shell2Indiecies[i]]); for(int i = 0 ; i < Shell3Indiecies.size(); i++) DataShell3[i] = static_cast(b[Shell2Indiecies[i]]); // Normalize the Signal: Si/S0 S_S0Normalization(DataShell1, shell1b0Norm); S_S0Normalization(DataShell2, shell2b0Norm); S_S0Normalization(DataShell3, shell2b0Norm); *///fsl fix -------------------------------------------ende-- ///correct version for(unsigned int i = 0 ; i < Shell1Indiecies.size(); i++) DataShell1[i] = static_cast(b[Shell1Indiecies[i]]); for(unsigned int i = 0 ; i < Shell2Indiecies.size(); i++) DataShell2[i] = static_cast(b[Shell2Indiecies[i]]); for(unsigned int i = 0 ; i < Shell3Indiecies.size(); i++) DataShell3[i] = static_cast(b[Shell3Indiecies[i]]); // Normalize the Signal: Si/S0 S_S0Normalization(DataShell1, shell1b0Norm); S_S0Normalization(DataShell2, shell2b0Norm); S_S0Normalization(DataShell3, shell3b0Norm); if(m_Interpolation_Flag) { E1 = tempInterpolationMatrixShell1 * DataShell1; E2 = tempInterpolationMatrixShell2 * DataShell2; E3 = tempInterpolationMatrixShell3 * DataShell3; }else{ E1 = (DataShell1); E2 = (DataShell2); E3 = (DataShell3); } //Implements Eq. [19] and Fig. 4. Projection1(E1); Projection1(E2); Projection1(E3); //inqualities [31]. Taking the lograithm of th first tree inqualities //convert the quadratic inqualities to linear ones. Projection2(E1,E2,E3); for( unsigned int i = 0; i< m_MaxDirections; i++ ) { double e1 = E1.get(i); double e2 = E2.get(i); double e3 = E3.get(i); P2 = e2-e1*e1; A = (e3 -e1*e2) / ( 2* P2); B2 = A * A -(e1 * e3 - e2 * e2) /P2; B = 0; if(B2 > 0) B = sqrt(B2); P = 0; if(P2 > 0) P = sqrt(P2); alpha = A + B; beta = A - B; PValues.put(i, P); AlphaValues.put(i, alpha); BetaValues.put(i, beta); } Projection3(PValues, AlphaValues, BetaValues); for(unsigned int i = 0 ; i < m_MaxDirections; i++) { const double fac = (PValues[i] * 2 ) / (AlphaValues[i] - BetaValues[i]); lambda = 0.5 + 0.5 * std::sqrt(1 - fac * fac);; ER1 = std::fabs(lambda * (AlphaValues[i] - BetaValues[i]) + (BetaValues[i] - E1.get(i) )) + std::fabs(lambda * (AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] - E2.get(i) )) + std::fabs(lambda * (AlphaValues[i] * AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] * BetaValues[i] - E3.get(i) )); ER2 = std::fabs((1-lambda) * (AlphaValues[i] - BetaValues[i]) + (BetaValues[i] - E1.get(i) )) + std::fabs((1-lambda) * (AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] - E2.get(i) )) + std::fabs((1-lambda) * (AlphaValues[i] * AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] * BetaValues[i] - E3.get(i))); if(ER1 < ER2) LAValues.put(i, lambda); else LAValues.put(i, 1-lambda); } DoubleLogarithm(AlphaValues); DoubleLogarithm(BetaValues); vnl_vector SignalVector(element_product((LAValues) , (AlphaValues)-(BetaValues)) + (BetaValues)); vnl_vector coeffs((*m_CoeffReconstructionMatrix) *SignalVector ); // the first coeff is a fix value coeffs[0] = 1.0/(2.0*sqrt(M_PI)); coeffPixel = element_cast(coeffs).data_block(); // Cast the Signal-Type from double to float for the ODF-Image odf = element_cast( (*m_ODFSphericalHarmonicBasisMatrix) * coeffs ).data_block(); odf *= ((M_PI*4)/NODF); } // set ODF to ODF-Image coefficientImageIterator.Set(coeffPixel); odfOutputImageIterator.Set( odf ); ++odfOutputImageIterator; ++coefficientImageIterator; ++gradientInputImageIterator; } } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter:: ComputeSphericalHarmonicsBasis(vnl_matrix * QBallReference, vnl_matrix *SHBasisOutput, int LOrder , vnl_matrix* LaplaciaBaltramiOutput, vnl_vector* SHOrderAssociation, vnl_matrix* SHEigenvalues) { // MITK_INFO << *QBallReference; for(unsigned int i=0; i< (*SHBasisOutput).rows(); i++) { for(int k = 0; k <= LOrder; k += 2) { for(int m =- k; m <= k; m++) { int j = ( k * k + k + 2 ) / 2 + m - 1; // Compute SHBasisFunctions if(QBallReference){ double phi = (*QBallReference)(0,i); double th = (*QBallReference)(1,i); (*SHBasisOutput)(i,j) = mitk::sh::Yj(m,k,th,phi); } // Laplacian Baltrami Order Association if(LaplaciaBaltramiOutput) (*LaplaciaBaltramiOutput)(j,j) = k*k*(k + 1)*(k+1); // SHEigenvalues with order Accosiation kj if(SHEigenvalues) (*SHEigenvalues)(j,j) = -k* (k+1); // Order Association if(SHOrderAssociation) (*SHOrderAssociation)[j] = k; } } } } template< class T, class TG, class TO, int L, int NOdfDirections> void DiffusionMultiShellQballReconstructionImageFilter ::ComputeReconstructionMatrix(IndiciesVector const & refVector) { typedef std::unique_ptr< vnl_matrix< double> > MatrixDoublePtr; typedef std::unique_ptr< vnl_vector< int > > VectorIntPtr; typedef std::unique_ptr< vnl_matrix_inverse< double > > InverseMatrixDoublePtr; int numberOfGradientDirections = refVector.size(); if( numberOfGradientDirections <= (((L+1)*(L+2))/2) || numberOfGradientDirections < 6 ) { itkExceptionMacro( << "At least (L+1)(L+2)/2 gradient directions for each shell are required; current : " << numberOfGradientDirections ); } CheckDuplicateDiffusionGradients(); const int LOrder = L; int NumberOfCoeffs = (int)(LOrder*LOrder + LOrder + 2.0)/2.0 + LOrder; MatrixDoublePtr SHBasisMatrix(new vnl_matrix(numberOfGradientDirections,NumberOfCoeffs)); SHBasisMatrix->fill(0.0); VectorIntPtr SHOrderAssociation(new vnl_vector(NumberOfCoeffs)); SHOrderAssociation->fill(0.0); MatrixDoublePtr LaplacianBaltrami(new vnl_matrix(NumberOfCoeffs,NumberOfCoeffs)); LaplacianBaltrami->fill(0.0); MatrixDoublePtr FRTMatrix(new vnl_matrix(NumberOfCoeffs,NumberOfCoeffs)); FRTMatrix->fill(0.0); MatrixDoublePtr SHEigenvalues(new vnl_matrix(NumberOfCoeffs,NumberOfCoeffs)); SHEigenvalues->fill(0.0); MatrixDoublePtr Q(new vnl_matrix(3, numberOfGradientDirections)); // Convert Cartesian to Spherical Coordinates refVector -> Q ComputeSphericalFromCartesian(Q.get(), refVector); // SHBasis-Matrix + LaplacianBaltrami-Matrix + SHOrderAssociationVector ComputeSphericalHarmonicsBasis(Q.get() ,SHBasisMatrix.get() , LOrder , LaplacianBaltrami.get(), SHOrderAssociation.get(), SHEigenvalues.get()); // Compute FunkRadon Transformation Matrix Associated to SHBasis Order lj for(int i=0; i(((SHBasisMatrix->transpose()) * (*SHBasisMatrix)) + (m_Lambda * (*LaplacianBaltrami)))); InverseMatrixDoublePtr pseudo_inv(new vnl_matrix_inverse((*temp))); MatrixDoublePtr inverse(new vnl_matrix(NumberOfCoeffs,NumberOfCoeffs)); (*inverse) = pseudo_inv->inverse(); const double factor = (1.0/(16.0*M_PI*M_PI)); MatrixDoublePtr SignalReonstructionMatrix (new vnl_matrix((*inverse) * (SHBasisMatrix->transpose()))); m_CoeffReconstructionMatrix = new vnl_matrix(( factor * ((*FRTMatrix) * ((*SHEigenvalues) * (*SignalReonstructionMatrix))) )); // SH Basis for ODF-reconstruction vnl_matrix_fixed* U = PointShell >::DistributePointShell(); for(int i=0; i( U->as_matrix() )); m_ODFSphericalHarmonicBasisMatrix = new vnl_matrix(NOdfDirections,NumberOfCoeffs); ComputeSphericalHarmonicsBasis(tempPtr.get(), m_ODFSphericalHarmonicBasisMatrix, LOrder); } template< class T, class TG, class TO, int L, int NOdfDirections> void DiffusionMultiShellQballReconstructionImageFilter ::ComputeSphericalFromCartesian(vnl_matrix * Q, IndiciesVector const & refShell) { for(unsigned int i = 0; i < refShell.size(); i++) { double x = m_GradientDirectionContainer->ElementAt(refShell[i]).normalize().get(0); double y = m_GradientDirectionContainer->ElementAt(refShell[i]).normalize().get(1); double z = m_GradientDirectionContainer->ElementAt(refShell[i]).normalize().get(2); double cart[3]; mitk::sh::Cart2Sph(x,y,z,cart); (*Q)(0,i) = cart[0]; (*Q)(1,i) = cart[1]; (*Q)(2,i) = cart[2]; } } template< class T, class TG, class TO, int L, int NODF> bool DiffusionMultiShellQballReconstructionImageFilter ::CheckDuplicateDiffusionGradients() { bool value = false; BValueMapIteraotr mapIterator = m_BValueMap.begin(); mapIterator++; while(mapIterator != m_BValueMap.end()) { std::vector::const_iterator it1 = mapIterator->second.begin(); std::vector::const_iterator it2 = mapIterator->second.begin(); for(; it1 != mapIterator->second.end(); ++it1) { for(; it2 != mapIterator->second.end(); ++it2) { if(m_GradientDirectionContainer->ElementAt(*it1) == m_GradientDirectionContainer->ElementAt(*it2) && it1 != it2) { itkWarningMacro( << "Some of the Diffusion Gradients equal each other. Corresponding image data should be averaged before calling this filter." ); value = true; } } } ++mapIterator; } return value; } template< class T, class TG, class TO, int L, int NODF> std::vector DiffusionMultiShellQballReconstructionImageFilter ::GetAllDirections() { IndiciesVector directioncontainer; BValueMapIteraotr mapIterator = m_BValueMap.begin(); mapIterator++; IndiciesVector shell1 = mapIterator->second; mapIterator++; IndiciesVector shell2 = mapIterator->second; mapIterator++; IndiciesVector shell3 = mapIterator->second; while(shell1.size()>0) { unsigned int wntIndex = shell1.back(); shell1.pop_back(); IndiciesVector::iterator containerIt = directioncontainer.begin(); bool directionExist = false; while(containerIt != directioncontainer.end()) { if (fabs(dot(m_GradientDirectionContainer->ElementAt(*containerIt), m_GradientDirectionContainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { directioncontainer.push_back(wntIndex); } } while(shell2.size()>0) { unsigned int wntIndex = shell2.back(); shell2.pop_back(); IndiciesVector::iterator containerIt = directioncontainer.begin(); bool directionExist = false; while(containerIt != directioncontainer.end()) { if (fabs(dot(m_GradientDirectionContainer->ElementAt(*containerIt), m_GradientDirectionContainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { directioncontainer.push_back(wntIndex); } } while(shell3.size()>0) { unsigned int wntIndex = shell3.back(); shell3.pop_back(); IndiciesVector::iterator containerIt = directioncontainer.begin(); bool directionExist = false; while(containerIt != directioncontainer.end()) { if (fabs(dot(m_GradientDirectionContainer->ElementAt(*containerIt), m_GradientDirectionContainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { directioncontainer.push_back(wntIndex); } } return directioncontainer; } // corresponding directions between shells (e.g. dir1_shell1 vs dir1_shell2) differ more than 1 degree. template< class T, class TG, class TO, int L, int NODF> bool DiffusionMultiShellQballReconstructionImageFilter ::CheckForDifferingShellDirections() { bool interp_flag = false; BValueMapIteraotr mapIterator = m_BValueMap.begin(); mapIterator++; IndiciesVector shell1 = mapIterator->second; mapIterator++; IndiciesVector shell2 = mapIterator->second; mapIterator++; IndiciesVector shell3 = mapIterator->second; for (unsigned int i=0; i< shell1.size(); i++) if (fabs(dot(m_GradientDirectionContainer->ElementAt(shell1[i]), m_GradientDirectionContainer->ElementAt(shell2[i]))) <= 0.9998) {interp_flag=true; break;} for (unsigned int i=0; i< shell1.size(); i++) if (fabs(dot(m_GradientDirectionContainer->ElementAt(shell1[i]), m_GradientDirectionContainer->ElementAt(shell3[i]))) <= 0.9998) {interp_flag=true; break;} for (unsigned int i=0; i< shell1.size(); i++) if (fabs(dot(m_GradientDirectionContainer->ElementAt(shell2[i]), m_GradientDirectionContainer->ElementAt(shell3[i]))) <= 0.9998) {interp_flag=true; break;} return interp_flag; } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { std::locale C("C"); std::locale originalLocale = os.getloc(); os.imbue(C); Superclass::PrintSelf(os,indent); //os << indent << "OdfReconstructionMatrix: " << m_ReconstructionMatrix << std::endl; if ( m_GradientDirectionContainer ) { os << indent << "GradientDirectionContainer: " << m_GradientDirectionContainer << std::endl; } else { os << indent << "GradientDirectionContainer: (Gradient directions not set)" << std::endl; } os << indent << "NumberOfGradientDirections: " << m_NumberOfGradientDirections << std::endl; os << indent << "NumberOfBaselineImages: " << m_NumberOfBaselineImages << std::endl; os << indent << "Threshold for reference B0 image: " << m_Threshold << std::endl; os << indent << "BValue: " << m_BValue << std::endl; os.imbue( originalLocale ); } } #endif // __itkDiffusionMultiShellQballReconstructionImageFilter_cpp diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Registration/mitkPyramidImageRegistrationMethod.h b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Registration/mitkPyramidImageRegistrationMethod.h index 13d73a9cdd..83ab77bb4b 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Registration/mitkPyramidImageRegistrationMethod.h +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Registration/mitkPyramidImageRegistrationMethod.h @@ -1,341 +1,343 @@ /*=================================================================== 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 MITKPYRAMIDIMAGEREGISTRATION_H #define MITKPYRAMIDIMAGEREGISTRATION_H #include #include #include "itkImageMaskSpatialObject.h" #include "itkNotImageFilter.h" #include +#include + #include #include "mitkImage.h" #include "mitkBaseProcess.h" #include "mitkPyramidRegistrationMethodHelper.h" #include #include "mitkImageToItk.h" #include "mitkImageCast.h" #include "mitkImageCaster.h" #include "mitkITKImageImport.h" #include "mitkIOUtil.h" namespace mitk { /** * @brief The PyramidImageRegistration class implements a multi-scale registration method * * The PyramidImageRegistration class is suitable for aligning (f.e.) brain MR images. The method offers two * transform types * - Rigid: optimizing translation and rotation only and * - Affine ( default ): with scaling in addition ( 12 DOF ) * * The error metric is internally chosen based on the selected task type : \sa SetCrossModalityOn * * It uses * - MattesMutualInformation for CrossModality=on ( default ) and * - NormalizedCorrelation for CrossModality=off. */ class MITKDIFFUSIONCORE_EXPORT PyramidImageRegistrationMethod : public itk::Object { public: /** Typedefs */ mitkClassMacroItkParent(PyramidImageRegistrationMethod, itk::Object) /** Smart pointer support */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) typedef itk::OptimizerParameters ParametersType; /** Typedef for the transformation matrix, corresponds to the InternalMatrixType from ITK transforms */ typedef vnl_matrix_fixed< double, 3, 3> TransformMatrixType; typedef itk::AffineTransform< double > AffineTransformType; typedef itk::Euler3DTransform< double > RigidTransformType; /** Registration is between modalities - will take MattesMutualInformation as error metric */ void SetCrossModalityOn() { m_CrossModalityRegistration = true; } /** Registration is between modalities - will take NormalizedCorrelation as error metric */ void SetCrossModalityOff() { m_CrossModalityRegistration = false; } /** Turn the cross-modality on/off */ void SetCrossModality(bool flag) { if( flag ) this->SetCrossModalityOn(); else this->SetCrossModalityOff(); } /** Controll the verbosity of the registration output * * for true, each iteration step of the optimizer is watched and passed to the std::cout */ void SetVerbose(bool flag) { if( flag ) this->SetVerboseOn(); else this->SetVerboseOff(); } /** Turn verbosity on, \sa SetVerbose */ void SetVerboseOn() { m_Verbose = true; } /** Turn verbosity off, \sa SetVerbose */ void SetVerboseOff() { m_Verbose = false; } /** A rigid ( 6dof : translation + rotation ) transform is optimized */ void SetTransformToRigid() { m_UseAffineTransform = false; } /** An affine ( 12dof : Rigid + scale + skew ) transform is optimized */ void SetTransformToAffine() { m_UseAffineTransform = true; } /** Input image, the reference one */ void SetFixedImage( mitk::Image::Pointer ); /** Input image, the one to be transformed */ void SetMovingImage( mitk::Image::Pointer ); /** Fixed image mask, excludes the masked voxels from the registration metric*/ void SetFixedImageMask( mitk::Image::Pointer mask); /** \brief Use the itk::CenteredVersorTransformInitializer to perform initialization step for the registration * * The initializer takes the geometries and their features to perform an initialization for the successive registration */ void SetInitializeByGeometry(bool flag) { m_InitializeByGeometry = flag; } void Update(); /** * @brief Get the number of parameters optimized ( 12 or 6 ) * * @return number of paramters */ unsigned int GetNumberOfParameters() { unsigned int retValue = 12; if(!m_UseAffineTransform) retValue = 6; return retValue; } /** * @brief Copies the estimated parameters to the given array * @param paramArray, target array for copy, make sure to allocate enough space */ void GetParameters( double* paramArray) { if( m_EstimatedParameters == nullptr ) { mitkThrow() << "No parameters were estimated yet, call Update() first."; } unsigned int dim = 12; if( !m_UseAffineTransform ) dim = 6; for( unsigned int i=0; i * * It returns identity if the internal parameters are not-yet allocated ( i.e. the filter did not run yet ) * * @return \sa TransformMatrixType */ TransformMatrixType GetLastRotationMatrix(); protected: PyramidImageRegistrationMethod(); ~PyramidImageRegistrationMethod(); /** Fixed image, used as reference for registration */ mitk::Image::Pointer m_FixedImage; /** Moving image, will be transformed */ mitk::Image::Pointer m_MovingImage; mitk::Image::Pointer m_FixedImageMask; bool m_CrossModalityRegistration; bool m_UseAffineTransform; bool m_UseWindowedSincInterpolator; bool m_UseNearestNeighborInterpolator; bool m_UseMask; double* m_EstimatedParameters; ParametersType m_InitialParameters; /** Control the verbosity of the regsitistration output */ bool m_Verbose; bool m_InitializeByGeometry; /** * @brief The method takes two itk::Images and performs a multi-scale registration on them * * Can be accessed by the AccessTwoImagesFixedDimensionByItk macro. * * @note Currently the access is currently reduced only for short and float ( the only types occuring with mitk::DiffusionImage ) and * hence the method is accessed by means of the \sa AccessTwoImagesFixedDimensionTypeSubsetByItk macro. */ template void RegisterTwoImagesV4(itk::Image* itkImage1, itk::Image* itkImage2); /** * @brief ResampleMitkImage applies the functionality of an the itk::ResampleImageFilter to the given * mitk::Image. * * The API of the function is conform to the interface of \sa AccessByItk_1 macros. */ template< typename TPixel, unsigned int VDimension> void ResampleMitkImage( itk::Image* itkImage, mitk::Image::Pointer& outputImage ); }; } // end namespace #endif // MITKPYRAMIDIMAGEREGISTRATION_H diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.h index c4a7b68b95..07a62a7216 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.h @@ -1,221 +1,221 @@ /*=================================================================== 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 __itkMLBSTrackingFilter_h_ #define __itkMLBSTrackingFilter_h_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace itk{ /** * \brief Performs streamline tracking on the input image. Depending on the tracking handler this can be a tensor, peak or machine learning based tracking. */ class MITKFIBERTRACKING_EXPORT StreamlineTrackingFilter : public ProcessObject { public: typedef StreamlineTrackingFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ProcessObject Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(MLBSTrackingFilter, ImageToImageFilter) typedef itk::Image ItkUcharImgType; typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkFloatImgType; typedef vtkSmartPointer< vtkPolyData > PolyDataType; typedef std::deque< itk::Point > FiberType; typedef std::vector< FiberType > BundleType; volatile bool m_PauseTracking; bool m_AbortTracking; bool m_BuildFibersFinished; int m_BuildFibersReady; volatile bool m_Stop; mitk::PointSet::Pointer m_SamplingPointset; mitk::PointSet::Pointer m_StopVotePointset; mitk::PointSet::Pointer m_AlternativePointset; void SetStepSize(float v) ///< Integration step size in voxels, default is 0.5 * voxel { m_StepSizeVox = v; } void SetAngularThreshold(float v) ///< Angular threshold per step (in degree), default is 90deg x stepsize { m_AngularThresholdDeg = v; } void SetSamplingDistance(float v) ///< Maximum distance of sampling points in voxels, default is 0.25 * voxel { m_SamplingDistanceVox = v; } itkGetMacro( OutputProbabilityMap, ItkDoubleImgType::Pointer) ///< Output probability map itkGetMacro( FiberPolyData, PolyDataType ) ///< Output fibers itkGetMacro( UseOutputProbabilityMap, bool) itkSetMacro( SeedImage, ItkUcharImgType::Pointer) ///< Seeds are only placed inside of this mask. itkSetMacro( MaskImage, ItkUcharImgType::Pointer) ///< Tracking is only performed inside of this mask image. itkSetMacro( TissueImage, ItkUcharImgType::Pointer) ///< itkSetMacro( SeedsPerVoxel, int) ///< One seed placed in the center of each voxel or multiple seeds randomly placed inside each voxel. itkSetMacro( MinTractLength, float ) ///< Shorter tracts are discarded. itkSetMacro( MaxTractLength, float ) ///< Streamline progression stops if tract is longer than specified. itkSetMacro( UseStopVotes, bool ) ///< Frontal sampling points can vote for stopping the streamline even if the remaining sampling points keep pushing itkSetMacro( OnlyForwardSamples, bool ) ///< Don't use sampling points behind the current position in progression direction itkSetMacro( DeflectionMod, float ) ///< Deflection distance modifier itkSetMacro( StoppingRegions, ItkUcharImgType::Pointer) ///< Streamlines entering a stopping region will stop immediately itkSetMacro( DemoMode, bool ) itkSetMacro( SeedOnlyGm, bool ) ///< place seed points only in the gray matter itkSetMacro( ControlGmEndings, bool ) ///< itkSetMacro( NumberOfSamples, unsigned int ) ///< Number of neighborhood sampling points itkSetMacro( AposterioriCurvCheck, bool ) ///< Checks fiber curvature (angular deviation across 5mm) is larger than 30°. If yes, the streamline progression is stopped. itkSetMacro( AvoidStop, bool ) ///< Use additional sampling points to avoid premature streamline termination itkSetMacro( RandomSampling, bool ) ///< If true, the sampling points are distributed randomly around the current position, not sphericall in the specified sampling distance. itkSetMacro( NumPreviousDirections, unsigned int ) ///< How many "old" steps do we want to consider in our decision where to go next? - itkSetMacro( MaxNumTracts, unsigned int ) ///< Tracking is stopped if the maximum number of tracts is exceeded + itkSetMacro( MaxNumTracts, int ) ///< Tracking is stopped if the maximum number of tracts is exceeded itkSetMacro( Random, bool ) ///< If true, seedpoints are shuffled randomly before tracking itkSetMacro( Verbose, bool ) ///< If true, output tracking progress (might be slower) itkSetMacro( UseOutputProbabilityMap, bool) ///< If true, no tractogram but a probability map is created as output. itkSetMacro( StopTracking, bool ) ///< Use manually defined points in physical space as seed points instead of seed image void SetSeedPoints( const std::vector< itk::Point >& sP) { m_SeedPoints = sP; } void SetTrackingHandler( mitk::TrackingDataHandler* h ) ///< { m_TrackingHandler = h; } virtual void Update() override{ this->GenerateData(); } std::string GetStatusText(); protected: void GenerateData() override; StreamlineTrackingFilter(); ~StreamlineTrackingFilter() {} void InitGrayMatterEndings(); void CheckFiberForGmEnding(FiberType* fib); void FiberToProbmap(FiberType* fib); void GetSeedPointsFromSeedImage(); void CalculateNewPosition(itk::Point& pos, vnl_vector_fixed& dir); ///< Calculate next integration step. float FollowStreamline(itk::Point start_pos, vnl_vector_fixed dir, FiberType* fib, float tractLength, bool front); ///< Start streamline in one direction. bool IsValidPosition(const itk::Point& pos); ///< Are we outside of the mask image? bool IsInGm(const itk::Point &pos); vnl_vector_fixed GetNewDirection(itk::Point& pos, std::deque< vnl_vector_fixed >& olddirs, itk::Index<3>& oldIndex); ///< Determine new direction by sample voting at the current position taking the last progression direction into account. std::vector< vnl_vector_fixed > CreateDirections(int NPoints); void BeforeTracking(); void AfterTracking(); PolyDataType m_FiberPolyData; vtkSmartPointer m_Points; vtkSmartPointer m_Cells; BundleType m_Tractogram; BundleType m_GmStubs; ItkUcharImgType::Pointer m_StoppingRegions; ItkUcharImgType::Pointer m_SeedImage; ItkUcharImgType::Pointer m_MaskImage; ItkUcharImgType::Pointer m_TissueImage; ItkDoubleImgType::Pointer m_OutputProbabilityMap; float m_AngularThresholdDeg; float m_StepSizeVox; float m_SamplingDistanceVox; float m_AngularThreshold; float m_StepSize; int m_MaxLength; float m_MinTractLength; float m_MaxTractLength; int m_SeedsPerVoxel; bool m_AvoidStop; bool m_RandomSampling; float m_SamplingDistance; float m_DeflectionMod; bool m_OnlyForwardSamples; bool m_UseStopVotes; unsigned int m_NumberOfSamples; unsigned int m_NumPreviousDirections; int m_WmLabel; int m_GmLabel; bool m_SeedOnlyGm; bool m_ControlGmEndings; int m_MaxNumTracts; bool m_Verbose; bool m_AposterioriCurvCheck; bool m_DemoMode; bool m_Random; bool m_UseOutputProbabilityMap; std::vector< itk::Point > m_SeedPoints; unsigned int m_CurrentTracts; unsigned int m_Progress; bool m_StopTracking; void BuildFibers(bool check); int CheckCurvature(FiberType* fib, bool front); // decision forest mitk::TrackingDataHandler* m_TrackingHandler; std::vector< PolyDataType > m_PolyDataContainer; std::chrono::time_point m_StartTime; std::chrono::time_point m_EndTime; private: }; } //#ifndef ITK_MANUAL_INSTANTIATION //#include "itkMLBSTrackingFilter.cpp" //#endif #endif //__itkMLBSTrackingFilter_h_ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp index c458671d01..ab570096a5 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp @@ -1,414 +1,414 @@ #include "itkTractsToVectorImageFilter.h" // VTK #include #include #include // ITK #include #include // misc #define _USE_MATH_DEFINES #include #include namespace itk{ -static bool CompareVectorLengths(const vnl_vector_fixed< double, 3 >& v1, const vnl_vector_fixed< double, 3 >& v2) +static inline bool CompareVectorLengths(const vnl_vector_fixed< double, 3 >& v1, const vnl_vector_fixed< double, 3 >& v2) { return (v1.magnitude()>v2.magnitude()); } template< class PixelType > TractsToVectorImageFilter< PixelType >::TractsToVectorImageFilter(): m_AngularThreshold(0.7), m_Epsilon(0.999), m_NormalizeVectors(false), m_UseWorkingCopy(true), m_MaxNumDirections(3), m_SizeThreshold(0.3), m_CreateDirectionImages(true) { this->SetNumberOfRequiredOutputs(1); } template< class PixelType > TractsToVectorImageFilter< PixelType >::~TractsToVectorImageFilter() { } template< class PixelType > vnl_vector_fixed TractsToVectorImageFilter< PixelType >::GetVnlVector(double point[]) { vnl_vector_fixed vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } template< class PixelType > itk::Point TractsToVectorImageFilter< PixelType >::GetItkPoint(double point[]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } template< class PixelType > void TractsToVectorImageFilter< PixelType >::GenerateData() { mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry(); // calculate new image parameters itk::Vector spacing3; itk::Point origin3; itk::Matrix direction3; ImageRegion<3> imageRegion3; if (!m_MaskImage.IsNull()) { spacing3 = m_MaskImage->GetSpacing(); imageRegion3 = m_MaskImage->GetLargestPossibleRegion(); origin3 = m_MaskImage->GetOrigin(); direction3 = m_MaskImage->GetDirection(); } else { spacing3 = geometry->GetSpacing(); origin3 = geometry->GetOrigin(); mitk::BaseGeometry::BoundsArrayType bounds = geometry->GetBounds(); origin3[0] += bounds.GetElement(0); origin3[1] += bounds.GetElement(2); origin3[2] += bounds.GetElement(4); for (int i=0; i<3; i++) for (int j=0; j<3; j++) direction3[j][i] = geometry->GetMatrixColumn(i)[j]; imageRegion3.SetSize(0, geometry->GetExtent(0)+1); imageRegion3.SetSize(1, geometry->GetExtent(1)+1); imageRegion3.SetSize(2, geometry->GetExtent(2)+1); m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( spacing3 ); m_MaskImage->SetOrigin( origin3 ); m_MaskImage->SetDirection( direction3 ); m_MaskImage->SetRegions( imageRegion3 ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } OutputImageType::RegionType::SizeType outImageSize = imageRegion3.GetSize(); m_OutImageSpacing = m_MaskImage->GetSpacing(); m_ClusteredDirectionsContainer = ContainerType::New(); // initialize num directions image m_NumDirectionsImage = ItkUcharImgType::New(); m_NumDirectionsImage->SetSpacing( spacing3 ); m_NumDirectionsImage->SetOrigin( origin3 ); m_NumDirectionsImage->SetDirection( direction3 ); m_NumDirectionsImage->SetRegions( imageRegion3 ); m_NumDirectionsImage->Allocate(); m_NumDirectionsImage->FillBuffer(0); itk::Vector spacing4; itk::Point origin4; itk::Matrix direction4; itk::ImageRegion<4> imageRegion4; spacing4[0] = spacing3[0]; spacing4[1] = spacing3[1]; spacing4[2] = spacing3[2]; spacing4[3] = 1; origin4[0] = origin3[0]; origin4[1] = origin3[1]; origin4[2] = origin3[2]; origin3[3] = 0; for (int r=0; r<3; r++) for (int c=0; c<3; c++) direction4[r][c] = direction3[r][c]; direction4[3][3] = 1; imageRegion4.SetSize(0, imageRegion3.GetSize()[0]); imageRegion4.SetSize(1, imageRegion3.GetSize()[1]); imageRegion4.SetSize(2, imageRegion3.GetSize()[2]); imageRegion4.SetSize(3, m_MaxNumDirections*3); m_DirectionImage = ItkDirectionImageType::New(); m_DirectionImage->SetSpacing( spacing4 ); m_DirectionImage->SetOrigin( origin4 ); m_DirectionImage->SetDirection( direction4 ); m_DirectionImage->SetRegions( imageRegion4 ); m_DirectionImage->Allocate(); m_DirectionImage->FillBuffer(0.0); // resample fiber bundle double minSpacing = 1; if(m_OutImageSpacing[0]GetDeepCopy(); // resample fiber bundle for sufficient voxel coverage m_FiberBundle->ResampleLinear(minSpacing/10); // iterate over all fibers vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); int numFibers = m_FiberBundle->GetNumFibers(); m_DirectionsContainer = ContainerType::New(); VectorContainer< unsigned int, std::vector< double > >::Pointer peakLengths = VectorContainer< unsigned int, std::vector< double > >::New(); MITK_INFO << "Generating directions from tractogram"; boost::progress_display disp(numFibers); for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints<2) continue; vnl_vector_fixed dir; itk::Point worldPos; vnl_vector v; float fiberWeight = m_FiberBundle->GetFiberWeight(i); for( int j=0; jGetPoint(j); worldPos = GetItkPoint(temp); itk::Index<3> index; m_MaskImage->TransformPhysicalPointToIndex(worldPos, index); if (!m_MaskImage->GetLargestPossibleRegion().IsInside(index) || m_MaskImage->GetPixel(index)==0) continue; // get fiber tangent direction at this position v = GetVnlVector(temp); dir = GetVnlVector(points->GetPoint(j+1))-v; if (dir.is_zero()) continue; dir.normalize(); // add direction to container unsigned int idx = index[0] + outImageSize[0]*(index[1] + outImageSize[1]*index[2]); DirectionContainerType::Pointer dirCont; if (m_DirectionsContainer->IndexExists(idx)) { peakLengths->ElementAt(idx).push_back(fiberWeight); dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->push_back(dir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->push_back(dir); } else { dirCont = DirectionContainerType::New(); dirCont->push_back(dir); m_DirectionsContainer->InsertElement(idx, dirCont); std::vector< double > lengths; lengths.push_back(fiberWeight); peakLengths->InsertElement(idx, lengths); } } } vtkSmartPointer m_VtkCellArray = vtkSmartPointer::New(); vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); itk::ImageRegionIterator dirIt(m_NumDirectionsImage, m_NumDirectionsImage->GetLargestPossibleRegion()); MITK_INFO << "Clustering directions"; boost::progress_display disp2(outImageSize[0]*outImageSize[1]*outImageSize[2]); while(!dirIt.IsAtEnd()) { ++disp2; OutputImageType::IndexType idx3 = dirIt.GetIndex(); int idx_lin = idx3[0]+(idx3[1]+idx3[2]*outImageSize[1])*outImageSize[0]; itk::Index<4> idx4; idx4[0] = idx3[0]; idx4[1] = idx3[1]; idx4[2] = idx3[2]; if (!m_DirectionsContainer->IndexExists(idx_lin)) { ++dirIt; continue; } DirectionContainerType::Pointer dirCont = m_DirectionsContainer->GetElement(idx_lin); if (dirCont.IsNull() || dirCont->empty()) { ++dirIt; continue; } // std::vector< double > lengths; lengths.resize(dirCont->size(), 1); // all peaks have size 1 DirectionContainerType::Pointer directions; if (m_MaxNumDirections>0) { directions = FastClustering(dirCont, peakLengths->GetElement(idx_lin)); std::sort( directions->begin(), directions->end(), CompareVectorLengths ); } else directions = dirCont; unsigned int numDir = directions->size(); if (m_MaxNumDirections>0 && numDir>m_MaxNumDirections) numDir = m_MaxNumDirections; int count = 0; for (unsigned int i=0; i container = vtkSmartPointer::New(); itk::ContinuousIndex center; center[0] = idx3[0]; center[1] = idx3[1]; center[2] = idx3[2]; itk::Point worldCenter; m_MaskImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); DirectionType dir = directions->at(i); if (dir.magnitude()SetPixel(idx4, dir[j]); } // add direction to vector field (with spacing compensation) itk::Point worldStart; worldStart[0] = worldCenter[0]-dir[0]/2*minSpacing; worldStart[1] = worldCenter[1]-dir[1]/2*minSpacing; worldStart[2] = worldCenter[2]-dir[2]/2*minSpacing; vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer()); container->GetPointIds()->InsertNextId(id); itk::Point worldEnd; worldEnd[0] = worldCenter[0]+dir[0]/2*minSpacing; worldEnd[1] = worldCenter[1]+dir[1]/2*minSpacing; worldEnd[2] = worldCenter[2]+dir[2]/2*minSpacing; id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer()); container->GetPointIds()->InsertNextId(id); m_VtkCellArray->InsertNextCell(container); } dirIt.Set(count); ++dirIt; } vtkSmartPointer directionsPolyData = vtkSmartPointer::New(); directionsPolyData->SetPoints(m_VtkPoints); directionsPolyData->SetLines(m_VtkCellArray); m_OutputFiberBundle = mitk::FiberBundle::New(directionsPolyData); } template< class PixelType > TractsToVectorImageFilter< PixelType >::DirectionContainerType::Pointer TractsToVectorImageFilter< PixelType >::FastClustering(DirectionContainerType::Pointer inDirs, std::vector< double > lengths) { DirectionContainerType::Pointer outDirs = DirectionContainerType::New(); if (inDirs->size()<2) return inDirs; DirectionType oldMean, currentMean; std::vector< int > touched; // initialize touched.resize(inDirs->size(), 0); bool free = true; currentMean = inDirs->at(0); // initialize first seed currentMean.normalize(); double length = lengths.at(0); touched[0] = 1; std::vector< double > newLengths; bool meanChanged = false; double max = 0; while (free) { oldMean.fill(0.0); // start mean-shift clustering double angle = 0; while (fabs(dot_product(currentMean, oldMean))<0.99) { oldMean = currentMean; currentMean.fill(0.0); for (unsigned int i=0; isize(); i++) { angle = dot_product(oldMean, inDirs->at(i)); if (angle>=m_AngularThreshold) { currentMean += inDirs->at(i); if (meanChanged) length += lengths.at(i); touched[i] = 1; meanChanged = true; } else if (-angle>=m_AngularThreshold) { currentMean -= inDirs->at(i); if (meanChanged) length += lengths.at(i); touched[i] = 1; meanChanged = true; } } if(!meanChanged) currentMean = oldMean; else currentMean.normalize(); } // found stable mean outDirs->push_back(currentMean); newLengths.push_back(length); if (length>max) max = length; // find next unused seed free = false; for (unsigned int i=0; iat(i); free = true; meanChanged = false; length = lengths.at(i); touched[i] = 1; break; } } if (inDirs->size()==outDirs->size()) { if (max>0) for (unsigned int i=0; isize(); i++) outDirs->SetElement(i, outDirs->at(i)*newLengths.at(i)/max); return outDirs; } else return FastClustering(outDirs, newLengths); } } diff --git a/Modules/DiffusionImaging/Quantification/Algorithms/itkSkeletonizationFilter.txx b/Modules/DiffusionImaging/Quantification/Algorithms/itkSkeletonizationFilter.txx index 934e2a8340..527f3724c0 100644 --- a/Modules/DiffusionImaging/Quantification/Algorithms/itkSkeletonizationFilter.txx +++ b/Modules/DiffusionImaging/Quantification/Algorithms/itkSkeletonizationFilter.txx @@ -1,306 +1,306 @@ /*=================================================================== 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 _itkSkeletonizationFilter_txx #define _itkSkeletonizationFilter_txx #include "itkSkeletonizationFilter.h" #include "mitkProgressBar.h" #include #include namespace itk { template< class TInputImage, class TOutputImage > SkeletonizationFilter::SkeletonizationFilter() { m_DirectionImage = VectorImageType::New(); } template< class TInputImage, class TOutputImage > SkeletonizationFilter::~SkeletonizationFilter() { } template< class TInputImage, class TOutputImage > void SkeletonizationFilter::GenerateData() { //----------------------------------------------------------------------// // Progress bar // //----------------------------------------------------------------------// mitk::ProgressBar::GetInstance()->AddStepsToDo( 3 ); std::cout << "Skeletonize" << std::endl; const InputImageType* faImage = this->GetInput(); typename InputImageType::SizeType size = faImage->GetRequestedRegion().GetSize(); //typename RealImageType::SizeType size = m_FaImage->GetRequestedRegion().GetSize(); m_DirectionImage->SetRegions(faImage->GetRequestedRegion()); m_DirectionImage->SetDirection(faImage->GetDirection()); m_DirectionImage->SetSpacing(faImage->GetSpacing()); m_DirectionImage->SetOrigin(faImage->GetOrigin()); m_DirectionImage->Allocate(); m_DirectionImage->FillBuffer(0.0); for(unsigned int z=1; zGetPixel(ix); if(theval != 0) { /* Calculate point of gravity. We will consider each 3x3x3 neighbourhood as a unit cube. The center * point of each voxel will be a multiplicative of 1/6. The center of the unit cube is 3/6 = 1/2/ */ float cogX = 0.0; float cogY = 0.0; float cogZ = 0.0; float sum = 0.0; float l; int vecX = 0; int vecY = 0; int vecZ = 0; for(int dz=-1; dz<=1; dz++) for(int dy=-1; dy<=1; dy++) for(int dx=-1; dx<=1;dx++) { typename InputImageType::IndexType p; p[0] = x+dx; p[1] = y+dy; p[2] = z+dz; float mass = faImage->GetPixel(p); sum += mass; cogX += (float)dx*mass; cogY += (float)dy*mass; cogZ += (float)dz*mass; } cogX /= sum; cogY /= sum; cogZ /= sum; l = sqrt(cogX*cogX + cogY*cogY + cogZ*cogZ); if (l > 0.1) /* is CofG far enough away from centre voxel? */ { vecX = std::max(std::min(round(cogX/l),1),-1); vecY = std::max(std::min(round(cogY/l),1),-1); vecZ = std::max(std::min(round(cogZ/l),1),-1); } else // Find direction of max curvature { float maxcost=0, centreval=2*theval; for(int zz=0; zz<=1; zz++) // note - starts at zero as we're only searching half the voxels { for(int yy=-1; yy<=1; yy++) { for(int xx=-1; xx<=1; xx++) { if ( (zz==1) || (yy==1) || ((yy==0)&&(xx==1)) ) { float weighting = pow( (float)(xx*xx+yy*yy+zz*zz) , (float)-0.7 ); // power is arbitrary: maybe test other functions here typename InputImageType::IndexType i,j; i[0] = x+xx; i[1] = y+yy; i[2] = z+zz; j[0] = x-xx; j[1] = y-yy; j[2] = z-zz; float cost = weighting * ( centreval - (float)faImage->GetPixel(i) - (float)faImage->GetPixel(j)); if (cost>maxcost) { maxcost=cost; vecX=xx; vecY=yy; vecZ=zz; } } } } } } VectorType vec; vec[0] = vecX; vec[1] = vecY; vec[2]=vecZ; m_DirectionImage->SetPixel(ix, vec); } } mitk::ProgressBar::GetInstance()->Progress(); // Smooth m_DirectionImage and store in directionSmoothed by finding the // mode in a 3*3 neighbourhoud VectorImageType::Pointer directionSmoothed = VectorImageType::New(); directionSmoothed->SetRegions(faImage->GetRequestedRegion()); directionSmoothed->SetDirection(faImage->GetDirection()); directionSmoothed->SetSpacing(faImage->GetSpacing()); directionSmoothed->SetOrigin(faImage->GetOrigin()); directionSmoothed->Allocate(); VectorImageType::PixelType p; p[0]=0; p[1]=0; p[2]=0; directionSmoothed->FillBuffer(p); for(unsigned int z=1; zGetPixel(i); xxx = v[0]; yyy = v[1]; zzz = v[2]; localsum[(1+zzz)*9+(1+yyy)*3+1+xxx]++; localsum[(1-zzz)*9+(1-yyy)*3+1-xxx]++; } for(int zz=-1; zz<=1; zz++) for(int yy=-1; yy<=1; yy++) for(int xx=-1; xx<=1; xx++) { if (localsum[(1+zz)*9+(1+yy)*3+1+xx]>localmax) { localmax=localsum[(1+zz)*9+(1+yy)*3+1+xx]; VectorType v; v[0] = xx; v[1] = yy; v[2] = zz; directionSmoothed->SetPixel(ix, v); } } - delete localsum; + delete[] localsum; } m_DirectionImage = directionSmoothed; mitk::ProgressBar::GetInstance()->Progress(); // Do non-max-suppression in the direction of perp and set as output of the filter typename OutputImageType::Pointer outputImg = OutputImageType::New(); outputImg->SetRegions(faImage->GetRequestedRegion()); outputImg->SetDirection(faImage->GetDirection()); outputImg->SetSpacing(faImage->GetSpacing()); outputImg->SetOrigin(faImage->GetOrigin()); outputImg->Allocate(); outputImg->FillBuffer(0.0); for(unsigned int z=1; zGetPixel(ix); VectorType v = directionSmoothed->GetPixel(ix); typename VectorImageType::IndexType i; i[0] = x-v[0]; i[1] = y-v[1]; i[2] = z-v[2]; float min = faImage->GetPixel(i); i[0] = x+v[0]; i[1] = y+v[1]; i[2] = z+v[2]; float plus = faImage->GetPixel(i); i[0] = x-2*v[0]; i[1] = y-2*v[1]; i[2] = z-2*v[2]; float minmin = faImage->GetPixel(i); i[0] = x+2*v[0]; i[1] = y+2*v[1]; i[2] = z+2*v[2]; float plusplus = faImage->GetPixel(i); if( ((v[0]!=0) || (v[1]!=0) || (v[2]!=0)) && theval >= plus && theval > min && theval >= plusplus && theval > minmin ) { outputImg->SetPixel(ix, theval); } } Superclass::SetNthOutput( 0, outputImg ); mitk::ProgressBar::GetInstance()->Progress(); } // Can provide a vector image to visualize the gradient image used in the search for local maxima. template< class TInputImage, class TOutputImage > itk::VectorImage::Pointer SkeletonizationFilter::GetGradientImage() { GradientImageType::Pointer gradImg = GradientImageType::New(); if(m_DirectionImage.IsNotNull()) { gradImg->SetSpacing(m_DirectionImage->GetSpacing()); gradImg->SetOrigin(m_DirectionImage->GetOrigin()); gradImg->SetDirection(m_DirectionImage->GetDirection()); gradImg->SetRegions(m_DirectionImage->GetLargestPossibleRegion().GetSize()); gradImg->SetVectorLength(3); gradImg->Allocate(); VectorImageType::SizeType size = m_DirectionImage->GetLargestPossibleRegion().GetSize(); for(std::size_t i=0; i ix; ix[0] = i; ix[1] = j; ix[2] = k; VectorType vec = m_DirectionImage->GetPixel(ix); itk::VariableLengthVector pixel; pixel.SetSize(3); pixel.SetElement(0, vec.GetElement(0)); pixel.SetElement(1, vec.GetElement(1)); pixel.SetElement(2, vec.GetElement(2)); gradImg->SetPixel(ix, pixel); } } } } return gradImg; } } #endif // _itkSkeletonizationFilter_txx diff --git a/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.h b/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.h index 107b3ed15d..02052c5fef 100644 --- a/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.h +++ b/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.h @@ -1,174 +1,174 @@ /*=================================================================== 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 __itkShortestPathCostFunctionLiveWire_h #define __itkShortestPathCostFunctionLiveWire_h #include "itkShortestPathCostFunction.h" #include "itkImageRegionConstIterator.h" namespace itk { /** \brief Cost function for LiveWire purposes. Specific features are considered to calculate cummulative costs of a link between two pixels. These are: - Gradient Magnitude - Gradient Direction - Laplacian Zero Crossing By default the Gradient Magnitude is mapped linearly to cost values between 0 (good) and 1 (bad). Via SetDynamicCostMap( std::map< int, int > &costMap) a cost map can be set to dynamically map Gradient Magnitude (non linear). Thus, lower values can be considered with lower costs than higher values of gradient magnitudes. To compute the costs of the gradient magnitude dynamically an iverted map of the histogram of gradient magnitude image is used. */ template class ITK_EXPORT ShortestPathCostFunctionLiveWire : public ShortestPathCostFunction { public: /** Standard class typedefs. */ typedef ShortestPathCostFunctionLiveWire Self; typedef ShortestPathCostFunction Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef itk::ImageRegionConstIterator ConstIteratorType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Run-time type information (and related methods). */ itkTypeMacro(ShortestPathCostFunctionLiveWire, ShortestPathCostFunction); typedef itk::Image UnsignedCharImageType; typedef itk::Image FloatImageType; typedef float ComponentType; typedef itk::CovariantVector OutputPixelType; typedef itk::Image VectorOutputImageType; typedef typename TInputImageType::IndexType IndexType; typedef TInputImageType ImageType; typedef itk::ImageRegion<2> RegionType; /** \brief calculates the costs for going from p1 to p2*/ - virtual double GetCost(IndexType p1, IndexType p2); + virtual double GetCost(IndexType p1, IndexType p2) override; /** \brief returns the minimal costs possible (needed for A*)*/ - virtual double GetMinCost(); + virtual double GetMinCost() override; /** \brief Initialize the metric*/ - virtual void Initialize(); + virtual void Initialize() override; /** \brief Add void pixel in cost map*/ virtual void AddRepulsivePoint(const IndexType &index); /** \brief Remove void pixel in cost map*/ virtual void RemoveRepulsivePoint(const IndexType &index); /** \brief Clear repulsive points in cost function*/ virtual void ClearRepulsivePoints(); itkSetMacro(RequestedRegion, RegionType); itkGetMacro(RequestedRegion, RegionType); // Set/Get function for sigma parameter itkSetMacro(UseApproximateGradient, bool); itkGetMacro(UseApproximateGradient, bool); - virtual void SetImage(const TInputImageType *_arg); + virtual void SetImage(const TInputImageType *_arg) override; void SetDynamicCostMap(std::map &costMap) { this->m_CostMap = costMap; this->m_UseCostMap = true; this->m_MaxMapCosts = -1; this->Modified(); } void SetUseCostMap(bool useCostMap) { this->m_UseCostMap = useCostMap; } /** \brief Set the maximum of the dynamic cost map to save computation time. */ void SetCostMapMaximum(double max) { this->m_MaxMapCosts = max; } enum Constants { MAPSCALEFACTOR = 10 }; /** \brief Returns the y value of gaussian with given offset and amplitude gaussian approximation f(x) = v(bin) * e^ ( -1/2 * (|x-k(bin)| / sigma)^2 ) \param x \param xOfGaussian - offset \param yOfGaussian - amplitude */ static double Gaussian(double x, double xOfGaussian, double yOfGaussian); const UnsignedCharImageType *GetMaskImage() { return this->m_MaskImage.GetPointer(); }; const FloatImageType *GetGradientMagnitudeImage() { return this->m_GradientMagnitudeImage.GetPointer(); }; const FloatImageType *GetEdgeImage() { return this->m_EdgeImage.GetPointer(); }; const VectorOutputImageType *GetGradientImage() { return this->m_GradientImage.GetPointer(); }; protected: ShortestPathCostFunctionLiveWire(); virtual ~ShortestPathCostFunctionLiveWire(){}; FloatImageType::Pointer m_GradientMagnitudeImage; FloatImageType::Pointer m_EdgeImage; UnsignedCharImageType::Pointer m_MaskImage; VectorOutputImageType::Pointer m_GradientImage; double minCosts; bool m_UseRepulsivePoints; typename Superclass::PixelType val; typename Superclass::PixelType startValue; typename Superclass::PixelType endValue; double m_GradientMax; RegionType m_RequestedRegion; bool m_UseApproximateGradient; bool m_Initialized; std::map m_CostMap; bool m_UseCostMap; double m_MaxMapCosts; private: double SigmoidFunction(double I, double max, double min, double alpha, double beta); }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkShortestPathCostFunctionLiveWire.txx" #endif #endif /* __itkShortestPathCostFunctionLiveWire_h */ diff --git a/Modules/GraphAlgorithms/itkShortestPathImageFilter.h b/Modules/GraphAlgorithms/itkShortestPathImageFilter.h index 5a7a33930b..03000f9121 100644 --- a/Modules/GraphAlgorithms/itkShortestPathImageFilter.h +++ b/Modules/GraphAlgorithms/itkShortestPathImageFilter.h @@ -1,235 +1,235 @@ /*=================================================================== 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 __itkShortestPathImageFilter_h #define __itkShortestPathImageFilter_h #include "itkImageToImageFilter.h" #include "itkShortestPathCostFunction.h" #include "itkShortestPathNode.h" #include #include // ------- INFORMATION ---------- /// SET FUNCTIONS // void SetInput( ItkImage ) // Compulsory // void SetStartIndex (const IndexType & StartIndex); // Compulsory // void SetEndIndex(const IndexType & EndIndex); // Compulsory // void SetFullNeighborsMode(bool) // Optional (default=false), if false N4, if true N26 // void SetActivateTimeOut(bool) // Optional (default=false), for debug issues: after 30s algorithms terminates. You can // have a look at the VectorOrderImage to see how far it came // void SetMakeOutputImage(bool) // Optional (default=true), Generate an outputimage of the path. You can also get the // path directoy with GetVectorPath() // void SetCalcAllDistances(bool) // Optional (default=false), Calculate Distances over the whole image. CAREFUL, // algorithm time extends a lot. Necessary for GetDistanceImage // void SetStoreVectorOrder(bool) // Optional (default=false), Stores in which order the pixels were checked. Necessary // for GetVectorOrderImage // void AddEndIndex(const IndexType & EndIndex) //Optional. By calling this function you can add several endpoints! The // algorithm will look for several shortest Pathes. From Start to all Endpoints. // /// GET FUNCTIONS // std::vector< itk::Index<3> > GetVectorPath(); // returns the shortest path as vector // std::vector< std::vector< itk::Index<3> > GetMultipleVectorPathe(); // returns a vector of shortest Pathes (which are // vectors of points) // GetDistanceImage // Returns the distance image // GetVectorOrderIMage // Returns the Vector Order image // // EXAMPLE USE // pleae see qmitkmitralvalvesegmentation4dtee bundle namespace itk { template class ShortestPathImageFilter : public ImageToImageFilter { public: // Standard Typedefs typedef ShortestPathImageFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; // Typdefs for metric typedef ShortestPathCostFunction CostFunctionType; typedef typename CostFunctionType::Pointer CostFunctionTypePointer; // More typdefs for convenience typedef TInputImageType InputImageType; typedef typename TInputImageType::Pointer InputImagePointer; typedef typename TInputImageType::PixelType InputImagePixelType; typedef typename TInputImageType::SizeType InputImageSizeType; typedef typename TInputImageType::IndexType IndexType; typedef typename itk::ImageRegionIteratorWithIndex InputImageIteratorType; typedef TOutputImageType OutputImageType; typedef typename TOutputImageType::Pointer OutputImagePointer; typedef typename TOutputImageType::PixelType OutputImagePixelType; typedef typename TOutputImageType::IndexType OutputImageIndexType; typedef ImageRegionIteratorWithIndex OutputImageIteratorType; typedef itk::ShapedNeighborhoodIterator itkShapedNeighborhoodIteratorType; // New Macro for smartpointer instantiation itkFactorylessNewMacro(Self) itkCloneMacro(Self) // Run-time type information itkTypeMacro(ShortestPathImageFilter, ImageToImageFilter) // Display - void PrintSelf(std::ostream &os, Indent indent) const; + void PrintSelf(std::ostream &os, Indent indent) const override; // Compare function for A_STAR struct CompareNodeStar { bool operator()(ShortestPathNode *a, ShortestPathNode *b) { return (a->distAndEst > b->distAndEst); } }; // \brief Set Starpoint for ShortestPath Calculation void SetStartIndex(const IndexType &StartIndex); // \brief Adds Endpoint for multiple ShortestPath Calculation void AddEndIndex(const IndexType &index); // \brief Set Endpoint for ShortestPath Calculation void SetEndIndex(const IndexType &EndIndex); // \brief Set FullNeighborsMode. false = no diagonal neighbors, in 2D this means N4 Neigborhood. true = would be N8 // in 2D itkSetMacro(FullNeighborsMode, bool); itkGetMacro(FullNeighborsMode, bool); // \brief Set Graph_fullNeighbors. false = no diagonal neighbors, in 2D this means N4 Neigborhood. true = would be // N8 in 2D itkSetMacro(Graph_fullNeighbors, bool) // \brief (default=true), Produce output image, which shows the shortest path. But you can also get the shortest // Path directly as vector with the function GetVectorPath itkSetMacro(MakeOutputImage, bool); itkGetMacro(MakeOutputImage, bool); // \brief (default=false), Store an Vector of Order, so you can call getVectorOrderImage after update itkSetMacro(StoreVectorOrder, bool); itkGetMacro(StoreVectorOrder, bool); // \brief (default=false), // Calculate all Distances to all pixels, so you can call getDistanceImage after update // (warning algo will take a long time) itkSetMacro(CalcAllDistances, bool); itkGetMacro(CalcAllDistances, bool); // \brief (default=false), for debug issues: after 30s algorithms terminates. You can have a look at the // VectorOrderImage to see how far it came itkSetMacro(ActivateTimeOut, bool); itkGetMacro(ActivateTimeOut, bool); // \brief returns shortest Path as vector std::vector GetVectorPath(); // \brief returns Multiple shortest Paths. You can call this function, when u performed a multiple shortest path // search (one start, several ends) std::vector> GetMultipleVectorPaths(); // \brief returns the vector order image. It shows in which order the pixels were checked. good for debugging. Be // sure to have m_StoreVectorOrder=true OutputImagePointer GetVectorOrderImage(); // \brief returns the distance image. It shows the distances from the startpoint to all other pixels. Be sure to // have m_CalcAllDistances=true OutputImagePointer GetDistanceImage(); // \brief Fill m_VectorPath void MakeShortestPathVector(); // \brief cleans up the filter void CleanUp(); itkSetObjectMacro(CostFunction, CostFunctionType); // itkSetObjectMacro = set function that uses pointer as parameter itkGetObjectMacro(CostFunction, CostFunctionType); protected: std::vector m_endPoints; // if you fill this vector, the algo will not rest until all endPoints have been reached std::vector m_endPointsClosed; ShortestPathNode *m_Nodes; // main list that contains all nodes NodeNumType m_Graph_NumberOfNodes; NodeNumType m_Graph_StartNode; NodeNumType m_Graph_EndNode; unsigned int m_ImageDimensions; bool m_Graph_fullNeighbors; std::vector m_Graph_DiscoveredNodeList; ShortestPathImageFilter(Self &); // intentionally not implemented void operator=(const Self &); // intentionally not implemented const static int BACKGROUND = 0; const static int FOREGROUND = 255; bool m_FullNeighborsMode; bool m_MakeOutputImage; bool m_StoreVectorOrder; // Store an Vector of Order, so you can call getVectorOrderImage after update bool m_CalcAllDistances; // Calculate all Distances, so you can call getDistanceImage after update (warning algo // will take a long time) bool multipleEndPoints; bool m_ActivateTimeOut; // if true, then i search max. 30 secs. then abort bool m_Initialized; CostFunctionTypePointer m_CostFunction; IndexType m_StartIndex, m_EndIndex; std::vector m_VectorPath; std::vector> m_MultipleVectorPaths; std::vector m_VectorOrder; ShortestPathImageFilter(); ~ShortestPathImageFilter(); // \brief Create all the outputs void MakeOutputs(); // \brief Generate Data - void GenerateData(); + void GenerateData() override; // \brief gets the estimate costs from pixel a to target. double getEstimatedCostsToTarget(const IndexType &a); typename InputImageType::Pointer m_magnitudeImage; // \brief Convert a indexnumber of a node in m_Nodes to image coordinates typename TInputImageType::IndexType NodeToCoord(NodeNumType); // \brief Convert image coordinate to a indexnumber of a node in m_Nodes unsigned int CoordToNode(IndexType); // \brief Returns the neighbors of a node std::vector GetNeighbors(NodeNumType nodeNum, bool FullNeighbors); // \brief Check if coords are in bounds of image bool CoordIsInBounds(IndexType); // \brief Initializes the graph void InitGraph(); // \brief Start ShortestPathSearch void StartShortestPathSearch(); }; } // end of namespace itk #include "itkShortestPathImageFilter.txx" #endif diff --git a/Modules/IGT/Common/mitkSerialCommunication.cpp b/Modules/IGT/Common/mitkSerialCommunication.cpp index 39485df6f5..c7138a9dc6 100644 --- a/Modules/IGT/Common/mitkSerialCommunication.cpp +++ b/Modules/IGT/Common/mitkSerialCommunication.cpp @@ -1,509 +1,511 @@ /*=================================================================== 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 "mitkSerialCommunication.h" #ifdef WIN32 //#include #include #else // Posix #include #include #include #include #include #include #include #include #define INVALID_HANDLE_VALUE -1 #endif #define OK 1 #define ERROR_VALUE 0 mitk::SerialCommunication::SerialCommunication() : itk::Object(), m_DeviceName(""), m_PortNumber(COM1), m_BaudRate(BaudRate9600), m_DataBits(DataBits8), m_Parity(None), m_StopBits(StopBits1), m_HardwareHandshake(HardwareHandshakeOff), m_ReceiveTimeout(500), m_SendTimeout(500), m_Connected(false) { #ifdef WIN32 // Windows m_ComPortHandle = INVALID_HANDLE_VALUE; #else // Posix m_FileDescriptor = INVALID_HANDLE_VALUE; #endif } mitk::SerialCommunication::~SerialCommunication() { CloseConnection(); } bool mitk::SerialCommunication::IsConnected() { return m_Connected; } int mitk::SerialCommunication::OpenConnection() { if (m_Connected) return ERROR_VALUE; #ifdef WIN32 std::stringstream ss; if (m_DeviceName.empty()) ss << "\\\\.\\COM" << static_cast(m_PortNumber); // use m_PortNumber else ss << "\\\\.\\" << m_DeviceName; // use m_DeviceName m_ComPortHandle = CreateFile(ss.str().c_str(), GENERIC_READ | GENERIC_WRITE, 0, // no sharing 0, // no security flags OPEN_EXISTING, // open com port, don't create it 0, // no flags 0); // no template if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; GetCommState(m_ComPortHandle, &m_PreviousDeviceControlBlock); GetCommTimeouts(m_ComPortHandle, &m_PreviousTimeout); GetCommMask(m_ComPortHandle, &m_PreviousMask); if (this->ApplyConfiguration() != OK) // set interface parameters { CloseHandle(m_ComPortHandle); m_ComPortHandle = INVALID_HANDLE_VALUE; return ERROR_VALUE; } m_Connected = true; return OK; #else // Posix std::stringstream ss; if (m_DeviceName.empty()) ss << "/dev/ttyS" << static_cast(m_PortNumber) - 1; // use m_PortNumber, COM1 = ttyS0 else ss << m_DeviceName; // use m_DeviceName //m_FileDescriptor = open(ss.str().c_str(), O_RDWR | O_NONBLOCK | O_NDELAY | O_NOCTTY | O_EXCL); // open device file m_FileDescriptor = open(ss.str().c_str(), O_RDWR|O_NONBLOCK|O_EXCL); // open device file if (m_FileDescriptor < 0) return ERROR_VALUE; fcntl(m_FileDescriptor, F_SETFL, 0); // change to blocking mode tcflush(m_FileDescriptor, TCIOFLUSH); // flush buffers if (this->ApplyConfiguration() != OK) // set interface parameters { close(m_FileDescriptor); m_FileDescriptor = INVALID_HANDLE_VALUE; return ERROR_VALUE; } m_Connected = true; return OK; #endif } void mitk::SerialCommunication::CloseConnection() { #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return; ClearReceiveBuffer(); ClearSendBuffer(); SetCommState(m_ComPortHandle, &m_PreviousDeviceControlBlock); // restore previous settings SetCommTimeouts(m_ComPortHandle, &m_PreviousTimeout); // restore previous timeout values SetCommMask(m_ComPortHandle, m_PreviousMask); // restore previous mask value PurgeComm(m_ComPortHandle, PURGE_TXCLEAR | PURGE_RXCLEAR); // empty buffers CloseHandle(m_ComPortHandle); // close handle m_ComPortHandle = INVALID_HANDLE_VALUE; m_Connected = false; return; #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return; ClearReceiveBuffer(); ClearSendBuffer(); close(m_FileDescriptor); m_FileDescriptor = INVALID_HANDLE_VALUE; m_Connected = false; return; #endif } int mitk::SerialCommunication::Receive(std::string& answer, unsigned int numberOfBytes, const char *eol) { if (numberOfBytes == 0) return OK; if (m_Connected == false) return ERROR_VALUE; #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; DWORD numberOfBytesRead = 0; char* buffer = new char[numberOfBytes]; if (ReadFile(m_ComPortHandle, buffer, numberOfBytes, &numberOfBytesRead, nullptr) != 0) { if (numberOfBytesRead > 0) // data read { answer.assign(buffer, numberOfBytesRead); // copy buffer to answer delete buffer; if (numberOfBytesRead == numberOfBytes) { return OK; // everything was received } else { return ERROR_VALUE; // some data was received, but not as much as expected } } else // error { answer = ""; delete buffer; return ERROR_VALUE; } } delete buffer; return OK; #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return ERROR_VALUE; unsigned long bytesRead = 0; unsigned long bytesLeft = numberOfBytes; auto buffer = new char[numberOfBytes]; while ((bytesLeft > 0) && (bytesRead < numberOfBytes)) { int num = read(m_FileDescriptor, &buffer[bytesRead], 1); // read one byte if (num == -1) // ERROR_VALUE { if (errno == EAGAIN) // nonblocking, no byte there right now, but maybe next time continue; else break; // ERROR_VALUE, stop trying to read } if (num == 0) // timeout or eof(?) break; bytesLeft -= num; // n is number of chars left to read bytesRead += num; // i is the number of chars read if (eol && *eol == buffer[bytesRead-1]) // end of line char reached break; } if (bytesRead > 0) answer.assign(buffer, bytesRead); // copy buffer to answer - delete buffer; + + delete[] buffer; + if ( bytesRead == numberOfBytes || // everything was received (eol && answer.size() > 0 && *eol == answer.at(answer.size()-1)) ) // end of line char reached return OK; else return ERROR_VALUE; // some data was received, but not as much as expected #endif } int mitk::SerialCommunication::Send(const std::string& input, bool block) { //long retval = E2ERR_OPENFAILED; if (input.empty()) return OK; if (m_Connected == false) return ERROR_VALUE; #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; DWORD bytesWritten = 0; if (WriteFile(m_ComPortHandle, input.data(), static_cast(input.size()), &bytesWritten, nullptr) == TRUE) return OK; else return GetLastError(); #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return ERROR_VALUE; long bytesWritten = 0; long bytesLeft = input.size(); while (bytesLeft > 0) { bytesWritten = write(m_FileDescriptor, input.data() + bytesWritten, bytesLeft); if (bytesWritten <= 0) return ERROR_VALUE; //return ERROR_VALUE bytesLeft -= bytesWritten; } if (block) { // wait for output to be physically sent if (tcdrain(m_FileDescriptor) == -1) return ERROR_VALUE; } return OK; #endif } int mitk::SerialCommunication::ApplyConfiguration() { #ifdef WIN32 // Windows implementation return ApplyConfigurationWin(); #else // Posix return ApplyConfigurationUnix(); #endif } /** * The Code for Baud rates is highly platform specific and divided into separate subroutines for readability. */ #ifdef WIN32 int mitk::SerialCommunication::ApplyConfigurationWin() { if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; DCB controlSettings; if (GetCommState(m_ComPortHandle, &controlSettings) == 0) { return ERROR_VALUE; } std::ostringstream o; o << "baud=" << m_BaudRate << " parity=" << static_cast(m_Parity) << " data=" << m_DataBits << " stop=" << m_StopBits; if (BuildCommDCBA(o.str().c_str(), &controlSettings) == 0) // Build device-control block return ERROR_VALUE; if (m_HardwareHandshake == HardwareHandshakeOn) // Modify hardware handshake values { controlSettings.fDtrControl = DTR_CONTROL_ENABLE; controlSettings.fRtsControl = RTS_CONTROL_ENABLE; controlSettings.fOutxCtsFlow = TRUE; controlSettings.fRtsControl = RTS_CONTROL_HANDSHAKE; } else { controlSettings.fDtrControl = DTR_CONTROL_DISABLE; controlSettings.fRtsControl = RTS_CONTROL_DISABLE; controlSettings.fOutxCtsFlow = FALSE; controlSettings.fRtsControl = RTS_CONTROL_DISABLE; } if (SetCommState(m_ComPortHandle, &controlSettings) == FALSE) // Configure com port return GetLastError(); COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout = m_ReceiveTimeout; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = m_ReceiveTimeout; timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = m_SendTimeout; if (SetCommTimeouts(m_ComPortHandle, &timeouts) == FALSE) // set timeout values return GetLastError(); PurgeComm(m_ComPortHandle, PURGE_TXCLEAR | PURGE_RXCLEAR); // clear read and write buffers return OK; } #else /** * \brief Applies the configuration for Linux */ int mitk::SerialCommunication::ApplyConfigurationUnix() { if ( m_FileDescriptor == INVALID_HANDLE_VALUE ) return ERROR_VALUE; struct termios termIOStructure; if ( tcgetattr(m_FileDescriptor, &termIOStructure) != 0 ) // retrieve parameters from com port return ERROR_VALUE; cfmakeraw(&termIOStructure); // set flags to raw mode termIOStructure.c_cflag |= CLOCAL; if (m_HardwareHandshake == HardwareHandshakeOn) { // enable termIOStructure.c_cflag |= CRTSCTS; termIOStructure.c_iflag &= ~(IXON|IXOFF); } else { // disable termIOStructure.c_cflag &= ~CRTSCTS; termIOStructure.c_iflag &= ~(IXON|IXOFF); } termIOStructure.c_cflag &= ~CSIZE; // set number of data bits switch (m_DataBits) { case DataBits7: termIOStructure.c_cflag |= CS7; break; case DataBits8: default: termIOStructure.c_cflag |= CS8; } switch (m_StopBits) // set number of stop bits { case StopBits2: termIOStructure.c_cflag |= CSTOPB; break; case StopBits1: default: termIOStructure.c_cflag &= ~CSTOPB; } switch (m_Parity) // set parity { case Odd: termIOStructure.c_cflag |= (PARENB|PARODD); break; case Even: termIOStructure.c_cflag |= PARENB; termIOStructure.c_cflag &= ~PARODD; case None: default: termIOStructure.c_cflag &= ~PARENB; break; } speed_t baudrate; // set baudrate switch (m_BaudRate) { case BaudRate9600: baudrate = B9600; break; case BaudRate14400: baudrate = B9600; //14400 is not defined for posix, use 9600 instead break; case BaudRate19200: baudrate = B19200; break; case BaudRate38400: baudrate = B38400; break; case BaudRate57600: baudrate = B57600; break; case BaudRate115200: baudrate = B115200; break; case BaudRate230400: baudrate = B230400; break; // the following baud rates do not work for apple #ifndef __APPLE__ case BaudRate460800: baudrate = B460800; break; case BaudRate500000: baudrate = B500000; break; case BaudRate576000: baudrate = B576000; break; case BaudRate921600: baudrate = B921600; break; case BaudRate1000000: baudrate = B1000000; break; case BaudRate1152000: baudrate = B1152000; break; //case BaudRate1228739: //baudrate = B1228739; //break; case BaudRate1500000: baudrate = B1500000; break; case BaudRate2000000: baudrate = B2000000; break; case BaudRate2500000: baudrate = B2500000; break; case BaudRate3000000: baudrate = B3000000; break; case BaudRate3500000: baudrate = B3500000; break; case BaudRate4000000: baudrate = B4000000; break; #endif default: MITK_WARN("mitk::SerialCommunication") << "Baud rate not recognized, using default of 9600 Baud."; baudrate = B9600; break; } cfsetispeed(&termIOStructure, baudrate); cfsetospeed(&termIOStructure, baudrate); termIOStructure.c_cc[VMIN] = 0; termIOStructure.c_cc[VTIME] = m_ReceiveTimeout / 100; // timeout in 1/10 sec, not in ms. Rounded down. if (tcsetattr(m_FileDescriptor, TCSANOW, &termIOStructure) == 0) return OK; else return ERROR_VALUE; } #endif void mitk::SerialCommunication::SendBreak(unsigned int ms) { #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return; SetCommBreak(m_ComPortHandle); itksys::SystemTools::Delay(ms); ClearCommBreak(m_ComPortHandle); return; #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return; tcsendbreak(m_FileDescriptor, ms); return; #endif } void mitk::SerialCommunication::ClearReceiveBuffer() { #ifdef WIN32 if (m_ComPortHandle != INVALID_HANDLE_VALUE) PurgeComm(m_ComPortHandle, PURGE_RXCLEAR); #else // Posix if (m_FileDescriptor != INVALID_HANDLE_VALUE) tcflush(m_FileDescriptor, TCIFLUSH); #endif } void mitk::SerialCommunication::ClearSendBuffer() { #ifdef WIN32 if ( m_ComPortHandle != INVALID_HANDLE_VALUE ) PurgeComm(m_ComPortHandle, PURGE_TXCLEAR); #else // Posix if ( m_FileDescriptor != INVALID_HANDLE_VALUE ) tcflush(m_FileDescriptor, TCOFLUSH); #endif } diff --git a/Modules/IGT/Rendering/mitkNavigationDataSliceVisualization.cpp b/Modules/IGT/Rendering/mitkNavigationDataSliceVisualization.cpp index e9f822f90f..47bdf6326a 100644 --- a/Modules/IGT/Rendering/mitkNavigationDataSliceVisualization.cpp +++ b/Modules/IGT/Rendering/mitkNavigationDataSliceVisualization.cpp @@ -1,223 +1,223 @@ /*=================================================================== 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 "mitkNavigationDataSliceVisualization.h" #include "mitkBaseRenderer.h" mitk::NavigationDataSliceVisualization::NavigationDataSliceVisualization() : mitk::NavigationDataToNavigationDataFilter(), m_Renderer(nullptr), m_ViewDirection(Axial) { m_TipOffset[0] = 0.0f; m_TipOffset[1] = 0.0f; m_TipOffset[2] = 0.0f; m_ToolTrajectory[0] = 0; m_ToolTrajectory[1] = 0; m_ToolTrajectory[2] = -1; m_WorldVerticalVector[0] = 0.0; m_WorldVerticalVector[1] = 1.0; m_WorldVerticalVector[2] = 0.0; } void mitk::NavigationDataSliceVisualization::SetToolTrajectory(Vector3D direction) { if (Equal(direction.GetNorm(), 0.0)) { MITK_WARN << "Ignoring invalid direction of projection: " << direction; return; } if (m_ToolTrajectory != direction) { m_ToolTrajectory = direction; this->SetViewDirection(Oblique); this->Modified(); } } void mitk::NavigationDataSliceVisualization::GenerateData() { // check if renderer was set if (m_Renderer.IsNull()) { itkExceptionMacro(<< "Renderer was not properly set"); } /* update outputs with tracking data from tools */ unsigned int numberOfInputs = this->GetNumberOfInputs(); if (numberOfInputs == 0) { return; } for (unsigned int i = 0; i < numberOfInputs ; ++i) { NavigationData* output = this->GetOutput(i); assert(output); const NavigationData* input = this->GetInput(i); assert(input); if (!input->IsDataValid()) continue; output->Graft(input); // First, copy all information from input to output } // Nothing left to do if we don't have an input with valid data if (numberOfInputs == 0 || !this->GetInput()->IsDataValid()) return; // get position from NavigationData to move the slice to this position Point3D slicePosition = this->GetInput()->GetPosition(); { NavigationData::OrientationType orientation = this->GetInput()->GetOrientation(); Vector3D transformedTipOffset; transformedTipOffset.SetVnlVector(orientation.rotate(m_TipOffset.GetVnlVector())); slicePosition += transformedTipOffset; mitk::SliceNavigationController::Pointer snc = m_Renderer->GetSliceNavigationController(); if (Axial == m_ViewDirection) { snc->SetViewDirection(mitk::SliceNavigationController::Axial); snc->SelectSliceByPoint(slicePosition); } else if (Sagittal == m_ViewDirection) { snc->SetViewDirection(mitk::SliceNavigationController::Sagittal); snc->SelectSliceByPoint(slicePosition); } else if (Frontal == m_ViewDirection) { snc->SetViewDirection(mitk::SliceNavigationController::Frontal); snc->SelectSliceByPoint(slicePosition); } else if (AxialOblique == m_ViewDirection || SagittalOblique == m_ViewDirection) { const int slicingPlaneXAxis = AxialOblique == m_ViewDirection ? 0 : 2; // The column 0 is the slicing plane's x-axis, column 1 is the slicing plane's y-axis - const mitk::Geometry2D::TransformType::MatrixType &m = + const mitk::PlaneGeometry::TransformType::MatrixType &m = m_Renderer->GetCurrentWorldPlaneGeometry()->GetIndexToWorldTransform()->GetMatrix(); // Rotate the tool trajectory vector into world coordinate frame (assuming // NavigationData has passed through a NavigationDataTransformFilter to // convert it into world coordinate frame) Vector3D slicingPlaneYAxisVector; slicingPlaneYAxisVector.SetVnlVector(orientation.rotate(m_ToolTrajectory.GetVnlVector())); // Project the tool trajectory onto the plane normal to x-axis of this // oblique slicing. This defines the y-axis ("up") of the oblique slicing // plane slicingPlaneYAxisVector[slicingPlaneXAxis] = 0.0; // Do nothing for ambigous/undefined cases: // - the R-L component of the x-axis is zero (for AxialOblique) // - the S-I component of the x-axis is zero (for SagittalOblique) // - the A-P component of the y-axis is zero if ( m(slicingPlaneXAxis,0) == 0.0 || m(1,1) == 0.0 || (slicingPlaneXAxis != 0 && slicingPlaneYAxisVector[0] == 0.0) || (slicingPlaneXAxis != 1 && slicingPlaneYAxisVector[1] == 0.0) || (slicingPlaneXAxis != 2 && slicingPlaneYAxisVector[2] == 0.0) ) { return; } // Maintain the A-P orientation of the slice's y-axis regardless of what // direction the tool trajectory points /// @todo Use std::signbit if ( (m(1,1) > 0) != (slicingPlaneYAxisVector[1] > 0) ) { slicingPlaneYAxisVector *= -1; } Vector3D slicingPlaneXAxisVector; slicingPlaneXAxisVector.Fill(0.0); // For AxialOblique: maintain the Left/Right direction of the slice's x-axis // For SagittalOblique: maintain the Superior/Inferior direction of the slice's x-axis /// @todo Use std::copysign slicingPlaneXAxisVector[slicingPlaneXAxis] = m(slicingPlaneXAxis,0) > 0 ? 1.0 : -1.0; Point3D origin; FillVector3D(origin, 0.0, 0.0, 0.0); snc->ReorientSlices(origin, slicingPlaneXAxisVector, slicingPlaneYAxisVector); snc->SelectSliceByPoint(slicePosition); } else if (Oblique == m_ViewDirection) { Vector3D slicingPlaneNormalVector; slicingPlaneNormalVector.SetVnlVector(orientation.rotate(m_ToolTrajectory.GetVnlVector())); // The second column of the Index-to-World matrix is the positive y-axis // of the current slicing plane in world coordinates. - const mitk::Geometry2D::TransformType::MatrixType &m = + const mitk::PlaneGeometry::TransformType::MatrixType &m = m_Renderer->GetCurrentWorldPlaneGeometry()->GetIndexToWorldTransform()->GetMatrix(); mitk::Vector3D currentSlicingPlaneUpVector; mitk::FillVector3D(currentSlicingPlaneUpVector, m[0][1], m[1][1], m[2][1]); mitk::Vector3D worldUpVector = m_WorldVerticalVector; if (angle(worldUpVector.GetVnlVector(), currentSlicingPlaneUpVector.GetVnlVector()) > vnl_math::pi_over_2 ) { worldUpVector *= -1; } mitk::PlaneGeometry::Pointer slicingPlane = mitk::PlaneGeometry::New(); Point3D origin; FillVector3D(origin, 0.0, 0.0, 0.0); slicingPlane->InitializePlane(origin, slicingPlaneNormalVector); // Now that we have the direction of WorldVerticalVector chosen to be the // most "up" direction, project it onto the slicing plane to define the // up vector (y-axis) of the reoriented slices mitk::Vector3D slicingPlaneUpVector; if ( slicingPlane->Project(worldUpVector, slicingPlaneUpVector) ) { // slicingPlaneUpVector CROSS slicingPlaneNormalVector -> slicingPlaneRightVector // Math is done in double precision as much as possible to get more // orthogonal right and up vectors which fixes a VNL SVD error when // the WorldGeometry matrix is later inverted itk::Vector slicingPlaneUpVector_double; FillVector3D(slicingPlaneUpVector_double, slicingPlaneUpVector[0], slicingPlaneUpVector[1], slicingPlaneUpVector[2]); itk::Vector slicingPlaneNormalVector_double; FillVector3D(slicingPlaneNormalVector_double, slicingPlaneNormalVector[0], slicingPlaneNormalVector[1], slicingPlaneNormalVector[2]); itk::Vector slicingPlaneRightVector_double = itk::CrossProduct(slicingPlaneUpVector_double, slicingPlaneNormalVector_double); mitk::Vector3D slicingPlaneRightVector; mitk::FillVector3D(slicingPlaneRightVector, slicingPlaneRightVector_double[0], slicingPlaneRightVector_double[1], slicingPlaneRightVector_double[2]); mitk::FillVector3D(slicingPlaneUpVector, slicingPlaneUpVector_double[0], slicingPlaneUpVector_double[1], slicingPlaneUpVector_double[2]); snc->ReorientSlices(origin, slicingPlaneRightVector, slicingPlaneUpVector); snc->SelectSliceByPoint(slicePosition); } } else { MITK_ERROR << "Unsupported ViewDirection: " << m_ViewDirection; } m_Renderer->RequestUpdate(); } } diff --git a/Modules/IGT/Testing/mitkNavigationDataSetReaderWriterCSVTest.cpp b/Modules/IGT/Testing/mitkNavigationDataSetReaderWriterCSVTest.cpp index 70df50d874..faefa746f0 100644 --- a/Modules/IGT/Testing/mitkNavigationDataSetReaderWriterCSVTest.cpp +++ b/Modules/IGT/Testing/mitkNavigationDataSetReaderWriterCSVTest.cpp @@ -1,133 +1,132 @@ /*=================================================================== 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. ===================================================================*/ //testing headers //#include #include #include #include #include #include #include #include #include #include #include #include #include //for exceptions #include "mitkIGTException.h" #include "mitkIGTIOException.h" class mitkNavigationDataSetReaderWriterCSVTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkNavigationDataSetReaderWriterCSVTestSuite); // MITK_TEST(TestCompareFunction); MITK_TEST(TestReadWrite); CPPUNIT_TEST_SUITE_END(); private: std::string pathRead; std::string pathWrite; std::string pathWrong; mitk::NavigationDataSet::Pointer set; public: void setUp() override { pathRead = GetTestDataFilePath("IGT-Data/RecordedNavigationData.xml"); pathWrong = GetTestDataFilePath("IGT-Data/NavigationDataTestData.CSV"); pathWrite="C:\\test.csv"; } void tearDown() override { } void TestReadWrite() { // Aim is to read an CSV into a pointset, write that CSV again, and compare the output set = dynamic_cast(mitk::IOUtil::Load(pathRead)[0].GetPointer() ); CPPUNIT_ASSERT_MESSAGE("Testing whether something was read at all", set != nullptr); mitk::IOUtil::Save(set, pathWrite); //FIXME: Commented out, because test fails under linux. binary comparison of files is probably not the wa to go // See Bug 17775 //CPPUNIT_ASSERT_MESSAGE( "Testing if read/write cycle creates identical files", CompareFiles(pathRead, pathWrite)); //remove(pathWrite.c_str()); } bool CompareFiles(std::string file) { set = dynamic_cast(mitk::IOUtil::Load(file)[0].GetPointer()); double sample[2][30] ={ {5134019.44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5134019.44, 0, 1, 101.2300034, -62.63999939, -203.2400055, -0.3059000075, 0.5752000213, 0, 0.7585999966, 5134019.44, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {5134082.84, 5134073.64, 1, -172.6100006, 12.60999966, -299.4500122, -0.1588999927, 0.4370000064, 0, 0.8852000237, 5134082.84, 5134073.64, 1, 101.2300034, -62.63999939, -203.2400055, -0.3059000075, 0.5752000213, 0, 0.7585999966, 5134082.84, 5134073.64, 0, 0, 0, 0, 0, 0, 0, 0} }; bool returnValue = true; for(int line = 0 ; line < 2; line++) { for (int tool =0; tool < 3; tool ++) { mitk::NavigationData::Pointer testline = set->GetNavigationDataForIndex(line,tool) ; returnValue = returnValue && mitk::Equal( testline->GetIGTTimeStamp() , sample [line] [(tool*10)] ); returnValue = returnValue && mitk::Equal( testline->IsDataValid() , sample [line] [(tool*10)+1] ); mitk::NavigationData::PositionType pos = testline->GetPosition(); returnValue = returnValue && mitk::Equal( pos[0] , sample [line] [(tool*10)+2] ); returnValue = returnValue && mitk::Equal( pos[1] , sample [line] [(tool*10)+3] ); returnValue = returnValue && mitk::Equal( pos[2] , sample [line] [(tool*10)+4] ); mitk::NavigationData::OrientationType ori = testline->GetOrientation(); returnValue = returnValue && mitk::Equal( ori[0] , sample [line] [(tool*10)+5] ); returnValue = returnValue && mitk::Equal( ori[1] , sample [line] [(tool*10)+6] ); returnValue = returnValue && mitk::Equal( ori[2] , sample [line] [(tool*10)+7] ); returnValue = returnValue && mitk::Equal( ori[3] , sample [line] [(tool*10)+8] ); } - - return returnValue; } + return returnValue; } void TestCompareFunction() { CPPUNIT_ASSERT_MESSAGE("Checking if csv-file reader is working properly", CompareFiles(pathRead)); //CPPUNIT_ASSERT_MESSAGE("Asserting that compare function for files works correctly - Negative Test", ! CompareFiles(pathWrong) ); } }; MITK_TEST_SUITE_REGISTRATION(mitkNavigationDataSetReaderWriterCSV) diff --git a/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp b/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp index b7abbed6a5..2db194367a 100644 --- a/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp +++ b/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp @@ -1,1731 +1,1731 @@ /*=================================================================== 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 "mitkImageStatisticsCalculator.h" #include #include #include #include #include #include #include #include #include #include #include /** * \brief Test class for mitkImageStatisticsCalculator * * This test covers: * - instantiation of an ImageStatisticsCalculator class * - correctness of statistics when using PlanarFigures for masking */ class mitkImageStatisticsCalculatorTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkImageStatisticsCalculatorTestSuite); MITK_TEST(TestUninitializedImage); MITK_TEST(TestCase1); MITK_TEST(TestCase2); MITK_TEST(TestCase3); MITK_TEST(TestCase4); MITK_TEST(TestCase5); MITK_TEST(TestCase6); MITK_TEST(TestCase7); MITK_TEST(TestCase8); MITK_TEST(TestCase9); MITK_TEST(TestCase10); MITK_TEST(TestCase11); MITK_TEST(TestCase12); MITK_TEST(TestImageMaskingEmpty); MITK_TEST(TestImageMaskingNonEmpty); MITK_TEST(TestRecomputeOnModifiedMask); MITK_TEST(TestPic3DStatistics); MITK_TEST(TestPic3DAxialPlanarFigureMaskStatistics); MITK_TEST(TestPic3DSagittalPlanarFigureMaskStatistics); MITK_TEST(TestPic3DCoronalPlanarFigureMaskStatistics); MITK_TEST(TestPic3DImageMaskStatistics_label1); MITK_TEST(TestPic3DImageMaskStatistics_label2); MITK_TEST(TestPic3DIgnorePixelValueMaskStatistics); MITK_TEST(TestPic3DSecondaryMaskStatistics); MITK_TEST(TestUS4DCylStatistics_time1); MITK_TEST(TestUS4DCylAxialPlanarFigureMaskStatistics_time1); MITK_TEST(TestUS4DCylSagittalPlanarFigureMaskStatistics_time1); MITK_TEST(TestUS4DCylCoronalPlanarFigureMaskStatistics_time1); MITK_TEST(TestUS4DCylImageMaskStatistics_time1_label_1); MITK_TEST(TestUS4DCylImageMaskStatistics_time2_label_1); MITK_TEST(TestUS4DCylImageMaskStatistics_time1_label_2); MITK_TEST(TestUS4DCylIgnorePixelValueMaskStatistics_time1); MITK_TEST(TestUS4DCylSecondaryMaskStatistics_time1); CPPUNIT_TEST_SUITE_END(); public: void setUp() override; void tearDown() override; void TestUninitializedImage(); void TestCase1(); void TestCase2(); void TestCase3(); void TestCase4(); void TestCase5(); void TestCase6(); void TestCase7(); void TestCase8(); void TestCase9(); void TestCase10(); void TestCase11(); void TestCase12(); void TestImageMaskingEmpty(); void TestImageMaskingNonEmpty(); void TestRecomputeOnModifiedMask(); void TestPic3DStatistics(); void TestPic3DAxialPlanarFigureMaskStatistics(); void TestPic3DSagittalPlanarFigureMaskStatistics(); void TestPic3DCoronalPlanarFigureMaskStatistics(); void TestPic3DImageMaskStatistics_label1(); void TestPic3DImageMaskStatistics_label2(); void TestPic3DIgnorePixelValueMaskStatistics(); void TestPic3DSecondaryMaskStatistics(); void TestUS4DCylStatistics_time1(); void TestUS4DCylAxialPlanarFigureMaskStatistics_time1(); void TestUS4DCylSagittalPlanarFigureMaskStatistics_time1(); void TestUS4DCylCoronalPlanarFigureMaskStatistics_time1(); void TestUS4DCylImageMaskStatistics_time1_label_1(); void TestUS4DCylImageMaskStatistics_time2_label_1(); void TestUS4DCylImageMaskStatistics_time1_label_2(); void TestUS4DCylIgnorePixelValueMaskStatistics_time1(); void TestUS4DCylSecondaryMaskStatistics_time1(); void TestDifferentNBinsForHistogramStatistics(); void TestDifferentBinSizeForHistogramStatistic(); void TestSwitchFromBinSizeToNBins(); void TestSwitchFromNBinsToBinSize(); private: mitk::Image::Pointer m_TestImage; mitk::Image::Pointer m_Pic3DImage; mitk::Image::Pointer m_Pic3DImageMask; mitk::Image::Pointer m_Pic3DImageMask2; mitk::PlanarFigure::Pointer m_Pic3DPlanarFigureAxial; mitk::PlanarFigure::Pointer m_Pic3DPlanarFigureSagittal; mitk::PlanarFigure::Pointer m_Pic3DPlanarFigureCoronal; mitk::Image::Pointer m_US4DImage; mitk::Image::Pointer m_US4DImageMask; mitk::Image::Pointer m_US4DImageMask2; mitk::PlanarFigure::Pointer m_US4DPlanarFigureAxial; mitk::PlanarFigure::Pointer m_US4DPlanarFigureSagittal; mitk::PlanarFigure::Pointer m_US4DPlanarFigureCoronal; mitk::PlaneGeometry::Pointer m_Geometry; // calculate statistics for the given image and planarpolygon const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer ComputeStatistics( mitk::Image::Pointer image, mitk::PlanarFigure::Pointer polygon ); // calculate statistics for the given image and mask const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer ComputeStatistics( mitk::Image::Pointer image, mitk::Image::Pointer image_mask ); // universal function to calculate statistics const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer ComputeStatisticsNew(mitk::Image::Pointer image, int timeStep=0, mitk::MaskGenerator::Pointer maskGen=nullptr, mitk::MaskGenerator::Pointer secondardMaskGen=nullptr, unsigned short label=1); void VerifyStatistics(mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer stats, double testMean, double testSD, double testMedian=0); void VerifyStatistics(mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer stats, long N, double mean, double MPP, double median, double skewness, double kurtosis, double uniformity, double UPP, double variance, double stdev, double min, double max, double RMS, double entropy, vnl_vector minIndex, vnl_vector maxIndex); }; void mitkImageStatisticsCalculatorTestSuite::tearDown() { m_TestImage = nullptr; m_Pic3DImage = nullptr; m_Pic3DImageMask = nullptr; m_Pic3DImageMask2 = nullptr; m_Pic3DPlanarFigureAxial = nullptr; m_Pic3DPlanarFigureSagittal = nullptr; m_Pic3DPlanarFigureCoronal = nullptr; m_US4DImage = nullptr; m_US4DImageMask = nullptr; m_US4DImageMask2 = nullptr; m_US4DPlanarFigureAxial = nullptr; m_US4DPlanarFigureSagittal = nullptr; m_US4DPlanarFigureCoronal = nullptr; m_Geometry = nullptr; } void mitkImageStatisticsCalculatorTestSuite::setUp() { std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.dcm"); std::string Pic3DFile = this->GetTestDataFilePath("Pic3D.nrrd"); std::string Pic3DImageMaskFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3D-labels.nrrd"); std::string Pic3DImageMaskFile2 = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3D-labels2.nrrd"); std::string Pic3DAxialPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3DAxialPlanarFigure.pf"); std::string Pic3DSagittalPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3DSagittalPlanarFigure.pf"); std::string Pic3DCoronalPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3DCoronalPlanarFigure.pf"); std::string US4DFile = this->GetTestDataFilePath("US4DCyl.nrrd"); std::string US4DImageMaskFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4D-labels.nrrd"); std::string US4DImageMaskFile2 = this->GetTestDataFilePath("ImageStatisticsTestData/US4D-labels2.nrrd"); std::string US4DAxialPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4DAxialPlanarFigure.pf"); std::string US4DSagittalPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4DSagittalPlanarFigure.pf"); std::string US4DCoronalPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4DCoronalPlanarFigure.pf"); if (filename.empty() || Pic3DFile.empty() || Pic3DImageMaskFile.empty() || Pic3DAxialPlanarFigureFile.empty() || Pic3DSagittalPlanarFigureFile.empty() || Pic3DCoronalPlanarFigureFile.empty() || US4DFile.empty() || US4DImageMaskFile.empty() || US4DAxialPlanarFigureFile.empty() || US4DSagittalPlanarFigureFile.empty() || US4DCoronalPlanarFigureFile.empty()) { MITK_TEST_FAILED_MSG( << "Could not find test file" ) } MITK_TEST_OUTPUT(<< "Loading test image '" << filename << "'") m_TestImage = dynamic_cast(mitk::IOUtil::Load(filename)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_TestImage.IsNotNull(), "Loaded an mitk::Image" ); m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0); MITK_TEST_CONDITION_REQUIRED( m_Geometry.IsNotNull(), "Getting image geometry" ); m_Pic3DImage = dynamic_cast(mitk::IOUtil::Load(Pic3DFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_Pic3DImage.IsNotNull(), "Loaded Pic3D" ); m_Pic3DImageMask = dynamic_cast(mitk::IOUtil::Load(Pic3DImageMaskFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_Pic3DImageMask.IsNotNull(), "Loaded Pic3D image mask" ); m_Pic3DImageMask2 = dynamic_cast(mitk::IOUtil::Load(Pic3DImageMaskFile2)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_Pic3DImageMask2.IsNotNull(), "Loaded Pic3D image secondary mask" ); m_Pic3DPlanarFigureAxial = dynamic_cast(mitk::IOUtil::Load(Pic3DAxialPlanarFigureFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_Pic3DPlanarFigureAxial.IsNotNull(), "Loaded Pic3D axial planarFigure" ); m_Pic3DPlanarFigureSagittal = dynamic_cast(mitk::IOUtil::Load(Pic3DSagittalPlanarFigureFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_Pic3DPlanarFigureSagittal.IsNotNull(), "Loaded Pic3D sagittal planarFigure" ); m_Pic3DPlanarFigureCoronal = dynamic_cast(mitk::IOUtil::Load(Pic3DCoronalPlanarFigureFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_Pic3DPlanarFigureCoronal.IsNotNull(), "Loaded Pic3D coronal planarFigure" ); m_US4DImage = dynamic_cast(mitk::IOUtil::Load(US4DFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_US4DImage.IsNotNull(), "Loaded US4D" ); m_US4DImageMask = dynamic_cast(mitk::IOUtil::Load(US4DImageMaskFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_US4DImageMask.IsNotNull(), "Loaded US4D image mask" ); m_US4DImageMask2 = dynamic_cast(mitk::IOUtil::Load(US4DImageMaskFile2)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_US4DImageMask2.IsNotNull(), "Loaded US4D image mask2" ); m_US4DPlanarFigureAxial = dynamic_cast(mitk::IOUtil::Load(US4DAxialPlanarFigureFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_US4DPlanarFigureAxial.IsNotNull(), "Loaded US4D axial planarFigure" ); m_US4DPlanarFigureSagittal = dynamic_cast(mitk::IOUtil::Load(US4DSagittalPlanarFigureFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_US4DPlanarFigureSagittal.IsNotNull(), "Loaded US4D sagittal planarFigure" ); m_US4DPlanarFigureCoronal = dynamic_cast(mitk::IOUtil::Load(US4DCoronalPlanarFigureFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_US4DPlanarFigureCoronal.IsNotNull(), "Loaded US4D coronal planarFigure" ); } void mitkImageStatisticsCalculatorTestSuite::TestCase1() { /***************************** * one whole white pixel * -> mean of 255 expected ******************************/ MITK_INFO << std::endl << "Test case 1:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 10.5 ; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 10.5; pnt4[1] = 4.5; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure1.GetPointer()), 255.0, 0.0, 255.0); } void mitkImageStatisticsCalculatorTestSuite::TestCase2() { /***************************** * half pixel in x-direction (white) * -> mean of 255 expected ******************************/ MITK_INFO << std::endl << "Test case 2:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 10.0 ; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 10.0; pnt4[1] = 4.5; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure1.GetPointer()), 255.0, 0.0, 255.0); } void mitkImageStatisticsCalculatorTestSuite::TestCase3() { /***************************** * half pixel in diagonal-direction (white) * -> mean of 255 expected ******************************/ MITK_INFO << std::endl << "Test case 3:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 10.5 ; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); figure1->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure1.GetPointer()), 255.0, 0.0, 255.0); } void mitkImageStatisticsCalculatorTestSuite::TestCase4() { /***************************** * one pixel (white) + 2 half pixels (white) + 1 half pixel (black) * -> mean of 191.25 expected ******************************/ MITK_INFO << std::endl << "Test case 4:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 1.1; pnt1[1] = 1.1; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 2.0; pnt2[1] = 2.0; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 3.0; pnt3[1] = 1.0; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 2.0; pnt4[1] = 0.0; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure1.GetPointer()), 191.25, 110.41, 242.250); } void mitkImageStatisticsCalculatorTestSuite::TestCase5() { /***************************** * whole pixel (white) + half pixel (gray) in x-direction * -> mean of 191.5 expected ******************************/ MITK_INFO << std::endl << "Test case 5:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.0; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 11.0; pnt4[1] = 4.5; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure1.GetPointer()), 191.50, 63.50, 134.340); } void mitkImageStatisticsCalculatorTestSuite::TestCase6() { /***************************** * quarter pixel (black) + whole pixel (white) + half pixel (gray) in x-direction * -> mean of 191.5 expected ******************************/ MITK_INFO << std::endl << "Test case 6:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.0; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.25; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.25; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 11.0; pnt4[1] = 4.5; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure1.GetPointer()), 191.5, 63.50, 134.340); } void mitkImageStatisticsCalculatorTestSuite::TestCase7() { /***************************** * half pixel (black) + whole pixel (white) + half pixel (gray) in x-direction * -> mean of 127.66 expected ******************************/ MITK_INFO << std::endl << "Test case 7:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.0; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.0; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.0; pnt3[1] = 4.0; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 11.0; pnt4[1] = 4.0; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure1.GetPointer()), 127.66, 104.1, 140.250); } void mitkImageStatisticsCalculatorTestSuite::TestCase8() { /***************************** * whole pixel (gray) * -> mean of 128 expected ******************************/ MITK_INFO << std::endl << "Test case 8:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.5; pnt1[1] = 10.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 11.5; pnt2[1] = 11.5; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 12.5; pnt3[1] = 11.5; figure2->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 12.5; pnt4[1] = 10.5; figure2->SetControlPoint( 3, pnt4, true ); figure2->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure2.GetPointer()), 128.0, 0.0, 128.0); } void mitkImageStatisticsCalculatorTestSuite::TestCase9() { /***************************** * whole pixel (gray) + half pixel (white) in y-direction * -> mean of 191.5 expected ******************************/ MITK_INFO << std::endl << "Test case 9:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.5; pnt1[1] = 10.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 11.5; pnt2[1] = 12.0; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 12.5; pnt3[1] = 12.0; figure2->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 12.5; pnt4[1] = 10.5; figure2->SetControlPoint( 3, pnt4, true ); figure2->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure2.GetPointer()), 191.5, 63.50, 134.340); } void mitkImageStatisticsCalculatorTestSuite::TestCase10() { /***************************** * 2 whole pixel (white) + 2 whole pixel (black) in y-direction * -> mean of 127.66 expected ******************************/ MITK_INFO << std::endl << "Test case 10:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.5; pnt1[1] = 10.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 11.5; pnt2[1] = 13.5; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 12.5; pnt3[1] = 13.5; figure2->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 12.5; pnt4[1] = 10.5; figure2->SetControlPoint( 3, pnt4, true ); figure2->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure2.GetPointer()), 127.66, 104.1, 140.250); } void mitkImageStatisticsCalculatorTestSuite::TestCase11() { /***************************** * 9 whole pixels (white) + 3 half pixels (white) * + 3 whole pixel (black) [ + 3 slightly less than half pixels (black)] * -> mean of 204.0 expected ******************************/ MITK_INFO << std::endl << "Test case 11:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 0.5; pnt1[1] = 0.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 3.5; pnt2[1] = 3.5; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 8.4999; pnt3[1] = 3.5; figure2->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 5.4999; pnt4[1] = 0.5; figure2->SetControlPoint( 3, pnt4, true ); figure2->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure2.GetPointer()), 204.0, 102.00, 242.250); } void mitkImageStatisticsCalculatorTestSuite::TestCase12() { /***************************** * half pixel (white) + whole pixel (white) + half pixel (black) * -> mean of 212.66 expected ******************************/ MITK_INFO << std::endl << "Test case 12:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 9.5; pnt1[1] = 0.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 2.5; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 11.5; pnt3[1] = 2.5; figure2->SetControlPoint( 2, pnt3, true ); figure2->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure2.GetPointer()), 212.66, 59.860, 248.640); } void mitkImageStatisticsCalculatorTestSuite::TestImageMaskingEmpty() { MITK_INFO << std::endl << "TestImageMaskingEmpty:-----------------------------------------------------------------------------------"; mitk::Image::Pointer mask_image = mitk::ImageGenerator::GenerateImageFromReference( m_TestImage, 0 ); this->VerifyStatistics( ComputeStatistics( m_TestImage, mask_image ), -21474836.480, -21474836.480, -21474836.480); // empty statisticsContainer (default values) } void mitkImageStatisticsCalculatorTestSuite::TestImageMaskingNonEmpty() { MITK_INFO << std::endl << "TestImageMaskingNonEmpty:-----------------------------------------------------------------------------------"; mitk::Image::Pointer mask_image = mitk::ImageGenerator::GenerateImageFromReference( m_TestImage, 0 ); std::vector< itk::Index<3U> > activated_indices; itk::Index<3U> index = {{10, 8, 0}}; activated_indices.push_back( index ); index[0] = 9; index[1] = 8; index[2] = 0; activated_indices.push_back( index ); index[0] = 9; index[1] = 7; index[2] = 0; activated_indices.push_back( index ); index[0] = 10; index[1] = 7; index[2] = 0; activated_indices.push_back( index ); std::vector< itk::Index<3U> >::const_iterator indexIter = activated_indices.begin(); // activate voxel in the mask image mitk::ImagePixelWriteAccessor< unsigned char, 3> writeAccess( mask_image ); while( indexIter != activated_indices.end() ) { writeAccess.SetPixelByIndex( (*indexIter++), 1); } this->VerifyStatistics( ComputeStatistics( m_TestImage, mask_image ), 127.5, 127.5, 12.750); } void mitkImageStatisticsCalculatorTestSuite::TestRecomputeOnModifiedMask() { MITK_INFO << std::endl << "TestRecomputeOnModifiedMask:-----------------------------------------------------------------------------------"; mitk::Image::Pointer mask_image = mitk::ImageGenerator::GenerateImageFromReference( m_TestImage, 0 ); mitk::ImageStatisticsCalculator::Pointer statisticsCalculator = mitk::ImageStatisticsCalculator::New(); statisticsCalculator->SetInputImage( m_TestImage ); mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New(); imgMaskGen->SetImageMask(mask_image); statisticsCalculator->SetMask(imgMaskGen.GetPointer()); this->VerifyStatistics( statisticsCalculator->GetStatistics(), -21474836.480, -21474836.480, -21474836.480); // activate voxel in the mask image - itk::Index<3U> test_index = {11, 8, 0}; + itk::Index<3U> test_index = {{11, 8, 0}}; mitk::ImagePixelWriteAccessor< unsigned char, 3> writeAccess( mask_image ); writeAccess.SetPixelByIndex( test_index, 1); mask_image->Modified(); mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer stat = statisticsCalculator->GetStatistics(); this->VerifyStatistics( stat, 128.0, 0.0, 128.0); MITK_TEST_CONDITION( stat->GetN() == 1, "Calculated mask voxel count '" << stat->GetN() << "' is equal to the desired value '" << 1 << "'" ); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DStatistics() { MITK_INFO << std::endl << "Test plain Pic3D:-----------------------------------------------------------------------------------"; long expected_N = 3211264; double expected_mean = -365.80015345982144; double expected_MPP = 111.80226129535752; double expected_median = -105.16000366210938; double expected_skewness = -0.26976612134147004; double expected_kurtosis = 1.4655017209571437; double expected_uniformity = 0.06087994379480554; double expected_UPP = 0.011227934437026977; double expected_variance = 224036.80150510342; double expected_standarddev = 473.32525973700518; double expected_min = -1023; double expected_max = 1361; double expected_RMS = 598.20276978323352; double expected_entropy = 4.6727423654570357; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 0; expected_minIndex[1] = 0; expected_minIndex[2] = 0; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 139; expected_maxIndex[1] = 182; expected_maxIndex[2] = 43; const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DAxialPlanarFigureMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D axial pf:-----------------------------------------------------------------------------------"; double expected_entropy = 5.6719817476387417; double expected_kurtosis = 5.8846935191205221; double expected_MPP = 230.43933685003768; double expected_max = 1206; double expected_mean = 182.30282131661443; double expected_median = 95.970001220703125; double expected_min = -156; long expected_N = 3190; double expected_RMS = 301.93844376702253; double expected_skewness = 1.6400489794326298; double expected_standarddev = 240.69172225993557; double expected_UPP = 0.024889790784288681; double expected_uniformity = 0.027579917650180332; double expected_variance = 57932.505164453964; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 156; expected_minIndex[1] = 133; expected_minIndex[2] = 24; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 125; expected_maxIndex[1] = 167; expected_maxIndex[2] = 24; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_Pic3DImage); pfMaskGen->SetPlanarFigure(m_Pic3DPlanarFigureAxial); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0, pfMaskGen.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DSagittalPlanarFigureMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D sagittal pf:-----------------------------------------------------------------------------------"; double expected_entropy = 5.6051911962074286; double expected_kurtosis = 6.5814062739142338; double expected_MPP = 249.03202846975088; double expected_max = 1240; double expected_mean = 233.93602693602693; double expected_median = 174.9849853515625; double expected_min = -83; long expected_N = 1188; double expected_RMS = 332.03230188484594; double expected_skewness = 1.7489809015501814; double expected_standarddev = 235.62551813489128; double expected_UPP = 0.026837539253364174; double expected_uniformity = 0.027346982734188126; double expected_variance = 55519.384796335973; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 128; expected_minIndex[1] = 119; expected_minIndex[2] = 22; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 128; expected_maxIndex[1] = 167; expected_maxIndex[2] = 22; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_Pic3DImage); pfMaskGen->SetPlanarFigure(m_Pic3DPlanarFigureSagittal); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0, pfMaskGen.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DCoronalPlanarFigureMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D coronal pf:-----------------------------------------------------------------------------------"; double expected_entropy = 6.0677398647867449; double expected_kurtosis = 1.6242929941303372; double expected_MPP = 76.649350649350652; double expected_max = 156; double expected_mean = -482.14807692307693; double expected_median = -660.07501220703125; double expected_min = -897; long expected_N = 520; double expected_RMS = 595.09446729069839; double expected_skewness = 0.51691492278851858; double expected_standarddev = 348.81321207686312; double expected_UPP = 0.0021560650887573964; double expected_uniformity = 0.020295857988165685; double expected_variance = 121670.6569193787; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 217; expected_minIndex[1] = 127; expected_minIndex[2] = 43; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 209; expected_maxIndex[1] = 127; expected_maxIndex[2] = 39; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_Pic3DImage); pfMaskGen->SetPlanarFigure(m_Pic3DPlanarFigureCoronal); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0, pfMaskGen.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DImageMaskStatistics_label1() { MITK_INFO << std::endl << "Test Pic3D image mask label 1 pf:-----------------------------------------------------------------------------------"; double expected_entropy = 5.695858251095868; double expected_kurtosis = 4.2728827997815717; double expected_MPP = 413.52408256880733; double expected_max = 1206; double expected_mean = 413.52408256880733; double expected_median = 324; double expected_min = 6; long expected_N = 872; double expected_RMS = 472.02024695145235; double expected_skewness = 1.3396074364415382; double expected_standarddev = 227.59821323493802; double expected_UPP = 0.029758648261930806; double expected_uniformity = 0.029758648261930806; double expected_variance = 51800.946667736309; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 135; expected_minIndex[1] = 158; expected_minIndex[2] = 24; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 125; expected_maxIndex[1] = 167; expected_maxIndex[2] = 24; mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New(); imgMaskGen->SetImageMask(m_Pic3DImageMask); imgMaskGen->SetInputImage(m_Pic3DImage); imgMaskGen->SetTimeStep(0); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0, imgMaskGen.GetPointer(), nullptr, 1); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DImageMaskStatistics_label2() { MITK_INFO << std::endl << "Test Pic3D image mask label 2 pf:-----------------------------------------------------------------------------------"; double expected_entropy = 4.3685781901212764; double expected_kurtosis = 9.7999112757587934; double expected_MPP = -nan(""); double expected_max = -145; double expected_mean = -897.92833876221493; double expected_median = -969.16499900817871; double expected_min = -1008; long expected_N = 307; double expected_RMS = 913.01496468179471; double expected_skewness = 2.6658524648889736; double expected_standarddev = 165.29072623903585; double expected_UPP = 0; double expected_uniformity = 0.087544695434434425; double expected_variance = 27321.024180627897; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 170; expected_minIndex[1] = 60; expected_minIndex[2] = 24; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 173; expected_maxIndex[1] = 57; expected_maxIndex[2] = 24; mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New(); imgMaskGen->SetImageMask(m_Pic3DImageMask); imgMaskGen->SetInputImage(m_Pic3DImage); imgMaskGen->SetTimeStep(0); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0, imgMaskGen.GetPointer(), nullptr, 2); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DIgnorePixelValueMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D ignore zero pixels:-----------------------------------------------------------------------------------"; double expected_entropy = 4.671045011438645; double expected_kurtosis = 1.4638176488404484; double expected_MPP = 111.80226129535752; double expected_max = 1361; double expected_mean = -366.48547402877585; double expected_median = -105.16000366210938; double expected_min = -1023; long expected_N = 3205259; double expected_RMS = 598.76286909522139; double expected_skewness = -0.26648854845130782; double expected_standarddev = 473.50329537717545; double expected_UPP = 0.011270044547276429; double expected_uniformity = 0.061029773286547614; double expected_variance = 224205.37073304466; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 0; expected_minIndex[1] = 0; expected_minIndex[2] = 0; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 139; expected_maxIndex[1] = 182; expected_maxIndex[2] = 43; mitk::IgnorePixelMaskGenerator::Pointer ignPixelValMask = mitk::IgnorePixelMaskGenerator::New(); ignPixelValMask->SetInputImage(m_Pic3DImage); ignPixelValMask->SetIgnoredPixelValue(0); ignPixelValMask->SetTimeStep(0); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0, ignPixelValMask.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DSecondaryMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D ignore zero pixels AND Image mask 2:-----------------------------------------------------------------------------------"; double expected_entropy = 5.9741637167320176; double expected_kurtosis = 3.490663358061596; double expected_MPP = 332.43534482758622; double expected_max = 1206; double expected_mean = 320.63333333333333; double expected_median = 265.06500244140625; double expected_min = -57; long expected_N = 720; double expected_RMS = 433.57749531594055; double expected_skewness = 1.1047775627624981; double expected_standarddev = 291.86248474238687; double expected_UPP = 0.020628858024691339; double expected_uniformity = 0.021377314814814797; double expected_variance = 85183.710000000006; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 116; expected_minIndex[1] = 170; expected_minIndex[2] = 24; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 125; expected_maxIndex[1] = 167; expected_maxIndex[2] = 24; mitk::IgnorePixelMaskGenerator::Pointer ignPixelValMask = mitk::IgnorePixelMaskGenerator::New(); ignPixelValMask->SetInputImage(m_Pic3DImage); ignPixelValMask->SetIgnoredPixelValue(0); ignPixelValMask->SetTimeStep(0); mitk::ImageMaskGenerator::Pointer imgMaskGen2 = mitk::ImageMaskGenerator::New(); imgMaskGen2->SetImageMask(m_Pic3DImageMask2); imgMaskGen2->SetInputImage(m_Pic3DImage); imgMaskGen2->SetTimeStep(0); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0, imgMaskGen2.GetPointer(), ignPixelValMask.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylStatistics_time1() { MITK_INFO << std::endl << "Test plain US4D timeStep1:-----------------------------------------------------------------------------------"; double expected_entropy = 4.8272774900452502; double expected_kurtosis = 6.1336513352934432; double expected_MPP = 53.395358640738536; double expected_max = 199; double expected_mean = 35.771298153622375; double expected_median = 20.894999504089355; double expected_min = 0; long expected_N = 3409920; double expected_RMS = 59.244523377028408; double expected_skewness = 1.8734292240015058; double expected_standarddev = 47.226346233600559; double expected_UPP = 0.12098731125004937; double expected_uniformity = 0.12098731125004937; double expected_variance = 2230.3277785759178; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 0; expected_minIndex[1] = 0; expected_minIndex[2] = 0; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 268; expected_maxIndex[1] = 101; expected_maxIndex[2] = 0; const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylAxialPlanarFigureMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4D axial pf timeStep1:-----------------------------------------------------------------------------------"; double expected_entropy = 6.218151288002292; double expected_kurtosis = 1.7322676370242023; double expected_MPP = 121.11663807890223; double expected_max = 199; double expected_mean = 121.11663807890223; double expected_median = 120.14999771118164; double expected_min = 9; long expected_N = 2332; double expected_RMS = 134.41895158590751; double expected_skewness = -0.1454808104597369; double expected_standarddev = 58.30278317472294; double expected_UPP = 0.021354765820606133; double expected_uniformity = 0.021354765820606133; double expected_variance = 3399.214525918756; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 129; expected_minIndex[1] = 131; expected_minIndex[2] = 19; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 126; expected_maxIndex[1] = 137; expected_maxIndex[2] = 19; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_US4DImage); pfMaskGen->SetPlanarFigure(m_US4DPlanarFigureAxial); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1, pfMaskGen.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylSagittalPlanarFigureMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4D sagittal pf timeStep1:-----------------------------------------------------------------------------------"; double expected_entropy = 5.2003987046387508; double expected_kurtosis = 2.7574491062430142; double expected_MPP = 26.212534059945504; double expected_max = 59; double expected_mean = 26.176870748299319; double expected_median = 26.254999160766602; double expected_min = 0; long expected_N = 735; double expected_RMS = 28.084905283121476; double expected_skewness = 0.18245181360752327; double expected_standarddev = 10.175133541567705; double expected_UPP = 0.032921467906890628; double expected_uniformity = 0.032921467906890628; double expected_variance = 103.53334258873615; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 147; expected_minIndex[1] = 94; expected_minIndex[2] = 21; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 147; expected_maxIndex[1] = 77; expected_maxIndex[2] = 24; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_US4DImage); pfMaskGen->SetPlanarFigure(m_US4DPlanarFigureSagittal); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1, pfMaskGen.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylCoronalPlanarFigureMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4D coronal pf timeStep1:-----------------------------------------------------------------------------------"; double expected_entropy = 5.8892941136639161; double expected_kurtosis = 4.6434920707409564; double expected_MPP = 55.486426346239433; double expected_max = 199; double expected_mean = 55.118479221927501; double expected_median = 36.815000534057617; double expected_min = 0; long expected_N = 2262; double expected_RMS = 71.98149752438627; double expected_skewness = 1.4988288344523237; double expected_standarddev = 46.29567187238105; double expected_UPP = 0.023286748110675673; double expected_uniformity = 0.023286748110675673; double expected_variance = 2143.2892341151742; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 214; expected_minIndex[1] = 169; expected_minIndex[2] = 10; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 99; expected_maxIndex[1] = 169; expected_maxIndex[2] = 17; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_US4DImage); pfMaskGen->SetPlanarFigure(m_US4DPlanarFigureCoronal); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1, pfMaskGen.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylImageMaskStatistics_time1_label_1() { MITK_INFO << std::endl << "Test US4D image mask time 1 label 1:-----------------------------------------------------------------------------------"; double expected_entropy = 5.0082903903398677; double expected_kurtosis = 3.6266994778237809; double expected_MPP = 169.58938547486034; double expected_max = 199; double expected_mean = 169.58938547486034; double expected_median = 187.44000244140625; double expected_min = 63; long expected_N = 716; double expected_RMS = 173.09843164831432; double expected_skewness = -1.2248969838579555; double expected_standarddev = 34.677188083311712; double expected_UPP = 0.076601073624418703; double expected_uniformity = 0.076601073624418703; double expected_variance = 1202.5073733653758; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 82; expected_minIndex[1] = 158; expected_minIndex[2] = 19; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 126; expected_maxIndex[1] = 140; expected_maxIndex[2] = 19; mitk::ImageMaskGenerator::Pointer imgMask1 = mitk::ImageMaskGenerator::New(); imgMask1->SetInputImage(m_US4DImage); imgMask1->SetImageMask(m_US4DImageMask); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1, imgMask1.GetPointer(), nullptr, 1); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylImageMaskStatistics_time2_label_1() { MITK_INFO << std::endl << "Test US4D image mask time 2 label 1:-----------------------------------------------------------------------------------"; double expected_entropy = 5.1857604214916506; double expected_kurtosis = 3.0692303858330683; double expected_MPP = 167.97194163860831; double expected_max = 199; double expected_mean = 167.97194163860831; double expected_median = 184.39499664306641; double expected_min = 72; long expected_N = 891; double expected_RMS = 171.67986611998634; double expected_skewness = -1.1221651136259736; double expected_standarddev = 35.488071983870803; double expected_UPP = 0.063124070232188439; double expected_uniformity = 0.063124070232188439; double expected_variance = 1259.4032531323958; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 103; expected_minIndex[1] = 212; expected_minIndex[2] = 19; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 102; expected_maxIndex[1] = 168; expected_maxIndex[2] = 19; mitk::ImageMaskGenerator::Pointer imgMask1 = mitk::ImageMaskGenerator::New(); imgMask1->SetInputImage(m_US4DImage); imgMask1->SetImageMask(m_US4DImageMask); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 2, imgMask1.GetPointer(), nullptr, 1); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylImageMaskStatistics_time1_label_2() { MITK_INFO << std::endl << "Test US4D image mask time 1 label 2:-----------------------------------------------------------------------------------"; double expected_entropy = 5.0822234230119001; double expected_kurtosis = 2.4346603343623747; double expected_MPP = 20.733626373626375; double expected_max = 46; double expected_mean = 20.624836029733274; double expected_median = 20.010000228881836; double expected_min = 0; long expected_N = 2287; double expected_RMS = 22.508347574573804; double expected_skewness = 0.13837218490626488; double expected_standarddev = 9.0134260569684965; double expected_UPP = 0.034783970308787; double expected_uniformity = 0.034783970308787; double expected_variance = 81.241849284438644; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 178; expected_minIndex[1] = 76; expected_minIndex[2] = 19; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 198; expected_maxIndex[1] = 90; expected_maxIndex[2] = 19; mitk::ImageMaskGenerator::Pointer imgMask1 = mitk::ImageMaskGenerator::New(); imgMask1->SetInputImage(m_US4DImage); imgMask1->SetImageMask(m_US4DImageMask); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1, imgMask1.GetPointer(), nullptr, 2); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylIgnorePixelValueMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4D ignore zero pixels:-----------------------------------------------------------------------------------"; double expected_entropy = 5.8609813848087962; double expected_kurtosis = 4.7556214582883651; double expected_MPP = 53.395358640738536; double expected_max = 199; double expected_mean = 53.395358640738536; double expected_median = 35.649999618530273; double expected_min = 1; long expected_N = 2284417; double expected_RMS = 72.382339046507084; double expected_skewness = 1.588289859859108; double expected_standarddev = 48.868585834566694; double expected_UPP = 0.023927063695115193; double expected_uniformity = 0.023927063695115193; double expected_variance = 2388.1386814704128; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 187; expected_minIndex[1] = 19; expected_minIndex[2] = 0; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 268; expected_maxIndex[1] = 101; expected_maxIndex[2] = 0; mitk::IgnorePixelMaskGenerator::Pointer ignPixelValMask = mitk::IgnorePixelMaskGenerator::New(); ignPixelValMask->SetInputImage(m_US4DImage); ignPixelValMask->SetIgnoredPixelValue(0); ignPixelValMask->SetTimeStep(1); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1, ignPixelValMask.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylSecondaryMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4d ignore zero pixels AND Image mask 2:-----------------------------------------------------------------------------------"; double expected_entropy = 4.9955858614274558; double expected_kurtosis = 17.471042803365179; double expected_MPP = 32.791403286978507; double expected_max = 199; double expected_mean = 32.791403286978507; double expected_median = 25.75; double expected_min = 1; long expected_N = 17402; double expected_RMS = 42.776697859745241; double expected_skewness = 3.3991813038552596; double expected_standarddev = 27.469433016621732; double expected_UPP = 0.043040554251756687; double expected_uniformity = 0.043040554251756687; double expected_variance = 754.56975025466807; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 177; expected_minIndex[1] = 27; expected_minIndex[2] = 36; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 109; expected_maxIndex[1] = 116; expected_maxIndex[2] = 36; mitk::IgnorePixelMaskGenerator::Pointer ignPixelValMask = mitk::IgnorePixelMaskGenerator::New(); ignPixelValMask->SetInputImage(m_US4DImage); ignPixelValMask->SetIgnoredPixelValue(0); mitk::ImageMaskGenerator::Pointer imgMaskGen2 = mitk::ImageMaskGenerator::New(); imgMaskGen2->SetImageMask(m_US4DImageMask2); imgMaskGen2->SetInputImage(m_US4DImage); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1, imgMaskGen2.GetPointer(), ignPixelValMask.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer mitkImageStatisticsCalculatorTestSuite::ComputeStatistics( mitk::Image::Pointer image, mitk::PlanarFigure::Pointer polygon ) { mitk::ImageStatisticsCalculator::Pointer statisticsCalculator = mitk::ImageStatisticsCalculator::New(); statisticsCalculator->SetInputImage( image ); statisticsCalculator->SetNBinsForHistogramStatistics(10); mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New(); planFigMaskGen->SetInputImage(image); planFigMaskGen->SetPlanarFigure(polygon); statisticsCalculator->SetMask(planFigMaskGen.GetPointer()); try { return statisticsCalculator->GetStatistics(); } catch( ... ) { } return mitk::ImageStatisticsCalculator::StatisticsContainer::New(); } const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer mitkImageStatisticsCalculatorTestSuite::ComputeStatistics(mitk::Image::Pointer image, mitk::Image::Pointer image_mask ) { mitk::ImageStatisticsCalculator::Pointer statisticsCalculator = mitk::ImageStatisticsCalculator::New(); statisticsCalculator->SetInputImage(image); statisticsCalculator->SetNBinsForHistogramStatistics(10); mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New(); imgMaskGen->SetImageMask(image_mask); statisticsCalculator->SetMask(imgMaskGen.GetPointer()); return statisticsCalculator->GetStatistics(); } const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer mitkImageStatisticsCalculatorTestSuite::ComputeStatisticsNew(mitk::Image::Pointer image, int timeStep, mitk::MaskGenerator::Pointer maskGen, mitk::MaskGenerator::Pointer secondardMaskGen, unsigned short label) { mitk::ImageStatisticsCalculator::Pointer imgStatCalc = mitk::ImageStatisticsCalculator::New(); imgStatCalc->SetInputImage(image); if (maskGen.IsNotNull()) { imgStatCalc->SetMask(maskGen.GetPointer()); if (secondardMaskGen.IsNotNull()) { imgStatCalc->SetSecondaryMask(secondardMaskGen.GetPointer()); } } return imgStatCalc->GetStatistics(timeStep, label); } void mitkImageStatisticsCalculatorTestSuite::VerifyStatistics(mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer stats, double testMean, double testSD, double testMedian) { int tmpMean = stats->GetMean() * 100; double calculatedMean = tmpMean / 100.0; MITK_TEST_CONDITION( calculatedMean == testMean, "Calculated mean grayvalue '" << calculatedMean << "' is equal to the desired value '" << testMean << "'" ); int tmpSD = stats->GetStd() * 100; double calculatedSD = tmpSD / 100.0; MITK_TEST_CONDITION( calculatedSD == testSD, "Calculated grayvalue sd '" << calculatedSD << "' is equal to the desired value '" << testSD <<"'" ); int tmpMedian = stats->GetMedian() * 100; double calculatedMedian = tmpMedian / 100.0; MITK_TEST_CONDITION( testMedian == calculatedMedian, "Calculated median grayvalue '" << calculatedMedian << "' is equal to the desired value '" << testMedian << "'"); } void mitkImageStatisticsCalculatorTestSuite::VerifyStatistics(mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer stats, long N, double mean, double MPP, double median, double skewness, double kurtosis, double uniformity, double UPP, double variance, double stdev, double min, double max, double RMS, double entropy, vnl_vector minIndex, vnl_vector maxIndex) { MITK_TEST_CONDITION(std::abs(stats->GetN() - N) < mitk::eps, "calculated N: " << stats->GetN() << " expected N: " << N); MITK_TEST_CONDITION(std::abs(stats->GetMean() - mean) < mitk::eps, "calculated mean: " << stats->GetMean() << " expected mean: " << mean); // in one test case MPP is None because the roi has no positive pixels if (!std::isnan(stats->GetMPP())) { MITK_TEST_CONDITION(std::abs(stats->GetMPP() - MPP) < mitk::eps, "calculated MPP: " << stats->GetMPP() << " expected MPP: " << MPP); } MITK_TEST_CONDITION(std::abs(stats->GetMedian() - median) < mitk::eps, "calculated median: " << stats->GetMedian() << " expected median: " << median); MITK_TEST_CONDITION(std::abs(stats->GetSkewness() - skewness) < mitk::eps, "calculated skewness: " << stats->GetSkewness() << " expected skewness: " << skewness); MITK_TEST_CONDITION(std::abs(stats->GetKurtosis() - kurtosis) < mitk::eps, "calculated kurtosis: " << stats->GetKurtosis() << " expected kurtosis: " << kurtosis); MITK_TEST_CONDITION(std::abs(stats->GetUniformity() - uniformity) < mitk::eps, "calculated uniformity: " << stats->GetUniformity() << " expected uniformity: " << uniformity); MITK_TEST_CONDITION(std::abs(stats->GetUPP() - UPP) < mitk::eps, "calculated UPP: " << stats->GetUPP() << " expected UPP: " << UPP); MITK_TEST_CONDITION(std::abs(stats->GetVariance() - variance) < mitk::eps, "calculated variance: " << stats->GetVariance() << " expected variance: " << variance); MITK_TEST_CONDITION(std::abs(stats->GetStd() - stdev) < mitk::eps, "calculated stdev: " << stats->GetStd() << " expected stdev: " << stdev); MITK_TEST_CONDITION(std::abs(stats->GetMin() - min) < mitk::eps, "calculated min: " << stats->GetMin() << " expected min: " << min); MITK_TEST_CONDITION(std::abs(stats->GetMax() - max) < mitk::eps, "calculated max: " << stats->GetMax() << " expected max: " << max); MITK_TEST_CONDITION(std::abs(stats->GetRMS() - RMS) < mitk::eps, "calculated RMS: " << stats->GetRMS() << " expected RMS: " << RMS); MITK_TEST_CONDITION(std::abs(stats->GetEntropy() - entropy) < mitk::eps, "calculated entropy: " << stats->GetEntropy() << " expected entropy: " << entropy); for (unsigned int i = 0; i < minIndex.size(); ++i) { MITK_TEST_CONDITION(std::abs(stats->GetMinIndex()[i] - minIndex[i]) < mitk::eps, "minIndex [" << i << "] = " << stats->GetMinIndex()[i] << " expected: " << minIndex[i]); } for (unsigned int i = 0; i < maxIndex.size(); ++i) { MITK_TEST_CONDITION(std::abs(stats->GetMaxIndex()[i] - maxIndex[i]) < mitk::eps, "maxIndex [" << i << "] = " << stats->GetMaxIndex()[i] << " expected: " << maxIndex[i]); } } void mitkImageStatisticsCalculatorTestSuite::TestUninitializedImage() { /***************************** * loading uninitialized image to datastorage ******************************/ MITK_INFO << std::endl << "Test uninitialized image: -----------------------------------------------------------------------------------"; MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::Exception) mitk::Image::Pointer image = mitk::Image::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(image); mitk::ImageStatisticsCalculator::Pointer is = mitk::ImageStatisticsCalculator::New(); is->GetStatistics(); MITK_TEST_FOR_EXCEPTION_END(mitk::Exception) } MITK_TEST_SUITE_REGISTRATION(mitkImageStatisticsCalculator) diff --git a/Modules/Persistence/Testing/mitkPersistenceTest.cpp b/Modules/Persistence/Testing/mitkPersistenceTest.cpp index 434a1d5b50..8af0fbe4bb 100644 --- a/Modules/Persistence/Testing/mitkPersistenceTest.cpp +++ b/Modules/Persistence/Testing/mitkPersistenceTest.cpp @@ -1,191 +1,191 @@ /*=================================================================== 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 #include #include #include #include #include #include #include struct PersistenceTestClass { PersistenceTestClass() : id(""), param1(1), param2(2), param3(false) {} std::string id; int param1; double param2; bool param3; PERSISTENCE_CREATE3(PersistenceTestClass, id, param1, param2, param3) }; struct TestPropertyListReplacedObserver : public mitk::PropertyListReplacedObserver { TestPropertyListReplacedObserver() : counter(0) {} virtual void BeforePropertyListReplaced(const std::string &id, mitk::PropertyList *) override { if (id == m_Id) ++counter; } virtual void AfterPropertyListReplaced(const std::string &id, mitk::PropertyList *) override { if (id == m_Id) ++counter; } int counter; std::string m_Id; }; class mitkPersistenceTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPersistenceTestSuite); MITK_TEST(PersistenceTest); CPPUNIT_TEST_SUITE_END(); private: // private test members that are initialized by setUp() std::string testClassId; int param1; double param2; bool param3; public: void setUp() override { testClassId = "testClass"; param1 = 100; param2 = 201.56; param3 = true; } void PersistenceTest() { // dummy load of SceneIO, otherwise PersistenceService won't be available mitk::PersistenceService::LoadModule(); PERSISTENCE_GET_SERVICE_MACRO CPPUNIT_ASSERT_MESSAGE("Testing availability of the PersistenceService.", persistenceService != nullptr); // Initialize testable parameter values std::string defaultPersistenceFile = persistenceService->GetDefaultPersistenceFile(); PersistenceTestClass autoLoadTestClass; autoLoadTestClass.id = testClassId; if (itksys::SystemTools::FileExists(defaultPersistenceFile.c_str(), true) && persistenceService->GetAutoLoadAndSave()) { /// Test auto load/save of the PersistenceService. itksys::SystemTools::RemoveFile(defaultPersistenceFile.c_str()); autoLoadTestClass.FromPropertyList(); testParams(autoLoadTestClass, "autoLoadTestClass"); } std::string testTempFile = mitk::IOUtil::CreateTemporaryFile("XXXXXX.mitk"); std::string testXmlTempFile = mitk::IOUtil::CreateTemporaryFile("PersistenceTestFileXXXXXX.xml"); MITK_INFO << "Testing standard write to scene file/xml file."; PersistenceTestClass testClass; testClass.id = testClassId; testClass.param1 = param1; testClass.param2 = param2; testClass.param3 = param3; CPPUNIT_ASSERT_MESSAGE("Testing to save a scene file", testClass.Save(testTempFile)); CPPUNIT_ASSERT_MESSAGE("testing to save an xml file", testClass.Save(testXmlTempFile)); CPPUNIT_ASSERT_MESSAGE("Testing read from scene file: persistenceService->RemovePropertyList(testClassId)", persistenceService->RemovePropertyList(testClassId)); PersistenceTestClass testClass2; testClass2.id = testClassId; CPPUNIT_ASSERT_MESSAGE("Testing read from scene file: testClass2.Load(testTempFile.path())", testClass2.Load(testTempFile)); testParams(testClass2, "testClass2"); CPPUNIT_ASSERT_MESSAGE("Testing read from xml file: persistenceService->RemovePropertyList(testClassId)", persistenceService->RemovePropertyList(testClassId)); PersistenceTestClass testClass3; testClass3.id = testClassId; CPPUNIT_ASSERT_MESSAGE("Testing read from xml file: testClass3.Load(testXmlTempFile.path())", testClass3.Load(testXmlTempFile)); testParams(testClass3, "testClass3"); CPPUNIT_ASSERT_MESSAGE( "Testing appendChanges functionality with scene load/write: persistenceService->RemovePropertyList(testClassId)", persistenceService->RemovePropertyList(testClassId)); CPPUNIT_ASSERT_MESSAGE( "Testing appendChanges functionality with scene load/write: persistenceService->Save(testTempFile.path())", persistenceService->Save(testTempFile, true)); CPPUNIT_ASSERT_MESSAGE( "Testing appendChanges functionality with scene load/write: persistenceService->Load(testTempFile.path())", persistenceService->Load(testTempFile)); PersistenceTestClass testClass4; testClass4.id = testClassId; testClass4.FromPropertyList(); testParams(testClass4, "testClass4"); CPPUNIT_ASSERT_MESSAGE( "Testing appendChanges functionality with xml load/write: persistenceService->RemovePropertyList(testClassId)", persistenceService->RemovePropertyList(testClassId)); CPPUNIT_ASSERT_MESSAGE( "Testing appendChanges functionality with xml load/write: persistenceService->Save(testXmlTempFile.path())", persistenceService->Save(testXmlTempFile, true)); CPPUNIT_ASSERT_MESSAGE( "Testing appendChanges functionality with xml load/write: persistenceService->Load(testXmlTempFile.path())", persistenceService->Load(testXmlTempFile)); PersistenceTestClass testClass5; testClass5.id = testClassId; testClass5.FromPropertyList(); testParams(testClass5, "testClass5"); // Test Observer Functionality TestPropertyListReplacedObserver testObserver; testObserver.m_Id = testClassId; persistenceService->AddPropertyListReplacedObserver(&testObserver); persistenceService->Load(testTempFile); CPPUNIT_ASSERT_MESSAGE( - "Testing observer functionality: testObserver.counter == 2, testObserver.counter is " + testObserver.counter, + "Testing observer functionality: testObserver.counter == 2, testObserver.counter is " + std::to_string(testObserver.counter), testObserver.counter == 2); autoLoadTestClass.param1 = param1; autoLoadTestClass.param2 = param2; autoLoadTestClass.param3 = param3; autoLoadTestClass.ToPropertyList(); } /** * Helper Method that compares the returned class to its base values */ void testParams(const PersistenceTestClass &testClass, const std::string &) { CPPUNIT_ASSERT_MESSAGE("Parameter of TestClass not equal to reference value: testClass.id", testClass.id == testClassId); CPPUNIT_ASSERT_MESSAGE("Parameter of TestClass not equal to reference value: testClass.param1", testClass.param1 == param1); CPPUNIT_ASSERT_MESSAGE("Parameter of TestClass not equal to reference value: testClass.param2", testClass.param2 == param2); CPPUNIT_ASSERT_MESSAGE("Parameter of TestClass not equal to reference value: testClass.param3", testClass.param3 == param3); } }; MITK_TEST_SUITE_REGISTRATION(mitkPersistence) diff --git a/Modules/SceneSerializationBase/test/mitkVectorPropertySerializerTest.cpp b/Modules/SceneSerializationBase/test/mitkVectorPropertySerializerTest.cpp index 0417d7ccd1..f695a5dba7 100644 --- a/Modules/SceneSerializationBase/test/mitkVectorPropertySerializerTest.cpp +++ b/Modules/SceneSerializationBase/test/mitkVectorPropertySerializerTest.cpp @@ -1,145 +1,145 @@ /*=================================================================== 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 "mitkTestFixture.h" #include "mitkTestingMacros.h" #include "mitkBasePropertySerializer.h" #include "mitkVectorProperty.h" #include #include #include #include "mitkEqual.h" /** \brief Test for VectorPropertySerializer. Creates simple std::vector instances, puts them into a VectorProperty of appropriate type, then asks a serializer to serialize them into XML. Test expects that there is a deserializer somewhere in the system (i.e. registered with the ITK object factory. The test further expects that this deserializer is able to create a VectorProperty from XML and that this VectorProperty equals the input of serialization. */ class mitkVectorPropertySerializerTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkVectorPropertySerializerTestSuite); MITK_TEST(TestSerialize); MITK_TEST(TestSerialize); MITK_TEST(TestSerializeIntTypedef); MITK_TEST(TestSerializeDoubleTypedef); CPPUNIT_TEST_SUITE_END(); public: void setUp() override {} void tearDown() override {} template typename mitk::VectorProperty::Pointer MakeExampleProperty() { typename mitk::VectorProperty::Pointer vectorProperty = mitk::VectorProperty::New(); std::vector data; - data.push_back(-918273674.6172838); + data.push_back(static_cast(-918273674.6172838)); data.push_back(0); - data.push_back(+6172838.918273674); + data.push_back(static_cast(+6172838.918273674)); data.push_back(sqrt(2)); if (std::numeric_limits::has_infinity) { data.push_back(std::numeric_limits::infinity()); data.push_back(-std::numeric_limits::infinity()); } // do NOT test NaN: cannot be == to itself, so cannot be tested like the others // NaN is covered in a different test (FloatToStringTest at the time of writing this) // data.push_back( std::numeric_limits::quiet_NaN() ); vectorProperty->SetValue(data); return vectorProperty; } mitk::BaseProperty::Pointer TestSerialize(mitk::BaseProperty *property) { std::string serializername = std::string(property->GetNameOfClass()) + "Serializer"; std::list allSerializers = itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str()); CPPUNIT_ASSERT_EQUAL(size_t(1), allSerializers.size()); mitk::BasePropertySerializer *serializer = dynamic_cast(allSerializers.begin()->GetPointer()); CPPUNIT_ASSERT(serializer != nullptr); if (!serializer) return nullptr; serializer->SetProperty(property); TiXmlElement *serialization(nullptr); try { serialization = serializer->Serialize(); } catch (...) { } CPPUNIT_ASSERT(serialization != nullptr); if (!serialization) return nullptr; mitk::BaseProperty::Pointer restoredProperty = serializer->Deserialize(serialization); CPPUNIT_ASSERT(restoredProperty.IsNotNull()); return restoredProperty; } template void TestSerialize() { auto property = MakeExampleProperty(); mitk::BaseProperty::Pointer restored_property = TestSerialize(property); typename mitk::VectorProperty::Pointer restored_vector_property = dynamic_cast *>(restored_property.GetPointer()); CPPUNIT_ASSERT(restored_vector_property.IsNotNull()); auto orig_vector = property->GetValue(); auto restored_vector = restored_vector_property->GetValue(); CPPUNIT_ASSERT_EQUAL(orig_vector.size(), restored_vector.size()); for (unsigned int i = 0; i < orig_vector.size(); ++i) { // compare using Equal, i.e. with tolerance of mitk::eps CPPUNIT_ASSERT_MESSAGE(std::string("Verifying element ") + boost::lexical_cast(i), mitk::Equal(orig_vector[i], restored_vector[i])); } } void TestSerializeIntTypedef() { mitk::IntVectorProperty::Pointer intVectorProperty = MakeExampleProperty().GetPointer(); TestSerialize(intVectorProperty.GetPointer()); } void TestSerializeDoubleTypedef() { mitk::DoubleVectorProperty::Pointer doubleVectorProperty = MakeExampleProperty().GetPointer(); TestSerialize(doubleVectorProperty.GetPointer()); } }; // class MITK_TEST_SUITE_REGISTRATION(mitkVectorPropertySerializer) diff --git a/Modules/Segmentation/Algorithms/mitkContourSetToPointSetFilter.cpp b/Modules/Segmentation/Algorithms/mitkContourSetToPointSetFilter.cpp index c05ac76e5c..1427d01af2 100644 --- a/Modules/Segmentation/Algorithms/mitkContourSetToPointSetFilter.cpp +++ b/Modules/Segmentation/Algorithms/mitkContourSetToPointSetFilter.cpp @@ -1,88 +1,88 @@ /*=================================================================== 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 "mitkContourSetToPointSetFilter.h" #include #include mitk::ContourSetToPointSetFilter::ContourSetToPointSetFilter() { OutputType::Pointer output = dynamic_cast(this->MakeOutput(0).GetPointer()); this->SetNumberOfRequiredInputs(1); this->SetNumberOfIndexedOutputs(1); this->SetNthOutput(0, output.GetPointer()); m_Frequency = 5; } mitk::ContourSetToPointSetFilter::~ContourSetToPointSetFilter() { } void mitk::ContourSetToPointSetFilter::GenerateOutputInformation() { } void mitk::ContourSetToPointSetFilter::GenerateData() { mitk::ContourSet *input = (mitk::ContourSet *)(this->GetInput()); mitk::PointSet::Pointer output = this->GetOutput(); mitk::ContourSet::ContourVectorType contourVec = input->GetContours(); auto contourIt = contourVec.begin(); unsigned int pointId = 0; while (contourIt != contourVec.end()) { mitk::Contour *nextContour = (mitk::Contour *)(*contourIt).second; mitk::Contour::InputType idx = nextContour->GetContourPath()->StartOfInput(); mitk::Contour::OutputType point; mitk::Contour::InputType end = nextContour->GetContourPath()->EndOfInput(); if (end > 50000) end = 0; while (idx <= end) { point = nextContour->GetContourPath()->Evaluate(idx); Contour::BoundingBoxType::PointType p; p.CastFrom(point); mitk::PointOperation popInsert(mitk::OpINSERT, p, pointId++); mitk::PointOperation popDeactivate(mitk::OpDESELECTPOINT, p, pointId++); output->ExecuteOperation(&popInsert); output->ExecuteOperation(&popDeactivate); idx += m_Frequency; } contourIt++; } } const mitk::ContourSet *mitk::ContourSetToPointSetFilter::GetInput(void) { if (this->GetNumberOfInputs() < 1) { return nullptr; } - return static_cast(this->BaseProcess::GetInput(0)); + return static_cast(this->BaseDataSource::GetInput(0)); } void mitk::ContourSetToPointSetFilter::SetInput(const mitk::ContourSet *input) { // Process object is not const-correct so the const_cast is required here - this->BaseProcess::SetNthInput(0, const_cast(input)); + this->BaseDataSource::SetNthInput(0, const_cast(input)); } diff --git a/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp b/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp index 6876100ffc..fb239fe012 100644 --- a/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp +++ b/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp @@ -1,514 +1,514 @@ /*=================================================================== 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 "mitkShowSegmentationAsSmoothedSurface.h" #include "itkIntelligentBinaryClosingFilter.h" #include "mitkImageCast.h" #include "mitkImageToItk.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace mitk; using namespace std; ShowSegmentationAsSmoothedSurface::ShowSegmentationAsSmoothedSurface() { } ShowSegmentationAsSmoothedSurface::~ShowSegmentationAsSmoothedSurface() { } void ShowSegmentationAsSmoothedSurface::Initialize(const NonBlockingAlgorithm *other) { Superclass::Initialize(other); bool syncVisibility = false; if (other != nullptr) other->GetParameter("Sync visibility", syncVisibility); SetParameter("Sync visibility", syncVisibility); SetParameter("Wireframe", false); // The Smoothing value is used as variance for a Gauss filter. // A reasonable default value equals the image spacing in mm. SetParameter("Smoothing", 1.0f); // Valid range for decimation value is [0, 1). High values // increase decimation, especially when very close to 1. // A value of 0 disables decimation. SetParameter("Decimation", 0.5f); // Valid range for closing value is [0, 1]. Higher values // increase closing. A value of 0 disables closing. SetParameter("Closing", 0.0f); } bool ShowSegmentationAsSmoothedSurface::ReadyToRun() { try { mitk::Image::Pointer image; GetPointerParameter("Input", image); return image.IsNotNull() && GetGroupNode(); } catch (const invalid_argument &) { return false; } } bool ShowSegmentationAsSmoothedSurface::ThreadedUpdateFunction() { Image::Pointer image; GetPointerParameter("Input", image); float smoothing; GetParameter("Smoothing", smoothing); float decimation; GetParameter("Decimation", decimation); float closing; GetParameter("Closing", closing); int timeNr = 0; GetParameter("TimeNr", timeNr); if (image->GetDimension() == 4) MITK_INFO << "CREATING SMOOTHED POLYGON MODEL (t = " << timeNr << ')'; else MITK_INFO << "CREATING SMOOTHED POLYGON MODEL"; MITK_INFO << " Smoothing = " << smoothing; MITK_INFO << " Decimation = " << decimation; MITK_INFO << " Closing = " << closing; Geometry3D::Pointer geometry = dynamic_cast(image->GetGeometry()->Clone().GetPointer()); // Make ITK image out of MITK image typedef itk::Image CharImageType; typedef itk::Image ShortImageType; typedef itk::Image FloatImageType; if (image->GetDimension() == 4) { ImageTimeSelector::Pointer imageTimeSelector = ImageTimeSelector::New(); imageTimeSelector->SetInput(image); imageTimeSelector->SetTimeNr(timeNr); imageTimeSelector->UpdateLargestPossibleRegion(); image = imageTimeSelector->GetOutput(0); } ImageToItk::Pointer imageToItkFilter = ImageToItk::New(); try { imageToItkFilter->SetInput(image); } catch (const itk::ExceptionObject &e) { // Most probably the input image type is wrong. Binary images are expected to be // >unsigned< char images. MITK_ERROR << e.GetDescription() << endl; return false; } imageToItkFilter->Update(); CharImageType::Pointer itkImage = imageToItkFilter->GetOutput(); // Get bounding box and relabel MITK_INFO << "Extracting VOI..."; int imageLabel = 1; bool roiFound = false; CharImageType::IndexType minIndex; minIndex.Fill(numeric_limits::max()); CharImageType::IndexType maxIndex; maxIndex.Fill(numeric_limits::min()); itk::ImageRegionIteratorWithIndex iter(itkImage, itkImage->GetLargestPossibleRegion()); for (iter.GoToBegin(); !iter.IsAtEnd(); ++iter) { if (iter.Get() == imageLabel) { roiFound = true; iter.Set(1); CharImageType::IndexType currentIndex = iter.GetIndex(); for (unsigned int dim = 0; dim < 3; ++dim) { minIndex[dim] = min(currentIndex[dim], minIndex[dim]); maxIndex[dim] = max(currentIndex[dim], maxIndex[dim]); } } else { iter.Set(0); } } if (!roiFound) { ProgressBar::GetInstance()->Progress(8); MITK_ERROR << "Didn't found segmentation labeled with " << imageLabel << "!" << endl; return false; } ProgressBar::GetInstance()->Progress(1); // Extract and pad bounding box typedef itk::RegionOfInterestImageFilter ROIFilterType; ROIFilterType::Pointer roiFilter = ROIFilterType::New(); CharImageType::RegionType region; CharImageType::SizeType size; for (unsigned int dim = 0; dim < 3; ++dim) { size[dim] = maxIndex[dim] - minIndex[dim] + 1; } region.SetIndex(minIndex); region.SetSize(size); roiFilter->SetInput(itkImage); roiFilter->SetRegionOfInterest(region); roiFilter->ReleaseDataFlagOn(); roiFilter->ReleaseDataBeforeUpdateFlagOn(); typedef itk::ConstantPadImageFilter PadFilterType; PadFilterType::Pointer padFilter = PadFilterType::New(); const PadFilterType::SizeValueType pad[3] = {10, 10, 10}; padFilter->SetInput(roiFilter->GetOutput()); padFilter->SetConstant(0); padFilter->SetPadLowerBound(pad); padFilter->SetPadUpperBound(pad); padFilter->ReleaseDataFlagOn(); padFilter->ReleaseDataBeforeUpdateFlagOn(); padFilter->Update(); CharImageType::Pointer roiImage = padFilter->GetOutput(); roiImage->DisconnectPipeline(); roiFilter = nullptr; padFilter = nullptr; // Correct origin of real geometry (changed by cropping and padding) typedef Geometry3D::TransformType TransformType; TransformType::Pointer transform = TransformType::New(); TransformType::OutputVectorType translation; for (unsigned int dim = 0; dim < 3; ++dim) translation[dim] = (int)minIndex[dim] - (int)pad[dim]; transform->SetIdentity(); transform->Translate(translation); geometry->Compose(transform, true); ProgressBar::GetInstance()->Progress(1); // Median MITK_INFO << "Median..."; typedef itk::BinaryMedianImageFilter MedianFilterType; MedianFilterType::Pointer medianFilter = MedianFilterType::New(); - CharImageType::SizeType radius = {0}; + CharImageType::SizeType radius = {{0}}; medianFilter->SetRadius(radius); medianFilter->SetBackgroundValue(0); medianFilter->SetForegroundValue(1); medianFilter->SetInput(roiImage); medianFilter->ReleaseDataFlagOn(); medianFilter->ReleaseDataBeforeUpdateFlagOn(); medianFilter->Update(); ProgressBar::GetInstance()->Progress(1); // Intelligent closing MITK_INFO << "Intelligent closing..."; unsigned int surfaceRatio = (unsigned int)((1.0f - closing) * 100.0f); typedef itk::IntelligentBinaryClosingFilter ClosingFilterType; ClosingFilterType::Pointer closingFilter = ClosingFilterType::New(); closingFilter->SetInput(medianFilter->GetOutput()); closingFilter->ReleaseDataFlagOn(); closingFilter->ReleaseDataBeforeUpdateFlagOn(); closingFilter->SetSurfaceRatio(surfaceRatio); closingFilter->Update(); ShortImageType::Pointer closedImage = closingFilter->GetOutput(); closedImage->DisconnectPipeline(); roiImage = nullptr; medianFilter = nullptr; closingFilter = nullptr; ProgressBar::GetInstance()->Progress(1); // Gaussian blur MITK_INFO << "Gauss..."; typedef itk::BinaryThresholdImageFilter BinaryThresholdToFloatFilterType; BinaryThresholdToFloatFilterType::Pointer binThresToFloatFilter = BinaryThresholdToFloatFilterType::New(); binThresToFloatFilter->SetInput(closedImage); binThresToFloatFilter->SetLowerThreshold(1); binThresToFloatFilter->SetUpperThreshold(1); binThresToFloatFilter->SetInsideValue(100); binThresToFloatFilter->SetOutsideValue(0); binThresToFloatFilter->ReleaseDataFlagOn(); binThresToFloatFilter->ReleaseDataBeforeUpdateFlagOn(); typedef itk::DiscreteGaussianImageFilter GaussianFilterType; // From the following line on, IntelliSense (VS 2008) is broken. Any idea how to fix it? GaussianFilterType::Pointer gaussFilter = GaussianFilterType::New(); gaussFilter->SetInput(binThresToFloatFilter->GetOutput()); gaussFilter->SetUseImageSpacing(true); gaussFilter->SetVariance(smoothing); gaussFilter->ReleaseDataFlagOn(); gaussFilter->ReleaseDataBeforeUpdateFlagOn(); typedef itk::BinaryThresholdImageFilter BinaryThresholdFromFloatFilterType; BinaryThresholdFromFloatFilterType::Pointer binThresFromFloatFilter = BinaryThresholdFromFloatFilterType::New(); binThresFromFloatFilter->SetInput(gaussFilter->GetOutput()); binThresFromFloatFilter->SetLowerThreshold(50); binThresFromFloatFilter->SetUpperThreshold(255); binThresFromFloatFilter->SetInsideValue(1); binThresFromFloatFilter->SetOutsideValue(0); binThresFromFloatFilter->ReleaseDataFlagOn(); binThresFromFloatFilter->ReleaseDataBeforeUpdateFlagOn(); binThresFromFloatFilter->Update(); CharImageType::Pointer blurredImage = binThresFromFloatFilter->GetOutput(); blurredImage->DisconnectPipeline(); closedImage = nullptr; binThresToFloatFilter = nullptr; gaussFilter = nullptr; ProgressBar::GetInstance()->Progress(1); // Fill holes MITK_INFO << "Filling cavities..."; typedef itk::ConnectedThresholdImageFilter ConnectedThresholdFilterType; ConnectedThresholdFilterType::Pointer connectedThresFilter = ConnectedThresholdFilterType::New(); CharImageType::IndexType corner; corner[0] = 0; corner[1] = 0; corner[2] = 0; connectedThresFilter->SetInput(blurredImage); connectedThresFilter->SetSeed(corner); connectedThresFilter->SetLower(0); connectedThresFilter->SetUpper(0); connectedThresFilter->SetReplaceValue(2); connectedThresFilter->ReleaseDataFlagOn(); connectedThresFilter->ReleaseDataBeforeUpdateFlagOn(); typedef itk::BinaryThresholdImageFilter BinaryThresholdFilterType; BinaryThresholdFilterType::Pointer binThresFilter = BinaryThresholdFilterType::New(); binThresFilter->SetInput(connectedThresFilter->GetOutput()); binThresFilter->SetLowerThreshold(0); binThresFilter->SetUpperThreshold(0); binThresFilter->SetInsideValue(50); binThresFilter->SetOutsideValue(0); binThresFilter->ReleaseDataFlagOn(); binThresFilter->ReleaseDataBeforeUpdateFlagOn(); typedef itk::AddImageFilter AddFilterType; AddFilterType::Pointer addFilter = AddFilterType::New(); addFilter->SetInput1(blurredImage); addFilter->SetInput2(binThresFilter->GetOutput()); addFilter->ReleaseDataFlagOn(); addFilter->ReleaseDataBeforeUpdateFlagOn(); addFilter->Update(); ProgressBar::GetInstance()->Progress(1); // Surface extraction MITK_INFO << "Surface extraction..."; Image::Pointer filteredImage = Image::New(); CastToMitkImage(addFilter->GetOutput(), filteredImage); filteredImage->SetGeometry(geometry); ImageToSurfaceFilter::Pointer imageToSurfaceFilter = ImageToSurfaceFilter::New(); imageToSurfaceFilter->SetInput(filteredImage); imageToSurfaceFilter->SetThreshold(50); imageToSurfaceFilter->SmoothOn(); imageToSurfaceFilter->SetDecimate(ImageToSurfaceFilter::NoDecimation); m_Surface = imageToSurfaceFilter->GetOutput(0); ProgressBar::GetInstance()->Progress(1); // Mesh decimation if (decimation > 0.0f && decimation < 1.0f) { MITK_INFO << "Quadric mesh decimation..."; vtkQuadricDecimation *quadricDecimation = vtkQuadricDecimation::New(); quadricDecimation->SetInputData(m_Surface->GetVtkPolyData()); quadricDecimation->SetTargetReduction(decimation); quadricDecimation->AttributeErrorMetricOn(); quadricDecimation->GlobalWarningDisplayOff(); quadricDecimation->Update(); vtkCleanPolyData *cleaner = vtkCleanPolyData::New(); cleaner->SetInputConnection(quadricDecimation->GetOutputPort()); cleaner->PieceInvariantOn(); cleaner->ConvertLinesToPointsOn(); cleaner->ConvertStripsToPolysOn(); cleaner->PointMergingOn(); cleaner->Update(); m_Surface->SetVtkPolyData(cleaner->GetOutput()); } ProgressBar::GetInstance()->Progress(1); // Compute Normals vtkPolyDataNormals *computeNormals = vtkPolyDataNormals::New(); computeNormals->SetInputData(m_Surface->GetVtkPolyData()); computeNormals->SetFeatureAngle(360.0f); computeNormals->AutoOrientNormalsOn(); computeNormals->FlipNormalsOff(); computeNormals->Update(); m_Surface->SetVtkPolyData(computeNormals->GetOutput()); return true; } void ShowSegmentationAsSmoothedSurface::ThreadedUpdateSuccessful() { DataNode::Pointer node = DataNode::New(); bool wireframe = false; GetParameter("Wireframe", wireframe); if (wireframe) { VtkRepresentationProperty *representation = dynamic_cast(node->GetProperty("material.representation")); if (representation != nullptr) representation->SetRepresentationToWireframe(); } node->SetProperty("opacity", FloatProperty::New(1.0)); node->SetProperty("line width", IntProperty::New(1)); node->SetProperty("scalar visibility", BoolProperty::New(false)); std::string groupNodeName = "surface"; DataNode *groupNode = GetGroupNode(); if (groupNode != nullptr) groupNode->GetName(groupNodeName); node->SetProperty("name", StringProperty::New(groupNodeName)); node->SetData(m_Surface); BaseProperty *colorProperty = groupNode->GetProperty("color"); if (colorProperty != nullptr) node->ReplaceProperty("color", colorProperty->Clone()); else node->SetProperty("color", ColorProperty::New(1.0f, 0.0f, 0.0f)); bool showResult = true; GetParameter("Show result", showResult); bool syncVisibility = false; GetParameter("Sync visibility", syncVisibility); Image::Pointer image; GetPointerParameter("Input", image); BaseProperty *organTypeProperty = image->GetProperty("organ type"); if (organTypeProperty != nullptr) m_Surface->SetProperty("organ type", organTypeProperty); BaseProperty *visibleProperty = groupNode->GetProperty("visible"); if (visibleProperty != nullptr && syncVisibility) node->ReplaceProperty("visible", visibleProperty->Clone()); else node->SetProperty("visible", BoolProperty::New(showResult)); InsertBelowGroupNode(node); Superclass::ThreadedUpdateSuccessful(); } diff --git a/Modules/SegmentationUI/Qmitk/QmitkSliceBasedInterpolatorWidget.cpp b/Modules/SegmentationUI/Qmitk/QmitkSliceBasedInterpolatorWidget.cpp index 8cfc33c57e..4ca48522d9 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkSliceBasedInterpolatorWidget.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkSliceBasedInterpolatorWidget.cpp @@ -1,688 +1,688 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkSliceBasedInterpolatorWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "QmitkStdMultiWidget.h" #include #include #include #include #include QmitkSliceBasedInterpolatorWidget::QmitkSliceBasedInterpolatorWidget(QWidget *parent, const char * /*name*/) : QWidget(parent), m_SliceInterpolatorController(mitk::SliceBasedInterpolationController::New()), m_ToolManager(nullptr), m_Activated(false), m_DataStorage(nullptr), m_LastSNC(0), m_LastSliceIndex(0) { m_Controls.setupUi(this); m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); Q_ASSERT(m_ToolManager); m_ToolManager->WorkingDataChanged += mitk::MessageDelegate( this, &QmitkSliceBasedInterpolatorWidget::OnToolManagerWorkingDataModified); connect(m_Controls.m_btStart, SIGNAL(toggled(bool)), this, SLOT(OnToggleWidgetActivation(bool))); connect(m_Controls.m_btApplyForCurrentSlice, SIGNAL(clicked()), this, SLOT(OnAcceptInterpolationClicked())); connect(m_Controls.m_btApplyForAllSlices, SIGNAL(clicked()), this, SLOT(OnAcceptAllInterpolationsClicked())); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSliceBasedInterpolatorWidget::OnSliceInterpolationInfoChanged); m_InterpolationInfoChangedObserverTag = m_SliceInterpolatorController->AddObserver(itk::ModifiedEvent(), command); // feedback node and its visualization properties m_PreviewNode = mitk::DataNode::New(); m_PreviewNode->SetName("3D tool preview"); m_PreviewNode->SetProperty("texture interpolation", mitk::BoolProperty::New(false)); m_PreviewNode->SetProperty("layer", mitk::IntProperty::New(100)); m_PreviewNode->SetProperty("binary", mitk::BoolProperty::New(true)); m_PreviewNode->SetProperty("outline binary", mitk::BoolProperty::New(true)); m_PreviewNode->SetProperty("outline binary shadow", mitk::BoolProperty::New(true)); m_PreviewNode->SetProperty("helper object", mitk::BoolProperty::New(true)); m_PreviewNode->SetOpacity(1.0); m_PreviewNode->SetColor(0.0, 1.0, 0.0); m_Controls.m_btApplyForCurrentSlice->setEnabled(false); m_Controls.m_btApplyForAllSlices->setEnabled(false); this->setEnabled(false); } QmitkSliceBasedInterpolatorWidget::~QmitkSliceBasedInterpolatorWidget() { m_ToolManager->WorkingDataChanged -= mitk::MessageDelegate( this, &QmitkSliceBasedInterpolatorWidget::OnToolManagerWorkingDataModified); foreach (mitk::SliceNavigationController *slicer, m_ControllerToSliceObserverTag.keys()) { slicer->RemoveObserver(m_ControllerToDeleteObserverTag.take(slicer)); slicer->RemoveObserver(m_ControllerToTimeObserverTag.take(slicer)); slicer->RemoveObserver(m_ControllerToSliceObserverTag.take(slicer)); } m_ActionToSliceDimensionMap.clear(); // remove observer m_SliceInterpolatorController->RemoveObserver(m_InterpolationInfoChangedObserverTag); } const QmitkSliceBasedInterpolatorWidget::ActionToSliceDimensionMapType QmitkSliceBasedInterpolatorWidget::CreateActionToSliceDimension() { ActionToSliceDimensionMapType actionToSliceDimension; foreach (mitk::SliceNavigationController *slicer, m_ControllerToDeleteObserverTag.keys()) { std::string name = slicer->GetRenderer()->GetName(); if (name == "stdmulti.widget1") name = "Axial (red window)"; else if (name == "stdmulti.widget2") name = "Sagittal (green window)"; else if (name == "stdmulti.widget3") name = "Coronal (blue window)"; actionToSliceDimension[new QAction(QString::fromStdString(name), 0)] = slicer; } return actionToSliceDimension; } void QmitkSliceBasedInterpolatorWidget::SetDataStorage(mitk::DataStorage &storage) { m_DataStorage = &storage; } void QmitkSliceBasedInterpolatorWidget::SetSliceNavigationControllers( const QList &controllers) { Q_ASSERT(!controllers.empty()); // connect to the slice navigation controller. after each change, call the interpolator foreach (mitk::SliceNavigationController *slicer, controllers) { // Has to be initialized m_LastSNC = slicer; m_TimeStep.insert(slicer, slicer->GetTime()->GetPos()); itk::MemberCommand::Pointer deleteCommand = itk::MemberCommand::New(); deleteCommand->SetCallbackFunction(this, &QmitkSliceBasedInterpolatorWidget::OnSliceNavigationControllerDeleted); m_ControllerToDeleteObserverTag.insert(slicer, slicer->AddObserver(itk::DeleteEvent(), deleteCommand)); itk::MemberCommand::Pointer timeChangedCommand = itk::MemberCommand::New(); timeChangedCommand->SetCallbackFunction(this, &QmitkSliceBasedInterpolatorWidget::OnTimeChanged); m_ControllerToTimeObserverTag.insert( slicer, - slicer->AddObserver(mitk::SliceNavigationController::TimeSlicedGeometryEvent(nullptr, 0), timeChangedCommand)); + slicer->AddObserver(mitk::SliceNavigationController::TimeGeometryEvent(nullptr, 0), timeChangedCommand)); itk::MemberCommand::Pointer sliceChangedCommand = itk::MemberCommand::New(); sliceChangedCommand->SetCallbackFunction(this, &QmitkSliceBasedInterpolatorWidget::OnSliceChanged); m_ControllerToSliceObserverTag.insert( slicer, slicer->AddObserver(mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), sliceChangedCommand)); } m_ActionToSliceDimensionMap = this->CreateActionToSliceDimension(); } void QmitkSliceBasedInterpolatorWidget::OnToolManagerWorkingDataModified() { mitk::DataNode *workingNode = this->m_ToolManager->GetWorkingData(0); if (!workingNode) { this->setEnabled(false); return; } mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); // TODO adapt tool manager so that this check is done there, e.g. convenience function // Q_ASSERT(workingImage); if (!workingImage) { this->setEnabled(false); return; } if (workingImage->GetDimension() > 4 || workingImage->GetDimension() < 3) { this->setEnabled(false); return; } m_WorkingImage = workingImage; this->setEnabled(true); } void QmitkSliceBasedInterpolatorWidget::OnTimeChanged(itk::Object *sender, const itk::EventObject &e) { // Check if we really have a GeometryTimeEvent if (!dynamic_cast(&e)) return; mitk::SliceNavigationController *slicer = dynamic_cast(sender); Q_ASSERT(slicer); m_TimeStep[slicer] /* = event.GetPos()*/; // TODO Macht das hier wirklich Sinn???? if (m_LastSNC == slicer) { slicer->SendSlice(); // will trigger a new interpolation } } void QmitkSliceBasedInterpolatorWidget::OnSliceChanged(itk::Object *sender, const itk::EventObject &e) { if (m_Activated && m_WorkingImage.IsNotNull()) { // Check whether we really have a GeometrySliceEvent if (!dynamic_cast(&e)) return; mitk::SliceNavigationController *slicer = dynamic_cast(sender); if (slicer) { this->TranslateAndInterpolateChangedSlice(e, slicer); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); // slicer->GetRenderer()->RequestUpdate(); } } } void QmitkSliceBasedInterpolatorWidget::TranslateAndInterpolateChangedSlice(const itk::EventObject &e, mitk::SliceNavigationController *slicer) { if (m_Activated && m_WorkingImage.IsNotNull()) { const mitk::SliceNavigationController::GeometrySliceEvent &geometrySliceEvent = dynamic_cast(e); mitk::TimeGeometry *timeGeometry = geometrySliceEvent.GetTimeGeometry(); if (timeGeometry && m_TimeStep.contains(slicer)) { mitk::SlicedGeometry3D *slicedGeometry = dynamic_cast(timeGeometry->GetGeometryForTimeStep(m_TimeStep[slicer]).GetPointer()); if (slicedGeometry) { mitk::PlaneGeometry *plane = slicedGeometry->GetPlaneGeometry(geometrySliceEvent.GetPos()); if (plane) { m_LastSNC = slicer; this->Interpolate(plane, m_TimeStep[slicer], slicer); } } } } } void QmitkSliceBasedInterpolatorWidget::Interpolate(mitk::PlaneGeometry *plane, unsigned int timeStep, mitk::SliceNavigationController *slicer) { int clickedSliceDimension(-1); int clickedSliceIndex(-1); // calculate real slice position, i.e. slice of the image and not slice of the TimeSlicedGeometry // see if timestep is needed here mitk::SegTool2D::DetermineAffectedImageSlice(m_WorkingImage, plane, clickedSliceDimension, clickedSliceIndex); mitk::Image::Pointer interpolation = m_SliceInterpolatorController->Interpolate(clickedSliceDimension, clickedSliceIndex, plane, timeStep); m_PreviewNode->SetData(interpolation); const mitk::Color &color = m_WorkingImage->GetActiveLabel()->GetColor(); m_PreviewNode->SetColor(color); m_LastSNC = slicer; m_LastSliceIndex = clickedSliceIndex; } mitk::Image::Pointer QmitkSliceBasedInterpolatorWidget::GetWorkingSlice(const mitk::PlaneGeometry *planeGeometry) { unsigned int timeStep = m_LastSNC->GetTime()->GetPos(); // Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk // reslicer vtkSmartPointer reslice = vtkSmartPointer::New(); // set to false to extract a slice reslice->SetOverwriteMode(false); reslice->Modified(); // use ExtractSliceFilter with our specific vtkImageReslice for overwriting and extracting mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); extractor->SetInput(m_WorkingImage); extractor->SetTimeStep(timeStep); extractor->SetWorldGeometry(planeGeometry); extractor->SetVtkOutputRequest(false); extractor->SetResliceTransformByGeometry(m_WorkingImage->GetTimeGeometry()->GetGeometryForTimeStep(timeStep)); extractor->Modified(); try { extractor->Update(); } catch (itk::ExceptionObject &excep) { MITK_ERROR << "Exception caught: " << excep.GetDescription(); return nullptr; } mitk::Image::Pointer slice = extractor->GetOutput(); // specify the undo operation with the non edited slice // MLI TODO added code starts here mitk::SlicedGeometry3D *sliceGeometry = dynamic_cast(slice->GetGeometry()); // m_undoOperation = new mitk::DiffSliceOperation(m_WorkingImage, extractor->GetVtkOutput(), slice->GetGeometry(), // timeStep, const_cast(planeGeometry)); // added code ends here m_undoOperation = new mitk::DiffSliceOperation( m_WorkingImage, extractor->GetOutput(), sliceGeometry, timeStep, const_cast(planeGeometry)); slice->DisconnectPipeline(); return slice; } void QmitkSliceBasedInterpolatorWidget::OnToggleWidgetActivation(bool enabled) { Q_ASSERT(m_ToolManager); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); if (!workingNode) return; m_Controls.m_btApplyForCurrentSlice->setEnabled(enabled); m_Controls.m_btApplyForAllSlices->setEnabled(enabled); if (enabled) m_Controls.m_btStart->setText("Stop"); else m_Controls.m_btStart->setText("Start"); unsigned int numberOfExistingTools = m_ToolManager->GetTools().size(); for (unsigned int i = 0; i < numberOfExistingTools; i++) { // mitk::SegTool2D* tool = dynamic_cast(m_ToolManager->GetToolById(i)); // MLI TODO // if (tool) tool->SetEnable2DInterpolation( enabled ); } if (enabled) { if (!m_DataStorage->Exists(m_PreviewNode)) { m_DataStorage->Add(m_PreviewNode); } m_SliceInterpolatorController->SetWorkingImage(m_WorkingImage); this->UpdateVisibleSuggestion(); } else { if (m_DataStorage->Exists(m_PreviewNode)) { m_DataStorage->Remove(m_PreviewNode); } mitk::UndoController::GetCurrentUndoModel()->Clear(); } m_Activated = enabled; mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } template void QmitkSliceBasedInterpolatorWidget::WritePreviewOnWorkingImage(itk::Image *targetSlice, const mitk::Image *sourceSlice, int overwritevalue) { typedef itk::Image ImageType; typename ImageType::Pointer sourceSliceITK; mitk::CastToItkImage(sourceSlice, sourceSliceITK); // now the original slice and the ipSegmentation-painted slice are in the same format, and we can just copy all pixels // that are non-zero typedef itk::ImageRegionIterator OutputIteratorType; typedef itk::ImageRegionConstIterator InputIteratorType; InputIteratorType inputIterator(sourceSliceITK, sourceSliceITK->GetLargestPossibleRegion()); OutputIteratorType outputIterator(targetSlice, targetSlice->GetLargestPossibleRegion()); outputIterator.GoToBegin(); inputIterator.GoToBegin(); int activePixelValue = m_WorkingImage->GetActiveLabel()->GetValue(); if (activePixelValue == 0) // if exterior is the active label { while (!outputIterator.IsAtEnd()) { if (inputIterator.Get() != 0) { outputIterator.Set(overwritevalue); } ++outputIterator; ++inputIterator; } } else if (overwritevalue != 0) // if we are not erasing { while (!outputIterator.IsAtEnd()) { int targetValue = static_cast(outputIterator.Get()); if (inputIterator.Get() != 0) { if (!m_WorkingImage->GetLabel(targetValue)->GetLocked()) outputIterator.Set(overwritevalue); } ++outputIterator; ++inputIterator; } } else // if we are erasing { while (!outputIterator.IsAtEnd()) { const int targetValue = outputIterator.Get(); if (inputIterator.Get() != 0) { if (targetValue == activePixelValue) outputIterator.Set(overwritevalue); } ++outputIterator; ++inputIterator; } } } void QmitkSliceBasedInterpolatorWidget::OnAcceptInterpolationClicked() { if (m_WorkingImage.IsNotNull() && m_PreviewNode->GetData()) { const mitk::PlaneGeometry *planeGeometry = m_LastSNC->GetCurrentPlaneGeometry(); if (!planeGeometry) return; mitk::Image::Pointer sliceImage = this->GetWorkingSlice(planeGeometry); if (sliceImage.IsNull()) return; mitk::Image::Pointer previewSlice = dynamic_cast(m_PreviewNode->GetData()); AccessFixedDimensionByItk_2( sliceImage, WritePreviewOnWorkingImage, 2, previewSlice, m_WorkingImage->GetActiveLabel()->GetValue()); // Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk // reslicer vtkSmartPointer overwrite = vtkSmartPointer::New(); overwrite->SetInputSlice(sliceImage->GetVtkImageData()); // set overwrite mode to true to write back to the image volume overwrite->SetOverwriteMode(true); overwrite->Modified(); unsigned int timeStep = m_LastSNC->GetTime()->GetPos(); mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(overwrite); extractor->SetInput(m_WorkingImage); extractor->SetTimeStep(timeStep); extractor->SetWorldGeometry(planeGeometry); extractor->SetVtkOutputRequest(false); extractor->SetResliceTransformByGeometry(m_WorkingImage->GetTimeGeometry()->GetGeometryForTimeStep(timeStep)); extractor->Modified(); try { extractor->Update(); } catch (itk::ExceptionObject &excep) { MITK_ERROR << "Exception caught: " << excep.GetDescription(); return; } // the image was modified within the pipeline, but not marked so m_WorkingImage->Modified(); int clickedSliceDimension(-1); int clickedSliceIndex(-1); mitk::SegTool2D::DetermineAffectedImageSlice( m_WorkingImage, planeGeometry, clickedSliceDimension, clickedSliceIndex); m_SliceInterpolatorController->SetChangedSlice(sliceImage, clickedSliceDimension, clickedSliceIndex, timeStep); // specify the undo operation with the edited slice // MLI TODO added code starts here mitk::SlicedGeometry3D *sliceGeometry = dynamic_cast(sliceImage->GetGeometry()); // m_undoOperation = new mitk::DiffSliceOperation(m_WorkingImage, extractor->GetVtkOutput(), slice->GetGeometry(), // timeStep, const_cast(planeGeometry)); // added code ends here m_doOperation = new mitk::DiffSliceOperation(m_WorkingImage, extractor->GetOutput(), sliceGeometry, timeStep, const_cast(planeGeometry)); // create an operation event for the undo stack mitk::OperationEvent *undoStackItem = new mitk::OperationEvent( mitk::DiffSliceOperationApplier::GetInstance(), m_doOperation, m_undoOperation, "Slice Interpolation"); // add it to the undo controller mitk::UndoController::GetCurrentUndoModel()->SetOperationEvent(undoStackItem); // clear the pointers as the operation are stored in the undo controller and also deleted from there m_undoOperation = nullptr; m_doOperation = nullptr; m_PreviewNode->SetData(nullptr); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSliceBasedInterpolatorWidget::AcceptAllInterpolations(mitk::SliceNavigationController *slicer) { // Since we need to shift the plane it must be clone so that the original plane isn't altered mitk::PlaneGeometry::Pointer reslicePlane = slicer->GetCurrentPlaneGeometry()->Clone(); unsigned int timeStep = slicer->GetTime()->GetPos(); int sliceDimension(-1); int sliceIndex(-1); mitk::SegTool2D::DetermineAffectedImageSlice(m_WorkingImage, reslicePlane, sliceDimension, sliceIndex); unsigned int zslices = m_WorkingImage->GetDimension(sliceDimension); mitk::ProgressBar::GetInstance()->Reset(); mitk::ProgressBar::GetInstance()->AddStepsToDo(zslices); mitk::Point3D origin = reslicePlane->GetOrigin(); for (unsigned int idx = 0; idx < zslices; ++idx) { // Transforming the current origin of the reslice plane // so that it matches the one of the next slice m_WorkingImage->GetSlicedGeometry()->WorldToIndex(origin, origin); origin[sliceDimension] = idx; m_WorkingImage->GetSlicedGeometry()->IndexToWorld(origin, origin); reslicePlane->SetOrigin(origin); mitk::Image::Pointer interpolation = m_SliceInterpolatorController->Interpolate(sliceDimension, idx, reslicePlane, timeStep); if (interpolation.IsNotNull()) { m_PreviewNode->SetData(interpolation); mitk::Image::Pointer sliceImage = this->GetWorkingSlice(reslicePlane); if (sliceImage.IsNull()) return; AccessFixedDimensionByItk_2( sliceImage, WritePreviewOnWorkingImage, 2, interpolation, m_WorkingImage->GetActiveLabel()->GetValue()); // Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk // reslicer vtkSmartPointer overwrite = vtkSmartPointer::New(); overwrite->SetInputSlice(sliceImage->GetVtkImageData()); // set overwrite mode to true to write back to the image volume overwrite->SetOverwriteMode(true); overwrite->Modified(); mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(overwrite); extractor->SetInput(m_WorkingImage); extractor->SetTimeStep(timeStep); extractor->SetWorldGeometry(reslicePlane); extractor->SetVtkOutputRequest(true); extractor->SetResliceTransformByGeometry(m_WorkingImage->GetTimeGeometry()->GetGeometryForTimeStep(timeStep)); extractor->Modified(); try { extractor->Update(); } catch (itk::ExceptionObject &excep) { MITK_ERROR << "Exception caught: " << excep.GetDescription(); return; } m_WorkingImage->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); } mitk::ProgressBar::GetInstance()->Progress(); } m_SliceInterpolatorController->SetWorkingImage(m_WorkingImage); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSliceBasedInterpolatorWidget::OnAcceptAllInterpolationsClicked() { QMenu orientationPopup(this); std::map::const_iterator it; for (it = m_ActionToSliceDimensionMap.begin(); it != m_ActionToSliceDimensionMap.end(); it++) orientationPopup.addAction(it->first); connect(&orientationPopup, SIGNAL(triggered(QAction *)), this, SLOT(OnAcceptAllPopupActivated(QAction *))); orientationPopup.exec(QCursor::pos()); } void QmitkSliceBasedInterpolatorWidget::OnAcceptAllPopupActivated(QAction *action) { ActionToSliceDimensionMapType::const_iterator iter = m_ActionToSliceDimensionMap.find(action); if (iter != m_ActionToSliceDimensionMap.end()) { mitk::SliceNavigationController *slicer = iter->second; this->AcceptAllInterpolations(slicer); } } void QmitkSliceBasedInterpolatorWidget::UpdateVisibleSuggestion() { if (m_Activated && m_LastSNC) { // determine which one is the current view, try to do an initial interpolation mitk::BaseRenderer *renderer = m_LastSNC->GetRenderer(); if (renderer && renderer->GetMapperID() == mitk::BaseRenderer::Standard2D) { const mitk::TimeGeometry *timeGeometry = dynamic_cast(renderer->GetWorldTimeGeometry()); if (timeGeometry) { mitk::SliceNavigationController::GeometrySliceEvent event(const_cast(timeGeometry), renderer->GetSlice()); this->TranslateAndInterpolateChangedSlice(event, m_LastSNC); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } } void QmitkSliceBasedInterpolatorWidget::OnSliceInterpolationInfoChanged(const itk::EventObject & /*e*/) { // something (e.g. undo) changed the interpolation info, we should refresh our display this->UpdateVisibleSuggestion(); } void QmitkSliceBasedInterpolatorWidget::OnSliceNavigationControllerDeleted(const itk::Object *sender, const itk::EventObject & /*e*/) { // Don't know how to avoid const_cast here?! mitk::SliceNavigationController *slicer = dynamic_cast(const_cast(sender)); if (slicer) { m_ControllerToTimeObserverTag.remove(slicer); m_ControllerToSliceObserverTag.remove(slicer); m_ControllerToDeleteObserverTag.remove(slicer); } } void QmitkSliceBasedInterpolatorWidget::WaitCursorOn() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } void QmitkSliceBasedInterpolatorWidget::WaitCursorOff() { this->RestoreOverrideCursor(); } void QmitkSliceBasedInterpolatorWidget::RestoreOverrideCursor() { QApplication::restoreOverrideCursor(); } diff --git a/Modules/XNAT/src/QmitkXnatTreeModel.cpp b/Modules/XNAT/src/QmitkXnatTreeModel.cpp index 4d35e90c16..c3acde60e3 100644 --- a/Modules/XNAT/src/QmitkXnatTreeModel.cpp +++ b/Modules/XNAT/src/QmitkXnatTreeModel.cpp @@ -1,316 +1,316 @@ /*=================================================================== 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 "QmitkXnatTreeModel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include QmitkXnatTreeModel::QmitkXnatTreeModel() : ctkXnatTreeModel() { } QModelIndexList QmitkXnatTreeModel::match( const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const { QModelIndexList result; uint matchType = flags & 0x0F; Qt::CaseSensitivity cs = flags & Qt::MatchCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; bool recurse = flags & Qt::MatchRecursive; bool wrap = flags & Qt::MatchWrap; bool allHits = (hits == -1); QString text; // only convert to a string if it is needed QModelIndex p = parent(start); int from = start.row(); int to = rowCount(p); // iterates twice if wrapping for (int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) { for (int r = from; (r < to) && (allHits || result.count() < hits); ++r) { QModelIndex idx = index(r, start.column(), p); if (!idx.isValid()) continue; QVariant v = data(idx, role); // QVariant based matching if (matchType == Qt::MatchExactly) { if (value != v) result.append(idx); } else { // QString based matching if (text.isEmpty()) // lazy conversion text = value.toString(); QString t = v.toString(); switch (matchType) { case Qt::MatchRegExp: if (!QRegExp(text, cs).exactMatch(t)) result.append(idx); break; case Qt::MatchWildcard: if (!QRegExp(text, cs, QRegExp::Wildcard).exactMatch(t)) result.append(idx); break; case Qt::MatchStartsWith: if (!t.startsWith(text, cs)) result.append(idx); break; case Qt::MatchEndsWith: if (!t.endsWith(text, cs)) result.append(idx); break; case Qt::MatchFixedString: - if (!t.compare(text, cs) == 0) + if (t.compare(text, cs) != 0) result.append(idx); break; case Qt::MatchContains: default: if (!t.contains(text, cs)) result.append(idx); } } if (recurse && hasChildren(idx)) { // search the hierarchy result += match(index(0, idx.column(), idx), role, (text.isEmpty() ? value : text), (allHits ? -1 : hits - result.count()), flags); } } // prepare for the next iteration from = 0; to = start.row(); } return result; } void QmitkXnatTreeModel::fetchMore(const QModelIndex &index) { try { ctkXnatTreeModel::fetchMore(index); } catch (ctkRuntimeException e) { QmitkHttpStatusCodeHandler::HandleErrorMessage(e.what()); emit Error(index); } } QVariant QmitkXnatTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (role == Qt::DecorationRole) { ctkXnatObject *xnatObject = this->xnatObject(index); QString path; if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-server.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-project.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-subject.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-experiment.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-folder.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-resource.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-folder.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-scan.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-file.png"; } return QIcon(path); } return ctkXnatTreeModel::data(index, role); } bool QmitkXnatTreeModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex &parent) { if (action == Qt::IgnoreAction) return true; // Return true if data can be handled bool returnVal(false); if (data->hasFormat(QmitkMimeTypes::DataNodePtrs)) { returnVal = true; QList droppedNodes = QmitkMimeTypes::ToDataNodePtrList(data); ctkXnatObject *parentXnatObj = this->xnatObject(parent); emit ResourceDropped(droppedNodes, parentXnatObj, parent); } return returnVal; } Qt::DropActions QmitkXnatTreeModel::supportedDropActions() { return Qt::CopyAction; } Qt::ItemFlags QmitkXnatTreeModel::flags(const QModelIndex &index) const { Qt::ItemFlags defaultFlags = ctkXnatTreeModel::flags(index); if (index.isValid()) { bool droppingAllowed = dynamic_cast(this->xnatObject(index)) != nullptr; droppingAllowed |= dynamic_cast(this->xnatObject(index)) != nullptr; droppingAllowed |= dynamic_cast(this->xnatObject(index)) != nullptr; droppingAllowed |= dynamic_cast(this->xnatObject(index)) != nullptr; // No dropping at project, session or data model level allowed if (droppingAllowed) { return Qt::ItemIsDropEnabled | defaultFlags; } else { return defaultFlags; } } else return defaultFlags; } ctkXnatObject *QmitkXnatTreeModel::InternalGetXnatObjectFromUrl(const QString &xnatObjectType, const QString &url, ctkXnatObject *parent) { // 1. Find project int start = url.lastIndexOf(xnatObjectType); if (start == -1) return nullptr; start += xnatObjectType.length(); int length = url.indexOf("/", start); length -= start; parent->fetch(); QList children = parent->children(); foreach (ctkXnatObject *child, children) { if (url.indexOf(child->resourceUri()) != -1) { return child; } } return nullptr; } ctkXnatObject *QmitkXnatTreeModel::GetXnatObjectFromUrl(const QString &url) { QModelIndex index = this->index(0, 0, QModelIndex()); ctkXnatObject *currentXnatObject = nullptr; currentXnatObject = this->xnatObject(index); if (currentXnatObject != nullptr) { // 1. Find project ctkXnatObject *project = nullptr; project = this->InternalGetXnatObjectFromUrl("projects/", url, currentXnatObject); // 2. Find subject ctkXnatObject *subject = nullptr; if (project != nullptr) { currentXnatObject = project; subject = this->InternalGetXnatObjectFromUrl("subjects/", url, project); } // 3. Find experiment ctkXnatObject *experiment = nullptr; if (subject != nullptr) { currentXnatObject = subject; experiment = this->InternalGetXnatObjectFromUrl("experiments/", url, subject); } // 4. Find scan ctkXnatObject *scan = nullptr; if (experiment != nullptr) { currentXnatObject = experiment; scan = this->InternalGetXnatObjectFromUrl("scans/", url, experiment); } if (scan != nullptr) { scan->fetch(); QList scans = scan->children(); foreach (ctkXnatObject *child, scans) { if (url.indexOf(child->resourceUri()) != -1) { return child; } } } currentXnatObject->fetch(); QList bla = currentXnatObject->children(); foreach (ctkXnatObject *child, bla) { if (child->name() == "Resources") return child; } } return nullptr; } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryContainerPlaceholder.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryContainerPlaceholder.cpp index 1c0aca109a..12470e503c 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryContainerPlaceholder.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryContainerPlaceholder.cpp @@ -1,132 +1,132 @@ /*=================================================================== BlueBerry Platform 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 "berryContainerPlaceholder.h" #include "berryPartPlaceholder.h" #include "berryILayoutContainer.h" namespace berry { int ContainerPlaceholder::nextId = 0; ContainerPlaceholder::ContainerPlaceholder(const QString& id) : - PartPlaceholder(id == "" ? "Container Placeholder " + nextId++ : id) + PartPlaceholder(id == "" ? QString("Container Placeholder ") + nextId++ : id) { } void ContainerPlaceholder::Add(LayoutPart::Pointer child) { if (child.Cast() == 0) { return; } realContainer->Add(child); } bool ContainerPlaceholder::AllowsAdd(LayoutPart::Pointer /*toAdd*/) { return false; } QList ContainerPlaceholder::GetChildren() const { return realContainer->GetChildren(); } QString ContainerPlaceholder::GetID() const { return LayoutPart::GetID(); } LayoutPart::Pointer ContainerPlaceholder::GetRealContainer() { return realContainer.Cast(); } void ContainerPlaceholder::Remove(LayoutPart::Pointer child) { if (child.Cast () == 0) { return; } realContainer->Remove(child); } void ContainerPlaceholder::Replace(LayoutPart::Pointer oldChild, LayoutPart::Pointer newChild) { if (oldChild.Cast() == 0 && newChild.Cast() == 0) { return; } realContainer->Replace(oldChild, newChild); } void ContainerPlaceholder::SetRealContainer( ILayoutContainer::Pointer container) { if (container == 0) { // set the parent container of the children back to the real container if (realContainer != 0) { QList children = realContainer->GetChildren(); for (QList::iterator iter = children.begin(); iter != children.end(); ++iter) { (*iter)->SetContainer(realContainer); } } } else { // replace the real container with this place holder QList children = container->GetChildren(); for (QList::iterator iter = children.begin(); iter != children.end(); ++iter) { (*iter)->SetContainer(ILayoutContainer::Pointer(this)); } } this->realContainer = container; } void ContainerPlaceholder::FindSashes(LayoutPart::Pointer /*part*/, PartPane::Sashes& sashes) { ILayoutContainer::Pointer container = this->GetContainer(); if (container != 0) { container->FindSashes(LayoutPart::Pointer(this), sashes); } } void ContainerPlaceholder::ResizeChild(LayoutPart::Pointer /*childThatChanged*/) { } bool ContainerPlaceholder::AllowsAutoFocus() { return false; } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationView.cpp index 58349bf5d5..18bc2269f4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationView.cpp @@ -1,359 +1,358 @@ /*=================================================================== 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. ===================================================================*/ // Qmitk #include "QmitkRandomParcellationView.h" // Blueberry #include #include // Qt #include // Includes for image casting between ITK and MITK #include "mitkImageCast.h" #include "mitkImageAccessByItk.h" #include "mitkITKImageImport.h" //To convert integer to string #include #include //Itk Iterators #include #include // mitk #include #include //Child const std::string QmitkRandomParcellationView::PROPERTYNAME = "name"; const std::string QmitkRandomParcellationView::PROPERTYOPACITY = "opacity"; const std::string QmitkRandomParcellationView::m_NAMEFORRANDOMVOXELIMAGE = "Random Voxel Image"; const std::string QmitkRandomParcellationView::VIEW_ID = "org.mitk.views.randomparcellationview"; void QmitkRandomParcellationView::SetFocus() { m_Controls.buttonSelectRandomNodes->setFocus(); } void QmitkRandomParcellationView::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); connect( m_Controls.buttonSelectRandomNodes, SIGNAL(clicked()), this, SLOT(SelectRandomNodes()) ); connect( m_Controls.checkBoxMerging, SIGNAL(stateChanged(int)),this, SLOT(OnMergingCheckboxChanged(int))); connect( m_Controls.radioButtonNumberParcels, SIGNAL(clicked()), this, SLOT(OnRadioButtonNumberParcelsChanged(int))); connect( m_Controls.radioButtonSmallestParcel, SIGNAL(clicked()), this, SLOT(OnRadioButtonSmallestParcelChanged(int))); } void QmitkRandomParcellationView::OnMergingCheckboxChanged(int ) { if (m_Controls.checkBoxMerging->isChecked()) { //Make the frame visible m_Controls.frameMerging->setEnabled(true); m_Controls.frameNumberParcels->setEnabled(true); m_Controls.frameSmallestParcel->setEnabled(true); } else { m_Controls.frameMerging->setEnabled(false); } } void QmitkRandomParcellationView::OnRadioButtonNumberParcelsChanged(int ) { if (m_Controls.radioButtonNumberParcels->isChecked()) { m_Controls.frameNumberParcels->setEnabled(true); m_Controls.radioButtonSmallestParcel->setChecked(false); } else { m_Controls.frameNumberParcels->setEnabled(false); } } void QmitkRandomParcellationView::OnRadioButtonSmallestParcelChanged(int ) { if (m_Controls.radioButtonSmallestParcel->isChecked()) { m_Controls.frameSmallestParcel->setEnabled(true); m_Controls.radioButtonNumberParcels->setChecked(false); } else { m_Controls.frameSmallestParcel->setEnabled(false); } } void QmitkRandomParcellationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { // iterate all selected objects, adjust warning visibility for (mitk::DataNode::Pointer node: nodes) { if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_Controls.labelWarning->setVisible( false ); m_Controls.buttonSelectRandomNodes->setEnabled( true ); mitk::Image* imageDisplay = dynamic_cast(node->GetData()); AccessFixedDimensionByItk(imageDisplay, ShowNumberOfVoxels, 3); return; } } m_Controls.labelWarning->setVisible( true ); m_Controls.buttonSelectRandomNodes->setEnabled( false ); } template void QmitkRandomParcellationView::ShowNumberOfVoxels( itk::Image * inputImage) { - typedef itk::Image< TPixel, VImageDimension > ImageType; mitk::RegionVoxelCounter counter; counter.SetRegion(inputImage->GetLargestPossibleRegion()); counter.SetImage(inputImage); int numberVoxelsDisplay = counter.VoxelWithValue(1); std::string stringDisplay = "Number of voxels with value 1: "; std::ostringstream convertDisplay; convertDisplay << numberVoxelsDisplay; std::string stringNumberVoxels = convertDisplay.str(); stringDisplay += stringNumberVoxels; QString textNumberVoxelsDisplay = QString::fromStdString(stringDisplay); m_Controls.labelNumberVoxels->setText(textNumberVoxelsDisplay); } void QmitkRandomParcellationView::SelectRandomNodes() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataNode* node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information( nullptr, "No image available", "Please load and select an image before starting image processing."); return; } // here we have a valid mitk::DataNode // a node itself is not very useful, we need its data item (the image) mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast( data ); if (image) { //get numberNodes (number of nodes) with SpinBox int numberNodes( 0 ); numberNodes = m_Controls.spinBoxNumberNodes->value(); std::stringstream message; std::string name; message << "Selecting " << numberNodes << " random nodes for "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; } message << "."; MITK_INFO << message.str(); //MITK into ITK image, function GetRandomParcels gets executed, Dimension is 3 AccessFixedDimensionByItk(image, GetRandomParcels, 3); } } } template void QmitkRandomParcellationView::GetRandomParcels( itk::Image * inputImage) { typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::Image< int, VImageDimension > IntegerImageType; //new Image which will contain the parcellation typename IntegerImageType::Pointer voxelImage = IntegerImageType::New(); voxelImage->SetRegions(inputImage->GetLargestPossibleRegion().GetSize()); voxelImage->SetSpacing(inputImage->GetSpacing()); voxelImage->SetOrigin(inputImage->GetOrigin()); voxelImage->Allocate(); //Voxel iterators itk::ImageRegionIterator it_inputImage(inputImage, inputImage->GetLargestPossibleRegion()); itk::ImageRegionIterator it_voxelImage(voxelImage, voxelImage->GetLargestPossibleRegion()); //Copy the inputImage -> voxelImage for (it_inputImage.GoToBegin(), it_voxelImage.GoToBegin(); !it_inputImage.IsAtEnd(); ++it_inputImage, ++it_voxelImage) { it_voxelImage.Value() = it_inputImage.Value(); } //Neighborhood Iterator typedef itk::NeighborhoodIterator< IntegerImageType > NeighborhoodIteratorType; typename NeighborhoodIteratorType::RadiusType radius; radius.Fill(1); //Counter for voxels with value 1 mitk::RegionVoxelCounter counter; counter.SetImage(voxelImage); counter.SetRegion(voxelImage->GetLargestPossibleRegion()); int numberVoxels = counter.VoxelWithValue(1); //Get numberNodes with SpinBox int numberNodes(0); numberNodes = m_Controls.spinBoxNumberNodes->value(); //WARNINGS if (numberNodes > numberVoxels ) { QMessageBox::information( nullptr, "Smaller Number of Nodes", "The number of nodes is greater than the number of voxels. Please choose a smaller number!"); return; } if (m_Controls.checkBoxMerging->isChecked() && m_Controls.radioButtonNumberParcels->isChecked()) { int numberParcels = m_Controls.spinBoxNumberParcels->value(); if (numberNodesisChecked() && m_Controls.radioButtonSmallestParcel->isChecked()) { int sizeSmallestParcel = m_Controls.spinBoxSmallestParcel->value(); if (sizeSmallestParcel > numberVoxels ) { QMessageBox::information( nullptr, "Smaller Size", "The size of the smallest parcel is greater than the number of voxels. Please choose a smaller size!"); return; } } //Get a RandomParcellationGenerator to generate the parcels mitk::RandomParcellationGenerator generator; generator.SetImage(voxelImage); generator.SetNumberNodes(numberNodes); //Chooses random initial voxels, with which we can start the parcellation growth generator.GetRandomSeedVoxels(); //Now we add all the voxels (which share a face with one of the voxels of a region) to a region, particular constraints have to be fulfilled generator.ParcelGrowthOverFaces(); //Because of the constraints or the position of some voxels we now add voxels to the regions which just share an edge or vertex with one region generator.FillOverEdgeOrVertex(); //Isolated voxels also have to be allocated to the regions generator.AllocateIsolatedVoxels(); //Show the sizeOfRegions in the window MITK_DEBUG << "Without merging we get the following size of regions: " << endl; generator.ShowSizeOfRegions(); //Check if the Merge-Buttons are chosen int newNumberNodes = 0; if (m_Controls.checkBoxMerging->isChecked()) { int givenSizeOfSmallestRegion(0); int desiredNumberOfParcels(0); int givenSizeOfSmallestRegionBeginning = numberVoxels; bool mergingWithNumberParcels(false); bool mergingWithSmallestParcel(false); bool justMergeSmallParcels(false); if (m_Controls.radioButtonSmallestParcel->isChecked() ) { mergingWithSmallestParcel = true; givenSizeOfSmallestRegionBeginning = m_Controls.spinBoxSmallestParcel->value(); if( m_Controls.checkBoxJustMergeSmallParcels-> isChecked() ) { //Spinbox: How many voxels should the smallest parcel have? givenSizeOfSmallestRegion = m_Controls.spinBoxSmallestParcel->value(); justMergeSmallParcels = true; } else { givenSizeOfSmallestRegion = numberVoxels; } } else if (m_Controls.radioButtonNumberParcels->isChecked()) { givenSizeOfSmallestRegion = numberVoxels; desiredNumberOfParcels = m_Controls.spinBoxNumberParcels->value(); mergingWithNumberParcels = true; } //Merge parcels according to a costfunction generator.SetVariablesForMerging(givenSizeOfSmallestRegion, desiredNumberOfParcels, givenSizeOfSmallestRegionBeginning); generator.SetBoolsForMerging(mergingWithNumberParcels, mergingWithSmallestParcel, justMergeSmallParcels); newNumberNodes = generator.MergeParcels(); MITK_DEBUG << "After merging we get the following size of regions:" << endl; generator.ShowSizeOfRegions(); } //Show NumberOfNodes on the GUI if (m_Controls.checkBoxMerging->isChecked()) //merging was used { ShowNumberOfNodes(newNumberNodes); } else { ShowNumberOfNodes(numberNodes); } //Change the values of the nodes, such that no gaps exist and the values starts with 1 generator.SetAppropriateValues(); //Get a new data node which contains the random parcellation mitk::Image::Pointer mitkRandomVoxelImage = mitk::GrabItkImageMemory( voxelImage ); mitk::DataNode::Pointer newRandomVoxelImageNode = mitk::DataNode::New(); newRandomVoxelImageNode->SetData(mitkRandomVoxelImage); newRandomVoxelImageNode->SetProperty(PROPERTYNAME.c_str(), mitk::StringProperty::New(m_NAMEFORRANDOMVOXELIMAGE)); newRandomVoxelImageNode->SetProperty(PROPERTYOPACITY.c_str(), mitk::FloatProperty::New(1.0)); this->GetDataStorage()->Add( newRandomVoxelImageNode ); return; } void QmitkRandomParcellationView::ShowNumberOfNodes(int numberNodes) { std::string string = "Number of nodes: "; std::string stringNumberNodes; std::ostringstream convert; convert << numberNodes; stringNumberNodes = convert.str(); string += stringNumberNodes; QString textNumberNodes = QString::fromStdString(string); m_Controls.labelNumberNodes->setText(textNumberNodes); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp index 57026a4fc4..75891c28d5 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp @@ -1,475 +1,473 @@ /*=================================================================== 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. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkFiberQuantificationView.h" // Qt #include // MITK #include #include #include #include #include #include #include #include #include #include // ITK #include #include #include #include #include #include #include #include #include #include const std::string QmitkFiberQuantificationView::VIEW_ID = "org.mitk.views.fiberquantification"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace mitk; QmitkFiberQuantificationView::QmitkFiberQuantificationView() : QmitkAbstractView() , m_Controls( 0 ) , m_UpsamplingFactor(5) { } // Destructor QmitkFiberQuantificationView::~QmitkFiberQuantificationView() { } void QmitkFiberQuantificationView::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::QmitkFiberQuantificationViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_ProcessFiberBundleButton, SIGNAL(clicked()), this, SLOT(ProcessSelectedBundles()) ); connect( m_Controls->m_ExtractFiberPeaks, SIGNAL(clicked()), this, SLOT(CalculateFiberDirections()) ); } } void QmitkFiberQuantificationView::SetFocus() { m_Controls->m_ProcessFiberBundleButton->setFocus(); } void QmitkFiberQuantificationView::CalculateFiberDirections() { typedef itk::Image ItkUcharImgType; - typedef itk::Image< itk::Vector< float, 3>, 3 > ItkDirectionImage3DType; - typedef itk::VectorContainer< unsigned int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(m_SelectedFB.back()->GetData()); itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); if (m_SelectedImage.IsNotNull()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); mitk::CastToItkImage(m_SelectedImage, itkMaskImage); fOdfFilter->SetMaskImage(itkMaskImage); } // extract directions from fiber bundle fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetAngularThreshold(cos(m_Controls->m_AngularThreshold->value()*M_PI/180)); fOdfFilter->SetNormalizeVectors(m_Controls->m_NormalizeDirectionsBox->isChecked()); fOdfFilter->SetUseWorkingCopy(true); fOdfFilter->SetCreateDirectionImages(m_Controls->m_DirectionImagesBox->isChecked()); fOdfFilter->SetSizeThreshold(m_Controls->m_PeakThreshold->value()); fOdfFilter->SetMaxNumDirections(m_Controls->m_MaxNumDirections->value()); fOdfFilter->Update(); QString name = m_SelectedFB.back()->GetName().c_str(); if (m_Controls->m_VectorFieldBox->isChecked()) { float minSpacing = 1; if (m_SelectedImage.IsNotNull()) { mitk::Vector3D outImageSpacing = m_SelectedImage->GetGeometry()->GetSpacing(); if(outImageSpacing[0]GetOutputFiberBundle(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(directions); node->SetName((name+"_VECTOR_FIELD").toStdString().c_str()); node->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(minSpacing)); node->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(false)); node->SetProperty("color", mitk::ColorProperty::New(1.0f, 1.0f, 1.0f)); GetDataStorage()->Add(node, m_SelectedFB.back()); } if (m_Controls->m_NumDirectionsBox->isChecked()) { mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( fOdfFilter->GetNumDirectionsImage().GetPointer() ); mitkImage->SetVolume( fOdfFilter->GetNumDirectionsImage()->GetBufferPointer() ); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitkImage); node->SetName((name+"_NUM_DIRECTIONS").toStdString().c_str()); GetDataStorage()->Add(node, m_SelectedFB.back()); } if (m_Controls->m_DirectionImagesBox->isChecked()) { itk::TractsToVectorImageFilter::ItkDirectionImageType::Pointer itkImg = fOdfFilter->GetDirectionImage(); if (itkImg.IsNull()) return; mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( itkImg.GetPointer() ); mitkImage->SetVolume( itkImg->GetBufferPointer() ); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitkImage); node->SetName( (name+"_DIRECTIONS").toStdString().c_str()); GetDataStorage()->Add(node, m_SelectedFB.back()); } } void QmitkFiberQuantificationView::UpdateGui() { m_Controls->m_ProcessFiberBundleButton->setEnabled(!m_SelectedFB.empty()); m_Controls->m_ExtractFiberPeaks->setEnabled(!m_SelectedFB.empty()); } void QmitkFiberQuantificationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { //reset existing Vectors containing FiberBundles and PlanarFigures from a previous selection m_SelectedFB.clear(); m_SelectedSurfaces.clear(); m_SelectedImage = nullptr; for (mitk::DataNode::Pointer node: nodes) { if ( dynamic_cast(node->GetData()) ) { m_SelectedFB.push_back(node); } else if (dynamic_cast(node->GetData())) m_SelectedImage = dynamic_cast(node->GetData()); else if (dynamic_cast(node->GetData())) { m_SelectedSurfaces.push_back(dynamic_cast(node->GetData())); } } UpdateGui(); GenerateStats(); } void QmitkFiberQuantificationView::GenerateStats() { if ( m_SelectedFB.empty() ) return; QString stats(""); for( unsigned int i=0; i(node->GetData())) { if (i>0) stats += "\n-----------------------------\n"; stats += QString(node->GetName().c_str()) + "\n"; mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); stats += "Number of fibers: "+ QString::number(fib->GetNumFibers()) + "\n"; stats += "Number of points: "+ QString::number(fib->GetNumberOfPoints()) + "\n"; stats += "Min. length: "+ QString::number(fib->GetMinFiberLength(),'f',1) + " mm\n"; stats += "Max. length: "+ QString::number(fib->GetMaxFiberLength(),'f',1) + " mm\n"; stats += "Mean length: "+ QString::number(fib->GetMeanFiberLength(),'f',1) + " mm\n"; stats += "Median length: "+ QString::number(fib->GetMedianFiberLength(),'f',1) + " mm\n"; stats += "Standard deviation: "+ QString::number(fib->GetLengthStDev(),'f',1) + " mm\n"; vtkSmartPointer weights = fib->GetFiberWeights(); if (weights!=nullptr) { float weight = -1; int c = 0; for (int i=0; iGetSize(); i++) if (!mitk::Equal(weights->GetValue(i),weight,0.0001)) { weight = weights->GetValue(i); c++; if (c>1) break; } if (c>1) stats += "Detected fiber weights. Fibers are not weighted uniformly.\n"; else stats += "Fibers are weighted equally.\n"; } else stats += "No fiber weight array found.\n"; } } this->m_Controls->m_StatsTextEdit->setText(stats); } void QmitkFiberQuantificationView::ProcessSelectedBundles() { if ( m_SelectedFB.empty() ){ QMessageBox::information( nullptr, "Warning", "No fibe bundle selected!"); MITK_WARN("QmitkFiberQuantificationView") << "no fibe bundle selected"; return; } int generationMethod = m_Controls->m_GenerationBox->currentIndex(); for( unsigned int i=0; i(node->GetData())) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); QString name(node->GetName().c_str()); DataNode::Pointer newNode = nullptr; switch(generationMethod){ case 0: newNode = GenerateTractDensityImage(fib, false, true); name += "_TDI"; break; case 1: newNode = GenerateTractDensityImage(fib, false, false); name += "_TDI"; break; case 2: newNode = GenerateTractDensityImage(fib, true, false); name += "_envelope"; break; case 3: newNode = GenerateColorHeatmap(fib); break; case 4: newNode = GenerateFiberEndingsImage(fib); name += "_fiber_endings"; break; case 5: newNode = GenerateFiberEndingsPointSet(fib); name += "_fiber_endings"; break; } if (newNode.IsNotNull()) { newNode->SetName(name.toStdString()); GetDataStorage()->Add(newNode); } } } } // generate pointset displaying the fiber endings mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateFiberEndingsPointSet(mitk::FiberBundle::Pointer fib) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); vtkSmartPointer fiberPolyData = fib->GetFiberPolyData(); int count = 0; int numFibers = fib->GetNumFibers(); for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints>0) { double* point = points->GetPoint(0); itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } if (numPoints>2) { double* point = points->GetPoint(numPoints-1); itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } } mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( pointSet ); return node; } // generate image displaying the fiber endings mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateFiberEndingsImage(mitk::FiberBundle::Pointer fib) { typedef unsigned int OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToFiberEndingsImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image OutImageType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate rgba heatmap from fiber bundle mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateColorHeatmap(mitk::FiberBundle::Pointer fib) { typedef itk::RGBAPixel OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToRgbaImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { itk::Image::Pointer itkImage = itk::Image::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate tract density image from fiber bundle mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateTractDensityImage(mitk::FiberBundle::Pointer fib, bool binary, bool absolute) { mitk::DataNode::Pointer node = mitk::DataNode::New(); if (binary) { typedef unsigned char OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(absolute); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node node->SetData(img); } else { typedef float OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(absolute); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } //generator->SetDoFiberResampling(false); generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node node->SetData(img); } return node; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.cpp index 41876e35d8..7458c81cb4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.cpp @@ -1,2145 +1,2144 @@ /*=================================================================== 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 "QmitkPartialVolumeAnalysisView.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "QmitkSliderNavigatorWidget.h" #include #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateOr.h" #include "mitkImageTimeSelector.h" #include "mitkProperties.h" #include "mitkProgressBar.h" #include "mitkImageCast.h" #include "mitkImageToItk.h" #include "mitkITKImageImport.h" #include "mitkDataNodeObject.h" #include "mitkNodePredicateData.h" #include "mitkPlanarFigureInteractor.h" #include "mitkTensorImage.h" #include "mitkPlanarCircle.h" #include "mitkPlanarRectangle.h" #include "mitkPlanarPolygon.h" #include "mitkPartialVolumeAnalysisClusteringCalculator.h" #include "usModuleRegistry.h" #include #include "itkTensorDerivedMeasurementsFilter.h" #include "itkDiffusionTensor3D.h" #include "itkCartesianToPolarVectorImageFilter.h" #include "itkPolarToCartesianVectorImageFilter.h" #include "itkBinaryThresholdImageFilter.h" #include "itkMaskImageFilter.h" #include "itkCastImageFilter.h" #include "itkImageMomentsCalculator.h" #include #include #include #include #include #define _USE_MATH_DEFINES #include #define PVA_PI M_PI const std::string QmitkPartialVolumeAnalysisView::VIEW_ID = "org.mitk.views.partialvolumeanalysisview"; class QmitkRequestStatisticsUpdateEvent : public QEvent { public: enum Type { StatisticsUpdateRequest = QEvent::MaxUser - 1025 }; QmitkRequestStatisticsUpdateEvent() : QEvent( (QEvent::Type) StatisticsUpdateRequest ) {}; }; typedef itk::Image ImageType; typedef itk::Image FloatImageType; typedef itk::Image, 3> VectorImageType; inline bool my_isnan(float x) { volatile float d = x; if(d!=d) return true; if(d==d) return false; return d != d; } QmitkPartialVolumeAnalysisView::QmitkPartialVolumeAnalysisView(QObject * /*parent*/, const char * /*name*/) : QmitkAbstractView(), m_Controls(nullptr), m_TimeStepperAdapter(nullptr), m_MeasurementInfoRenderer(nullptr), m_MeasurementInfoAnnotation(nullptr), m_IsTensorImage(false), m_SelectedRenderWindow(nullptr), m_LastRenderWindow(nullptr), m_ImageObserverTag(-1), m_ImageMaskObserverTag(-1), m_PlanarFigureObserverTag(-1), m_CurrentStatisticsValid(false), m_StatisticsUpdatePending(false), m_GaussianSigmaChangedSliding(false), m_NumberBinsSliding(false), m_UpsamplingChangedSliding(false), m_EllipseCounter(0), m_RectangleCounter(0), m_PolygonCounter(0), m_CurrentFigureNodeInitialized(false), m_QuantifyClass(2), m_IconTexOFF(new QIcon(":/QmitkPartialVolumeAnalysisView/texIntOFFIcon.png")), m_IconTexON(new QIcon(":/QmitkPartialVolumeAnalysisView/texIntONIcon.png")), m_TexIsOn(true), m_Visible(false) { } QmitkPartialVolumeAnalysisView::~QmitkPartialVolumeAnalysisView() { if ( m_SelectedImage.IsNotNull() ) m_SelectedImage->RemoveObserver( m_ImageObserverTag ); if ( m_SelectedImageMask.IsNotNull() ) m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); if ( m_SelectedPlanarFigure.IsNotNull() ) { m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); m_SelectedPlanarFigure->RemoveObserver( m_InitializedObserverTag ); } this->GetDataStorage()->AddNodeEvent -= mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeAddedInDataStorage ); m_SelectedPlanarFigureNodes->NodeChanged.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedPlanarFigureNodes->NodeRemoved.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); m_SelectedPlanarFigureNodes->PropertyChanged.RemoveListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); m_SelectedImageNodes->NodeChanged.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedImageNodes->NodeRemoved.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); m_SelectedImageNodes->PropertyChanged.RemoveListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); } void QmitkPartialVolumeAnalysisView::CreateQtPartControl(QWidget *parent) { if (m_Controls == nullptr) { m_Controls = new Ui::QmitkPartialVolumeAnalysisViewControls; m_Controls->setupUi(parent); this->CreateConnections(); } SetHistogramVisibility(); m_Controls->m_TextureIntON->setIcon(*m_IconTexON); m_Controls->m_SimilarAnglesFrame->setVisible(false); m_Controls->m_SimilarAnglesLabel->setVisible(false); vtkTextProperty *textProp = vtkTextProperty::New(); textProp->SetColor(1.0, 1.0, 1.0); m_MeasurementInfoAnnotation = vtkCornerAnnotation::New(); m_MeasurementInfoAnnotation->SetMaximumFontSize(12); m_MeasurementInfoAnnotation->SetTextProperty(textProp); m_MeasurementInfoRenderer = vtkRenderer::New(); m_MeasurementInfoRenderer->AddActor(m_MeasurementInfoAnnotation); m_SelectedPlanarFigureNodes = mitk::DataStorageSelection::New(this->GetDataStorage(), false); m_SelectedPlanarFigureNodes->NodeChanged.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedPlanarFigureNodes->NodeRemoved.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); m_SelectedPlanarFigureNodes->PropertyChanged.AddListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); m_SelectedImageNodes = mitk::DataStorageSelection::New(this->GetDataStorage(), false); m_SelectedImageNodes->PropertyChanged.AddListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); m_SelectedImageNodes->NodeChanged.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedImageNodes->NodeRemoved.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); this->GetDataStorage()->AddNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeAddedInDataStorage ) ); Select(nullptr,true,true); SetAdvancedVisibility(); } void QmitkPartialVolumeAnalysisView::SetFocus() { m_Controls->m_CircleButton->setFocus(); } void QmitkPartialVolumeAnalysisView::SetHistogramVisibility() { m_Controls->m_HistogramWidget->setVisible(m_Controls->m_DisplayHistogramCheckbox->isChecked()); } void QmitkPartialVolumeAnalysisView::SetAdvancedVisibility() { m_Controls->frame_7->setVisible(m_Controls->m_AdvancedCheckbox->isChecked()); } void QmitkPartialVolumeAnalysisView::CreateConnections() { if ( m_Controls ) { connect( m_Controls->m_DisplayHistogramCheckbox, SIGNAL( clicked() ) , this, SLOT( SetHistogramVisibility() ) ); connect( m_Controls->m_AdvancedCheckbox, SIGNAL( clicked() ) , this, SLOT( SetAdvancedVisibility() ) ); connect( m_Controls->m_NumberBinsSlider, SIGNAL( sliderReleased () ), this, SLOT( NumberBinsReleasedSlider( ) ) ); connect( m_Controls->m_UpsamplingSlider, SIGNAL( sliderReleased( ) ), this, SLOT( UpsamplingReleasedSlider( ) ) ); connect( m_Controls->m_GaussianSigmaSlider, SIGNAL( sliderReleased( ) ), this, SLOT( GaussianSigmaReleasedSlider( ) ) ); connect( m_Controls->m_SimilarAnglesSlider, SIGNAL( sliderReleased( ) ), this, SLOT( SimilarAnglesReleasedSlider( ) ) ); connect( m_Controls->m_NumberBinsSlider, SIGNAL( valueChanged (int) ), this, SLOT( NumberBinsChangedSlider( int ) ) ); connect( m_Controls->m_UpsamplingSlider, SIGNAL( valueChanged( int ) ), this, SLOT( UpsamplingChangedSlider( int ) ) ); connect( m_Controls->m_GaussianSigmaSlider, SIGNAL( valueChanged( int ) ), this, SLOT( GaussianSigmaChangedSlider( int ) ) ); connect( m_Controls->m_SimilarAnglesSlider, SIGNAL( valueChanged( int ) ), this, SLOT( SimilarAnglesChangedSlider(int) ) ); connect( m_Controls->m_OpacitySlider, SIGNAL( valueChanged( int ) ), this, SLOT( OpacityChangedSlider(int) ) ); connect( (QObject*)(m_Controls->m_ButtonCopyHistogramToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(ToClipBoard())); connect( m_Controls->m_CircleButton, SIGNAL( clicked() ) , this, SLOT( ActionDrawEllipseTriggered() ) ); connect( m_Controls->m_RectangleButton, SIGNAL( clicked() ) , this, SLOT( ActionDrawRectangleTriggered() ) ); connect( m_Controls->m_PolygonButton, SIGNAL( clicked() ) , this, SLOT( ActionDrawPolygonTriggered() ) ); connect( m_Controls->m_GreenRadio, SIGNAL( clicked(bool) ) , this, SLOT( GreenRadio(bool) ) ); connect( m_Controls->m_PartialVolumeRadio, SIGNAL( clicked(bool) ) , this, SLOT( PartialVolumeRadio(bool) ) ); connect( m_Controls->m_BlueRadio, SIGNAL( clicked(bool) ) , this, SLOT( BlueRadio(bool) ) ); connect( m_Controls->m_AllRadio, SIGNAL( clicked(bool) ) , this, SLOT( AllRadio(bool) ) ); connect( m_Controls->m_EstimateCircle, SIGNAL( clicked() ) , this, SLOT( EstimateCircle() ) ); connect( (QObject*)(m_Controls->m_TextureIntON), SIGNAL(clicked()), this, SLOT(TextIntON()) ); connect( m_Controls->m_ExportClusteringResultsButton, SIGNAL(clicked()), this, SLOT(ExportClusteringResults())); } } void QmitkPartialVolumeAnalysisView::ExportClusteringResults() { if (m_ClusteringResult.IsNull() || m_SelectedImage.IsNull()) return; mitk::BaseGeometry* geometry = m_SelectedImage->GetGeometry(); itk::Image< short, 3>::Pointer referenceImage = itk::Image< short, 3>::New(); itk::Vector newSpacing = geometry->GetSpacing(); mitk::Point3D newOrigin = geometry->GetOrigin(); mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); newOrigin[0] += bounds.GetElement(0); newOrigin[1] += bounds.GetElement(2); newOrigin[2] += bounds.GetElement(4); itk::Matrix newDirection; itk::ImageRegion<3> imageRegion; for (int i=0; i<3; i++) for (int j=0; j<3; j++) newDirection[j][i] = geometry->GetMatrixColumn(i)[j]/newSpacing[j]; imageRegion.SetSize(0, geometry->GetExtent(0)); imageRegion.SetSize(1, geometry->GetExtent(1)); imageRegion.SetSize(2, geometry->GetExtent(2)); // apply new image parameters referenceImage->SetSpacing( newSpacing ); referenceImage->SetOrigin( newOrigin ); referenceImage->SetDirection( newDirection ); referenceImage->SetRegions( imageRegion ); referenceImage->Allocate(); typedef itk::Image< float, 3 > OutType; mitk::Image::Pointer mitkInImage = dynamic_cast(m_ClusteringResult->GetData()); typedef itk::Image< itk::RGBAPixel, 3 > ItkRgbaImageType; typedef mitk::ImageToItk< ItkRgbaImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitkInImage); caster->Update(); ItkRgbaImageType::Pointer itkInImage = caster->GetOutput(); typedef itk::ExtractChannelFromRgbaImageFilter< itk::Image< short, 3>, OutType > ExtractionFilterType; ExtractionFilterType::Pointer filter = ExtractionFilterType::New(); filter->SetInput(itkInImage); filter->SetChannel(ExtractionFilterType::ALPHA); filter->SetReferenceImage(referenceImage); filter->Update(); OutType::Pointer outImg = filter->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); node->SetName("Clustering Result"); GetDataStorage()->Add(node); } void QmitkPartialVolumeAnalysisView::EstimateCircle() { typedef itk::Image SegImageType; SegImageType::Pointer mask_itk = SegImageType::New(); typedef mitk::ImageToItk CastType; CastType::Pointer caster = CastType::New(); caster->SetInput(m_SelectedImageMask); caster->Update(); typedef itk::ImageMomentsCalculator< SegImageType > MomentsType; MomentsType::Pointer momentsCalc = MomentsType::New(); momentsCalc->SetImage(caster->GetOutput()); momentsCalc->Compute(); MomentsType::VectorType cog = momentsCalc->GetCenterOfGravity(); MomentsType::MatrixType axes = momentsCalc->GetPrincipalAxes(); - MomentsType::VectorType moments = momentsCalc->GetPrincipalMoments(); // moments-coord conversion // third coordinate min oder max? // max-min = extent MomentsType::AffineTransformPointer trafo = momentsCalc->GetPhysicalAxesToPrincipalAxesTransform(); itk::ImageRegionIterator itimage(caster->GetOutput(), caster->GetOutput()->GetLargestPossibleRegion()); itimage.GoToBegin(); double max = -9999999999.0; double min = 9999999999.0; while( !itimage.IsAtEnd() ) { if(itimage.Get()) { ImageType::IndexType index = itimage.GetIndex(); itk::Point point; caster->GetOutput()->TransformIndexToPhysicalPoint(index,point); itk::Point newPoint; newPoint = trafo->TransformPoint(point); if(newPoint[2]max) max = newPoint[2]; } ++itimage; } double extent = max - min; MITK_DEBUG << "EXTENT = " << extent; mitk::Point3D origin; mitk::Vector3D right, bottom, normal; double factor = 1000.0; mitk::FillVector3D(origin, cog[0]-factor*axes[1][0]-factor*axes[2][0], cog[1]-factor*axes[1][1]-factor*axes[2][1], cog[2]-factor*axes[1][2]-factor*axes[2][2]); // mitk::FillVector3D(normal, axis[0][0],axis[0][1],axis[0][2]); mitk::FillVector3D(bottom, 2*factor*axes[1][0], 2*factor*axes[1][1], 2*factor*axes[1][2]); mitk::FillVector3D(right, 2*factor*axes[2][0], 2*factor*axes[2][1], 2*factor*axes[2][2]); mitk::PlaneGeometry::Pointer planegeometry = mitk::PlaneGeometry::New(); planegeometry->InitializeStandardPlane(right.GetVnlVector(), bottom.GetVnlVector()); planegeometry->SetOrigin(origin); double len1 = sqrt(axes[1][0]*axes[1][0] + axes[1][1]*axes[1][1] + axes[1][2]*axes[1][2]); double len2 = sqrt(axes[2][0]*axes[2][0] + axes[2][1]*axes[2][1] + axes[2][2]*axes[2][2]); mitk::Point2D point1; point1[0] = factor*len1; point1[1] = factor*len2; mitk::Point2D point2; point2[0] = factor*len1+extent*.5; point2[1] = factor*len2; mitk::PlanarCircle::Pointer circle = mitk::PlanarCircle::New(); circle->SetPlaneGeometry(planegeometry); circle->PlaceFigure( point1 ); circle->SetControlPoint(0,point1); circle->SetControlPoint(1,point2); //circle->SetCurrentControlPoint( point2 ); mitk::PlanarFigure::PolyLineType polyline = circle->GetPolyLine( 0 ); MITK_DEBUG << "SIZE of planar figure polyline: " << polyline.size(); AddFigureToDataStorage(circle, "Circle"); } bool QmitkPartialVolumeAnalysisView::AssertDrawingIsPossible(bool checked) { if (m_SelectedImageNodes->GetNode().IsNull()) { checked = false; this->HandleException("Please select an image!", dynamic_cast(this->parent()), true); return false; } //this->GetRenderWindowPart(OPEN)->EnableSlicingPlanes(false); return checked; } void QmitkPartialVolumeAnalysisView::ActionDrawEllipseTriggered() { bool checked = m_Controls->m_CircleButton->isChecked(); if(!this->AssertDrawingIsPossible(checked)) return; mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New(); // using PV_ prefix for planar figures from this view // to distinguish them from that ones created throught the measurement view this->AddFigureToDataStorage(figure, QString("PV_Circle%1").arg(++m_EllipseCounter)); MITK_DEBUG << "PlanarCircle created ..."; } void QmitkPartialVolumeAnalysisView::ActionDrawRectangleTriggered() { bool checked = m_Controls->m_RectangleButton->isChecked(); if(!this->AssertDrawingIsPossible(checked)) return; mitk::PlanarRectangle::Pointer figure = mitk::PlanarRectangle::New(); // using PV_ prefix for planar figures from this view // to distinguish them from that ones created throught the measurement view this->AddFigureToDataStorage(figure, QString("PV_Rectangle%1").arg(++m_RectangleCounter)); MITK_DEBUG << "PlanarRectangle created ..."; } void QmitkPartialVolumeAnalysisView::ActionDrawPolygonTriggered() { bool checked = m_Controls->m_PolygonButton->isChecked(); if(!this->AssertDrawingIsPossible(checked)) return; mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); figure->ClosedOn(); // using PV_ prefix for planar figures from this view // to distinguish them from that ones created throught the measurement view this->AddFigureToDataStorage(figure, QString("PV_Polygon%1").arg(++m_PolygonCounter)); MITK_DEBUG << "PlanarPolygon created ..."; } void QmitkPartialVolumeAnalysisView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey, mitk::BaseProperty *property ) { mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(name.toStdString()); newNode->SetData(figure); // Add custom property, if available if ( (propertyKey != nullptr) && (property != nullptr) ) { newNode->AddProperty( propertyKey, property ); } // figure drawn on the topmost layer / image this->GetDataStorage()->Add(newNode, m_SelectedImageNodes->GetNode() ); QList selectedNodes = this->GetDataManagerSelection(); for(int i = 0; i < selectedNodes.size(); ++i) { selectedNodes[i]->SetSelected(false); } std::vector selectedPFNodes = m_SelectedPlanarFigureNodes->GetNodes(); for(std::size_t i = 0; i < selectedPFNodes.size(); ++i) { selectedPFNodes[i]->SetSelected(false); } newNode->SetSelected(true); Select(newNode); } void QmitkPartialVolumeAnalysisView::PlanarFigureInitialized() { if(m_SelectedPlanarFigureNodes->GetNode().IsNull()) return; m_CurrentFigureNodeInitialized = true; this->Select(m_SelectedPlanarFigureNodes->GetNode()); m_Controls->m_CircleButton->setChecked(false); m_Controls->m_RectangleButton->setChecked(false); m_Controls->m_PolygonButton->setChecked(false); //this->GetRenderWindowPart(OPEN)->EnableSlicingPlanes(true); this->RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::PlanarFigureFocus(mitk::DataNode* node) { mitk::PlanarFigure* _PlanarFigure = 0; _PlanarFigure = dynamic_cast (node->GetData()); if (_PlanarFigure) { FindRenderWindow(node); const mitk::PlaneGeometry* _PlaneGeometry = _PlanarFigure->GetPlaneGeometry(); // make node visible if (m_SelectedRenderWindow) { mitk::Point3D centerP = _PlaneGeometry->GetOrigin(); m_SelectedRenderWindow->GetSliceNavigationController()->ReorientSlices( centerP, _PlaneGeometry->GetNormal()); m_SelectedRenderWindow->GetSliceNavigationController()->SelectSliceByPoint( centerP); } } } void QmitkPartialVolumeAnalysisView::FindRenderWindow(mitk::DataNode* node) { if (node && dynamic_cast (node->GetData())) { m_SelectedRenderWindow = 0; bool PlanarFigureInitializedWindow = false; foreach(QmitkRenderWindow * window, this->GetRenderWindowPart()->GetQmitkRenderWindows().values()) { if (!m_SelectedRenderWindow && node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, window->GetRenderer())) { m_SelectedRenderWindow = window; } } } } void QmitkPartialVolumeAnalysisView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList &nodes) { m_Controls->m_InputData->setTitle("Please Select Input Data"); if (!m_Visible) return; if ( nodes.empty() ) { if (m_ClusteringResult.IsNotNull()) { this->GetDataStorage()->Remove(m_ClusteringResult); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } Select(nullptr, true, true); } for (int i=0; iRemoveOrphanImages(); bool somethingChanged = false; if(node.IsNull()) { somethingChanged = true; if(clearMaskOnFirstArgnullptr) { if ( (m_SelectedImageMask.IsNotNull()) && (m_ImageMaskObserverTag >= 0) ) { m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); m_ImageMaskObserverTag = -1; } if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_PlanarFigureObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); m_PlanarFigureObserverTag = -1; } if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_InitializedObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_InitializedObserverTag ); m_InitializedObserverTag = -1; } m_SelectedPlanarFigure = nullptr; m_SelectedPlanarFigureNodes->RemoveAllNodes(); m_CurrentFigureNodeInitialized = false; m_SelectedRenderWindow = 0; m_SelectedMaskNode = nullptr; m_SelectedImageMask = nullptr; } if(clearImageOnFirstArgnullptr) { if ( (m_SelectedImage.IsNotNull()) && (m_ImageObserverTag >= 0) ) { m_SelectedImage->RemoveObserver( m_ImageObserverTag ); m_ImageObserverTag = -1; } m_SelectedImageNodes->RemoveAllNodes(); m_SelectedImage = nullptr; m_IsTensorImage = false; m_FAImage = nullptr; m_RDImage = nullptr; m_ADImage = nullptr; m_MDImage = nullptr; m_CAImage = nullptr; m_DirectionComp1Image = nullptr; m_DirectionComp2Image = nullptr; m_AngularErrorImage = nullptr; m_Controls->m_SimilarAnglesFrame->setVisible(false); m_Controls->m_SimilarAnglesLabel->setVisible(false); } } else { typedef itk::SimpleMemberCommand< QmitkPartialVolumeAnalysisView > ITKCommandType; ITKCommandType::Pointer changeListener; changeListener = ITKCommandType::New(); changeListener->SetCallbackFunction( this, &QmitkPartialVolumeAnalysisView::RequestStatisticsUpdate ); // Get selected element mitk::TensorImage *selectedTensorImage = dynamic_cast< mitk::TensorImage * >( node->GetData() ); mitk::Image *selectedImage = dynamic_cast< mitk::Image * >( node->GetData() ); mitk::PlanarFigure *selectedPlanar = dynamic_cast< mitk::PlanarFigure * >( node->GetData() ); bool isMask = false; bool isImage = false; bool isPlanar = false; bool isTensorImage = false; if (selectedTensorImage != nullptr) { isTensorImage = true; } else if(selectedImage != nullptr) { node->GetPropertyValue("binary", isMask); isImage = !isMask; } else if ( (selectedPlanar != nullptr) ) { isPlanar = true; } // image if(isImage && selectedImage->GetDimension()==3) { if(selectedImage != m_SelectedImage.GetPointer()) { somethingChanged = true; if ( (m_SelectedImage.IsNotNull()) && (m_ImageObserverTag >= 0) ) { m_SelectedImage->RemoveObserver( m_ImageObserverTag ); m_ImageObserverTag = -1; } *m_SelectedImageNodes = node; m_SelectedImage = selectedImage; m_IsTensorImage = false; m_FAImage = nullptr; m_RDImage = nullptr; m_ADImage = nullptr; m_MDImage = nullptr; m_CAImage = nullptr; m_DirectionComp1Image = nullptr; m_DirectionComp2Image = nullptr; m_AngularErrorImage = nullptr; // Add change listeners to selected objects m_ImageObserverTag = m_SelectedImage->AddObserver( itk::ModifiedEvent(), changeListener ); m_Controls->m_SimilarAnglesFrame->setVisible(false); m_Controls->m_SimilarAnglesLabel->setVisible(false); m_Controls->m_SelectedImageLabel->setText( m_SelectedImageNodes->GetNode()->GetName().c_str() ); } } //planar if(isPlanar) { if(selectedPlanar != m_SelectedPlanarFigure.GetPointer()) { MITK_DEBUG << "Planar selection changed"; somethingChanged = true; // Possibly previous change listeners if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_PlanarFigureObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); m_PlanarFigureObserverTag = -1; } if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_InitializedObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_InitializedObserverTag ); m_InitializedObserverTag = -1; } m_SelectedPlanarFigure = selectedPlanar; *m_SelectedPlanarFigureNodes = node; m_CurrentFigureNodeInitialized = selectedPlanar->IsPlaced(); m_SelectedMaskNode = nullptr; m_SelectedImageMask = nullptr; m_PlanarFigureObserverTag = m_SelectedPlanarFigure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), changeListener ); if(!m_CurrentFigureNodeInitialized) { typedef itk::SimpleMemberCommand< QmitkPartialVolumeAnalysisView > ITKCommandType; ITKCommandType::Pointer initializationCommand; initializationCommand = ITKCommandType::New(); // set the callback function of the member command initializationCommand->SetCallbackFunction( this, &QmitkPartialVolumeAnalysisView::PlanarFigureInitialized ); // add an observer m_InitializedObserverTag = selectedPlanar->AddObserver( mitk::EndPlacementPlanarFigureEvent(), initializationCommand ); } m_Controls->m_SelectedMaskLabel->setText( m_SelectedPlanarFigureNodes->GetNode()->GetName().c_str() ); PlanarFigureFocus(node); } } //mask this->m_Controls->m_EstimateCircle->setEnabled(isMask && selectedImage->GetDimension()==3); if(isMask && selectedImage->GetDimension()==3) { if(selectedImage != m_SelectedImage.GetPointer()) { somethingChanged = true; if ( (m_SelectedImageMask.IsNotNull()) && (m_ImageMaskObserverTag >= 0) ) { m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); m_ImageMaskObserverTag = -1; } m_SelectedMaskNode = node; m_SelectedImageMask = selectedImage; m_SelectedPlanarFigure = nullptr; m_SelectedPlanarFigureNodes->RemoveAllNodes(); m_ImageMaskObserverTag = m_SelectedImageMask->AddObserver( itk::ModifiedEvent(), changeListener ); m_Controls->m_SelectedMaskLabel->setText( m_SelectedMaskNode->GetName().c_str() ); } } //tensor image if(isTensorImage && selectedTensorImage->GetDimension()==3) { if(selectedImage != m_SelectedImage.GetPointer()) { somethingChanged = true; if ( (m_SelectedImage.IsNotNull()) && (m_ImageObserverTag >= 0) ) { m_SelectedImage->RemoveObserver( m_ImageObserverTag ); m_ImageObserverTag = -1; } *m_SelectedImageNodes = node; m_SelectedImage = selectedImage; m_IsTensorImage = true; ExtractTensorImages(selectedImage); // Add change listeners to selected objects m_ImageObserverTag = m_SelectedImage->AddObserver( itk::ModifiedEvent(), changeListener ); m_Controls->m_SimilarAnglesFrame->setVisible(true); m_Controls->m_SimilarAnglesLabel->setVisible(true); m_Controls->m_SelectedImageLabel->setText( m_SelectedImageNodes->GetNode()->GetName().c_str() ); } } } if(somethingChanged) { this->SetMeasurementInfoToRenderWindow(""); if(m_SelectedPlanarFigure.IsNull() && m_SelectedImageMask.IsNull() ) { m_Controls->m_SelectedMaskLabel->setText("mandatory"); m_Controls->m_ResampleOptionsFrame->setEnabled(false); m_Controls->m_HistogramWidget->setEnabled(false); m_Controls->m_ClassSelector->setEnabled(false); m_Controls->m_DisplayHistogramCheckbox->setEnabled(false); m_Controls->m_AdvancedCheckbox->setEnabled(false); m_Controls->frame_7->setEnabled(false); } else { m_Controls->m_ResampleOptionsFrame->setEnabled(true); m_Controls->m_HistogramWidget->setEnabled(true); m_Controls->m_ClassSelector->setEnabled(true); m_Controls->m_DisplayHistogramCheckbox->setEnabled(true); m_Controls->m_AdvancedCheckbox->setEnabled(true); m_Controls->frame_7->setEnabled(true); } // Clear statistics / histogram GUI if nothing is selected if ( m_SelectedImage.IsNull() ) { m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); m_Controls->m_OpacityFrame->setEnabled(false); m_Controls->m_SelectedImageLabel->setText("mandatory"); } else { m_Controls->m_PlanarFigureButtonsFrame->setEnabled(true); m_Controls->m_OpacityFrame->setEnabled(true); } if( !m_Visible || m_SelectedImage.IsNull() || (m_SelectedPlanarFigure.IsNull() && m_SelectedImageMask.IsNull()) ) { m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->m_HistogramWidget->ClearItemModel(); m_CurrentStatisticsValid = false; } else { m_Controls->m_InputData->setTitle("Input Data"); this->RequestStatisticsUpdate(); } } } void QmitkPartialVolumeAnalysisView::ShowClusteringResults() { typedef itk::Image MaskImageType; mitk::Image::Pointer mask = 0; MaskImageType::Pointer itkmask = 0; if(m_IsTensorImage && m_Controls->m_SimilarAnglesSlider->value() != 0) { typedef itk::Image AngularErrorImageType; typedef mitk::ImageToItk CastType; CastType::Pointer caster = CastType::New(); caster->SetInput(m_AngularErrorImage); caster->Update(); typedef itk::BinaryThresholdImageFilter< AngularErrorImageType, MaskImageType > ThreshType; ThreshType::Pointer thresh = ThreshType::New(); thresh->SetUpperThreshold((90-m_Controls->m_SimilarAnglesSlider->value())*(PVA_PI/180.0)); thresh->SetInsideValue(1.0); thresh->SetInput(caster->GetOutput()); thresh->Update(); itkmask = thresh->GetOutput(); mask = mitk::Image::New(); mask->InitializeByItk(itkmask.GetPointer()); mask->SetVolume(itkmask->GetBufferPointer()); // GetDataStorage()->Remove(m_newnode); // m_newnode = mitk::DataNode::New(); // m_newnode->SetData(mask); // m_newnode->SetName("masking node"); // m_newnode->SetIntProperty( "layer", 1002 ); // GetDataStorage()->Add(m_newnode, m_SelectedImageNodes->GetNode()); } mitk::Image::Pointer clusteredImage; ClusteringType::Pointer clusterer = ClusteringType::New(); if(m_QuantifyClass==3) { if(m_IsTensorImage) { double *green_fa, *green_rd, *green_ad, *green_md; //double *greengray_fa, *greengray_rd, *greengray_ad, *greengray_md; double *gray_fa, *gray_rd, *gray_ad, *gray_md; //double *redgray_fa, *redgray_rd, *redgray_ad, *redgray_md; double *red_fa, *red_rd, *red_ad, *red_md; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(0); mitk::Image::ConstPointer imgToCluster = tmpImg; red_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->b, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(3); mitk::Image::ConstPointer imgToCluster3 = tmpImg; red_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentRGBClusteringResults->rgbChannels->b, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(4); mitk::Image::ConstPointer imgToCluster4 = tmpImg; red_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentRGBClusteringResults->rgbChannels->b, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(5); mitk::Image::ConstPointer imgToCluster5 = tmpImg; red_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentRGBClusteringResults->rgbChannels->b, mask); // clipboard QString clipboardText("FA\t%1\t%2\t\t%3\t%4\t\t%5\t%6\t"); clipboardText = clipboardText .arg(red_fa[0]).arg(red_fa[1]) .arg(gray_fa[0]).arg(gray_fa[1]) .arg(green_fa[0]).arg(green_fa[1]); QString clipboardText3("RD\t%1\t%2\t\t%3\t%4\t\t%5\t%6\t"); clipboardText3 = clipboardText3 .arg(red_rd[0]).arg(red_rd[1]) .arg(gray_rd[0]).arg(gray_rd[1]) .arg(green_rd[0]).arg(green_rd[1]); QString clipboardText4("AD\t%1\t%2\t\t%3\t%4\t\t%5\t%6\t"); clipboardText4 = clipboardText4 .arg(red_ad[0]).arg(red_ad[1]) .arg(gray_ad[0]).arg(gray_ad[1]) .arg(green_ad[0]).arg(green_ad[1]); QString clipboardText5("MD\t%1\t%2\t\t%3\t%4\t\t%5\t%6"); clipboardText5 = clipboardText5 .arg(red_md[0]).arg(red_md[1]) .arg(gray_md[0]).arg(gray_md[1]) .arg(green_md[0]).arg(green_md[1]); QApplication::clipboard()->setText(clipboardText+clipboardText3+clipboardText4+clipboardText5, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("%1 %2 %3 \n"); plainInfoText = plainInfoText .arg("Red ", 20) .arg("Gray ", 20) .arg("Green", 20); QString plainInfoText0("FA:%1 ± %2%3 ± %4%5 ± %6\n"); plainInfoText0 = plainInfoText0 .arg(red_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(red_fa[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(gray_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(gray_fa[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(green_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(green_fa[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText3("RDx10³:%1 ± %2%3 ± %4%5 ± %6\n"); plainInfoText3 = plainInfoText3 .arg(1000.0 * red_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_rd[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * gray_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * gray_rd[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * green_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * green_rd[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText4("ADx10³:%1 ± %2%3 ± %4%5 ± %6\n"); plainInfoText4 = plainInfoText4 .arg(1000.0 * red_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_ad[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * gray_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * gray_ad[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * green_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * green_ad[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText5("MDx10³:%1 ± %2%3 ± %4%5 ± %6"); plainInfoText5 = plainInfoText5 .arg(1000.0 * red_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_md[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * gray_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * gray_md[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * green_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * green_md[1], -10, 'g', 2, QLatin1Char( ' ' )); this->SetMeasurementInfoToRenderWindow(plainInfoText+plainInfoText0+plainInfoText3+plainInfoText4+plainInfoText5); } else { double* green; double* gray; double* red; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalImage(); mitk::Image::ConstPointer imgToCluster = tmpImg; red = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->r); green = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->g); gray = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->b); // clipboard QString clipboardText("%1\t%2\t\t%3\t%4\t\t%5\t%6"); clipboardText = clipboardText.arg(red[0]).arg(red[1]) .arg(gray[0]).arg(gray[1]) .arg(green[0]).arg(green[1]); QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("Red: %1 ± %2\nGray: %3 ± %4\nGreen: %5 ± %6"); plainInfoText = plainInfoText.arg(red[0]).arg(red[1]) .arg(gray[0]).arg(gray[1]) .arg(green[0]).arg(green[1]); this->SetMeasurementInfoToRenderWindow(plainInfoText); } clusteredImage = m_CurrentRGBClusteringResults->rgb; } else { if(m_IsTensorImage) { double *red_fa, *red_rd, *red_ad, *red_md; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(0); mitk::Image::ConstPointer imgToCluster = tmpImg; red_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentPerformClusteringResults->clusteredImage, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(3); mitk::Image::ConstPointer imgToCluster3 = tmpImg; red_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentPerformClusteringResults->clusteredImage, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(4); mitk::Image::ConstPointer imgToCluster4 = tmpImg; red_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentPerformClusteringResults->clusteredImage, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(5); mitk::Image::ConstPointer imgToCluster5 = tmpImg; red_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentPerformClusteringResults->clusteredImage, mask); // clipboard QString clipboardText("FA\t%1\t%2\t"); clipboardText = clipboardText .arg(red_fa[0]).arg(red_fa[1]); QString clipboardText3("RD\t%1\t%2\t"); clipboardText3 = clipboardText3 .arg(red_rd[0]).arg(red_rd[1]); QString clipboardText4("AD\t%1\t%2\t"); clipboardText4 = clipboardText4 .arg(red_ad[0]).arg(red_ad[1]); QString clipboardText5("MD\t%1\t%2\t"); clipboardText5 = clipboardText5 .arg(red_md[0]).arg(red_md[1]); QApplication::clipboard()->setText(clipboardText+clipboardText3+clipboardText4+clipboardText5, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("%1 \n"); plainInfoText = plainInfoText .arg("Red ", 20); QString plainInfoText0("FA:%1 ± %2\n"); plainInfoText0 = plainInfoText0 .arg(red_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(red_fa[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText3("RDx10³:%1 ± %2\n"); plainInfoText3 = plainInfoText3 .arg(1000.0 * red_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_rd[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText4("ADx10³:%1 ± %2\n"); plainInfoText4 = plainInfoText4 .arg(1000.0 * red_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_ad[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText5("MDx10³:%1 ± %2"); plainInfoText5 = plainInfoText5 .arg(1000.0 * red_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_md[1], -10, 'g', 2, QLatin1Char( ' ' )); this->SetMeasurementInfoToRenderWindow(plainInfoText+plainInfoText0+plainInfoText3+plainInfoText4+plainInfoText5); } else { double* quant; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalImage(); mitk::Image::ConstPointer imgToCluster = tmpImg; quant = clusterer->PerformQuantification(imgToCluster, m_CurrentPerformClusteringResults->clusteredImage); // clipboard QString clipboardText("%1\t%2"); clipboardText = clipboardText.arg(quant[0]).arg(quant[1]); QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("Measurement: %1 ± %2"); plainInfoText = plainInfoText.arg(quant[0]).arg(quant[1]); this->SetMeasurementInfoToRenderWindow(plainInfoText); } clusteredImage = m_CurrentPerformClusteringResults->displayImage; } if(mask.IsNotNull()) { typedef itk::Image,3> RGBImageType; typedef mitk::ImageToItk ClusterCasterType; ClusterCasterType::Pointer clCaster = ClusterCasterType::New(); clCaster->SetInput(clusteredImage); clCaster->Update(); clCaster->GetOutput(); typedef itk::MaskImageFilter< RGBImageType, MaskImageType, RGBImageType > MaskType; MaskType::Pointer masker = MaskType::New(); masker->SetInput1(clCaster->GetOutput()); masker->SetInput2(itkmask); masker->Update(); clusteredImage = mitk::Image::New(); clusteredImage->InitializeByItk(masker->GetOutput()); clusteredImage->SetVolume(masker->GetOutput()->GetBufferPointer()); } if(m_ClusteringResult.IsNotNull()) { this->GetDataStorage()->Remove(m_ClusteringResult); } m_ClusteringResult = mitk::DataNode::New(); m_ClusteringResult->SetBoolProperty("helper object", true); m_ClusteringResult->SetIntProperty( "layer", 1000 ); m_ClusteringResult->SetBoolProperty("texture interpolation", m_TexIsOn); m_ClusteringResult->SetData(clusteredImage); m_ClusteringResult->SetName("Clusterprobs"); this->GetDataStorage()->Add(m_ClusteringResult, m_SelectedImageNodes->GetNode()); if(m_SelectedPlanarFigure.IsNotNull() && m_SelectedPlanarFigureNodes->GetNode().IsNotNull()) { m_SelectedPlanarFigureNodes->GetNode()->SetIntProperty( "layer", 1001 ); } this->RequestRenderWindowUpdate(); } void QmitkPartialVolumeAnalysisView::UpdateStatistics() { if(!m_CurrentFigureNodeInitialized && m_SelectedPlanarFigure.IsNotNull()) { MITK_DEBUG << "Selected planar figure not initialized. No stats calculation performed."; return; } // Remove any cached images that are no longer referenced elsewhere this->RemoveOrphanImages(); if ( m_SelectedImage.IsNotNull() ) { // Check if a the selected image is a multi-channel image. If yes, statistics // cannot be calculated currently. if ( !m_IsTensorImage && m_SelectedImage->GetPixelType().GetNumberOfComponents() > 1 ) { QMessageBox::information( nullptr, "Warning", "Non-tensor multi-component images not supported."); m_Controls->m_HistogramWidget->ClearItemModel(); m_CurrentStatisticsValid = false; return; } m_CurrentStatisticsCalculator = nullptr; if(!m_IsTensorImage) { // Retrieve HistogramStatisticsCalculator from has map (or create a new one // for this image if non-existant) PartialVolumeAnalysisMapType::iterator it = m_PartialVolumeAnalysisMap.find( m_SelectedImage ); if ( it != m_PartialVolumeAnalysisMap.end() ) { m_CurrentStatisticsCalculator = it->second; } } if(m_CurrentStatisticsCalculator.IsNull()) { m_CurrentStatisticsCalculator = mitk::PartialVolumeAnalysisHistogramCalculator::New(); m_CurrentStatisticsCalculator->SetPlanarFigureThickness(m_Controls->m_PlanarFiguresThickness->value()); if(m_IsTensorImage) { m_CurrentStatisticsCalculator->SetImage( m_CAImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_FAImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_DirectionComp1Image ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_DirectionComp2Image ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_RDImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_ADImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_MDImage ); } else { m_CurrentStatisticsCalculator->SetImage( m_SelectedImage ); } m_PartialVolumeAnalysisMap[m_SelectedImage] = m_CurrentStatisticsCalculator; MITK_DEBUG << "Creating StatisticsCalculator"; } std::string maskName; std::string maskType; unsigned int maskDimension; if ( m_SelectedImageMask.IsNotNull() ) { mitk::PixelType pixelType = m_SelectedImageMask->GetPixelType(); MITK_DEBUG << pixelType.GetPixelTypeAsString(); if(pixelType.GetComponentTypeAsString() == "char") { MITK_DEBUG << "Pixel type is char instead of uchar"; return; } if(pixelType.GetBitsPerComponent() == 16) { //convert from ushort to uchar typedef itk::Image UCharImageType; UCharImageType::Pointer charImage; if(pixelType.GetComponentTypeAsString() == "short" ) { typedef itk::Image ShortImageType; ShortImageType::Pointer shortImage; mitk::CastToItkImage( m_SelectedImageMask, shortImage ); typedef itk::ImageDuplicator< ShortImageType > DuplicatorType; DuplicatorType::Pointer duplicator = DuplicatorType::New(); duplicator->SetInputImage( shortImage ); duplicator->Update(); typedef itk::CastImageFilter ImageCasterType; ImageCasterType::Pointer caster = ImageCasterType::New(); caster->SetInput( duplicator->GetOutput() ); caster->Update(); charImage = caster->GetOutput(); } else { typedef itk::Image UShortImageType; UShortImageType::Pointer shortImage; mitk::CastToItkImage( m_SelectedImageMask, shortImage ); typedef itk::ImageDuplicator< UShortImageType > DuplicatorType; DuplicatorType::Pointer duplicator = DuplicatorType::New(); duplicator->SetInputImage( shortImage ); duplicator->Update(); typedef itk::CastImageFilter ImageCasterType; ImageCasterType::Pointer caster = ImageCasterType::New(); caster->SetInput( duplicator->GetOutput() ); caster->Update(); charImage = caster->GetOutput(); } m_SelectedImageMask = nullptr; m_SelectedImageMask = mitk::Image::New(); m_SelectedImageMask->InitializeByItk( charImage.GetPointer() ); m_SelectedImageMask->SetVolume( charImage->GetBufferPointer() ); mitk::CastToMitkImage(charImage, m_SelectedImageMask); } m_CurrentStatisticsCalculator->SetImageMask( m_SelectedImageMask ); m_CurrentStatisticsCalculator->SetMaskingModeToImage(); maskName = m_SelectedMaskNode->GetName(); maskType = m_SelectedImageMask->GetNameOfClass(); maskDimension = 3; std::stringstream maskLabel; maskLabel << maskName; if ( maskDimension > 0 ) { maskLabel << " [" << maskDimension << "D " << maskType << "]"; } m_Controls->m_SelectedMaskLabel->setText( maskLabel.str().c_str() ); } else if ( m_SelectedPlanarFigure.IsNotNull() && m_SelectedPlanarFigureNodes->GetNode().IsNotNull()) { m_CurrentStatisticsCalculator->SetPlanarFigure( m_SelectedPlanarFigure ); m_CurrentStatisticsCalculator->SetMaskingModeToPlanarFigure(); maskName = m_SelectedPlanarFigureNodes->GetNode()->GetName(); maskType = m_SelectedPlanarFigure->GetNameOfClass(); maskDimension = 2; } else { m_CurrentStatisticsCalculator->SetMaskingModeToNone(); maskName = "-"; maskType = ""; maskDimension = 0; } bool statisticsChanged = false; bool statisticsCalculationSuccessful = false; // Initialize progress bar mitk::ProgressBar::GetInstance()->AddStepsToDo( 100 ); // Install listener for progress events and initialize progress bar typedef itk::SimpleMemberCommand< QmitkPartialVolumeAnalysisView > ITKCommandType; ITKCommandType::Pointer progressListener; progressListener = ITKCommandType::New(); progressListener->SetCallbackFunction( this, &QmitkPartialVolumeAnalysisView::UpdateProgressBar ); unsigned long progressObserverTag = m_CurrentStatisticsCalculator ->AddObserver( itk::ProgressEvent(), progressListener ); ClusteringType::ParamsType *cparams = 0; ClusteringType::ClusterResultType *cresult = 0; ClusteringType::HistType *chist = 0; try { m_CurrentStatisticsCalculator->SetNumberOfBins(m_Controls->m_NumberBins->text().toInt()); m_CurrentStatisticsCalculator->SetUpsamplingFactor(m_Controls->m_Upsampling->text().toDouble()); m_CurrentStatisticsCalculator->SetGaussianSigma(m_Controls->m_GaussianSigma->text().toDouble()); // Compute statistics statisticsChanged = m_CurrentStatisticsCalculator->ComputeStatistics( ); mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalImage(); mitk::Image::ConstPointer imgToCluster = tmpImg; if(imgToCluster.IsNotNull()) { // perform clustering const HistogramType *histogram = m_CurrentStatisticsCalculator->GetHistogram( ); if(histogram != nullptr) { ClusteringType::Pointer clusterer = ClusteringType::New(); clusterer->SetStepsNumIntegration(200); clusterer->SetMaxIt(1000); mitk::Image::Pointer pFiberImg; if(m_QuantifyClass==3) { if(m_Controls->m_Quantiles->isChecked()) { m_CurrentRGBClusteringResults = clusterer->PerformRGBQuantiles(imgToCluster, histogram, m_Controls->m_q1->value(),m_Controls->m_q2->value()); } else { m_CurrentRGBClusteringResults = clusterer->PerformRGBClustering(imgToCluster, histogram); } pFiberImg = m_CurrentRGBClusteringResults->rgbChannels->r; cparams = m_CurrentRGBClusteringResults->params; cresult = m_CurrentRGBClusteringResults->result; chist = m_CurrentRGBClusteringResults->hist; } else { if(m_Controls->m_Quantiles->isChecked()) { m_CurrentPerformClusteringResults = clusterer->PerformQuantiles(imgToCluster, histogram, m_Controls->m_q1->value(),m_Controls->m_q2->value()); } else { m_CurrentPerformClusteringResults = clusterer->PerformClustering(imgToCluster, histogram, m_QuantifyClass); } pFiberImg = m_CurrentPerformClusteringResults->clusteredImage; cparams = m_CurrentPerformClusteringResults->params; cresult = m_CurrentPerformClusteringResults->result; chist = m_CurrentPerformClusteringResults->hist; } if(m_IsTensorImage) { m_AngularErrorImage = clusterer->CaculateAngularErrorImage( m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(1), m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(2), pFiberImg); // GetDataStorage()->Remove(m_newnode2); // m_newnode2 = mitk::DataNode::New(); // m_newnode2->SetData(m_AngularErrorImage); // m_newnode2->SetName(("AngularError")); // m_newnode2->SetIntProperty( "layer", 1003 ); // GetDataStorage()->Add(m_newnode2, m_SelectedImageNodes->GetNode()); // newnode = mitk::DataNode::New(); // newnode->SetData(m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(1)); // newnode->SetName(("Comp1")); // GetDataStorage()->Add(newnode, m_SelectedImageNodes->GetNode()); // newnode = mitk::DataNode::New(); // newnode->SetData(m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(2)); // newnode->SetName(("Comp2")); // GetDataStorage()->Add(newnode, m_SelectedImageNodes->GetNode()); } ShowClusteringResults(); } } statisticsCalculationSuccessful = true; } catch ( const std::runtime_error &e ) { QMessageBox::information( nullptr, "Warning", e.what()); } catch ( const std::exception &e ) { MITK_ERROR << "Caught exception: " << e.what(); QMessageBox::information( nullptr, "Warning", e.what()); } m_CurrentStatisticsCalculator->RemoveObserver( progressObserverTag ); // Make sure that progress bar closes mitk::ProgressBar::GetInstance()->Progress( 100 ); if ( statisticsCalculationSuccessful ) { if ( statisticsChanged ) { // Do not show any error messages m_CurrentStatisticsValid = true; } // m_Controls->m_HistogramWidget->SetHistogramModeToDirectHistogram(); m_Controls->m_HistogramWidget->SetParameters( cparams, cresult, chist ); // m_Controls->m_HistogramWidget->UpdateItemModelFromHistogram(); } else { m_Controls->m_SelectedMaskLabel->setText("mandatory"); // Clear statistics and histogram m_Controls->m_HistogramWidget->ClearItemModel(); m_CurrentStatisticsValid = false; // If a (non-closed) PlanarFigure is selected, display a line profile widget if ( m_SelectedPlanarFigure.IsNotNull() ) { // TODO: enable line profile widget //m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 1 ); //m_Controls->m_LineProfileWidget->SetImage( m_SelectedImage ); //m_Controls->m_LineProfileWidget->SetPlanarFigure( m_SelectedPlanarFigure ); //m_Controls->m_LineProfileWidget->UpdateItemModelFromPath(); } } } } void QmitkPartialVolumeAnalysisView::SetMeasurementInfoToRenderWindow(const QString& text) { FindRenderWindow(m_SelectedPlanarFigureNodes->GetNode()); if(m_LastRenderWindow != m_SelectedRenderWindow) { if(m_LastRenderWindow) { QObject::disconnect( m_LastRenderWindow, SIGNAL( destroyed(QObject*) ) , this, SLOT( OnRenderWindowDelete(QObject*) ) ); } m_LastRenderWindow = m_SelectedRenderWindow; if(m_LastRenderWindow) { QObject::connect( m_LastRenderWindow, SIGNAL( destroyed(QObject*) ) , this, SLOT( OnRenderWindowDelete(QObject*) ) ); } } if(m_LastRenderWindow && m_SelectedPlanarFigureNodes->GetNode().IsNotNull()) { if (!text.isEmpty()) { m_MeasurementInfoAnnotation->SetText(1, text.toLatin1().data()); mitk::VtkLayerController::GetInstance(m_LastRenderWindow->GetRenderWindow())->InsertForegroundRenderer( m_MeasurementInfoRenderer, true); } else { if (mitk::VtkLayerController::GetInstance( m_LastRenderWindow->GetRenderWindow()) ->IsRendererInserted( m_MeasurementInfoRenderer)) mitk::VtkLayerController::GetInstance(m_LastRenderWindow->GetRenderWindow())->RemoveRenderer( m_MeasurementInfoRenderer); } } else { mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); if ( renderWindowPart == nullptr ) { return; } if (!text.isEmpty()) { m_MeasurementInfoAnnotation->SetText(1, text.toLatin1().data()); mitk::VtkLayerController::GetInstance(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderWindow())->InsertForegroundRenderer( m_MeasurementInfoRenderer, true); } else { if (mitk::VtkLayerController::GetInstance( renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderWindow()) ->IsRendererInserted( m_MeasurementInfoRenderer)) mitk::VtkLayerController::GetInstance(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderWindow())->RemoveRenderer( m_MeasurementInfoRenderer); } } } void QmitkPartialVolumeAnalysisView::UpdateProgressBar() { mitk::ProgressBar::GetInstance()->Progress(); } void QmitkPartialVolumeAnalysisView::RequestStatisticsUpdate() { if ( !m_StatisticsUpdatePending ) { QApplication::postEvent( this, new QmitkRequestStatisticsUpdateEvent ); m_StatisticsUpdatePending = true; } } void QmitkPartialVolumeAnalysisView::RemoveOrphanImages() { PartialVolumeAnalysisMapType::iterator it = m_PartialVolumeAnalysisMap.begin(); while ( it != m_PartialVolumeAnalysisMap.end() ) { mitk::Image *image = it->first; mitk::PartialVolumeAnalysisHistogramCalculator *calculator = it->second; ++it; mitk::NodePredicateData::Pointer hasImage = mitk::NodePredicateData::New( image ); if ( this->GetDataStorage()->GetNode( hasImage ) == nullptr ) { if ( m_SelectedImage == image ) { m_SelectedImage = nullptr; m_SelectedImageNodes->RemoveAllNodes(); } if ( m_CurrentStatisticsCalculator == calculator ) { m_CurrentStatisticsCalculator = nullptr; } m_PartialVolumeAnalysisMap.erase( image ); it = m_PartialVolumeAnalysisMap.begin(); } } } void QmitkPartialVolumeAnalysisView::ExtractTensorImages( mitk::Image::Pointer tensorimage) { typedef itk::Image< itk::DiffusionTensor3D, 3> TensorImageType; typedef mitk::ImageToItk CastType; CastType::Pointer caster = CastType::New(); caster->SetInput(tensorimage); caster->Update(); TensorImageType::Pointer image = caster->GetOutput(); typedef itk::TensorDerivedMeasurementsFilter MeasurementsType; MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::FA); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer fa = measurementsCalculator->GetOutput(); m_FAImage = mitk::Image::New(); m_FAImage->InitializeByItk(fa.GetPointer()); m_FAImage->SetVolume(fa->GetBufferPointer()); // mitk::DataNode::Pointer node = mitk::DataNode::New(); // node->SetData(m_FAImage); // GetDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::CA); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer ca = measurementsCalculator->GetOutput(); m_CAImage = mitk::Image::New(); m_CAImage->InitializeByItk(ca.GetPointer()); m_CAImage->SetVolume(ca->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::RD); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer rd = measurementsCalculator->GetOutput(); m_RDImage = mitk::Image::New(); m_RDImage->InitializeByItk(rd.GetPointer()); m_RDImage->SetVolume(rd->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::AD); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer ad = measurementsCalculator->GetOutput(); m_ADImage = mitk::Image::New(); m_ADImage->InitializeByItk(ad.GetPointer()); m_ADImage->SetVolume(ad->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::RA); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer md = measurementsCalculator->GetOutput(); m_MDImage = mitk::Image::New(); m_MDImage->InitializeByItk(md.GetPointer()); m_MDImage->SetVolume(md->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDataStorage()->Add(node); typedef DirectionsFilterType::PeakImageType DirImageType; DirectionsFilterType::Pointer dirFilter = DirectionsFilterType::New(); dirFilter->SetInput(image ); dirFilter->SetUsePolarCoordinates(true); dirFilter->Update(); ItkUcharImgType::Pointer numDirImage = dirFilter->GetOutput(); DirImageType::Pointer dirImage = dirFilter->GetPeakImage(); itk::ImageRegionIterator itd(dirImage, dirImage->GetLargestPossibleRegion()); itd.GoToBegin(); while( !itd.IsAtEnd() ) { DirImageType::PixelType direction = itd.Get(); direction = fabs(direction); itd.Set(direction); ++itd; } typedef itk::Image CompImageType; CompImageType::Pointer comp1 = CompImageType::New(); comp1->SetSpacing( numDirImage->GetSpacing() ); // Set the image spacing comp1->SetOrigin( numDirImage->GetOrigin() ); // Set the image origin comp1->SetDirection( numDirImage->GetDirection() ); // Set the image direction comp1->SetRegions( numDirImage->GetLargestPossibleRegion() ); comp1->Allocate(); CompImageType::Pointer comp2 = CompImageType::New(); comp2->SetSpacing( numDirImage->GetSpacing() ); // Set the image spacing comp2->SetOrigin( numDirImage->GetOrigin() ); // Set the image origin comp2->SetDirection( numDirImage->GetDirection() ); // Set the image direction comp2->SetRegions( numDirImage->GetLargestPossibleRegion() ); comp2->Allocate(); itk::ImageRegionIterator it1(comp1, comp1->GetLargestPossibleRegion()); itk::ImageRegionIterator it2(comp2, comp2->GetLargestPossibleRegion()); it1.GoToBegin(); it2.GoToBegin(); while( !it2.IsAtEnd() ) { DirImageType::IndexType peakIndex; peakIndex[0] = it1.GetIndex()[0]; peakIndex[1] = it1.GetIndex()[1]; peakIndex[2] = it1.GetIndex()[2]; peakIndex[3] = 1; it1.Set(dirImage->GetPixel(peakIndex)); peakIndex[3] = 2; it2.Set(dirImage->GetPixel(peakIndex)); ++it1; ++it2; } m_DirectionComp1Image = mitk::Image::New(); m_DirectionComp1Image->InitializeByItk(comp1.GetPointer()); m_DirectionComp1Image->SetVolume(comp1->GetBufferPointer()); m_DirectionComp2Image = mitk::Image::New(); m_DirectionComp2Image->InitializeByItk(comp2.GetPointer()); m_DirectionComp2Image->SetVolume(comp2->GetBufferPointer()); } void QmitkPartialVolumeAnalysisView::OnRenderWindowDelete(QObject * obj) { if(obj == m_LastRenderWindow) m_LastRenderWindow = 0; if(obj == m_SelectedRenderWindow) m_SelectedRenderWindow = 0; } bool QmitkPartialVolumeAnalysisView::event( QEvent *event ) { if ( event->type() == (QEvent::Type) QmitkRequestStatisticsUpdateEvent::StatisticsUpdateRequest ) { // Update statistics m_StatisticsUpdatePending = false; this->UpdateStatistics(); return true; } return false; } void QmitkPartialVolumeAnalysisView::Activated() { mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigure* figure = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; // finally add all nodes to the model for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); figure = dynamic_cast(node->GetData()); if(figure) { figureInteractor = dynamic_cast(node->GetDataInteractor().GetPointer()); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New(); us::Module* planarFigureModule = us::ModuleRegistry::GetModule( "MitkPlanarFigure" ); figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule ); figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule ); figureInteractor->SetDataNode( node ); } } } } void QmitkPartialVolumeAnalysisView::Deactivated() { } void QmitkPartialVolumeAnalysisView::ActivatedZombieView(berry::IWorkbenchPartReference::Pointer) { this->SetMeasurementInfoToRenderWindow(""); mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigure* figure = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; // finally add all nodes to the model for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); figure = dynamic_cast(node->GetData()); if(figure) { figureInteractor = dynamic_cast(node->GetDataInteractor().GetPointer()); if(figureInteractor) figureInteractor->SetDataNode( nullptr ); } } } void QmitkPartialVolumeAnalysisView::Hidden() { if (m_ClusteringResult.IsNotNull()) { this->GetDataStorage()->Remove(m_ClusteringResult); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } Select(nullptr, true, true); m_Visible = false; } void QmitkPartialVolumeAnalysisView::Visible() { m_Visible = true; berry::IWorkbenchPart::Pointer bla; if (!this->GetCurrentSelection().empty()) { this->OnSelectionChanged(bla, this->GetCurrentSelection()); } else { this->OnSelectionChanged(bla, this->GetDataManagerSelection()); } } void QmitkPartialVolumeAnalysisView::GreenRadio(bool checked) { if(checked) { m_Controls->m_PartialVolumeRadio->setChecked(false); m_Controls->m_BlueRadio->setChecked(false); m_Controls->m_AllRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(true); } m_QuantifyClass = 0; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::PartialVolumeRadio(bool checked) { if(checked) { m_Controls->m_GreenRadio->setChecked(false); m_Controls->m_BlueRadio->setChecked(false); m_Controls->m_AllRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(true); } m_QuantifyClass = 1; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::BlueRadio(bool checked) { if(checked) { m_Controls->m_PartialVolumeRadio->setChecked(false); m_Controls->m_GreenRadio->setChecked(false); m_Controls->m_AllRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(true); } m_QuantifyClass = 2; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::AllRadio(bool checked) { if(checked) { m_Controls->m_BlueRadio->setChecked(false); m_Controls->m_PartialVolumeRadio->setChecked(false); m_Controls->m_GreenRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(false); } m_QuantifyClass = 3; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::NumberBinsChangedSlider(int) { m_Controls->m_NumberBins->setText(QString("%1").arg(m_Controls->m_NumberBinsSlider->value()*5.0)); } void QmitkPartialVolumeAnalysisView::UpsamplingChangedSlider(int) { m_Controls->m_Upsampling->setText(QString("%1").arg(m_Controls->m_UpsamplingSlider->value()/10.0)); } void QmitkPartialVolumeAnalysisView::GaussianSigmaChangedSlider(int) { m_Controls->m_GaussianSigma->setText(QString("%1").arg(m_Controls->m_GaussianSigmaSlider->value()/100.0)); } void QmitkPartialVolumeAnalysisView::SimilarAnglesChangedSlider(int) { m_Controls->m_SimilarAngles->setText(QString("%1°").arg(90-m_Controls->m_SimilarAnglesSlider->value())); ShowClusteringResults(); } void QmitkPartialVolumeAnalysisView::OpacityChangedSlider(int v ) { if(m_SelectedImageNodes->GetNode().IsNotNull()) { float opacImag = 1.0f-(v-5)/5.0f; opacImag = opacImag < 0 ? 0 : opacImag; m_SelectedImageNodes->GetNode()->SetFloatProperty("opacity", opacImag); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } if(m_ClusteringResult.IsNotNull()) { float opacClust = v/5.0f; opacClust = opacClust > 1 ? 1 : opacClust; m_ClusteringResult->SetFloatProperty("opacity", opacClust); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkPartialVolumeAnalysisView::NumberBinsReleasedSlider( ) { RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::UpsamplingReleasedSlider( ) { RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::GaussianSigmaReleasedSlider( ) { RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::SimilarAnglesReleasedSlider( ) { } void QmitkPartialVolumeAnalysisView::ToClipBoard() { std::vector* > vals = m_Controls->m_HistogramWidget->m_Vals; QString clipboardText; for (std::vector* >::iterator it = vals.begin(); it != vals.end(); ++it) { for (std::vector::iterator it2 = (**it).begin(); it2 != (**it).end(); ++it2) { clipboardText.append(QString("%1 \t").arg(*it2)); } clipboardText.append(QString("\n")); } QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); } void QmitkPartialVolumeAnalysisView::PropertyChanged(const mitk::DataNode* /*node*/, const mitk::BaseProperty* /*prop*/) { } void QmitkPartialVolumeAnalysisView::NodeChanged(const mitk::DataNode* /*node*/) { } void QmitkPartialVolumeAnalysisView::NodeRemoved(const mitk::DataNode* node) { if (dynamic_cast(node->GetData())) this->GetDataStorage()->Remove(m_ClusteringResult); if( node == m_SelectedPlanarFigureNodes->GetNode().GetPointer() || node == m_SelectedMaskNode.GetPointer() ) { this->Select(nullptr,true,false); SetMeasurementInfoToRenderWindow(""); } if( node == m_SelectedImageNodes->GetNode().GetPointer() ) { this->Select(nullptr,false,true); SetMeasurementInfoToRenderWindow(""); } } void QmitkPartialVolumeAnalysisView::NodeAddedInDataStorage(const mitk::DataNode* node) { if(!m_Visible) return; mitk::DataNode* nonConstNode = const_cast(node); mitk::PlanarFigure* figure = dynamic_cast(nonConstNode->GetData()); if(figure) { // set interactor for new node (if not already set) mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetDataInteractor().GetPointer()); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New(); us::Module* planarFigureModule = us::ModuleRegistry::GetModule( "MitkPlanarFigure" ); figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule ); figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule ); figureInteractor->SetDataNode( nonConstNode ); } // remove uninitialized old planars if( m_SelectedPlanarFigureNodes->GetNode().IsNotNull() && m_CurrentFigureNodeInitialized == false ) { this->GetDataStorage()->Remove(m_SelectedPlanarFigureNodes->GetNode()); } } } void QmitkPartialVolumeAnalysisView::TextIntON() { if(m_ClusteringResult.IsNotNull()) { if(m_TexIsOn) { m_Controls->m_TextureIntON->setIcon(*m_IconTexOFF); } else { m_Controls->m_TextureIntON->setIcon(*m_IconTexON); } m_ClusteringResult->SetBoolProperty("texture interpolation", !m_TexIsOn); m_TexIsOn = !m_TexIsOn; this->RequestRenderWindowUpdate(); } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingView.cpp index b921e98c4a..352f65f44c 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingView.cpp @@ -1,2203 +1,2198 @@ /*=================================================================== 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. ===================================================================*/ //#define MBILOG_ENABLE_DEBUG #include "QmitkPreprocessingView.h" #include "mitkDiffusionImagingConfigure.h" // qt includes #include // itk includes #include "itkTimeProbe.h" #include "itkB0ImageExtractionImageFilter.h" #include "itkB0ImageExtractionToSeparateImageFilter.h" #include "itkBrainMaskExtractionImageFilter.h" #include "itkCastImageFilter.h" #include "itkVectorContainer.h" #include #include #include #include #include #include // Multishell includes #include // Multishell Functors #include #include #include #include // mitk includes #include "QmitkDataStorageComboBox.h" #include "mitkProgressBar.h" #include "mitkStatusBar.h" #include "mitkNodePredicateDataType.h" #include "mitkProperties.h" #include "mitkVtkResliceInterpolationProperty.h" #include "mitkLookupTable.h" #include "mitkLookupTableProperty.h" #include "mitkTransferFunction.h" #include "mitkTransferFunctionProperty.h" #include "mitkDataNodeObject.h" #include "mitkOdfNormalizationMethodProperty.h" #include "mitkOdfScaleByProperty.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const std::string QmitkPreprocessingView::VIEW_ID = "org.mitk.views.preprocessing"; #define DI_INFO MITK_INFO("DiffusionImaging") typedef float TTensorPixelType; QmitkPreprocessingView::QmitkPreprocessingView() : QmitkAbstractView(), m_Controls(nullptr) { } QmitkPreprocessingView::~QmitkPreprocessingView() { } void QmitkPreprocessingView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkPreprocessingViewControls; m_Controls->setupUi(parent); this->CreateConnections(); m_Controls->m_MeasurementFrameTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); m_Controls->m_MeasurementFrameTable->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); m_Controls->m_DirectionMatrixTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); m_Controls->m_DirectionMatrixTable->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); } } void QmitkPreprocessingView::SetFocus() { m_Controls->m_MirrorGradientToHalfSphereButton->setFocus(); } void QmitkPreprocessingView::CreateConnections() { if ( m_Controls ) { m_Controls->m_NormalizationMaskBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_SelctedImageComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MergeDwiBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isMitkImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isQbi = mitk::NodePredicateDataType::New("QBallImage"); mitk::NodePredicateOr::Pointer isDiffusionImage = mitk::NodePredicateOr::New(isQbi, isDti); mitk::NodePredicateAnd::Pointer noDiffusionImage = mitk::NodePredicateAnd::New(isMitkImage, mitk::NodePredicateNot::New(isDiffusionImage)); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer binaryNoDiffusionImage = mitk::NodePredicateAnd::New(noDiffusionImage, isBinaryPredicate); m_Controls->m_NormalizationMaskBox->SetPredicate(binaryNoDiffusionImage); m_Controls->m_SelctedImageComboBox->SetPredicate(noDiffusionImage); m_Controls->m_MergeDwiBox->SetPredicate(isMitkImage); m_Controls->m_ExtractBrainMask->setVisible(false); m_Controls->m_BrainMaskIterationsBox->setVisible(false); m_Controls->m_ResampleIntFrame->setVisible(false); connect( (QObject*)(m_Controls->m_ButtonAverageGradients), SIGNAL(clicked()), this, SLOT(AverageGradients()) ); connect( (QObject*)(m_Controls->m_ButtonExtractB0), SIGNAL(clicked()), this, SLOT(ExtractB0()) ); connect( (QObject*)(m_Controls->m_ModifyMeasurementFrame), SIGNAL(clicked()), this, SLOT(DoApplyMesurementFrame()) ); connect( (QObject*)(m_Controls->m_ReduceGradientsButton), SIGNAL(clicked()), this, SLOT(DoReduceGradientDirections()) ); connect( (QObject*)(m_Controls->m_ShowGradientsButton), SIGNAL(clicked()), this, SLOT(DoShowGradientDirections()) ); connect( (QObject*)(m_Controls->m_MirrorGradientToHalfSphereButton), SIGNAL(clicked()), this, SLOT(DoHalfSphereGradientDirections()) ); connect( (QObject*)(m_Controls->m_MergeDwisButton), SIGNAL(clicked()), this, SLOT(MergeDwis()) ); connect( (QObject*)(m_Controls->m_ProjectSignalButton), SIGNAL(clicked()), this, SLOT(DoProjectSignal()) ); connect( (QObject*)(m_Controls->m_B_ValueMap_Rounder_SpinBox), SIGNAL(valueChanged(int)), this, SLOT(UpdateDwiBValueMapRounder(int))); connect( (QObject*)(m_Controls->m_CreateLengthCorrectedDwi), SIGNAL(clicked()), this, SLOT(DoLengthCorrection()) ); connect( (QObject*)(m_Controls->m_NormalizeImageValuesButton), SIGNAL(clicked()), this, SLOT(DoDwiNormalization()) ); connect( (QObject*)(m_Controls->m_ModifyDirection), SIGNAL(clicked()), this, SLOT(DoApplyDirectionMatrix()) ); connect( (QObject*)(m_Controls->m_ModifySpacingButton), SIGNAL(clicked()), this, SLOT(DoApplySpacing()) ); connect( (QObject*)(m_Controls->m_ModifyOriginButton), SIGNAL(clicked()), this, SLOT(DoApplyOrigin()) ); connect( (QObject*)(m_Controls->m_ResampleImageButton), SIGNAL(clicked()), this, SLOT(DoResampleImage()) ); connect( (QObject*)(m_Controls->m_ResampleTypeBox), SIGNAL(currentIndexChanged(int)), this, SLOT(DoUpdateInterpolationGui(int)) ); connect( (QObject*)(m_Controls->m_CropImageButton), SIGNAL(clicked()), this, SLOT(DoCropImage()) ); connect( (QObject*)(m_Controls->m_RemoveGradientButton), SIGNAL(clicked()), this, SLOT(DoRemoveGradient()) ); connect( (QObject*)(m_Controls->m_ExtractGradientButton), SIGNAL(clicked()), this, SLOT(DoExtractGradient()) ); connect( (QObject*)(m_Controls->m_FlipAxis), SIGNAL(clicked()), this, SLOT(DoFlipAxis()) ); connect( (QObject*)(m_Controls->m_FlipGradientsButton), SIGNAL(clicked()), this, SLOT(DoFlipGradientDirections()) ); connect( (QObject*)(m_Controls->m_ClearRotationButton), SIGNAL(clicked()), this, SLOT(DoClearRotationOfGradients()) ); connect( (QObject*)(m_Controls->m_SelctedImageComboBox), SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnImageSelectionChanged()) ); m_Controls->m_NormalizationMaskBox->SetZeroEntryText("--"); } } void QmitkPreprocessingView::DoFlipAxis() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(node) ); if (isDiffusionImage) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); itk::FixedArray flipAxes; flipAxes[0] = m_Controls->m_FlipX->isChecked(); flipAxes[1] = m_Controls->m_FlipY->isChecked(); flipAxes[2] = m_Controls->m_FlipZ->isChecked(); itk::FlipImageFilter< ItkDwiType >::Pointer flipper = itk::FlipImageFilter< ItkDwiType >::New(); flipper->SetInput(itkVectorImagePointer); flipper->SetFlipAxes(flipAxes); flipper->Update(); GradProp::GradientDirectionsContainerType::Pointer oldGradients = static_cast ( image->GetProperty(PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); GradProp::GradientDirectionsContainerType::Pointer newGradients = GradProp::GradientDirectionsContainerType::New(); for (unsigned int i=0; iSize(); i++) { GradProp::GradientDirectionType g = oldGradients->GetElement(i); GradProp::GradientDirectionType newG = g; if (flipAxes[0]) { newG[0] *= -1; } if (flipAxes[1]) { newG[1] *= -1; } if (flipAxes[2]) { newG[2] *= -1; } newGradients->InsertElement(i, newG); } mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( flipper->GetOutput() ); PropHelper::CopyProperties(image, newImage, true); newImage->GetPropertyList()->ReplaceProperty( PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), GradProp::New( newGradients ) ); PropHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); newImage->GetGeometry()->SetOrigin(image->GetGeometry()->GetOrigin()); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_flipped").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if( image->GetPixelType().GetNumberOfComponents() == 1 ) { AccessFixedDimensionByItk(image, TemplatedFlipAxis,3); } else { QMessageBox::warning(nullptr,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedFlipAxis(itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } itk::FixedArray flipAxes; flipAxes[0] = m_Controls->m_FlipX->isChecked(); flipAxes[1] = m_Controls->m_FlipY->isChecked(); flipAxes[2] = m_Controls->m_FlipZ->isChecked(); typename itk::FlipImageFilter< itk::Image >::Pointer flipper = itk::FlipImageFilter< itk::Image >::New(); flipper->SetInput(itkImage); flipper->SetFlipAxes(flipAxes); flipper->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( flipper->GetOutput() ); newImage->GetGeometry()->SetOrigin(image->GetGeometry()->GetOrigin()); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_flipped").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoRemoveGradient() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } std::vector< unsigned int > channelsToRemove; channelsToRemove.push_back(m_Controls->m_RemoveGradientBox->value()); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); itk::RemoveDwiChannelFilter< short >::Pointer filter = itk::RemoveDwiChannelFilter< short >::New(); filter->SetInput(itkVectorImagePointer); filter->SetChannelIndices(channelsToRemove); filter->SetDirections( static_cast ( image->GetProperty(PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( filter->GetOutput() ); PropHelper::CopyProperties(image, newImage, true); newImage->GetPropertyList()->ReplaceProperty( PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), GradProp::New( filter->GetNewDirections() ) ); PropHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_removedgradients").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoExtractGradient() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); unsigned int channel = m_Controls->m_ExtractGradientBox->value(); itk::ExtractDwiChannelFilter< short >::Pointer filter = itk::ExtractDwiChannelFilter< short >::New(); filter->SetInput( itkVectorImagePointer); filter->SetChannelIndex(channel); filter->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( filter->GetOutput() ); newImage->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName( (name+"_direction-"+QString::number(channel)).toStdString().c_str() ); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } void QmitkPreprocessingView::DoCropImage() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( isDiffusionImage ) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); ItkDwiType::SizeType lower; ItkDwiType::SizeType upper; lower[0] = m_Controls->m_XstartBox->value(); lower[1] = m_Controls->m_YstartBox->value(); lower[2] = m_Controls->m_ZstartBox->value(); upper[0] = m_Controls->m_XendBox->value(); upper[1] = m_Controls->m_YendBox->value(); upper[2] = m_Controls->m_ZendBox->value(); itk::CropImageFilter< ItkDwiType, ItkDwiType >::Pointer cropper = itk::CropImageFilter< ItkDwiType, ItkDwiType >::New(); cropper->SetLowerBoundaryCropSize(lower); cropper->SetUpperBoundaryCropSize(upper); cropper->SetInput( itkVectorImagePointer ); cropper->Update(); ItkDwiType::Pointer itkOutImage = cropper->GetOutput(); ItkDwiType::DirectionType dir = itkOutImage->GetDirection(); itk::Point origin = itkOutImage->GetOrigin(); itk::Point t; t[0] = lower[0]*itkOutImage->GetSpacing()[0]; t[1] = lower[1]*itkOutImage->GetSpacing()[1]; t[2] = lower[2]*itkOutImage->GetSpacing()[2]; t= dir*t; origin[0] += t[0]; origin[1] += t[1]; origin[2] += t[2]; itkOutImage->SetOrigin(origin); mitk::Image::Pointer newimage = mitk::GrabItkImageMemory( itkOutImage ); PropHelper::CopyProperties(image, newimage, false); PropHelper propertyHelper( newimage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newimage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_cropped").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if( image->GetPixelType().GetNumberOfComponents() ) { AccessFixedDimensionByItk(image, TemplatedCropImage,3); } else { QMessageBox::warning(nullptr,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedCropImage( itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } ItkDwiType::SizeType lower; ItkDwiType::SizeType upper; lower[0] = m_Controls->m_XstartBox->value(); lower[1] = m_Controls->m_YstartBox->value(); lower[2] = m_Controls->m_ZstartBox->value(); upper[0] = m_Controls->m_XendBox->value(); upper[1] = m_Controls->m_YendBox->value(); upper[2] = m_Controls->m_ZendBox->value(); typedef itk::Image ImageType; typename itk::CropImageFilter< ImageType, ImageType >::Pointer cropper = itk::CropImageFilter< ImageType, ImageType >::New(); cropper->SetLowerBoundaryCropSize(lower); cropper->SetUpperBoundaryCropSize(upper); cropper->SetInput(itkImage); cropper->Update(); typename ImageType::Pointer itkOutImage = cropper->GetOutput(); typename ImageType::DirectionType dir = itkOutImage->GetDirection(); itk::Point origin = itkOutImage->GetOrigin(); itk::Point t; t[0] = lower[0]*itkOutImage->GetSpacing()[0]; t[1] = lower[1]*itkOutImage->GetSpacing()[1]; t[2] = lower[2]*itkOutImage->GetSpacing()[2]; t= dir*t; origin[0] += t[0]; origin[1] += t[1]; origin[2] += t[2]; itkOutImage->SetOrigin(origin); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( itkOutImage.GetPointer() ); image->SetVolume( itkOutImage->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( image ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_cropped").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoApplySpacing() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( isDiffusionImage ) { mitk::Vector3D spacing; spacing[0] = m_Controls->m_HeaderSpacingX->value(); spacing[1] = m_Controls->m_HeaderSpacingY->value(); spacing[2] = m_Controls->m_HeaderSpacingZ->value(); mitk::Image::Pointer newImage = image->Clone(); newImage->GetGeometry()->SetSpacing( spacing ); PropHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_newspacing").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if( image->GetPixelType().GetNumberOfComponents() ) { AccessFixedDimensionByItk(image, TemplatedSetImageSpacing,3); } else { QMessageBox::warning(nullptr,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedSetImageSpacing( itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) return; mitk::Vector3D spacing; spacing[0] = m_Controls->m_HeaderSpacingX->value(); spacing[1] = m_Controls->m_HeaderSpacingY->value(); spacing[2] = m_Controls->m_HeaderSpacingZ->value(); typedef itk::ImageDuplicator< itk::Image > DuplicateFilterType; typename DuplicateFilterType::Pointer duplicator = DuplicateFilterType::New(); duplicator->SetInputImage( itkImage ); duplicator->Update(); typename itk::Image::Pointer newImage = duplicator->GetOutput(); newImage->SetSpacing(spacing); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( newImage.GetPointer() ); image->SetVolume( newImage->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( image ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_newspacing").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoApplyOrigin() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image)); if ( isDiffusionImage ) { mitk::Vector3D origin; origin[0] = m_Controls->m_HeaderOriginX->value(); origin[1] = m_Controls->m_HeaderOriginY->value(); origin[2] = m_Controls->m_HeaderOriginZ->value(); mitk::Image::Pointer newImage = image->Clone(); newImage->GetGeometry()->SetOrigin( origin ); PropHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_neworigin").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if( image->GetPixelType().GetNumberOfComponents() ) { AccessFixedDimensionByItk(image, TemplatedSetImageOrigin,3); } else { QMessageBox::warning(nullptr,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedSetImageOrigin( itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Vector3D origin; origin[0] = m_Controls->m_HeaderOriginX->value(); origin[1] = m_Controls->m_HeaderOriginY->value(); origin[2] = m_Controls->m_HeaderOriginZ->value(); typedef itk::ImageDuplicator< itk::Image > DuplicateFilterType; typename DuplicateFilterType::Pointer duplicator = DuplicateFilterType::New(); duplicator->SetInputImage( itkImage ); duplicator->Update(); typename itk::Image::Pointer newImage = duplicator->GetOutput(); newImage->SetOrigin(origin); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( newImage.GetPointer() ); image->SetVolume( newImage->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( image ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_neworigin").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoUpdateInterpolationGui(int i) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } switch (i) { case 0: { m_Controls->m_ResampleIntFrame->setVisible(false); m_Controls->m_ResampleDoubleFrame->setVisible(true); break; } case 1: { m_Controls->m_ResampleIntFrame->setVisible(false); m_Controls->m_ResampleDoubleFrame->setVisible(true); mitk::BaseGeometry* geom = image->GetGeometry(); m_Controls->m_ResampleDoubleX->setValue(geom->GetSpacing()[0]); m_Controls->m_ResampleDoubleY->setValue(geom->GetSpacing()[1]); m_Controls->m_ResampleDoubleZ->setValue(geom->GetSpacing()[2]); break; } case 2: { m_Controls->m_ResampleIntFrame->setVisible(true); m_Controls->m_ResampleDoubleFrame->setVisible(false); mitk::BaseGeometry* geom = image->GetGeometry(); m_Controls->m_ResampleIntX->setValue(geom->GetExtent(0)); m_Controls->m_ResampleIntY->setValue(geom->GetExtent(1)); m_Controls->m_ResampleIntZ->setValue(geom->GetExtent(2)); break; } default: { m_Controls->m_ResampleIntFrame->setVisible(false); m_Controls->m_ResampleDoubleFrame->setVisible(true); } } } void QmitkPreprocessingView::DoExtractBrainMask() { } void QmitkPreprocessingView::DoResampleImage() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( isDiffusionImage ) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); typedef itk::ResampleDwiImageFilter< short > ResampleFilter; ResampleFilter::Pointer resampler = ResampleFilter::New(); resampler->SetInput( itkVectorImagePointer ); switch (m_Controls->m_ResampleTypeBox->currentIndex()) { case 0: { itk::Vector< double, 3 > samplingFactor; samplingFactor[0] = m_Controls->m_ResampleDoubleX->value(); samplingFactor[1] = m_Controls->m_ResampleDoubleY->value(); samplingFactor[2] = m_Controls->m_ResampleDoubleZ->value(); resampler->SetSamplingFactor(samplingFactor); break; } case 1: { itk::Vector< double, 3 > newSpacing; newSpacing[0] = m_Controls->m_ResampleDoubleX->value(); newSpacing[1] = m_Controls->m_ResampleDoubleY->value(); newSpacing[2] = m_Controls->m_ResampleDoubleZ->value(); resampler->SetNewSpacing(newSpacing); break; } case 2: { itk::ImageRegion<3> newRegion; newRegion.SetSize(0, m_Controls->m_ResampleIntX->value()); newRegion.SetSize(1, m_Controls->m_ResampleIntY->value()); newRegion.SetSize(2, m_Controls->m_ResampleIntZ->value()); resampler->SetNewImageSize(newRegion); break; } default: { MITK_WARN << "Unknown resampling parameters!"; return; } } QString outAdd; switch (m_Controls->m_InterpolatorBox->currentIndex()) { case 0: { resampler->SetInterpolation(ResampleFilter::Interpolate_NearestNeighbour); outAdd = "NearestNeighbour"; break; } case 1: { resampler->SetInterpolation(ResampleFilter::Interpolate_Linear); outAdd = "Linear"; break; } case 2: { resampler->SetInterpolation(ResampleFilter::Interpolate_BSpline); outAdd = "BSpline"; break; } case 3: { resampler->SetInterpolation(ResampleFilter::Interpolate_WindowedSinc); outAdd = "WindowedSinc"; break; } default: { resampler->SetInterpolation(ResampleFilter::Interpolate_NearestNeighbour); outAdd = "NearestNeighbour"; } } resampler->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( resampler->GetOutput() ); PropHelper::CopyProperties(image, newImage, false); PropHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_resampled_"+outAdd).toStdString().c_str()); imageNode->SetVisibility(false); GetDataStorage()->Add(imageNode, node); } else if( image->GetPixelType().GetNumberOfComponents() ) { AccessFixedDimensionByItk(image, TemplatedResampleImage,3); } else { QMessageBox::warning(nullptr,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedResampleImage( itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } itk::Vector< double, 3 > newSpacing; itk::ImageRegion<3> newRegion; switch (m_Controls->m_ResampleTypeBox->currentIndex()) { case 0: { itk::Vector< double, 3 > sampling; sampling[0] = m_Controls->m_ResampleDoubleX->value(); sampling[1] = m_Controls->m_ResampleDoubleY->value(); sampling[2] = m_Controls->m_ResampleDoubleZ->value(); newSpacing = itkImage->GetSpacing(); newSpacing[0] /= sampling[0]; newSpacing[1] /= sampling[1]; newSpacing[2] /= sampling[2]; newRegion = itkImage->GetLargestPossibleRegion(); newRegion.SetSize(0, newRegion.GetSize(0)*sampling[0]); newRegion.SetSize(1, newRegion.GetSize(1)*sampling[1]); newRegion.SetSize(2, newRegion.GetSize(2)*sampling[2]); break; } case 1: { newSpacing[0] = m_Controls->m_ResampleDoubleX->value(); newSpacing[1] = m_Controls->m_ResampleDoubleY->value(); newSpacing[2] = m_Controls->m_ResampleDoubleZ->value(); itk::Vector< double, 3 > oldSpacing = itkImage->GetSpacing(); itk::Vector< double, 3 > sampling; sampling[0] = oldSpacing[0]/newSpacing[0]; sampling[1] = oldSpacing[1]/newSpacing[1]; sampling[2] = oldSpacing[2]/newSpacing[2]; newRegion = itkImage->GetLargestPossibleRegion(); newRegion.SetSize(0, newRegion.GetSize(0)*sampling[0]); newRegion.SetSize(1, newRegion.GetSize(1)*sampling[1]); newRegion.SetSize(2, newRegion.GetSize(2)*sampling[2]); break; } case 2: { newRegion.SetSize(0, m_Controls->m_ResampleIntX->value()); newRegion.SetSize(1, m_Controls->m_ResampleIntY->value()); newRegion.SetSize(2, m_Controls->m_ResampleIntZ->value()); itk::ImageRegion<3> oldRegion = itkImage->GetLargestPossibleRegion(); itk::Vector< double, 3 > sampling; sampling[0] = (double)newRegion.GetSize(0)/oldRegion.GetSize(0); sampling[1] = (double)newRegion.GetSize(1)/oldRegion.GetSize(1); sampling[2] = (double)newRegion.GetSize(2)/oldRegion.GetSize(2); newSpacing = itkImage->GetSpacing(); newSpacing[0] /= sampling[0]; newSpacing[1] /= sampling[1]; newSpacing[2] /= sampling[2]; break; } default: { MITK_WARN << "Unknown resampling parameters!"; return; } } itk::Point origin = itkImage->GetOrigin(); origin[0] -= itkImage->GetSpacing()[0]/2; origin[1] -= itkImage->GetSpacing()[1]/2; origin[2] -= itkImage->GetSpacing()[2]/2; origin[0] += newSpacing[0]/2; origin[1] += newSpacing[1]/2; origin[2] += newSpacing[2]/2; typedef itk::Image ImageType; typename ImageType::Pointer outImage = ImageType::New(); outImage->SetSpacing( newSpacing ); outImage->SetOrigin( origin ); outImage->SetDirection( itkImage->GetDirection() ); outImage->SetLargestPossibleRegion( newRegion ); outImage->SetBufferedRegion( newRegion ); outImage->SetRequestedRegion( newRegion ); outImage->Allocate(); typedef itk::ResampleImageFilter ResampleFilter; typename ResampleFilter::Pointer resampler = ResampleFilter::New(); resampler->SetInput(itkImage); resampler->SetOutputParametersFromImage(outImage); QString outAdd; switch (m_Controls->m_InterpolatorBox->currentIndex()) { case 0: { typename itk::NearestNeighborInterpolateImageFunction::Pointer interp = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(interp); outAdd = "NearestNeighbour"; break; } case 1: { typename itk::LinearInterpolateImageFunction::Pointer interp = itk::LinearInterpolateImageFunction::New(); resampler->SetInterpolator(interp); outAdd = "Linear"; break; } case 2: { typename itk::BSplineInterpolateImageFunction::Pointer interp = itk::BSplineInterpolateImageFunction::New(); resampler->SetInterpolator(interp); outAdd = "BSpline"; break; } case 3: { typename itk::WindowedSincInterpolateImageFunction::Pointer interp = itk::WindowedSincInterpolateImageFunction::New(); resampler->SetInterpolator(interp); outAdd = "WindowedSinc"; break; } default: { typename itk::NearestNeighborInterpolateImageFunction::Pointer interp = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(interp); outAdd = "NearestNeighbour"; } } resampler->Update(); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( resampler->GetOutput() ); image->SetVolume( resampler->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( image ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_resampled_"+outAdd).toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } void QmitkPreprocessingView::DoApplyDirectionMatrix() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( isDiffusionImage ) { ItkDwiType::DirectionType newDirection; for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item(r,c); if (!item) return; newDirection[r][c] = item->text().toDouble(); } } ItkDwiType::Pointer itkDwi = ItkDwiType::New(); mitk::CastToItkImage(image, itkDwi); itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage(itkDwi); duplicator->Update(); itkDwi = duplicator->GetOutput(); itkDwi->SetDirection(newDirection); mitk::Image::Pointer newDwi2 = mitk::GrabItkImageMemory( itkDwi.GetPointer() ); PropHelper::CopyProperties(image, newDwi2, false); PropHelper propertyHelper( newDwi2 ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newDwi2 ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_newdirection").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance() ->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if( image->GetPixelType().GetNumberOfComponents() ) { AccessFixedDimensionByItk(image, TemplatedApplyRotation,3); } else { QMessageBox::warning(nullptr,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedApplyRotation( itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } ItkDwiType::DirectionType newDirection; for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item(r,c); if (!item) return; newDirection[r][c] = item->text().toDouble(); } } typedef itk::Image ImageType; typename ImageType::Pointer newImage = ImageType::New(); newImage->SetSpacing( itkImage->GetSpacing() ); newImage->SetOrigin( itkImage->GetOrigin() ); newImage->SetDirection( newDirection ); newImage->SetLargestPossibleRegion( itkImage->GetLargestPossibleRegion() ); newImage->SetBufferedRegion( itkImage->GetLargestPossibleRegion() ); newImage->SetRequestedRegion( itkImage->GetLargestPossibleRegion() ); newImage->Allocate(); newImage->FillBuffer(0); itk::ImageRegionIterator< itk::Image > it(itkImage, itkImage->GetLargestPossibleRegion()); while(!it.IsAtEnd()) { newImage->SetPixel(it.GetIndex(), it.Get()); ++it; } mitk::Image::Pointer newMitkImage = mitk::Image::New(); newMitkImage->InitializeByItk(newImage.GetPointer()); newMitkImage->SetVolume(newImage->GetBufferPointer()); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newMitkImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_newdirection").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoProjectSignal() { switch(m_Controls->m_ProjectionMethodBox->currentIndex()) { case 0: DoADCAverage(); break; case 1: DoAKCFit(); break; case 2: DoBiExpFit(); break; default: DoADCAverage(); } } void QmitkPreprocessingView::DoDwiNormalization() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) { return; } GradientDirectionContainerType::Pointer gradientContainer = static_cast ( image->GetProperty(PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); int b0Index = -1; for (unsigned int i=0; isize(); i++) { GradientDirectionType g = gradientContainer->GetElement(i); if (g.magnitude()<0.001) { b0Index = i; break; } } if (b0Index==-1) { return; } typedef itk::DwiNormilzationFilter FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetGradientDirections( static_cast ( image->GetProperty(PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->SetNewMean(m_Controls->m_NewMean->value()); filter->SetNewStdev(m_Controls->m_NewStdev->value()); UcharImageType::Pointer itkImage = nullptr; if (m_Controls->m_NormalizationMaskBox->GetSelectedNode().IsNotNull()) { itkImage = UcharImageType::New(); if ( dynamic_cast(m_Controls->m_NormalizationMaskBox->GetSelectedNode()->GetData()) != nullptr ) { mitk::CastToItkImage( dynamic_cast(m_Controls->m_NormalizationMaskBox->GetSelectedNode()->GetData()), itkImage ); } filter->SetMaskImage(itkImage); } filter->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( filter->GetOutput() ); PropHelper::CopyProperties(image, newImage, false); PropHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_normalized").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } void QmitkPreprocessingView::DoLengthCorrection() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) { return; } typedef itk::DwiGradientLengthCorrectionFilter FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetRoundingValue( m_Controls->m_B_ValueMap_Rounder_SpinBox->value()); filter->SetReferenceBValue( static_cast (image->GetProperty(PropHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); filter->SetReferenceGradientDirectionContainer( static_cast ( image->GetProperty(PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( itkVectorImagePointer.GetPointer() ); newImage->SetImportVolume( itkVectorImagePointer->GetBufferPointer(), 0, 0, mitk::Image::CopyMemory); itkVectorImagePointer->GetPixelContainer()->ContainerManageMemoryOff(); PropHelper::CopyProperties(image, newImage, true); newImage->GetPropertyList()->ReplaceProperty( PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), GradProp::New( filter->GetOutputGradientDirectionContainer() ) ); newImage->GetPropertyList()->ReplaceProperty( PropHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( filter->GetNewBValue() ) ); PropHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_rounded").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } void QmitkPreprocessingView::UpdateDwiBValueMapRounder(int i) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(node) ); if ( ! isDiffusionImage ) { return; } UpdateBValueTableWidget(i); } void QmitkPreprocessingView:: CallMultishellToSingleShellFilter( itk::DWIVoxelFunctor * functor, mitk::Image::Pointer image, QString imageName, mitk::DataNode* parent ) { typedef itk::RadialMultishellToSingleshellImageFilter FilterType; // filter input parameter const mitk::BValueMapProperty::BValueMap& originalShellMap = static_cast (image->GetProperty(PropHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); ItkDwiType* vectorImage = itkVectorImagePointer.GetPointer(); const GradProp::GradientDirectionsContainerType::Pointer gradientContainer = static_cast ( image->GetProperty(PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); const unsigned int& bValue = static_cast (image->GetProperty(PropHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue(); mitk::DataNode::Pointer imageNode = 0; // filter call FilterType::Pointer filter = FilterType::New(); filter->SetInput(vectorImage); filter->SetOriginalGradientDirections(gradientContainer); filter->SetOriginalBValueMap(originalShellMap); filter->SetOriginalBValue(bValue); filter->SetFunctor(functor); filter->Update(); // create new DWI image mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( filter->GetOutput() ); PropHelper::CopyProperties(image, outImage, true); outImage->GetPropertyList()->ReplaceProperty( PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), GradProp::New( filter->GetTargetGradientDirections() ) ); outImage->GetPropertyList()->ReplaceProperty( PropHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( m_Controls->m_targetBValueSpinBox->value() ) ); PropHelper propertyHelper( outImage ); propertyHelper.InitializeImage(); imageNode = mitk::DataNode::New(); imageNode->SetData( outImage ); imageNode->SetName(imageName.toStdString().c_str()); GetDataStorage()->Add(imageNode, parent); // if(m_Controls->m_OutputRMSErrorImage->isChecked()){ // // create new Error image // FilterType::ErrorImageType::Pointer errImage = filter->GetErrorImage(); // mitk::Image::Pointer mitkErrImage = mitk::Image::New(); // mitkErrImage->InitializeByItk(errImage); // mitkErrImage->SetVolume(errImage->GetBufferPointer()); // imageNode = mitk::DataNode::New(); // imageNode->SetData( mitkErrImage ); // imageNode->SetName((imageName+"_Error").toStdString().c_str()); // GetDataStorage()->Add(imageNode); // } } void QmitkPreprocessingView::DoBiExpFit() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) { return; } itk::BiExpFitFunctor::Pointer functor = itk::BiExpFitFunctor::New(); QString name(node->GetName().c_str()); const mitk::BValueMapProperty::BValueMap& originalShellMap = static_cast (image->GetProperty(PropHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); mitk::BValueMapProperty::BValueMap::const_iterator it = originalShellMap.begin(); ++it;/* skip b=0*/ unsigned int s = 0; /*shell index */ vnl_vector bValueList(originalShellMap.size()-1); while( it != originalShellMap.end() ) { bValueList.put(s++,(it++)->first); } const double targetBValue = m_Controls->m_targetBValueSpinBox->value(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); CallMultishellToSingleShellFilter(functor,image,name + "_BiExp", node); } void QmitkPreprocessingView::DoAKCFit() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) { return; } itk::KurtosisFitFunctor::Pointer functor = itk::KurtosisFitFunctor::New(); QString name(node->GetName().c_str()); const mitk::BValueMapProperty::BValueMap& originalShellMap = static_cast (image->GetProperty(PropHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); mitk::BValueMapProperty::BValueMap::const_iterator it = originalShellMap.begin(); ++it;/* skip b=0*/ unsigned int s = 0; /*shell index */ vnl_vector bValueList(originalShellMap.size()-1); while(it != originalShellMap.end()) bValueList.put(s++,(it++)->first); const double targetBValue = m_Controls->m_targetBValueSpinBox->value(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); CallMultishellToSingleShellFilter(functor,image,name + "_AKC", node); } void QmitkPreprocessingView::DoADCFit() { // later } void QmitkPreprocessingView::DoADCAverage() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) return; itk::ADCAverageFunctor::Pointer functor = itk::ADCAverageFunctor::New(); QString name(node->GetName().c_str()); const mitk::BValueMapProperty::BValueMap &originalShellMap = static_cast(image->GetProperty(PropHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() )->GetBValueMap(); mitk::BValueMapProperty::BValueMap::const_iterator it = originalShellMap.begin(); ++it;/* skip b=0*/ unsigned int s = 0; /*shell index */ vnl_vector bValueList(originalShellMap.size()-1); while(it != originalShellMap.end()) bValueList.put(s++,(it++)->first); const double targetBValue = m_Controls->m_targetBValueSpinBox->value(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); CallMultishellToSingleShellFilter(functor,image,name + "_ADC", node); } void QmitkPreprocessingView::CleanBValueTableWidget() { m_Controls->m_B_ValueMap_TableWidget->clear(); m_Controls->m_B_ValueMap_TableWidget->setRowCount(1); QStringList headerList; headerList << "b-Value" << "Number of gradients"; m_Controls->m_B_ValueMap_TableWidget->setHorizontalHeaderLabels(headerList); m_Controls->m_B_ValueMap_TableWidget->setItem(0,0,new QTableWidgetItem("-")); m_Controls->m_B_ValueMap_TableWidget->setItem(0,1,new QTableWidgetItem("-")); } void QmitkPreprocessingView::UpdateBValueTableWidget(int) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { CleanBValueTableWidget(); return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage(false); isDiffusionImage = PropHelper::IsDiffusionWeightedImage(image); if ( ! isDiffusionImage ) { CleanBValueTableWidget(); } else { typedef mitk::BValueMapProperty::BValueMap BValueMap; typedef mitk::BValueMapProperty::BValueMap::iterator BValueMapIterator; BValueMapIterator it; BValueMap roundedBValueMap = static_cast (image->GetProperty(PropHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); m_Controls->m_B_ValueMap_TableWidget->clear(); m_Controls->m_B_ValueMap_TableWidget->setRowCount(roundedBValueMap.size() ); QStringList headerList; headerList << "b-Value" << "Number of gradients"; m_Controls->m_B_ValueMap_TableWidget->setHorizontalHeaderLabels(headerList); int i = 0 ; for(it = roundedBValueMap.begin() ;it != roundedBValueMap.end(); it++) { m_Controls->m_B_ValueMap_TableWidget->setItem(i,0,new QTableWidgetItem(QString::number(it->first))); QTableWidgetItem* item = m_Controls->m_B_ValueMap_TableWidget->item(i,0); item->setFlags(item->flags() & ~Qt::ItemIsEditable); m_Controls->m_B_ValueMap_TableWidget->setItem(i,1,new QTableWidgetItem(QString::number(it->second.size()))); i++; } } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedUpdateGui( itk::Image* itkImage) { for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item(r,c); delete item; item = new QTableWidgetItem(); item->setTextAlignment(Qt::AlignCenter | Qt::AlignVCenter); item->setText(QString::number(itkImage->GetDirection()[r][c])); m_Controls->m_DirectionMatrixTable->setItem(r,c,item); } } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedUpdateGui( itk::VectorImage* itkImage) { for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item(r,c); delete item; item = new QTableWidgetItem(); item->setTextAlignment(Qt::AlignCenter | Qt::AlignVCenter); item->setText(QString::number(itkImage->GetDirection()[r][c])); m_Controls->m_DirectionMatrixTable->setItem(r,c,item); } } } void QmitkPreprocessingView::OnSelectionChanged(berry::IWorkbenchPart::Pointer , const QList& nodes) { (void) nodes; this->OnImageSelectionChanged(); } void QmitkPreprocessingView::OnImageSelectionChanged() { bool foundImageVolume = true; mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } bool foundDwiVolume( PropHelper::IsDiffusionWeightedImage( node ) ); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool multiComponentVolume = (image->GetPixelType().GetNumberOfComponents() > 1); bool threeDplusTVolume = (image->GetTimeSteps() > 1); // we do not support multi-component and 3D+t images in the widget, check early to avoid access exception bool foundSingleImageVolume = foundDwiVolume || (foundImageVolume && (!multiComponentVolume) && (!threeDplusTVolume) ); m_Controls->m_ButtonAverageGradients->setEnabled(foundDwiVolume); m_Controls->m_ButtonExtractB0->setEnabled(foundDwiVolume); m_Controls->m_CheckExtractAll->setEnabled(foundDwiVolume); m_Controls->m_ModifyMeasurementFrame->setEnabled(foundDwiVolume); m_Controls->m_MeasurementFrameTable->setEnabled(foundDwiVolume); m_Controls->m_ReduceGradientsButton->setEnabled(foundDwiVolume); m_Controls->m_ShowGradientsButton->setEnabled(foundDwiVolume); m_Controls->m_MirrorGradientToHalfSphereButton->setEnabled(foundDwiVolume); m_Controls->m_MergeDwisButton->setEnabled(foundDwiVolume); m_Controls->m_B_ValueMap_Rounder_SpinBox->setEnabled(foundDwiVolume); m_Controls->m_ProjectSignalButton->setEnabled(foundDwiVolume); m_Controls->m_CreateLengthCorrectedDwi->setEnabled(foundDwiVolume); m_Controls->m_targetBValueSpinBox->setEnabled(foundDwiVolume); m_Controls->m_NormalizeImageValuesButton->setEnabled(foundDwiVolume); m_Controls->m_DirectionMatrixTable->setEnabled(foundSingleImageVolume); m_Controls->m_ModifyDirection->setEnabled(foundSingleImageVolume); m_Controls->m_ExtractBrainMask->setEnabled(foundSingleImageVolume); m_Controls->m_ResampleImageButton->setEnabled(foundSingleImageVolume); m_Controls->m_ModifySpacingButton->setEnabled(foundSingleImageVolume); m_Controls->m_ModifyOriginButton->setEnabled(foundSingleImageVolume); m_Controls->m_CropImageButton->setEnabled(foundSingleImageVolume); m_Controls->m_RemoveGradientButton->setEnabled(foundDwiVolume); m_Controls->m_ExtractGradientButton->setEnabled(foundDwiVolume); m_Controls->m_FlipAxis->setEnabled(foundSingleImageVolume); m_Controls->m_FlipGradientsButton->setEnabled(foundDwiVolume); m_Controls->m_ClearRotationButton->setEnabled(foundDwiVolume); // reset sampling frame to 1 and update all ealted components m_Controls->m_B_ValueMap_Rounder_SpinBox->setValue(1); UpdateBValueTableWidget(m_Controls->m_B_ValueMap_Rounder_SpinBox->value()); DoUpdateInterpolationGui(m_Controls->m_ResampleTypeBox->currentIndex()); if (foundDwiVolume) { m_Controls->m_InputData->setTitle("Input Data"); vnl_matrix_fixed< double, 3, 3 > mf = static_cast (image->GetProperty(PropHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str()).GetPointer() ) ->GetMeasurementFrame(); for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { // Measurement frame { QTableWidgetItem* item = m_Controls->m_MeasurementFrameTable->item( r, c ); delete item; item = new QTableWidgetItem(); item->setTextAlignment(Qt::AlignCenter | Qt::AlignVCenter); item->setText(QString::number(mf.get(r,c))); m_Controls->m_MeasurementFrameTable->setItem( r, c, item ); } // Direction matrix { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item( r, c ); delete item; item = new QTableWidgetItem(); item->setTextAlignment(Qt::AlignCenter | Qt::AlignVCenter); item->setText(QString::number(itkVectorImagePointer->GetDirection()[r][c])); m_Controls->m_DirectionMatrixTable->setItem( r, c, item ); } } } //calculate target bValue for MultishellToSingleShellfilter const mitk::BValueMapProperty::BValueMap & bValMap = static_cast (image->GetProperty(PropHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); mitk::BValueMapProperty::BValueMap::const_iterator it = bValMap.begin(); unsigned int targetBVal = 0; while(it != bValMap.end()) { targetBVal += (it++)->first; } targetBVal /= (float)bValMap.size()-1; m_Controls->m_targetBValueSpinBox->setValue(targetBVal); m_Controls->m_HeaderSpacingX->setValue(image->GetGeometry()->GetSpacing()[0]); m_Controls->m_HeaderSpacingY->setValue(image->GetGeometry()->GetSpacing()[1]); m_Controls->m_HeaderSpacingZ->setValue(image->GetGeometry()->GetSpacing()[2]); m_Controls->m_HeaderOriginX->setValue(image->GetGeometry()->GetOrigin()[0]); m_Controls->m_HeaderOriginY->setValue(image->GetGeometry()->GetOrigin()[1]); m_Controls->m_HeaderOriginZ->setValue(image->GetGeometry()->GetOrigin()[2]); m_Controls->m_XstartBox->setMaximum(image->GetGeometry()->GetExtent(0)-1); m_Controls->m_YstartBox->setMaximum(image->GetGeometry()->GetExtent(1)-1); m_Controls->m_ZstartBox->setMaximum(image->GetGeometry()->GetExtent(2)-1); m_Controls->m_XendBox->setMaximum(image->GetGeometry()->GetExtent(0)-1); m_Controls->m_YendBox->setMaximum(image->GetGeometry()->GetExtent(1)-1); m_Controls->m_ZendBox->setMaximum(image->GetGeometry()->GetExtent(2)-1); m_Controls->m_RemoveGradientBox->setMaximum(static_cast ( image->GetProperty(PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer()->Size()-1); m_Controls->m_ExtractGradientBox->setMaximum(static_cast ( image->GetProperty(PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer()->Size()-1); } else if (foundSingleImageVolume) { for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { QTableWidgetItem* item = m_Controls->m_MeasurementFrameTable->item(r,c); delete item; item = new QTableWidgetItem(); m_Controls->m_MeasurementFrameTable->setItem(r,c,item); } } m_Controls->m_HeaderSpacingX->setValue(image->GetGeometry()->GetSpacing()[0]); m_Controls->m_HeaderSpacingY->setValue(image->GetGeometry()->GetSpacing()[1]); m_Controls->m_HeaderSpacingZ->setValue(image->GetGeometry()->GetSpacing()[2]); m_Controls->m_HeaderOriginX->setValue(image->GetGeometry()->GetOrigin()[0]); m_Controls->m_HeaderOriginY->setValue(image->GetGeometry()->GetOrigin()[1]); m_Controls->m_HeaderOriginZ->setValue(image->GetGeometry()->GetOrigin()[2]); m_Controls->m_XstartBox->setMaximum(image->GetGeometry()->GetExtent(0)-1); m_Controls->m_YstartBox->setMaximum(image->GetGeometry()->GetExtent(1)-1); m_Controls->m_ZstartBox->setMaximum(image->GetGeometry()->GetExtent(2)-1); m_Controls->m_XendBox->setMaximum(image->GetGeometry()->GetExtent(0)-1); m_Controls->m_YendBox->setMaximum(image->GetGeometry()->GetExtent(1)-1); m_Controls->m_ZendBox->setMaximum(image->GetGeometry()->GetExtent(2)-1); AccessFixedDimensionByItk(image, TemplatedUpdateGui,3); } else { for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { { QTableWidgetItem* item = m_Controls->m_MeasurementFrameTable->item( r, c ); delete item; item = new QTableWidgetItem(); m_Controls->m_MeasurementFrameTable->setItem( r, c, item ); } { QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item( r, c ); delete item; item = new QTableWidgetItem(); m_Controls->m_DirectionMatrixTable->setItem( r, c, item ); } } } } } void QmitkPreprocessingView::Activated() { } void QmitkPreprocessingView::Deactivated() { OnImageSelectionChanged(); } void QmitkPreprocessingView::Visible() { OnImageSelectionChanged(); } void QmitkPreprocessingView::Hidden() { } void QmitkPreprocessingView::DoClearRotationOfGradients() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) return; mitk::Image::Pointer image = dynamic_cast(node->GetData()); if (image == nullptr) return; if(!PropHelper::IsDiffusionWeightedImage(image)) return; mitk::Image::Pointer newDwi = image->Clone(); PropHelper propertyHelper( newDwi ); propertyHelper.InitializeImage(); PropHelper::ClearMeasurementFrameAndRotationMatrixFromGradients(newDwi); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newDwi ); QString name = node->GetName().c_str(); imageNode->SetName( (name+"_OriginalGradients").toStdString().c_str() ); GetDataStorage()->Add( imageNode, node ); } void QmitkPreprocessingView::DoFlipGradientDirections() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } mitk::Image::Pointer newDwi = image->Clone(); GradientDirectionContainerType::Pointer gradientContainer = static_cast ( newDwi->GetProperty(PropHelper::ORIGINALGRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); for (unsigned int j=0; jSize(); j++) { if (m_Controls->m_FlipGradBoxX->isChecked()) { gradientContainer->at(j)[0] *= -1; } if (m_Controls->m_FlipGradBoxY->isChecked()) { gradientContainer->at(j)[1] *= -1; } if (m_Controls->m_FlipGradBoxZ->isChecked()) { gradientContainer->at(j)[2] *= -1; } } PropHelper::CopyProperties(image, newDwi, true); newDwi->GetPropertyList()->ReplaceProperty( PropHelper::ORIGINALGRADIENTCONTAINERPROPERTYNAME.c_str(), GradProp::New( gradientContainer ) ); PropHelper propertyHelper( newDwi ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newDwi ); QString name = node->GetName().c_str(); imageNode->SetName( (name+"_GradientFlip").toStdString().c_str() ); GetDataStorage()->Add( imageNode, node ); } void QmitkPreprocessingView::DoHalfSphereGradientDirections() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } mitk::Image::Pointer newDwi = image->Clone(); GradientDirectionContainerType::Pointer gradientContainer = static_cast ( newDwi->GetProperty(PropHelper::ORIGINALGRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); for (unsigned int j=0; jSize(); j++) { if (gradientContainer->at(j)[0]<0) { gradientContainer->at(j) = -gradientContainer->at(j); } } PropHelper::CopyProperties(image, newDwi, true); newDwi->GetPropertyList()->ReplaceProperty( PropHelper::ORIGINALGRADIENTCONTAINERPROPERTYNAME.c_str(), GradProp::New( gradientContainer ) ); PropHelper propertyHelper( newDwi ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newDwi ); QString name = node->GetName().c_str(); imageNode->SetName( (name+"_halfsphere").toStdString().c_str() ); GetDataStorage()->Add( imageNode, node ); } void QmitkPreprocessingView::DoApplyMesurementFrame() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) return; vnl_matrix_fixed< double, 3, 3 > mf; for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { QTableWidgetItem* item = m_Controls->m_MeasurementFrameTable->item(r,c); if (!item) return; mf[r][c] = item->text().toDouble(); } } mitk::Image::Pointer newDwi = image->Clone(); newDwi->GetPropertyList()->ReplaceProperty( PropHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( mf ) ); PropHelper propertyHelper( newDwi ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newDwi ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_new-MF").toStdString().c_str()); GetDataStorage()->Add( imageNode, node ); } void QmitkPreprocessingView::DoShowGradientDirections() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } int maxIndex = 0; unsigned int maxSize = image->GetDimension(0); if (maxSizeGetDimension(1)) { maxSize = image->GetDimension(1); maxIndex = 1; } if (maxSizeGetDimension(2)) { maxSize = image->GetDimension(2); maxIndex = 2; } mitk::Point3D origin = image->GetGeometry()->GetOrigin(); mitk::PointSet::Pointer originSet = mitk::PointSet::New(); typedef mitk::BValueMapProperty::BValueMap BValueMap; typedef mitk::BValueMapProperty::BValueMap::iterator BValueMapIterator; BValueMap bValMap = static_cast (image->GetProperty(PropHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); GradientDirectionContainerType::Pointer gradientContainer = static_cast ( image->GetProperty(PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); mitk::BaseGeometry::Pointer geometry = image->GetGeometry(); int shellCount = 1; for(BValueMapIterator it = bValMap.begin(); it!=bValMap.end(); ++it) { mitk::PointSet::Pointer pointset = mitk::PointSet::New(); for (unsigned int j=0; jsecond.size(); j++) { mitk::Point3D ip; vnl_vector_fixed< double, 3 > v = gradientContainer->at(it->second[j]); if (v.magnitude()>mitk::eps) { ip[0] = v[0]*maxSize*geometry->GetSpacing()[maxIndex]/2 + origin[0]-0.5*geometry->GetSpacing()[0] + geometry->GetSpacing()[0]*image->GetDimension(0)/2; ip[1] = v[1]*maxSize*geometry->GetSpacing()[maxIndex]/2 + origin[1]-0.5*geometry->GetSpacing()[1] + geometry->GetSpacing()[1]*image->GetDimension(1)/2; ip[2] = v[2]*maxSize*geometry->GetSpacing()[maxIndex]/2 + origin[2]-0.5*geometry->GetSpacing()[2] + geometry->GetSpacing()[2]*image->GetDimension(2)/2; pointset->InsertPoint(j, ip); } else if (originSet->IsEmpty()) { ip[0] = v[0]*maxSize*geometry->GetSpacing()[maxIndex]/2 + origin[0]-0.5*geometry->GetSpacing()[0] + geometry->GetSpacing()[0]*image->GetDimension(0)/2; ip[1] = v[1]*maxSize*geometry->GetSpacing()[maxIndex]/2 + origin[1]-0.5*geometry->GetSpacing()[1] + geometry->GetSpacing()[1]*image->GetDimension(1)/2; ip[2] = v[2]*maxSize*geometry->GetSpacing()[maxIndex]/2 + origin[2]-0.5*geometry->GetSpacing()[2] + geometry->GetSpacing()[2]*image->GetDimension(2)/2; originSet->InsertPoint(j, ip); } } if ( it->first < mitk::eps ) { continue; } // add shell to datastorage mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData(pointset); QString name = node->GetName().c_str(); name += "_Shell_"; name += QString::number( it->first ); newNode->SetName( name.toStdString().c_str() ); newNode->SetProperty( "pointsize", mitk::FloatProperty::New((float)maxSize / 50) ); int b0 = shellCount % 2; int b1 = 0; int b2 = 0; if (shellCount>4) { b2 = 1; } if (shellCount%4 >= 2) { b1 = 1; } newNode->SetProperty("color", mitk::ColorProperty::New( b2, b1, b0 )); GetDataStorage()->Add( newNode, node ); shellCount++; } // add origin to datastorage mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData(originSet); QString name = node->GetName().c_str(); name += "_Origin"; newNode->SetName(name.toStdString().c_str()); newNode->SetProperty("pointsize", mitk::FloatProperty::New((float)maxSize/50)); newNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); GetDataStorage()->Add(newNode, node); } void QmitkPreprocessingView::DoReduceGradientDirections() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } typedef itk::ElectrostaticRepulsionDiffusionGradientReductionFilter FilterType; typedef mitk::BValueMapProperty::BValueMap BValueMap; // GetShellSelection from GUI BValueMap shellSlectionMap; BValueMap originalShellMap = static_cast (image->GetProperty(PropHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); std::vector newNumGradientDirections; int shellCounter = 0; QString name = node->GetName().c_str(); for (int i=0; im_B_ValueMap_TableWidget->rowCount(); i++) { double BValue = m_Controls->m_B_ValueMap_TableWidget->item(i,0)->text().toDouble(); shellSlectionMap[BValue] = originalShellMap[BValue]; unsigned int num = m_Controls->m_B_ValueMap_TableWidget->item(i,1)->text().toUInt(); newNumGradientDirections.push_back(num); name += "_"; name += QString::number(num); shellCounter++; } if (newNumGradientDirections.empty()) { return; } GradientDirectionContainerType::Pointer gradientContainer = static_cast ( image->GetProperty(PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetOriginalGradientDirections(gradientContainer); filter->SetNumGradientDirections(newNumGradientDirections); filter->SetOriginalBValueMap(originalShellMap); filter->SetShellSelectionBValueMap(shellSlectionMap); filter->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( filter->GetOutput() ); PropHelper::CopyProperties(image, newImage, true); newImage->GetPropertyList()->ReplaceProperty( PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), GradProp::New( filter->GetGradientDirections() ) ); PropHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); imageNode->SetName(name.toStdString().c_str()); GetDataStorage()->Add(imageNode, node); // update the b-value widget to remove the modified number of gradients used for extraction this->CleanBValueTableWidget(); this->UpdateBValueTableWidget(0); } void QmitkPreprocessingView::MergeDwis() { typedef GradProp::GradientDirectionsContainerType GradientContainerType; mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } mitk::DataNode::Pointer node2 = m_Controls->m_MergeDwiBox->GetSelectedNode(); if (node2.IsNull()) { return; } mitk::Image::Pointer image2 = dynamic_cast(node2->GetData()); if ( image2 == nullptr ) { return; } typedef itk::VectorImage DwiImageType; - typedef DwiImageType::PixelType DwiPixelType; - typedef DwiImageType::RegionType DwiRegionType; typedef std::vector< DwiImageType::Pointer > DwiImageContainerType; typedef std::vector< GradientContainerType::Pointer > GradientListContainerType; DwiImageContainerType imageContainer; GradientListContainerType gradientListContainer; std::vector< double > bValueContainer; QString name = ""; { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); imageContainer.push_back( itkVectorImagePointer ); gradientListContainer.push_back( static_cast ( image->GetProperty(PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); bValueContainer.push_back( static_cast (image->GetProperty(PropHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); name += node->GetName().c_str(); } { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image2, itkVectorImagePointer); imageContainer.push_back( itkVectorImagePointer ); gradientListContainer.push_back( static_cast ( image2->GetProperty(PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); bValueContainer.push_back( static_cast (image2->GetProperty(PropHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); name += "+"; name += node2->GetName().c_str(); } typedef itk::MergeDiffusionImagesFilter FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetImageVolumes(imageContainer); filter->SetGradientLists(gradientListContainer); filter->SetBValues(bValueContainer); filter->Update(); vnl_matrix_fixed< double, 3, 3 > mf; mf.set_identity(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( filter->GetOutput() ); newImage->GetPropertyList()->ReplaceProperty( PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), GradProp::New( filter->GetOutputGradients() ) ); newImage->GetPropertyList()->ReplaceProperty( PropHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( mf ) ); newImage->GetPropertyList()->ReplaceProperty( PropHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( filter->GetB_Value() ) ); PropHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); imageNode->SetName(name.toStdString().c_str()); GetDataStorage()->Add(imageNode); } void QmitkPreprocessingView::ExtractB0() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } - typedef GradProp::GradientDirectionsContainerType GradientContainerType; - // call the extraction withou averaging if the check-box is checked if( this->m_Controls->m_CheckExtractAll->isChecked() ) { DoExtractBOWithoutAveraging(); return; } ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); // Extract image using found index typedef itk::B0ImageExtractionImageFilter FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetDirections( static_cast ( image->GetProperty(PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->Update(); mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( filter->GetOutput() ); mitkImage->SetVolume( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer newNode=mitk::DataNode::New(); newNode->SetData( mitkImage ); newNode->SetProperty( "name", mitk::StringProperty::New(node->GetName() + "_B0")); GetDataStorage()->Add(newNode, node); } void QmitkPreprocessingView::DoExtractBOWithoutAveraging() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } // typedefs - typedef GradProp::GradientDirectionsContainerType GradientContainerType; typedef itk::B0ImageExtractionToSeparateImageFilter< short, short> FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); // Extract image using found index FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetDirections( static_cast ( image->GetProperty(PropHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->Update(); mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( filter->GetOutput() ); mitkImage->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer newNode=mitk::DataNode::New(); newNode->SetData( mitkImage ); newNode->SetProperty( "name", mitk::StringProperty::New(node->GetName() + "_B0_ALL")); GetDataStorage()->Add(newNode, node); /*A reinitialization is needed to access the time channels via the ImageNavigationController The Global-Geometry can not recognize the time channel without a re-init. (for a new selection in datamanger a automatically updated of the Global-Geometry should be done - if it contains the time channel)*/ mitk::RenderingManager::GetInstance()->InitializeViews( newNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } void QmitkPreprocessingView::AverageGradients() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) return; mitk::Image::Pointer newDwi = image->Clone(); PropHelper propertyHelper(newDwi); propertyHelper.AverageRedundantGradients(m_Controls->m_Blur->value()); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newDwi ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_averaged").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationView.cpp index 20155ec4c9..0ae03c4b52 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationView.cpp @@ -1,760 +1,758 @@ /*=================================================================== 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 "QmitkDiffusionQuantificationView.h" #include "mitkDiffusionImagingConfigure.h" #include "itkTimeProbe.h" #include "itkImage.h" #include "mitkNodePredicateDataType.h" #include "mitkDataNodeObject.h" #include "mitkQBallImage.h" #include #include "mitkImageCast.h" #include "mitkStatusBar.h" #include "itkDiffusionQballGeneralizedFaImageFilter.h" #include "itkShiftScaleImageFilter.h" #include "itkTensorFractionalAnisotropyImageFilter.h" #include "itkTensorRelativeAnisotropyImageFilter.h" #include "itkTensorDerivedMeasurementsFilter.h" #include "QmitkDataStorageComboBox.h" #include #include "berryIWorkbenchWindow.h" #include "berryISelectionService.h" #include #include #include #include #include #include #include #include const std::string QmitkDiffusionQuantificationView::VIEW_ID = "org.mitk.views.diffusionquantification"; QmitkDiffusionQuantificationView::QmitkDiffusionQuantificationView() : QmitkAbstractView(), m_Controls(nullptr) { m_QBallImages = mitk::DataStorage::SetOfObjects::New(); m_TensorImages = mitk::DataStorage::SetOfObjects::New(); m_DwImages = mitk::DataStorage::SetOfObjects::New(); } QmitkDiffusionQuantificationView::~QmitkDiffusionQuantificationView() { } void QmitkDiffusionQuantificationView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkDiffusionQuantificationViewControls; m_Controls->setupUi(parent); this->CreateConnections(); GFACheckboxClicked(); #ifndef DIFFUSION_IMAGING_EXTENDED m_Controls->m_StandardGFACheckbox->setVisible(false); m_Controls->frame_3->setVisible(false); m_Controls->m_CurvatureButton->setVisible(false); #endif m_Controls->m_BallStickButton->setVisible(false); m_Controls->m_MultiTensorButton->setVisible(false); } } void QmitkDiffusionQuantificationView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_StandardGFACheckbox), SIGNAL(clicked()), this, SLOT(GFACheckboxClicked()) ); connect( (QObject*)(m_Controls->m_GFAButton), SIGNAL(clicked()), this, SLOT(GFA()) ); connect( (QObject*)(m_Controls->m_CurvatureButton), SIGNAL(clicked()), this, SLOT(Curvature()) ); connect( (QObject*)(m_Controls->m_FAButton), SIGNAL(clicked()), this, SLOT(FA()) ); connect( (QObject*)(m_Controls->m_RAButton), SIGNAL(clicked()), this, SLOT(RA()) ); connect( (QObject*)(m_Controls->m_ADButton), SIGNAL(clicked()), this, SLOT(AD()) ); connect( (QObject*)(m_Controls->m_RDButton), SIGNAL(clicked()), this, SLOT(RD()) ); connect( (QObject*)(m_Controls->m_MDButton), SIGNAL(clicked()), this, SLOT(MD()) ); connect( (QObject*)(m_Controls->m_MdDwiButton), SIGNAL(clicked()), this, SLOT(MD_DWI()) ); connect( (QObject*)(m_Controls->m_AdcDwiButton), SIGNAL(clicked()), this, SLOT(ADC_DWI()) ); connect( (QObject*)(m_Controls->m_ClusteringAnisotropy), SIGNAL(clicked()), this, SLOT(ClusterAnisotropy()) ); connect( (QObject*)(m_Controls->m_BallStickButton), SIGNAL(clicked()), this, SLOT(DoBallStickCalculation()) ); connect( (QObject*)(m_Controls->m_MultiTensorButton), SIGNAL(clicked()), this, SLOT(DoMultiTensorCalculation()) ); } } void QmitkDiffusionQuantificationView::SetFocus() { m_Controls->m_ScaleImageValuesBox->setFocus(); } void QmitkDiffusionQuantificationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { m_QBallImages = mitk::DataStorage::SetOfObjects::New(); m_TensorImages = mitk::DataStorage::SetOfObjects::New(); m_DwImages = mitk::DataStorage::SetOfObjects::New(); bool foundQBIVolume = false; bool foundTensorVolume = false; bool foundDwVolume = false; mitk::DataNode::Pointer selNode = nullptr; int c=0; for (mitk::DataNode::Pointer node: nodes) { if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { foundQBIVolume = true; m_QBallImages->push_back(node); selNode = node; c++; } else if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { foundTensorVolume = true; m_TensorImages->push_back(node); selNode = node; c++; } else if( node.IsNotNull() && dynamic_cast(node->GetData()) && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(dynamic_cast(node->GetData())) ) { foundDwVolume = true; m_DwImages->push_back(node); selNode = node; c++; } } m_Controls->m_GFAButton->setEnabled(foundQBIVolume); m_Controls->m_CurvatureButton->setEnabled(foundQBIVolume); if (c>0) { m_Controls->m_InputData->setTitle("Input Data"); m_Controls->m_InputImageLabel->setText(selNode->GetName().c_str()); } else { m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->m_InputImageLabel->setText("mandatory"); } m_Controls->m_FAButton->setEnabled(foundTensorVolume); m_Controls->m_RAButton->setEnabled(foundTensorVolume); m_Controls->m_ADButton->setEnabled(foundTensorVolume); m_Controls->m_RDButton->setEnabled(foundTensorVolume); m_Controls->m_MDButton->setEnabled(foundTensorVolume); m_Controls->m_ClusteringAnisotropy->setEnabled(foundTensorVolume); m_Controls->m_AdcDwiButton->setEnabled(foundDwVolume); m_Controls->m_MdDwiButton->setEnabled(foundDwVolume); m_Controls->m_BallStickButton->setEnabled(foundDwVolume); m_Controls->m_MultiTensorButton->setEnabled(foundDwVolume); } void QmitkDiffusionQuantificationView::ADC_DWI() { DoAdcCalculation(true); } void QmitkDiffusionQuantificationView::MD_DWI() { DoAdcCalculation(false); } void QmitkDiffusionQuantificationView::DoBallStickCalculation() { mitk::DataStorage::SetOfObjects::const_iterator itemiterend( m_DwImages->end() ); mitk::DataStorage::SetOfObjects::const_iterator itemiter( m_DwImages->begin() ); while ( itemiter != itemiterend ) // for all items { mitk::DataNode* node = *itemiter; mitk::Image::Pointer image = dynamic_cast(node->GetData()); typedef itk::BallAndSticksImageFilter< short, double > FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetGradientDirections( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->SetB_value( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); filter->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( filter->GetOutput() ); newImage->SetVolume( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_f").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); { FilterType::PeakImageType::Pointer itkImg = filter->GetPeakImage(); mitk::Image::Pointer newImage = mitk::Image::New(); CastToMitkImage(itkImg, newImage); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_Sticks").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } { mitk::Image::Pointer dOut = mitk::GrabItkImageMemory( filter->GetOutDwi().GetPointer() ); dOut->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ); dOut->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ); mitk::DiffusionPropertyHelper propertyHelper( dOut ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( dOut ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_Estimated-DWI").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } ++itemiter; } } void QmitkDiffusionQuantificationView::DoMultiTensorCalculation() { mitk::DataStorage::SetOfObjects::const_iterator itemiterend( m_DwImages->end() ); mitk::DataStorage::SetOfObjects::const_iterator itemiter( m_DwImages->begin() ); while ( itemiter != itemiterend ) // for all items { mitk::DataNode* node = *itemiter; mitk::Image::Pointer image = dynamic_cast(node->GetData()); typedef itk::MultiTensorImageFilter< short, double > FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetGradientDirections( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->SetB_value( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); filter->Update(); typedef itk::Image, 3> TensorImageType; for (int i=0; iGetTensorImages().at(i); mitk::TensorImage::Pointer image = mitk::TensorImage::New(); image->InitializeByItk( tensorImage.GetPointer() ); image->SetVolume( tensorImage->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( image ); QString name = node->GetName().c_str(); name.append("_Tensor"); name.append(boost::lexical_cast(i).c_str()); imageNode->SetName(name.toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } ++itemiter; } } void QmitkDiffusionQuantificationView::DoAdcCalculation(bool fit) { mitk::DataStorage::SetOfObjects::const_iterator itemiterend( m_DwImages->end() ); mitk::DataStorage::SetOfObjects::const_iterator itemiter( m_DwImages->begin() ); while ( itemiter != itemiterend ) // for all items { mitk::DataNode* node = *itemiter; mitk::Image::Pointer image = dynamic_cast(node->GetData()); typedef itk::AdcImageFilter< short, double > FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetGradientDirections( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->SetB_value( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); filter->SetFitSignal(fit); filter->Update(); typedef itk::ShiftScaleImageFilter::OutputImageType, itk::AdcImageFilter< short, double >::OutputImageType> ShiftScaleFilterType; ShiftScaleFilterType::Pointer multi = ShiftScaleFilterType::New(); multi->SetShift(0.0); multi->SetScale(m_Controls->m_ScaleImageValuesBox->value()); multi->SetInput(filter->GetOutput()); multi->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( multi->GetOutput() ); newImage->SetVolume( multi->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType( mitk::LookupTable::JET_TRANSPARENT ); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable( lut ); imageNode->SetProperty("LookupTable", lut_prop ); if (fit) imageNode->SetName((name+"_ADC").toStdString().c_str()); else imageNode->SetName((name+"_MD").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); ++itemiter; } } void QmitkDiffusionQuantificationView::GFACheckboxClicked() { m_Controls->frame_2->setVisible(m_Controls->m_StandardGFACheckbox->isChecked()); } void QmitkDiffusionQuantificationView::GFA() { if(m_Controls->m_StandardGFACheckbox->isChecked()) { QBIQuantify(13); } else { QBIQuantify(0); } } void QmitkDiffusionQuantificationView::Curvature() { QBIQuantify(12); } void QmitkDiffusionQuantificationView::FA() { TensorQuantify(0); } void QmitkDiffusionQuantificationView::RA() { TensorQuantify(1); } void QmitkDiffusionQuantificationView::AD() { TensorQuantify(2); } void QmitkDiffusionQuantificationView::RD() { TensorQuantify(3); } void QmitkDiffusionQuantificationView::ClusterAnisotropy() { TensorQuantify(4); } void QmitkDiffusionQuantificationView::MD() { TensorQuantify(5); } void QmitkDiffusionQuantificationView::QBIQuantify(int method) { QBIQuantification(m_QBallImages, method); } void QmitkDiffusionQuantificationView::TensorQuantify(int method) { TensorQuantification(m_TensorImages, method); } void QmitkDiffusionQuantificationView::QBIQuantification( mitk::DataStorage::SetOfObjects::Pointer inImages, int method) { itk::TimeProbe clock; QString status; int nrFiles = inImages->size(); if (!nrFiles) return; mitk::DataStorage::SetOfObjects::const_iterator itemiter( inImages->begin() ); mitk::DataStorage::SetOfObjects::const_iterator itemiterend( inImages->end() ); std::vector nodes; while ( itemiter != itemiterend ) // for all items { typedef float TOdfPixelType; const int odfsize = QBALL_ODFSIZE; typedef itk::Vector OdfVectorType; typedef itk::Image OdfVectorImgType; mitk::Image* vol = static_cast((*itemiter)->GetData()); OdfVectorImgType::Pointer itkvol = OdfVectorImgType::New(); mitk::CastToItkImage(vol, itkvol); std::string nodename; (*itemiter)->GetStringProperty("name", nodename); float p1 = m_Controls->m_ParamKEdit->text().toFloat(); float p2 = m_Controls->m_ParamPEdit->text().toFloat(); // COMPUTE RA clock.Start(); MBI_INFO << "Computing GFA "; mitk::StatusBar::GetInstance()->DisplayText(status.sprintf( "Computing GFA for %s", nodename.c_str()).toLatin1()); - typedef OdfVectorType::ValueType RealValueType; - typedef itk::Image< RealValueType, 3 > RAImageType; typedef itk::DiffusionQballGeneralizedFaImageFilter GfaFilterType; GfaFilterType::Pointer gfaFilter = GfaFilterType::New(); gfaFilter->SetInput(itkvol); std::string newname; newname.append(nodename); switch(method) { case 0: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_STANDARD); newname.append("GFA"); break; } case 1: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_QUANTILES_HIGH_LOW); newname.append("01"); break; } case 2: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_QUANTILE_HIGH); newname.append("02"); break; } case 3: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_MAX_ODF_VALUE); newname.append("03"); break; } case 4: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_DECONVOLUTION_COEFFS); newname.append("04"); break; } case 5: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_MIN_MAX_NORMALIZED_STANDARD); newname.append("05"); break; } case 6: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_NORMALIZED_ENTROPY); newname.append("06"); break; } case 7: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_NEMATIC_ORDER_PARAMETER); newname.append("07"); break; } case 8: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_QUANTILES_LOW_HIGH); newname.append("08"); break; } case 9: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_QUANTILE_LOW); newname.append("09"); break; } case 10: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_MIN_ODF_VALUE); newname.append("10"); break; } case 11: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_STD_BY_MAX); newname.append("11"); break; } case 12: { p1 = m_Controls->MinAngle->text().toFloat(); p2 = m_Controls->MaxAngle->text().toFloat(); gfaFilter->SetComputationMethod(GfaFilterType::GFA_PRINCIPLE_CURVATURE); QString paramString; paramString = paramString.append("PC%1-%2").arg(p1).arg(p2); newname.append(paramString.toLatin1()); gfaFilter->SetParam1(p1); gfaFilter->SetParam2(p2); break; } case 13: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_GENERALIZED_GFA); QString paramString; paramString = paramString.append("GFAK%1P%2").arg(p1).arg(p2); newname.append(paramString.toLatin1()); gfaFilter->SetParam1(p1); gfaFilter->SetParam2(p2); break; } default: { newname.append("0"); gfaFilter->SetComputationMethod(GfaFilterType::GFA_STANDARD); } } gfaFilter->Update(); clock.Stop(); typedef itk::Image ImgType; ImgType::Pointer img = ImgType::New(); img->SetSpacing( gfaFilter->GetOutput()->GetSpacing() ); // Set the image spacing img->SetOrigin( gfaFilter->GetOutput()->GetOrigin() ); // Set the image origin img->SetDirection( gfaFilter->GetOutput()->GetDirection() ); // Set the image direction img->SetLargestPossibleRegion( gfaFilter->GetOutput()->GetLargestPossibleRegion()); img->SetBufferedRegion( gfaFilter->GetOutput()->GetLargestPossibleRegion() ); img->Allocate(); itk::ImageRegionIterator ot (img, img->GetLargestPossibleRegion() ); ot.GoToBegin(); itk::ImageRegionConstIterator it (gfaFilter->GetOutput(), gfaFilter->GetOutput()->GetLargestPossibleRegion() ); for (it.GoToBegin(); !it.IsAtEnd(); ++it) { GfaFilterType::OutputImageType::PixelType val = it.Get(); ot.Set(val * m_Controls->m_ScaleImageValuesBox->value()); ++ot; } // GFA TO DATATREE mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( img.GetPointer() ); image->SetVolume( img->GetBufferPointer() ); mitk::DataNode::Pointer node=mitk::DataNode::New(); node->SetData( image ); node->SetProperty( "name", mitk::StringProperty::New(newname) ); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType( mitk::LookupTable::JET_TRANSPARENT ); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable( lut ); node->SetProperty("LookupTable", lut_prop ); GetDataStorage()->Add(node, *itemiter); mitk::StatusBar::GetInstance()->DisplayText("Computation complete."); ++itemiter; } this->GetRenderWindowPart()->RequestUpdate(); } void QmitkDiffusionQuantificationView::TensorQuantification( mitk::DataStorage::SetOfObjects::Pointer inImages, int method) { itk::TimeProbe clock; QString status; int nrFiles = inImages->size(); if (!nrFiles) return; mitk::DataStorage::SetOfObjects::const_iterator itemiter( inImages->begin() ); mitk::DataStorage::SetOfObjects::const_iterator itemiterend( inImages->end() ); std::vector nodes; while ( itemiter != itemiterend ) // for all items { typedef float TTensorPixelType; typedef itk::DiffusionTensor3D< TTensorPixelType > TensorPixelType; typedef itk::Image< TensorPixelType, 3 > TensorImageType; mitk::Image* vol = static_cast((*itemiter)->GetData()); TensorImageType::Pointer itkvol = TensorImageType::New(); mitk::CastToItkImage(vol, itkvol); std::string nodename; (*itemiter)->GetStringProperty("name", nodename); // COMPUTE FA clock.Start(); MBI_INFO << "Computing FA "; mitk::StatusBar::GetInstance()->DisplayText(status.sprintf( "Computing FA for %s", nodename.c_str()).toLatin1()); typedef itk::Image< TTensorPixelType, 3 > FAImageType; typedef itk::ShiftScaleImageFilter ShiftScaleFilterType; ShiftScaleFilterType::Pointer multi = ShiftScaleFilterType::New(); multi->SetShift(0.0); multi->SetScale(m_Controls->m_ScaleImageValuesBox->value()); typedef itk::TensorDerivedMeasurementsFilter MeasurementsType; if(method == 0) //FA { /* typedef itk::TensorFractionalAnisotropyImageFilter< TensorImageType, FAImageType > FilterType; FilterType::Pointer anisotropyFilter = FilterType::New(); anisotropyFilter->SetInput( itkvol.GetPointer() ); anisotropyFilter->Update(); multi->SetInput(anisotropyFilter->GetOutput()); nodename = QString(nodename.c_str()).append("_FA").toStdString();*/ MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::FA); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_FA").toStdString(); } else if(method == 1) //RA { /*typedef itk::TensorRelativeAnisotropyImageFilter< TensorImageType, FAImageType > FilterType; FilterType::Pointer anisotropyFilter = FilterType::New(); anisotropyFilter->SetInput( itkvol.GetPointer() ); anisotropyFilter->Update(); multi->SetInput(anisotropyFilter->GetOutput()); nodename = QString(nodename.c_str()).append("_RA").toStdString();*/ MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::RA); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_RA").toStdString(); } else if(method == 2) // AD (Axial diffusivity) { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::AD); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_AD").toStdString(); } else if(method == 3) // RD (Radial diffusivity, (Lambda2+Lambda3)/2 { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::RD); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_RD").toStdString(); } else if(method == 4) // 1-(Lambda2+Lambda3)/(2*Lambda1) { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::CA); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_CA").toStdString(); } else if(method == 5) // MD (Mean Diffusivity, (Lambda1+Lambda2+Lambda3)/3 ) { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::MD); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_MD").toStdString(); } multi->Update(); clock.Stop(); // FA TO DATATREE mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( multi->GetOutput() ); image->SetVolume( multi->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer node=mitk::DataNode::New(); node->SetData( image ); node->SetProperty( "name", mitk::StringProperty::New(nodename) ); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType( mitk::LookupTable::JET_TRANSPARENT ); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable( lut ); node->SetProperty("LookupTable", lut_prop ); GetDataStorage()->Add(node, *itemiter); ++itemiter; mitk::StatusBar::GetInstance()->DisplayText("Computation complete."); } this->GetRenderWindowPart()->RequestUpdate(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsView.cpp index bd0dc63aac..ff5e42d092 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsView.cpp @@ -1,385 +1,384 @@ /*=================================================================== 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. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkODFDetailsView.h" #include #include #include #include #include #include #include #include #include #include #include #include const std::string QmitkODFDetailsView::VIEW_ID = "org.mitk.views.odfdetails"; QmitkODFDetailsView::QmitkODFDetailsView() : QmitkAbstractView() , m_Controls( 0 ) , m_OdfNormalization(0) , m_ImageNode(nullptr) { m_VtkActor = vtkActor::New(); m_VtkMapper = vtkPolyDataMapper::New(); m_Renderer = vtkRenderer::New(); m_VtkRenderWindow = vtkRenderWindow::New(); m_RenderWindowInteractor = vtkRenderWindowInteractor::New(); m_Camera = vtkCamera::New(); m_VtkRenderWindow->SetSize(300,300); } QmitkODFDetailsView::~QmitkODFDetailsView() { if (m_ImageNode.IsNotNull()) m_ImageNode->RemoveObserver( m_PropertyObserverTag ); } void QmitkODFDetailsView::Activated() { } void QmitkODFDetailsView::Deactivated() { } void QmitkODFDetailsView::Visible() { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if (renderWindow) { { mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("axial"))->GetSliceNavigationController(); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); m_SliceObserverTag1 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), command ); } { mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("sagittal"))->GetSliceNavigationController(); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); m_SliceObserverTag2 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), command ); } { mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("coronal"))->GetSliceNavigationController(); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); m_SliceObserverTag3 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), command ); } } } void QmitkODFDetailsView::Hidden() { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if (renderWindow) { mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("axial"))->GetSliceNavigationController(); slicer->RemoveObserver(m_SliceObserverTag1); slicer = renderWindow->GetQmitkRenderWindow(QString("sagittal"))->GetSliceNavigationController(); slicer->RemoveObserver(m_SliceObserverTag2); slicer = renderWindow->GetQmitkRenderWindow(QString("coronal"))->GetSliceNavigationController(); slicer->RemoveObserver(m_SliceObserverTag3); } } void QmitkODFDetailsView::SetFocus() { this->m_Controls->m_OverviewTextEdit->setFocus(); } void QmitkODFDetailsView::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::QmitkODFDetailsViewControls; m_Controls->setupUi( parent ); m_Controls->m_OdfBox->setVisible(false); m_Controls->m_ODFRenderWidget->setVisible(false); } } void QmitkODFDetailsView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { if (m_ImageNode.IsNotNull()) m_ImageNode->RemoveObserver( m_PropertyObserverTag ); m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->m_InputImageLabel->setText("mandatory"); m_ImageNode = nullptr; // iterate selection for (mitk::DataNode::Pointer node: nodes) { if( node.IsNotNull() && (dynamic_cast(node->GetData()) || dynamic_cast(node->GetData())) ) { m_Controls->m_InputImageLabel->setText(node->GetName().c_str()); m_ImageNode = node; } } UpdateOdf(); if (m_ImageNode.IsNotNull()) { itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); m_PropertyObserverTag = m_ImageNode->AddObserver( itk::ModifiedEvent(), command ); m_Controls->m_InputData->setTitle("Input Data"); } } void QmitkODFDetailsView::UpdateOdf() { try { m_Controls->m_OverviewBox->setVisible(true); if (m_ImageNode.IsNull() || !this->GetRenderWindowPart()) { m_Controls->m_ODFRenderWidget->setVisible(false); m_Controls->m_OdfBox->setVisible(false); m_Controls->m_OverviewBox->setVisible(false); return; } // restore the input image label ( needed in case the last run resulted into an exception ) m_Controls->m_InputImageLabel->setText(m_ImageNode->GetName().c_str()); // ODF Normalization Property mitk::OdfNormalizationMethodProperty* nmp = dynamic_cast(m_ImageNode->GetProperty( "Normalization" )); if(nmp) m_OdfNormalization = nmp->GetNormalization(); m_TemplateOdf = itk::OrientationDistributionFunction::GetBaseMesh(); m_OdfTransform = vtkSmartPointer::New(); m_OdfTransform->Identity(); m_OdfVals = vtkSmartPointer::New(); m_OdfSource = vtkSmartPointer::New(); itk::OrientationDistributionFunction odf; mitk::Point3D world = this->GetRenderWindowPart()->GetSelectedPosition(); mitk::Point3D index; mitk::Image::Pointer img = dynamic_cast(m_ImageNode->GetData()); unsigned int *img_dimension = img->GetDimensions(); img->GetGeometry()->WorldToIndex(world, index); float sum = 0; float max = itk::NumericTraits::NonpositiveMin(); float min = itk::NumericTraits::max(); QString values; QString overviewText; // check if dynamic_cast successfull and if the crosshair position is inside of the geometry of the ODF data // otherwise possible crash for a scenario with multiple nodes if (dynamic_cast(m_ImageNode->GetData()) && ( m_ImageNode->GetData()->GetGeometry()->IsInside(world) ) ) { m_Controls->m_ODFRenderWidget->setVisible(true); m_Controls->m_OdfBox->setVisible(true); try { const mitk::QBallImage* qball_image = dynamic_cast< mitk::QBallImage* >( m_ImageNode->GetData() ); // get access to the qball image data with explicitely allowing exceptions if memory locked mitk::ImageReadAccessor readAccess( qball_image, qball_image->GetVolumeData(0), mitk::ImageAccessorBase::ExceptionIfLocked ); const float* qball_cPtr = static_cast< const float*>(readAccess.GetData()); OdfVectorImgType::IndexType ind; ind[0] = (int)(index[0]+0.5); ind[1] = (int)(index[1]+0.5); ind[2] = (int)(index[2]+0.5); // pixel size = QBALL_ODFSIZE // position offset = standard offset unsigned int offset_to_data = QBALL_ODFSIZE * (ind[2] * img_dimension[1] * img_dimension[0] + ind[1] * img_dimension[0] + ind[0]); const float *pixel_data = qball_cPtr + offset_to_data; for (int i=0; imax) max = val; if (val pd = odf.GetDirection(odf.GetPrincipleDiffusionDirection()); overviewText += "Main Diffusion:\n "+QString::number(pd[0])+"\n "+QString::number(pd[1])+"\n "+QString::number(pd[2])+"\n"; m_Controls->m_OdfValuesTextEdit->setText(values); m_Controls->m_OverviewTextEdit->setVisible(true); } catch( mitk::Exception &e ) { MITK_WARN << "LOCKED : " << e.what(); m_Controls->m_ODFRenderWidget->setVisible(false); m_Controls->m_OdfBox->setVisible(false); m_Controls->m_OverviewTextEdit->setVisible(false); // reset the selection m_Controls->m_InputImageLabel->setText("Click image to restore rendering!"); } } else if (dynamic_cast(m_ImageNode->GetData()) && ( m_ImageNode->GetData()->GetGeometry()->IsInside(world) ) ) { m_Controls->m_ODFRenderWidget->setVisible(true); m_Controls->m_OdfBox->setVisible(false); const mitk::TensorImage* qball_image = dynamic_cast< mitk::TensorImage*>(m_ImageNode->GetData()); // pixel access block try { // get access to the qball image data with explicitely allowing exceptions if memory locked mitk::ImageReadAccessor readAccess( qball_image, qball_image->GetVolumeData(0), mitk::ImageAccessorBase::ExceptionIfLocked ); const float* qball_cPtr = static_cast< const float*>(readAccess.GetData()); TensorImageType::IndexType ind; ind[0] = (int)(index[0]+0.5); ind[1] = (int)(index[1]+0.5); ind[2] = (int)(index[2]+0.5); // 6 - tensorsize // remaining computation - standard offset unsigned int offset_to_data = 6 * (ind[2] * img_dimension[1] * img_dimension[0] + ind[1] * img_dimension[0] + ind[0]); const float *pixel_data = qball_cPtr + offset_to_data; float tensorelems[6] = { *(pixel_data ), *(pixel_data + 1), *(pixel_data + 2), *(pixel_data + 3), *(pixel_data + 4), *(pixel_data + 5), }; itk::DiffusionTensor3D tensor(tensorelems); odf.InitFromTensor(tensor); /** Array of eigen-values. */ typedef itk::FixedArray EigenValuesArrayType; /** Matrix of eigen-vectors. */ - typedef itk::Matrix MatrixType; typedef itk::Matrix EigenVectorsMatrixType; EigenValuesArrayType eigenValues; EigenVectorsMatrixType eigenvectors; QString pos = QString::number(ind[0])+", "+QString::number(ind[1])+", "+QString::number(ind[2]); overviewText += "Coordinates: "+pos+"\n"; overviewText += "FA: "+QString::number(tensor.GetFractionalAnisotropy())+"\n"; overviewText += "RA: "+QString::number(tensor.GetRelativeAnisotropy())+"\n"; overviewText += "Trace: "+QString::number(tensor.GetTrace())+"\n"; tensor.ComputeEigenAnalysis(eigenValues,eigenvectors); overviewText += "Eigenvalues:\n "+QString::number(eigenValues[2])+"\n "+QString::number(eigenValues[1])+"\n "+QString::number(eigenValues[0])+"\n"; overviewText += "Main Diffusion:\n "+QString::number(eigenvectors(2, 0))+"\n "+QString::number(eigenvectors(2, 1))+"\n "+QString::number(eigenvectors(2, 2))+"\n"; overviewText += "Values:\n "+QString::number(tensorelems[0])+"\n "+QString::number(tensorelems[1])+"\n "+QString::number(tensorelems[2])+"\n "+QString::number(tensorelems[3])+"\n "+QString::number(tensorelems[4])+"\n "+QString::number(tensorelems[5])+"\n "+"\n"; m_Controls->m_OverviewTextEdit->setVisible(true); } // end pixel access block catch(mitk::Exception &e ) { MITK_WARN << "LOCKED : " << e.what(); m_Controls->m_ODFRenderWidget->setVisible(false); m_Controls->m_OdfBox->setVisible(false); m_Controls->m_OverviewTextEdit->setVisible(false); // reset the selection m_Controls->m_InputImageLabel->setText("Click image to restore rendering!"); } } else { m_Controls->m_ODFRenderWidget->setVisible(false); m_Controls->m_OdfBox->setVisible(false); overviewText += "Please reinit image geometry.\n"; } // proceed only if the render widget is visible which indicates that the // predecessing computations were successfull if( m_Controls->m_ODFRenderWidget->isVisible() ) { m_Controls->m_ODFDetailsWidget->SetParameters(odf); switch(m_OdfNormalization) { case 0: odf = odf.MinMaxNormalize(); break; case 1: odf = odf.MaxNormalize(); break; case 2: odf = odf.MaxNormalize(); break; default: odf = odf.MinMaxNormalize(); } m_Controls->m_ODFRenderWidget->GenerateODF(odf); m_Controls->m_OverviewTextEdit->setText(overviewText.toStdString().c_str()); } } catch(...) { QMessageBox::critical(0, "Error", "Data could not be analyzed. The image might be corrupted."); } } void QmitkODFDetailsView::OnSliceChanged(const itk::EventObject& /*e*/) { UpdateOdf(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDiffusionRegistrationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDiffusionRegistrationView.cpp index 228ac25321..475baeb8b0 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDiffusionRegistrationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDiffusionRegistrationView.cpp @@ -1,485 +1,483 @@ /*=================================================================== 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" // MITK #include #include #include #include #include #include // Qt #include #include #include #include #include #include #define _USE_MATH_DEFINES #include QmitkRegistrationWorker::QmitkRegistrationWorker(QmitkDiffusionRegistrationView* view) : m_View(view) { } void QmitkRegistrationWorker::run() { - typedef mitk::DiffusionPropertyHelper::BValueMapType BValueMap; - unsigned int totalImagesCount; if( !m_View->m_IsBatch ) { totalImagesCount = m_View->m_SelectedDiffusionNodes.size(); } else { totalImagesCount = m_View->m_BatchList.size(); } m_View->m_TotalFiles = totalImagesCount; QString inputPath = m_View->m_Controls->m_InputFolderTextbox->text(); QString outputPath = m_View->m_Controls->m_OutputFolderTextbox->text(); for(unsigned int i=0; i< totalImagesCount; i++) { if(m_View->m_IsAborted){ m_View->m_RegistrationThread.quit(); return; } m_View->m_CurrentFile = i+1; m_View->m_GlobalRegisterer = QmitkDiffusionRegistrationView::DWIHeadMotionCorrectionFilterType::New(); //mitk::DataNode::Pointer node = m_View->m_SelectedDiffusionNodes.at(i); mitk::Image::Pointer inImage; mitk::DataNode::Pointer node; if( !m_View->m_IsBatch ) { node = m_View->m_SelectedDiffusionNodes.at(i); inImage = dynamic_cast(node->GetData()); } else { mitk::Image::Pointer inImage = dynamic_cast(mitk::IOUtil::Load( m_View->m_BatchList.at(i).toStdString() )[0].GetPointer()); mitk::GradientDirectionsProperty::Pointer gradDir = static_cast(inImage->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer()); } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( inImage ) ); if(!isDiffusionImage) { 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() ) { if(! m_View->m_IsBatch) { mitk::Image::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); } else { QString name = m_View->m_BatchList.at(i); name = name.replace(".dwi", "_MC.dwi", Qt::CaseInsensitive); name = name.replace(inputPath, outputPath, Qt::CaseInsensitive); try { mitk::IOUtil::Save(m_View->m_GlobalRegisterer->GetOutput(), name.toStdString().c_str()); } catch( const itk::ExceptionObject& e) { MITK_ERROR << "Catched exception: " << e.what(); mitkThrow() << "Failed with exception from subprocess!"; } } } } m_View->m_RegistrationThread.quit(); } const std::string QmitkDiffusionRegistrationView::VIEW_ID = "org.mitk.views.diffusionregistrationview"; QmitkDiffusionRegistrationView::QmitkDiffusionRegistrationView() : QmitkAbstractView() , m_Controls( 0 ) , m_DiffusionImage( nullptr ) , m_ThreadIsRunning(false) , m_Steps(100) , m_LastStep(0) , m_GlobalRegisterer(nullptr) , m_RegistrationWorker(this) { 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( nullptr, "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()) ); connect( m_Controls->m_SelectInputButton, SIGNAL(clicked()), this, SLOT(AddInputFolderName()) ); connect( m_Controls->m_SelectOutputButton, SIGNAL(clicked()), this, SLOT(AddOutputFolderName()) ); connect( m_Controls->m_StartBatchButton, SIGNAL(clicked()), this, SLOT(StartBatch()) ); this->m_Parent = parent; } } // show/hide advanced settings frame void QmitkDiffusionRegistrationView::AdvancedSettings() { m_Controls->m_AdvancedFrame->setVisible(m_Controls->m_AdvancedSettingsCheckbox->isChecked()); } void QmitkDiffusionRegistrationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) { if (m_ThreadIsRunning) return; bool foundDwiVolume = false; QString tempSelectedNames = ""; m_DiffusionImage = nullptr; m_SelectedDiffusionNodes.clear(); // iterate selection for (mitk::DataNode::Pointer node: nodes) { bool isDiffusionImage(false); if( node.IsNotNull() ) { isDiffusionImage = mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(node->GetData())); } if( isDiffusionImage ) { 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()))+"%" ); m_Controls->m_CurrentFileLabel->setText( QString::number(m_CurrentFile)+" / "+QString::number(m_TotalFiles) ); } 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_StartBatchButton->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_StartBatchButton->setEnabled(true); 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_StartBatchButton->setEnabled(false); m_Controls->m_AdvancedFrame->setEnabled(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 = nullptr; if (m_SelectedDiffusionNodes.size()<1) { QMessageBox::information( nullptr, "Warning", "Please load and select a diffusion image before starting image processing."); return; } m_IsBatch = false; m_IsAborted = false; m_Controls->m_RegistrationStartButton->setEnabled(false); m_Controls->m_StartBatchButton->setEnabled(false); // start worker thread m_RegistrationThread.start(QThread::NormalPriority); return; } void QmitkDiffusionRegistrationView::StopRegistration() { if (m_GlobalRegisterer.IsNull()) return; m_IsAborted = true; m_GlobalRegisterer->SetAbortRegistration(true); m_Controls->m_RegistrationStopButton->setEnabled(false); m_Controls->m_RegistrationStopButton->setText("Stopping ..."); return; } void QmitkDiffusionRegistrationView::AddInputFolderName() { // SELECT FOLDER DIALOG QFileDialog* w = new QFileDialog( m_Parent, QString("Select the input folder with DWI files within") ); w->setFileMode( QFileDialog::Directory ); // RETRIEVE SELECTION if ( w->exec() != QDialog::Accepted ) return; m_Controls->m_InputFolderTextbox->setText(w->selectedFiles()[0]); } void QmitkDiffusionRegistrationView::AddOutputFolderName() { // SELECT FOLDER DIALOG QFileDialog* w = new QFileDialog( m_Parent, QString("Select the output folder") ); w->setFileMode( QFileDialog::Directory ); // RETRIEVE SELECTION if ( w->exec() != QDialog::Accepted ) return; m_Controls->m_OutputFolderTextbox->setText(w->selectedFiles()[0]); } void QmitkDiffusionRegistrationView::StartBatch() { QString inputPath = m_Controls->m_InputFolderTextbox->text(); QString outputPath = m_Controls->m_OutputFolderTextbox->text(); if(inputPath == outputPath){ QMessageBox::information( nullptr, "Error", "Input and Output folders can't be the same"); return; } QStringList list, filters; filters<<"*.dwi"; QDirIterator dirIterator(inputPath, filters, QDir::Files|QDir::NoSymLinks); while (dirIterator.hasNext()) { dirIterator.next(); list.append(dirIterator.fileInfo().absoluteFilePath()); std::cout << dirIterator.fileInfo().absoluteFilePath().toStdString() << std::endl; m_BatchList = list; m_IsBatch = true; m_IsAborted = false; if(m_ThreadIsRunning) { MITK_WARN("QmitkDiffusionRegistrationView")<<"Thread already running!"; return; } m_GlobalRegisterer = nullptr; if (m_BatchList.size()<1) { QMessageBox::information( nullptr, "Error", "No diffusion images were found in the selected input folder."); return; } m_Controls->m_RegistrationStartButton->setEnabled(false); m_Controls->m_StartBatchButton->setEnabled(false); // start worker thread m_RegistrationThread.start(QThread::NormalPriority); } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationView.cpp index a15cd277a9..6c388e9c7c 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationView.cpp @@ -1,502 +1,502 @@ /*=================================================================== 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. ===================================================================*/ // Qmitk #include "QmitkTbssSkeletonizationView.h" #include #include #include #include #include // mitk #include #include #include #include // Qt #include #include //vtk #include #include // Boost #include const std::string QmitkTbssSkeletonizationView::VIEW_ID = "org.mitk.views.tbssskeletonization"; using namespace berry; QmitkTbssSkeletonizationView::QmitkTbssSkeletonizationView() : QmitkAbstractView() , m_Controls( 0 ) , m_Activated(false) { } QmitkTbssSkeletonizationView::~QmitkTbssSkeletonizationView() { } void QmitkTbssSkeletonizationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { //datamanager selection changed if (!this->IsActivated()) return; bool found3dImage = false; bool found4dImage = false; this->m_Controls->m_TubularName->setText(QString("Tubular Structure Mask: ")); this->m_Controls->m_TubularName->setEnabled(false); this->m_Controls->m_MeanLabel->setText(QString("Mean: ")); this->m_Controls->m_MeanLabel->setEnabled(false); this->m_Controls->m_PatientDataLabel->setText(QString("Patient Data: ")); this->m_Controls->m_PatientDataLabel->setEnabled(false); // iterate selection for (mitk::DataNode::Pointer node: nodes) { // only look at interesting types from valid nodes mitk::BaseData* nodeData = node->GetData(); std::string name = ""; node->GetStringProperty("name", name); if(nodeData) { if(QString("Image").compare(nodeData->GetNameOfClass())==0) { mitk::Image* img = static_cast(nodeData); if(img->GetDimension() == 3) { bool isBinary(false); node->GetBoolProperty("binary", isBinary); if(isBinary) { QString label("Tubular Structure Mask: "); label.append(QString(name.c_str())); this->m_Controls->m_TubularName->setText(label); this->m_Controls->m_TubularName->setEnabled(true); } else { found3dImage = true; QString label("Mean: "); label.append(QString(name.c_str())); this->m_Controls->m_MeanLabel->setText(label); this->m_Controls->m_MeanLabel->setEnabled(true); } } else if(img->GetDimension() == 4) { found4dImage = true; QString label("Patient Data: "); label.append(QString(name.c_str())); this->m_Controls->m_PatientDataLabel->setText(label); this->m_Controls->m_PatientDataLabel->setEnabled(true); } } } } this->m_Controls->m_Skeletonize->setEnabled(found3dImage); this->m_Controls->m_Project->setEnabled(found3dImage && found4dImage); this->m_Controls->m_OutputMask->setEnabled(found3dImage && found4dImage); this->m_Controls->m_OutputDistanceMap->setEnabled(found3dImage && found4dImage); } void QmitkTbssSkeletonizationView::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::QmitkTbssSkeletonizationViewControls; m_Controls->setupUi( parent ); this->CreateConnections(); } } void QmitkTbssSkeletonizationView::SetFocus() { m_Controls->m_Skeletonize->setFocus(); } void QmitkTbssSkeletonizationView::Activated() { m_Activated = true; } void QmitkTbssSkeletonizationView::Deactivated() { m_Activated = false; } bool QmitkTbssSkeletonizationView::IsActivated() const { return m_Activated; } void QmitkTbssSkeletonizationView::Visible() { } void QmitkTbssSkeletonizationView::Hidden() { } void QmitkTbssSkeletonizationView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_Skeletonize), SIGNAL(clicked()), this, SLOT(Skeletonize() )); connect( (QObject*)(m_Controls->m_Project), SIGNAL(clicked()), this, SLOT(Project() )); } } void QmitkTbssSkeletonizationView::Skeletonize() { typedef itk::SkeletonizationFilter SkeletonisationFilterType; SkeletonisationFilterType::Pointer skeletonizer = SkeletonisationFilterType::New(); QList nodes = this->GetDataManagerSelection(); mitk::Image::Pointer meanImage = mitk::Image::New(); std::string name = ""; for (auto node: nodes) { // process only on valid nodes mitk::BaseData* nodeData = node->GetData(); if(nodeData) { if(QString("Image").compare(nodeData->GetNameOfClass())==0) { bool isBinary(false); node->GetBoolProperty("binary", isBinary); mitk::Image* img = static_cast(nodeData); if(img->GetDimension() == 3 && !isBinary) { meanImage = img; name = node->GetName(); } } } } // Calculate skeleton FloatImageType::Pointer itkImg = FloatImageType::New(); mitk::CastToItkImage(meanImage, itkImg); skeletonizer->SetInput(itkImg); skeletonizer->Update(); FloatImageType::Pointer output = skeletonizer->GetOutput(); mitk::Image::Pointer mitkOutput = mitk::Image::New(); mitk::CastToMitkImage(output, mitkOutput); name += "_skeleton"; AddToDataStorage(mitkOutput, name); } void QmitkTbssSkeletonizationView::Project() { typedef itk::SkeletonizationFilter SkeletonisationFilterType; typedef itk::ProjectionFilter ProjectionFilterType; typedef itk::DistanceMapFilter DistanceMapFilterType; SkeletonisationFilterType::Pointer skeletonizer = SkeletonisationFilterType::New(); QList nodes = this->GetDataManagerSelection(); mitk::Image::Pointer meanImage = mitk::Image::New(); mitk::Image::Pointer subjects = mitk::Image::New(); mitk::Image::Pointer tubular = mitk::Image::New(); for (auto node: nodes) { // process only on valid nodes mitk::BaseData* nodeData = node->GetData(); if(nodeData) { if(QString("Image").compare(nodeData->GetNameOfClass())==0) { mitk::Image* img = static_cast(nodeData); if(img->GetDimension() == 3) { bool isBinary(false); node->GetBoolProperty("binary", isBinary); if(isBinary) { tubular = img; } else { meanImage = img; } } else if(img->GetDimension() == 4) { subjects = img; } } } } Float4DImageType::Pointer allFA; mitkPixelTypeMultiplex2(ConvertToItk,subjects->GetChannelDescriptor().GetPixelType(),subjects, allFA); // Calculate skeleton FloatImageType::Pointer itkImg = FloatImageType::New(); mitk::CastToItkImage(meanImage, itkImg); skeletonizer->SetInput(itkImg); skeletonizer->Update(); FloatImageType::Pointer output = skeletonizer->GetOutput(); mitk::Image::Pointer mitkOutput = mitk::Image::New(); mitk::CastToMitkImage(output, mitkOutput); AddToDataStorage(mitkOutput, "mean_FA_skeletonised"); // Retrieve direction image needed later by the projection filter DirectionImageType::Pointer directionImg = skeletonizer->GetVectorImage(); // Calculate distance image DistanceMapFilterType::Pointer distanceMapFilter = DistanceMapFilterType::New(); distanceMapFilter->SetInput(output); distanceMapFilter->Update(); FloatImageType::Pointer distanceMap = distanceMapFilter->GetOutput(); if(m_Controls->m_OutputDistanceMap->isChecked()) { mitk::Image::Pointer mitkDistance = mitk::Image::New(); mitk::CastToMitkImage(distanceMap, mitkDistance); AddToDataStorage(mitkDistance, "distance map"); } // Do projection // Ask a threshold to create a skeleton mask double threshold = -1.0; while(threshold == -1.0) { threshold = QInputDialog::getDouble(m_Controls->m_Skeletonize, tr("Specify the FA threshold"), tr("Threshold:"), QLineEdit::Normal, 0.2); if(threshold < 0.0 || threshold > 1.0) { QMessageBox msgBox; msgBox.setText("Please choose a value between 0 and 1"); msgBox.exec(); threshold = -1.0; } } typedef itk::BinaryThresholdImageFilter ThresholdFilterType; ThresholdFilterType::Pointer thresholder = ThresholdFilterType::New(); thresholder->SetInput(output); thresholder->SetLowerThreshold(threshold); thresholder->SetUpperThreshold(std::numeric_limits::max()); thresholder->SetOutsideValue(0); thresholder->SetInsideValue(1); thresholder->Update(); CharImageType::Pointer thresholdedImg = thresholder->GetOutput(); if(m_Controls->m_OutputMask->isChecked()) { mitk::Image::Pointer mitkThresholded = mitk::Image::New(); mitk::CastToMitkImage(thresholdedImg, mitkThresholded); std::string maskName = "skeleton_mask_at_" + boost::lexical_cast(threshold); AddToDataStorage(mitkThresholded, maskName); } CharImageType::Pointer itkTubular = CharImageType::New(); mitk::CastToItkImage(tubular, itkTubular); ProjectionFilterType::Pointer projectionFilter = ProjectionFilterType::New(); projectionFilter->SetDistanceMap(distanceMap); projectionFilter->SetDirections(directionImg); projectionFilter->SetAllFA(allFA); projectionFilter->SetTube(itkTubular); projectionFilter->SetSkeleton(thresholdedImg); projectionFilter->Project(); Float4DImageType::Pointer projected = projectionFilter->GetProjections(); mitk::Image::Pointer mitkProjections = mitk::Image::New(); mitk::CastToMitkImage(projected, mitkProjections); AddToDataStorage(mitkProjections, "all_FA_projected"); } void QmitkTbssSkeletonizationView::AddToDataStorage(mitk::Image* img, std::string name) { mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetProperty( "name", mitk::StringProperty::New(name) ); result->SetData( img ); // add new image to data storage and set as active to ease further processing GetDataStorage()->Add( result ); } template void QmitkTbssSkeletonizationView::ConvertToItk(mitk::PixelType, mitk::Image* image, Float4DImageType::Pointer output) { output = Float4DImageType::New(); mitk::BaseGeometry* geo = image->GetGeometry(); mitk::Vector3D mitkSpacing = geo->GetSpacing(); mitk::Point3D mitkOrigin = geo->GetOrigin(); Float4DImageType::SpacingType spacing; spacing[0] = mitkSpacing[0]; spacing[1] = mitkSpacing[1]; spacing[2] = mitkSpacing[2]; spacing[3] = 1.0; // todo: check if spacing has length 4 Float4DImageType::PointType origin; origin[0] = mitkOrigin[0]; origin[1] = mitkOrigin[1]; origin[2] = mitkOrigin[2]; origin[3] = 0; Float4DImageType::SizeType size; size[0] = image->GetDimension(0); size[1] = image->GetDimension(1); size[2] = image->GetDimension(2); size[3] = image->GetDimension(3); Float4DImageType::DirectionType dir; vtkLinearTransform* lin = geo->GetVtkTransform(); vtkMatrix4x4 *m = lin->GetMatrix(); dir.Fill(0.0); for(int x=0; x<3; x++) { for(int y=0; y<3; y++) { dir[x][y] = m->GetElement(x,y); } } dir[3][3] = 1; output->SetSpacing(spacing); output->SetOrigin(origin); output->SetRegions(size); output->SetDirection(dir); output->Allocate(); if(image->GetDimension() == 4) { unsigned int timesteps = image->GetDimension(3); try{ // REPLACE THIS METHODE()ConvertToItk) WITH mitk::CastToItk // iterate through the subjects and copy data to output for(unsigned int t=0; t inAcc(image,image->GetVolumeData(t)); for(unsigned int x=0; xGetDimension(0); x++) { for(unsigned int y=0; yGetDimension(1); y++) { for(unsigned int z=0; zGetDimension(2); z++) { - itk::Index<3> ix = {x, y, z}; - itk::Index<4> ix4 = {x, y, z, t}; + itk::Index<3> ix = {{x, y, z}}; + itk::Index<4> ix4 = {{x, y, z, t}}; output->SetPixel(ix4, inAcc.GetPixelByIndex(ix)); } } } } } catch(const std::exception & e) { MITK_INFO << e.what(); } } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStochasticFiberTrackingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStochasticFiberTrackingView.cpp index 09997deb74..dd9fc4cbf4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStochasticFiberTrackingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStochasticFiberTrackingView.cpp @@ -1,278 +1,275 @@ /*=================================================================== 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. ===================================================================*/ // Blueberry #include #include #include // Qmitk #include "QmitkStochasticFiberTrackingView.h" // Qt #include // MITK #include #include #include // VTK #include #include #include #include #include #include const std::string QmitkStochasticFiberTrackingView::VIEW_ID = "org.mitk.views.stochasticfibertracking"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace berry; QmitkStochasticFiberTrackingView::QmitkStochasticFiberTrackingView() : QmitkAbstractView() , m_Controls( 0 ) , m_SeedRoi( nullptr ) , m_DiffusionImage( nullptr ) { } // Destructor QmitkStochasticFiberTrackingView::~QmitkStochasticFiberTrackingView() { } void QmitkStochasticFiberTrackingView::CreateQtPartControl( QWidget *parent ) { if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkStochasticFiberTrackingViewControls; m_Controls->setupUi( parent ); connect( m_Controls->commandLinkButton, SIGNAL(clicked()), this, SLOT(DoFiberTracking()) ); connect( m_Controls->m_SeedsPerVoxelSlider, SIGNAL(valueChanged(int)), this, SLOT(OnSeedsPerVoxelChanged(int)) ); connect( m_Controls->m_MaxCacheSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(OnMaxCacheSizeChanged(int)) ); connect( m_Controls->m_MaxTractLengthSlider, SIGNAL(valueChanged(int)), this, SLOT(OnMaxTractLengthChanged(int)) ); } } void QmitkStochasticFiberTrackingView::SetFocus() { m_Controls->commandLinkButton->setFocus(); } void QmitkStochasticFiberTrackingView::OnSeedsPerVoxelChanged(int value) { m_Controls->m_SeedsPerVoxelLabel->setText(QString("Seeds per Voxel: ")+QString::number(value)); } void QmitkStochasticFiberTrackingView::OnMaxTractLengthChanged(int value) { m_Controls->m_MaxTractLengthLabel->setText(QString("Max. Tract Length: ")+QString::number(value)); } void QmitkStochasticFiberTrackingView::OnMaxCacheSizeChanged(int value) { m_Controls->m_MaxCacheSizeLabel->setText(QString("Max. Cache Size: ")+QString::number(value)+"GB"); } void QmitkStochasticFiberTrackingView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { m_DiffusionImageNode = nullptr; m_DiffusionImage = nullptr; m_SeedRoi = nullptr; m_Controls->m_DiffusionImageLabel->setText("mandatory"); m_Controls->m_RoiImageLabel->setText("mandatory"); for (mitk::DataNode::Pointer node: nodes) { if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(node->GetData())) ); if ( isDiffusionImage ) { m_DiffusionImageNode = node; m_DiffusionImage = dynamic_cast(node->GetData()); m_Controls->m_DiffusionImageLabel->setText(node->GetName().c_str()); } else { bool isBinary = false; node->GetPropertyValue("binary", isBinary); if (isBinary) { m_SeedRoi = dynamic_cast(node->GetData()); m_Controls->m_RoiImageLabel->setText(node->GetName().c_str()); } } } } if(m_DiffusionImage.IsNotNull() && m_SeedRoi.IsNotNull()) { m_Controls->m_InputData->setTitle("Input Data"); m_Controls->commandLinkButton->setEnabled(true); } else { m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->commandLinkButton->setEnabled(false); } } void QmitkStochasticFiberTrackingView::DoFiberTracking() { typedef itk::VectorImage< short int, 3 > DWIVectorImageType; typedef itk::Image< float, 3 > FloatImageType; typedef itk::Image< unsigned int, 3 > CImageType; typedef itk::StochasticTractographyFilter< DWIVectorImageType, FloatImageType, CImageType > TrackingFilterType; - typedef itk::DTITubeSpatialObject<3> DTITubeType; - typedef itk::DTITubeSpatialObjectPoint<3> DTITubePointType; - typedef itk::SceneSpatialObject<3> SceneSpatialObjectType; /* get Gradients/Direction of dwi */ GradientDirectionContainerType::Pointer Pdir = static_cast( m_DiffusionImage->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(); /* bValueContainer, Container includes b-values according to corresponding gradient-direction*/ TrackingFilterType::bValueContainerType::Pointer vecCont = TrackingFilterType::bValueContainerType::New(); /* for each gradient set b-Value; for 0-gradient set b-value eq. 0 */ for ( int i=0; i<(int)Pdir->size(); ++i) { vnl_vector_fixed valsGrad = Pdir->at(i); if (valsGrad.get(0) == 0 && valsGrad.get(1) == 0 && valsGrad.get(2) == 0) { //set 0-Gradient to bValue 0 vecCont->InsertElement(i,0); }else{ vecCont->InsertElement(i, static_cast(m_DiffusionImage->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue()); } } /* define measurement frame (identity-matrix 3x3) */ TrackingFilterType::MeasurementFrameType measurement_frame = static_cast(m_DiffusionImage->GetProperty(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str()).GetPointer() )->GetMeasurementFrame(); /* generate white matterImage (dummy?)*/ ITKDiffusionImageType::Pointer itkVectorImagePointer = ITKDiffusionImageType::New(); mitk::CastToItkImage(m_DiffusionImage, itkVectorImagePointer); FloatImageType::Pointer wmImage = FloatImageType::New(); wmImage->SetSpacing( itkVectorImagePointer->GetSpacing() ); wmImage->SetOrigin( itkVectorImagePointer->GetOrigin() ); wmImage->SetDirection( itkVectorImagePointer->GetDirection() ); wmImage->SetLargestPossibleRegion( itkVectorImagePointer->GetLargestPossibleRegion() ); wmImage->SetBufferedRegion( wmImage->GetLargestPossibleRegion() ); wmImage->SetRequestedRegion( wmImage->GetLargestPossibleRegion() ); wmImage->Allocate(); wmImage->FillBuffer(1); /* init TractographyFilter */ TrackingFilterType::Pointer trackingFilter = TrackingFilterType::New(); trackingFilter->SetPrimaryInput(itkVectorImagePointer.GetPointer()); trackingFilter->SetbValues(vecCont); trackingFilter->SetGradients(Pdir); trackingFilter->SetMeasurementFrame(measurement_frame); trackingFilter->SetWhiteMatterProbabilityImage(wmImage); trackingFilter->SetTotalTracts(m_Controls->m_SeedsPerVoxelSlider->value()); trackingFilter->SetMaxLikelihoodCacheSize(m_Controls->m_MaxCacheSizeSlider->value()*1000); trackingFilter->SetMaxTractLength(m_Controls->m_MaxTractLengthSlider->value()); BinaryImageType::Pointer mask = BinaryImageType::New(); mitk::CastToItkImage(m_SeedRoi, mask); vtkSmartPointer vPoints = vtkSmartPointer::New(); vtkSmartPointer vCellArray = vtkSmartPointer::New(); itk::ImageRegionConstIterator< BinaryImageType > it(mask, mask->GetRequestedRegion()); it.GoToBegin(); mitk::BaseGeometry* geom = m_DiffusionImage->GetGeometry(); while(!it.IsAtEnd()) { itk::ImageConstIterator::PixelType tmpPxValue = it.Get(); if(tmpPxValue != 0){ mitk::Point3D point; itk::ImageRegionConstIterator< BinaryImageType >::IndexType seedIdx = it.GetIndex(); trackingFilter->SetSeedIndex(seedIdx); trackingFilter->Update(); /* get results from Filter */ /* write each single tract into member container */ TrackingFilterType::TractContainerType::Pointer container_tmp = trackingFilter->GetOutputTractContainer(); TrackingFilterType::TractContainerType::Iterator elIt = container_tmp->Begin(); TrackingFilterType::TractContainerType::Iterator end = container_tmp->End(); bool addTract = true; while( elIt != end ){ TrackingFilterType::TractContainerType::Element tract = elIt.Value(); TrackingFilterType::TractContainerType::Element::ObjectType::VertexListType::ConstPointer vertexlist = tract->GetVertexList(); vtkSmartPointer vPolyLine = vtkSmartPointer::New(); for( int j=0; j<(int)vertexlist->Size(); j++) { TrackingFilterType::TractContainerType::Element::ObjectType::VertexListType::Element vertex = vertexlist->GetElement(j); mitk::Point3D index; index[0] = (float)vertex[0]; index[1] = (float)vertex[1]; index[2] = (float)vertex[2]; if (geom->IsIndexInside(index)) { geom->IndexToWorld(index, point); vtkIdType id = vPoints->InsertNextPoint(point.GetDataPointer()); vPolyLine->GetPointIds()->InsertNextId(id); } else { addTract = false; break; } } if (addTract) vCellArray->InsertNextCell(vPolyLine); ++elIt; } } ++it; } vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); fiberPolyData->SetPoints(vPoints); fiberPolyData->SetLines(vCellArray); mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(fiberPolyData); fib->SetReferenceGeometry(dynamic_cast(m_DiffusionImageNode->GetData())->GetGeometry()); mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(fib); QString name("FiberBundle_"); name += m_DiffusionImageNode->GetName().c_str(); name += "_Probabilistic"; fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode, m_DiffusionImageNode); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp index 3b2074a76a..9fdce66909 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp @@ -1,842 +1,842 @@ /*=================================================================== 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. ===================================================================*/ // Blueberry #include #include #include // Qmitk #include "QmitkStreamlineTrackingView.h" #include "QmitkStdMultiWidget.h" // Qt #include // MITK #include #include #include #include #include #include #include #include #include #include #include #include // VTK #include #include #include #include #include #include #include #include #include const std::string QmitkStreamlineTrackingView::VIEW_ID = "org.mitk.views.streamlinetracking"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace berry; QmitkStreamlineTrackingWorker::QmitkStreamlineTrackingWorker(QmitkStreamlineTrackingView* view) : m_View(view) { } void QmitkStreamlineTrackingWorker::run() { m_View->m_Tracker->Update(); m_View->m_TrackingThread.quit(); } QmitkStreamlineTrackingView::QmitkStreamlineTrackingView() : m_TrackingWorker(this) , m_Controls(nullptr) , m_FirstTensorProbRun(true) , m_FirstInteractiveRun(true) , m_TrackingHandler(nullptr) , m_ThreadIsRunning(false) , m_DeleteTrackingHandler(false) { m_TrackingWorker.moveToThread(&m_TrackingThread); connect(&m_TrackingThread, SIGNAL(started()), this, SLOT(BeforeThread())); connect(&m_TrackingThread, SIGNAL(started()), &m_TrackingWorker, SLOT(run())); connect(&m_TrackingThread, SIGNAL(finished()), this, SLOT(AfterThread())); m_TrackingTimer = new QTimer(this); } // Destructor QmitkStreamlineTrackingView::~QmitkStreamlineTrackingView() { if (m_Tracker.IsNull()) return; m_Tracker->SetStopTracking(true); m_TrackingThread.wait(); } void QmitkStreamlineTrackingView::CreateQtPartControl( QWidget *parent ) { if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkStreamlineTrackingViewControls; m_Controls->setupUi( parent ); m_Controls->m_FaImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_SeedImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MaskImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_StopImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_TissueImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ForestBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isTractographyForest = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinaryPredicate = mitk::NodePredicateNot::New( isBinaryPredicate ); mitk::NodePredicateAnd::Pointer isNotABinaryImagePredicate = mitk::NodePredicateAnd::New( isImagePredicate, isNotBinaryPredicate ); mitk::NodePredicateDimension::Pointer dimensionPredicate = mitk::NodePredicateDimension::New(3); m_Controls->m_ForestBox->SetPredicate(isTractographyForest); m_Controls->m_FaImageBox->SetPredicate( mitk::NodePredicateAnd::New(isNotABinaryImagePredicate, dimensionPredicate) ); m_Controls->m_FaImageBox->SetZeroEntryText("--"); m_Controls->m_SeedImageBox->SetPredicate( mitk::NodePredicateAnd::New(isBinaryPredicate, dimensionPredicate) ); m_Controls->m_SeedImageBox->SetZeroEntryText("--"); m_Controls->m_MaskImageBox->SetPredicate( mitk::NodePredicateAnd::New(isBinaryPredicate, dimensionPredicate) ); m_Controls->m_MaskImageBox->SetZeroEntryText("--"); m_Controls->m_StopImageBox->SetPredicate( mitk::NodePredicateAnd::New(isBinaryPredicate, dimensionPredicate) ); m_Controls->m_StopImageBox->SetZeroEntryText("--"); m_Controls->m_TissueImageBox->SetPredicate( mitk::NodePredicateAnd::New(isNotABinaryImagePredicate, dimensionPredicate) ); m_Controls->m_TissueImageBox->SetZeroEntryText("--"); connect( m_TrackingTimer, SIGNAL(timeout()), this, SLOT(TimerUpdate()) ); connect( m_Controls->commandLinkButton_2, SIGNAL(clicked()), this, SLOT(StopTractography()) ); connect( m_Controls->commandLinkButton, SIGNAL(clicked()), this, SLOT(DoFiberTracking()) ); connect( m_Controls->m_InteractiveBox, SIGNAL(stateChanged(int)), this, SLOT(ToggleInteractive()) ); connect( m_Controls->m_TissueImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui()) ); connect( m_Controls->m_ModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui()) ); connect( m_Controls->m_FaImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(DeleteTrackingHandler()) ); connect( m_Controls->m_ModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(DeleteTrackingHandler()) ); connect( m_Controls->m_OutputProbMap, SIGNAL(stateChanged(int)), this, SLOT(OutputStyleSwitched()) ); connect( m_Controls->m_ModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_StopImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_MaskImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FaImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_ForestBox, SIGNAL(currentIndexChanged(int)), this, SLOT(ForestSwitched()) ); connect( m_Controls->m_ForestBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_SeedsPerVoxelBox, SIGNAL(valueChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_NumFibersBox, SIGNAL(valueChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_ScalarThresholdBox, SIGNAL(valueChanged(double)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_OdfCutoffBox, SIGNAL(valueChanged(double)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_StepSizeBox, SIGNAL(valueChanged(double)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_SamplingDistanceBox, SIGNAL(valueChanged(double)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_AngularThresholdBox, SIGNAL(valueChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_MinTractLengthBox, SIGNAL(valueChanged(double)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_fBox, SIGNAL(valueChanged(double)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_gBox, SIGNAL(valueChanged(double)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_NumSamplesBox, SIGNAL(valueChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_SeedRadiusBox, SIGNAL(valueChanged(double)), this, SLOT(InteractiveSeedChanged()) ); connect( m_Controls->m_NumSeedsBox, SIGNAL(valueChanged(int)), this, SLOT(InteractiveSeedChanged()) ); connect( m_Controls->m_OutputProbMap, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_SharpenOdfsBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_InterpolationBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_SeedGmBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FlipXBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FlipYBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FlipZBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FrontalSamplesBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_StopVotesBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); StartStopTrackingGui(false); } UpdateGui(); } void QmitkStreamlineTrackingView::StopTractography() { if (m_Tracker.IsNull()) return; m_Tracker->SetStopTracking(true); } void QmitkStreamlineTrackingView::TimerUpdate() { if (m_Tracker.IsNull()) return; QString status_text(m_Tracker->GetStatusText().c_str()); m_Controls->m_StatusTextBox->setText(status_text); } void QmitkStreamlineTrackingView::BeforeThread() { m_TrackingTimer->start(1000); } void QmitkStreamlineTrackingView::AfterThread() { m_TrackingTimer->stop(); if (!m_Tracker->GetUseOutputProbabilityMap()) { vtkSmartPointer fiberBundle = m_Tracker->GetFiberPolyData(); if (!m_Controls->m_InteractiveBox->isChecked() && fiberBundle->GetNumberOfLines() == 0) { QMessageBox warnBox; warnBox.setWindowTitle("Warning"); warnBox.setText("No fiberbundle was generated!"); warnBox.setDetailedText("No fibers were generated using the chosen parameters. Typical reasons are:\n\n- Cutoff too high. Some images feature very low FA/GFA/peak size. Try to lower this parameter.\n- Angular threshold too strict. Try to increase this parameter.\n- A small step sizes also means many steps to go wrong. Especially in the case of probabilistic tractography. Try to adjust the angular threshold."); warnBox.setIcon(QMessageBox::Warning); warnBox.exec(); if (m_InteractivePointSetNode.IsNotNull()) m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); StartStopTrackingGui(false); if (m_DeleteTrackingHandler) DeleteTrackingHandler(); UpdateGui(); return; } mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(fiberBundle); fib->SetReferenceGeometry(dynamic_cast(m_InputImageNodes.at(0)->GetData())->GetGeometry()); if (m_Controls->m_ResampleFibersBox->isChecked() && fiberBundle->GetNumberOfLines()>0) fib->Compress(m_Controls->m_FiberErrorBox->value()); fib->ColorFibersByOrientation(); if (m_Controls->m_InteractiveBox->isChecked()) { if (m_InteractiveNode.IsNull()) { m_InteractiveNode = mitk::DataNode::New(); QString name("Interactive"); m_InteractiveNode->SetName(name.toStdString()); GetDataStorage()->Add(m_InteractiveNode); } m_InteractiveNode->SetData(fib); if (auto renderWindowPart = this->GetRenderWindowPart()) renderWindowPart->RequestUpdate(); } else { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(fib); QString name("FiberBundle_"); name += m_InputImageNodes.at(0)->GetName().c_str(); name += "_Streamline"; node->SetName(name.toStdString()); GetDataStorage()->Add(node, m_InputImageNodes.at(0)); } } else { TrackerType::ItkDoubleImgType::Pointer outImg = m_Tracker->GetOutputProbabilityMap(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); if (m_Controls->m_InteractiveBox->isChecked()) { if (m_InteractiveNode.IsNull()) { m_InteractiveNode = mitk::DataNode::New(); QString name("Interactive"); m_InteractiveNode->SetName(name.toStdString()); GetDataStorage()->Add(m_InteractiveNode); } m_InteractiveNode->SetData(img); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType(mitk::LookupTable::JET_TRANSPARENT); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable(lut); m_InteractiveNode->SetProperty("LookupTable", lut_prop); m_InteractiveNode->SetProperty("opacity", mitk::FloatProperty::New(0.5)); if (auto renderWindowPart = this->GetRenderWindowPart()) renderWindowPart->RequestUpdate(); } else { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); QString name("ProbabilityMap_"); name += m_InputImageNodes.at(0)->GetName().c_str(); node->SetName(name.toStdString()); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType(mitk::LookupTable::JET_TRANSPARENT); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable(lut); node->SetProperty("LookupTable", lut_prop); node->SetProperty("opacity", mitk::FloatProperty::New(0.5)); GetDataStorage()->Add(node, m_InputImageNodes.at(0)); } } if (m_InteractivePointSetNode.IsNotNull()) m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); StartStopTrackingGui(false); if (m_DeleteTrackingHandler) DeleteTrackingHandler(); UpdateGui(); } void QmitkStreamlineTrackingView::InteractiveSeedChanged(bool posChanged) { if (m_ThreadIsRunning) return; if (!posChanged && (!m_Controls->m_InteractiveBox->isChecked() || !m_Controls->m_ParamUpdateBox->isChecked())) return; std::srand(std::time(0)); m_SeedPoints.clear(); itk::Point world_pos = this->GetRenderWindowPart()->GetSelectedPosition(); m_SeedPoints.push_back(world_pos); float radius = m_Controls->m_SeedRadiusBox->value(); int num = m_Controls->m_NumSeedsBox->value(); mitk::PointSet::Pointer pointset = mitk::PointSet::New(); pointset->InsertPoint(0, world_pos); m_InteractivePointSetNode->SetProperty("pointsize", mitk::FloatProperty::New(radius*2)); m_InteractivePointSetNode->SetProperty("point 2D size", mitk::FloatProperty::New(radius*2)); m_InteractivePointSetNode->SetData(pointset); for (int i=1; i p; p[0] = rand()%1000-500; p[1] = rand()%1000-500; p[2] = rand()%1000-500; p.Normalize(); p *= radius; m_SeedPoints.push_back(world_pos+p); } m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,0,0)); DoFiberTracking(); } void QmitkStreamlineTrackingView::OnParameterChanged() { if (m_Controls->m_InteractiveBox->isChecked() && m_Controls->m_ParamUpdateBox->isChecked()) DoFiberTracking(); } void QmitkStreamlineTrackingView::ToggleInteractive() { UpdateGui(); m_Controls->m_SeedsPerVoxelBox->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->m_SeedsPerVoxelLabel->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->m_SeedGmBox->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->m_SeedImageBox->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->label_6->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->m_TissueImageBox->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->label_10->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); if ( m_Controls->m_InteractiveBox->isChecked() ) { if (m_FirstInteractiveRun) { QMessageBox::information(nullptr, "Information", "Place and move a spherical seed region anywhere in the image by left-clicking and dragging. If the seed region is colored red, tracking is in progress. If the seed region is colored white, tracking is finished.\nPlacing the seed region for the first time in a newly selected dataset might cause a short delay, since the tracker needs to be initialized."); m_FirstInteractiveRun = false; } QApplication::setOverrideCursor(Qt::PointingHandCursor); QApplication::processEvents(); m_InteractivePointSetNode = mitk::DataNode::New(); m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); m_InteractivePointSetNode->SetName("InteractiveSeedRegion"); mitk::PointSetShapeProperty::Pointer shape_prop = mitk::PointSetShapeProperty::New(); shape_prop->SetValue(mitk::PointSetShapeProperty::PointSetShape::CIRCLE); m_InteractivePointSetNode->SetProperty("Pointset.2D.shape", shape_prop); GetDataStorage()->Add(m_InteractivePointSetNode); m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); } else { QApplication::restoreOverrideCursor(); QApplication::processEvents(); m_InteractiveNode = nullptr; m_InteractivePointSetNode = nullptr; m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); disconnect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); } } void QmitkStreamlineTrackingView::OnSliceChanged() { InteractiveSeedChanged(true); } void QmitkStreamlineTrackingView::SetFocus() { } void QmitkStreamlineTrackingView::DeleteTrackingHandler() { if (!m_ThreadIsRunning && m_TrackingHandler != nullptr) { delete m_TrackingHandler; m_TrackingHandler = nullptr; m_DeleteTrackingHandler = false; } else if (m_ThreadIsRunning) { m_DeleteTrackingHandler = true; } } void QmitkStreamlineTrackingView::ForestSwitched() { DeleteTrackingHandler(); } void QmitkStreamlineTrackingView::OutputStyleSwitched() { if (m_InteractiveNode.IsNotNull()) GetDataStorage()->Remove(m_InteractiveNode); m_InteractiveNode = nullptr; } void QmitkStreamlineTrackingView::OnSelectionChanged( berry::IWorkbenchPart::Pointer , const QList& nodes ) { std::vector< mitk::DataNode::Pointer > last_nodes = m_InputImageNodes; m_InputImageNodes.clear(); m_InputImages.clear(); m_AdditionalInputImages.clear(); bool retrack = false; for( auto node : nodes ) { if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { if( dynamic_cast(node->GetData()) ) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); retrack = true; } else if ( dynamic_cast(node->GetData()) ) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); retrack = true; } else if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(node->GetData())) ) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); retrack = true; } else { mitk::Image* img = dynamic_cast(node->GetData()); if (img!=nullptr) { int dim = img->GetDimension(); unsigned int* dimensions = img->GetDimensions(); if (dim==4 && dimensions[3]%3==0) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); retrack = true; } else if (dim==3) { m_AdditionalInputImages.push_back(dynamic_cast(node->GetData())); } } } } } // sometimes the OnSelectionChanged event is sent twice and actually no selection has changed for the first event. We need to catch that. if (last_nodes.size() == m_InputImageNodes.size()) { bool same_nodes = true; for (unsigned int i=0; im_TensorImageLabel->setText("mandatory"); m_Controls->m_fBox->setEnabled(false); m_Controls->m_fLabel->setEnabled(false); m_Controls->m_gBox->setEnabled(false); m_Controls->m_gLabel->setEnabled(false); m_Controls->m_FaImageBox->setEnabled(false); m_Controls->mFaImageLabel->setEnabled(false); m_Controls->m_OdfCutoffBox->setEnabled(false); m_Controls->m_OdfCutoffLabel->setEnabled(false); m_Controls->m_SharpenOdfsBox->setEnabled(false); m_Controls->m_ForestBox->setEnabled(false); m_Controls->m_ForestLabel->setEnabled(false); m_Controls->commandLinkButton->setEnabled(false); if (m_Controls->m_TissueImageBox->GetSelectedNode().IsNotNull()) m_Controls->m_SeedGmBox->setEnabled(true); else m_Controls->m_SeedGmBox->setEnabled(false); if(!m_InputImageNodes.empty()) { if (m_InputImageNodes.size()>1) - m_Controls->m_TensorImageLabel->setText(m_InputImageNodes.size()+" images selected"); + m_Controls->m_TensorImageLabel->setText( ( std::to_string(m_InputImageNodes.size()) + " images selected").c_str() ); else m_Controls->m_TensorImageLabel->setText(m_InputImageNodes.at(0)->GetName().c_str()); m_Controls->m_InputData->setTitle("Input Data"); m_Controls->commandLinkButton->setEnabled(!m_Controls->m_InteractiveBox->isChecked() && !m_ThreadIsRunning); m_Controls->m_ScalarThresholdBox->setEnabled(true); m_Controls->m_FaThresholdLabel->setEnabled(true); if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { m_Controls->m_fBox->setEnabled(true); m_Controls->m_fLabel->setEnabled(true); m_Controls->m_gBox->setEnabled(true); m_Controls->m_gLabel->setEnabled(true); m_Controls->mFaImageLabel->setEnabled(true); m_Controls->m_FaImageBox->setEnabled(true); } else if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { m_Controls->mFaImageLabel->setEnabled(true); m_Controls->m_FaImageBox->setEnabled(true); m_Controls->m_OdfCutoffBox->setEnabled(true); m_Controls->m_OdfCutoffLabel->setEnabled(true); m_Controls->m_SharpenOdfsBox->setEnabled(true); } else if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_InputImageNodes.at(0)->GetData())) ) { m_Controls->m_ForestBox->setEnabled(true); m_Controls->m_ForestLabel->setEnabled(true); m_Controls->m_ScalarThresholdBox->setEnabled(false); m_Controls->m_FaThresholdLabel->setEnabled(false); } } else m_Controls->m_InputData->setTitle("Please Select Input Data"); } void QmitkStreamlineTrackingView::StartStopTrackingGui(bool start) { m_ThreadIsRunning = start; if (!m_Controls->m_InteractiveBox->isChecked()) { m_Controls->commandLinkButton_2->setVisible(start); m_Controls->commandLinkButton->setVisible(!start); m_Controls->m_InteractiveBox->setEnabled(!start); m_Controls->m_StatusTextBox->setVisible(start); } } void QmitkStreamlineTrackingView::DoFiberTracking() { if (m_ThreadIsRunning) return; if (m_InputImages.empty()) return; if (m_Controls->m_InteractiveBox->isChecked() && m_SeedPoints.empty()) return; StartStopTrackingGui(true); m_Tracker = TrackerType::New(); if( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { typedef itk::Image< itk::DiffusionTensor3D, 3> TensorImageType; typedef mitk::ImageToItk CasterType; if (m_Controls->m_ModeBox->currentIndex()==1) { if (m_InputImages.size()>1) { QMessageBox::information(nullptr, "Information", "Probabilistic tensor tractography is only implemented for single-tensor mode!"); StartStopTrackingGui(false); return; } if (m_FirstTensorProbRun) { QMessageBox::information(nullptr, "Information", "Internally calculating ODF from tensor image and performing probabilistic ODF tractography. ODFs are sharpened (min-max normalized and raised to the power of 4). TEND parameters are ignored."); m_FirstTensorProbRun = false; } if (m_TrackingHandler==nullptr) { typedef mitk::ImageToItk< mitk::TrackingHandlerOdf::ItkOdfImageType > CasterType; m_TrackingHandler = new mitk::TrackingHandlerOdf(); TensorImageType::Pointer itkImg = TensorImageType::New(); mitk::CastToItkImage(m_InputImages.at(0), itkImg); typedef itk::TensorImageToQBallImageFilter< float, float > FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkImg ); filter->Update(); dynamic_cast(m_TrackingHandler)->SetOdfImage(filter->GetOutput()); if (m_Controls->m_FaImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageBox->GetSelectedNode()->GetData()), itkImg); dynamic_cast(m_TrackingHandler)->SetGfaImage(itkImg); } } dynamic_cast(m_TrackingHandler)->SetGfaThreshold(m_Controls->m_ScalarThresholdBox->value()); dynamic_cast(m_TrackingHandler)->SetOdfThreshold(0); dynamic_cast(m_TrackingHandler)->SetSharpenOdfs(true); } else { if (m_TrackingHandler==nullptr) { m_TrackingHandler = new mitk::TrackingHandlerTensor(); for (int i=0; i<(int)m_InputImages.size(); i++) { typedef mitk::ImageToItk< mitk::TrackingHandlerTensor::ItkTensorImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(m_InputImages.at(i)); caster->Update(); mitk::TrackingHandlerTensor::ItkTensorImageType::ConstPointer itkImg = caster->GetOutput(); dynamic_cast(m_TrackingHandler)->AddTensorImage(itkImg); } if (m_Controls->m_FaImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageBox->GetSelectedNode()->GetData()), itkImg); dynamic_cast(m_TrackingHandler)->SetFaImage(itkImg); } } dynamic_cast(m_TrackingHandler)->SetFaThreshold(m_Controls->m_ScalarThresholdBox->value()); dynamic_cast(m_TrackingHandler)->SetF((float)m_Controls->m_fBox->value()); dynamic_cast(m_TrackingHandler)->SetG((float)m_Controls->m_gBox->value()); } } else if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { if (m_TrackingHandler==nullptr) { typedef mitk::ImageToItk< mitk::TrackingHandlerOdf::ItkOdfImageType > CasterType; m_TrackingHandler = new mitk::TrackingHandlerOdf(); mitk::TrackingHandlerOdf::ItkOdfImageType::Pointer itkImg = mitk::TrackingHandlerOdf::ItkOdfImageType::New(); mitk::CastToItkImage(m_InputImages.at(0), itkImg); dynamic_cast(m_TrackingHandler)->SetOdfImage(itkImg); if (m_Controls->m_FaImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageBox->GetSelectedNode()->GetData()), itkImg); dynamic_cast(m_TrackingHandler)->SetGfaImage(itkImg); } } dynamic_cast(m_TrackingHandler)->SetGfaThreshold(m_Controls->m_ScalarThresholdBox->value()); dynamic_cast(m_TrackingHandler)->SetOdfThreshold(m_Controls->m_OdfCutoffBox->value()); dynamic_cast(m_TrackingHandler)->SetSharpenOdfs(m_Controls->m_SharpenOdfsBox->isChecked()); } else if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_InputImageNodes.at(0)->GetData())) ) { if ( m_Controls->m_ForestBox->GetSelectedNode().IsNull() ) { QMessageBox::information(nullptr, "Information", "Not random forest for machine learning based tractography selected."); StartStopTrackingGui(false); return; } if (m_TrackingHandler==nullptr) { mitk::TractographyForest::Pointer forest = dynamic_cast(m_Controls->m_ForestBox->GetSelectedNode()->GetData()); mitk::Image::Pointer dwi = dynamic_cast(m_InputImageNodes.at(0)->GetData()); std::vector< std::vector< ItkFloatImageType::Pointer > > additionalFeatureImages; additionalFeatureImages.push_back(std::vector< ItkFloatImageType::Pointer >()); for (auto img : m_AdditionalInputImages) { ItkFloatImageType::Pointer itkimg = ItkFloatImageType::New(); mitk::CastToItkImage(img, itkimg); additionalFeatureImages.at(0).push_back(itkimg); } bool forest_valid = false; if (forest->GetNumFeatures()>=100) { int num_previous_directions = (forest->GetNumFeatures() - (100 + additionalFeatureImages.at(0).size()))/3; m_TrackingHandler = new mitk::TrackingHandlerRandomForest<6, 100>(); dynamic_cast*>(m_TrackingHandler)->AddDwi(dwi); dynamic_cast*>(m_TrackingHandler)->SetAdditionalFeatureImages(additionalFeatureImages); dynamic_cast*>(m_TrackingHandler)->SetForest(forest); dynamic_cast*>(m_TrackingHandler)->SetNumPreviousDirections(num_previous_directions); forest_valid = dynamic_cast*>(m_TrackingHandler)->IsForestValid(); } else { int num_previous_directions = (forest->GetNumFeatures() - (28 + additionalFeatureImages.at(0).size()))/3; m_TrackingHandler = new mitk::TrackingHandlerRandomForest<6, 28>(); dynamic_cast*>(m_TrackingHandler)->AddDwi(dwi); dynamic_cast*>(m_TrackingHandler)->SetAdditionalFeatureImages(additionalFeatureImages); dynamic_cast*>(m_TrackingHandler)->SetForest(forest); dynamic_cast*>(m_TrackingHandler)->SetNumPreviousDirections(num_previous_directions); forest_valid = dynamic_cast*>(m_TrackingHandler)->IsForestValid(); } if (!forest_valid) { QMessageBox::information(nullptr, "Information", "Random forest is invalid. The forest signatue does not match the parameters of TrackingHandlerRandomForest."); StartStopTrackingGui(false); return; } } } else { if (m_Controls->m_ModeBox->currentIndex()==1) { QMessageBox::information(nullptr, "Information", "Probabilstic tractography is not implemented for peak images."); StartStopTrackingGui(false); return; } try { if (m_TrackingHandler==nullptr) { typedef mitk::ImageToItk< mitk::TrackingHandlerPeaks::PeakImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(m_InputImages.at(0)); caster->Update(); mitk::TrackingHandlerPeaks::PeakImgType::Pointer itkImg = caster->GetOutput(); m_TrackingHandler = new mitk::TrackingHandlerPeaks(); dynamic_cast(m_TrackingHandler)->SetPeakImage(itkImg); } dynamic_cast(m_TrackingHandler)->SetPeakThreshold(m_Controls->m_ScalarThresholdBox->value()); } catch(...) { StartStopTrackingGui(false); return; } } m_TrackingHandler->SetFlipX(m_Controls->m_FlipXBox->isChecked()); m_TrackingHandler->SetFlipY(m_Controls->m_FlipYBox->isChecked()); m_TrackingHandler->SetFlipZ(m_Controls->m_FlipZBox->isChecked()); m_TrackingHandler->SetInterpolate(m_Controls->m_InterpolationBox->isChecked()); switch (m_Controls->m_ModeBox->currentIndex()) { case 0: m_TrackingHandler->SetMode(mitk::TrackingDataHandler::MODE::DETERMINISTIC); break; case 1: m_TrackingHandler->SetMode(mitk::TrackingDataHandler::MODE::PROBABILISTIC); break; default: m_TrackingHandler->SetMode(mitk::TrackingDataHandler::MODE::DETERMINISTIC); } if (m_Controls->m_InteractiveBox->isChecked()) { m_Tracker->SetSeedPoints(m_SeedPoints); } else if (m_Controls->m_SeedImageBox->GetSelectedNode().IsNotNull()) { ItkUCharImageType::Pointer mask = ItkUCharImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_SeedImageBox->GetSelectedNode()->GetData()), mask); m_Tracker->SetSeedImage(mask); } if (m_Controls->m_MaskImageBox->GetSelectedNode().IsNotNull()) { ItkUCharImageType::Pointer mask = ItkUCharImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_MaskImageBox->GetSelectedNode()->GetData()), mask); m_Tracker->SetMaskImage(mask); } if (m_Controls->m_StopImageBox->GetSelectedNode().IsNotNull()) { ItkUCharImageType::Pointer mask = ItkUCharImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_StopImageBox->GetSelectedNode()->GetData()), mask); m_Tracker->SetStoppingRegions(mask); } if (m_Controls->m_TissueImageBox->GetSelectedNode().IsNotNull()) { ItkUCharImageType::Pointer mask = ItkUCharImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_TissueImageBox->GetSelectedNode()->GetData()), mask); m_Tracker->SetTissueImage(mask); m_Tracker->SetSeedOnlyGm(m_Controls->m_SeedGmBox->isChecked()); } m_Tracker->SetVerbose(!m_Controls->m_InteractiveBox->isChecked()); m_Tracker->SetSeedsPerVoxel(m_Controls->m_SeedsPerVoxelBox->value()); m_Tracker->SetStepSize(m_Controls->m_StepSizeBox->value()); m_Tracker->SetSamplingDistance(m_Controls->m_SamplingDistanceBox->value()); m_Tracker->SetUseStopVotes(m_Controls->m_StopVotesBox->isChecked()); m_Tracker->SetOnlyForwardSamples(m_Controls->m_FrontalSamplesBox->isChecked()); m_Tracker->SetAposterioriCurvCheck(false); m_Tracker->SetMaxNumTracts(m_Controls->m_NumFibersBox->value()); m_Tracker->SetNumberOfSamples(m_Controls->m_NumSamplesBox->value()); m_Tracker->SetTrackingHandler(m_TrackingHandler); m_Tracker->SetAngularThreshold(m_Controls->m_AngularThresholdBox->value()); m_Tracker->SetMinTractLength(m_Controls->m_MinTractLengthBox->value()); m_Tracker->SetUseOutputProbabilityMap(m_Controls->m_OutputProbMap->isChecked()); m_TrackingThread.start(QThread::LowestPriority); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp index 7fe4b64111..15144e92b7 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp @@ -1,1179 +1,1179 @@ /*=================================================================== 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 "QmitkControlVisualizationPropertiesView.h" #include "mitkNodePredicateDataType.h" #include "mitkDataNodeObject.h" #include "mitkOdfNormalizationMethodProperty.h" #include "mitkOdfScaleByProperty.h" #include "mitkResliceMethodProperty.h" #include "mitkRenderingManager.h" #include "mitkTbssImage.h" #include "mitkPlanarFigure.h" #include "mitkFiberBundle.h" #include "QmitkDataStorageComboBox.h" #include "mitkPlanarFigureInteractor.h" #include #include #include #include #include #include "usModuleRegistry.h" #include #include "mitkPlaneGeometry.h" #include #include "berryIWorkbenchWindow.h" #include "berryIWorkbenchPage.h" #include "berryISelectionService.h" #include "berryConstants.h" #include "berryPlatformUI.h" #include "itkRGBAPixel.h" #include #include "qwidgetaction.h" #include "qcolordialog.h" #include #include #include #define ROUND(a) ((a)>0 ? (int)((a)+0.5) : -(int)(0.5-(a))) const std::string QmitkControlVisualizationPropertiesView::VIEW_ID = "org.mitk.views.controlvisualizationpropertiesview"; using namespace berry; QmitkControlVisualizationPropertiesView::QmitkControlVisualizationPropertiesView() : QmitkAbstractView(), m_Controls(nullptr), m_CurrentSelection(0), m_IconTexOFF(new QIcon(":/QmitkDiffusionImaging/texIntOFFIcon.png")), m_IconTexON(new QIcon(":/QmitkDiffusionImaging/texIntONIcon.png")), m_IconGlyOFF_T(new QIcon(":/QmitkDiffusionImaging/glyphsoff_T.png")), m_IconGlyON_T(new QIcon(":/QmitkDiffusionImaging/glyphson_T.png")), m_IconGlyOFF_C(new QIcon(":/QmitkDiffusionImaging/glyphsoff_C.png")), m_IconGlyON_C(new QIcon(":/QmitkDiffusionImaging/glyphson_C.png")), m_IconGlyOFF_S(new QIcon(":/QmitkDiffusionImaging/glyphsoff_S.png")), m_IconGlyON_S(new QIcon(":/QmitkDiffusionImaging/glyphson_S.png")), m_GlyIsOn_T(false), m_GlyIsOn_C(false), m_GlyIsOn_S(false), m_CurrentPickingNode(0), m_FiberBundleObserverTag(0), m_FiberBundleObserveOpacityTag(0) { currentThickSlicesMode = 1; m_MyMenu = nullptr; int numThread = itk::MultiThreader::GetGlobalMaximumNumberOfThreads(); if (numThread > 12) numThread = 12; itk::MultiThreader::SetGlobalDefaultNumberOfThreads(numThread); } QmitkControlVisualizationPropertiesView::~QmitkControlVisualizationPropertiesView() { this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->RemovePostSelectionListener(/*"org.mitk.views.datamanager",*/ m_SelListener.data()); } void QmitkControlVisualizationPropertiesView::OnThickSlicesModeSelected( QAction* action ) { currentThickSlicesMode = action->data().toInt(); switch( currentThickSlicesMode ) { case 0: // toInt() returns 0 'otherwise'. return; // dummy code/todo: implement stuff. case 1: this->m_Controls->m_TSMenu->setText("MIP"); break; case 2: this->m_Controls->m_TSMenu->setText("SUM"); break; case 3: this->m_Controls->m_TSMenu->setText("WEIGH"); break; default: return; // dummy code/todo: implement stuff. } if (auto renderWindowPart = this->GetRenderWindowPart(OPEN)) { /// TODO There is no way to access the individual crosshair planes through the render window part API. /// There could be a new 'mitk::DataNode* mitk::ILinkedRenderWindowPart::GetSlicingPlane(const std::string& name) const' /// function for this purpose. For the time being, I comment out the lines below, but they are valid /// and they have to be re-enabled after the crosshair planes can be accessed again. // mitk::DataNode* n; // n = renderWindowPart->GetSlicingPlane("axial"); // if (n) { n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); } // n = renderWindowPart->GetSlicingPlane("sagittal"); // if (n) { n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); } // n = renderWindowPart->GetSlicingPlane("coronal"); // if (n) { n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); } mitk::BaseRenderer::Pointer renderer; renderer = renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer(); if (renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = renderWindowPart->GetQmitkRenderWindow("sagittal")->GetRenderer(); if (renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = renderWindowPart->GetQmitkRenderWindow("coronal")->GetRenderer(); if (renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer->GetRenderingManager()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::OnTSNumChanged( int num ) { if (auto renderWindowPart = this->GetRenderWindowPart(OPEN)) { /// TODO There is no way to access the individual crosshair planes through the render window part API. /// There could be a new 'mitk::DataNode* mitk::ILinkedRenderWindowPart::GetSlicingPlane(const std::string& name) const' /// function for this purpose. For the time being, I comment out the lines below, but they are valid /// and they have to be re-enabled after the crosshair planes can be accessed again. // if(num==0) // { // mitk::DataNode* n; // n = renderWindowPart->GetSlicingPlane("axial"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( 0 ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( false ) ); // // n = renderWindowPart->GetSlicingPlane("sagittal"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( 0 ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( false ) ); // // n = renderWindowPart->GetSlicingPlane("coronal"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( 0 ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( false ) ); // } // else // { // mitk::DataNode* n; // n = renderWindowPart->GetSlicingPlane("axial"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( (num>0) ) ); // // n = renderWindowPart->GetSlicingPlane("sagittal"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( (num>0) ) ); // // n = renderWindowPart->GetSlicingPlane("coronal"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( (num>0) ) ); // } m_TSLabel->setText(QString::number( num*2 + 1 )); mitk::BaseRenderer::Pointer renderer; renderer = renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = nullptr; renderer = renderWindowPart->GetQmitkRenderWindow("sagittal")->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = nullptr; renderer = renderWindowPart->GetQmitkRenderWindow("coronal")->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer->GetRenderingManager()->RequestUpdateAll(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); } } void QmitkControlVisualizationPropertiesView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkControlVisualizationPropertiesViewControls; m_Controls->setupUi(parent); this->CreateConnections(); // hide warning (ODFs in rotated planes) m_Controls->m_lblRotatedPlanesWarning->hide(); m_MyMenu = new QMenu(parent); m_Controls->m_TSMenu->setMenu( m_MyMenu ); QIcon iconFiberFade(":/QmitkDiffusionImaging/MapperEfx2D.png"); m_Controls->m_FiberFading2D->setIcon(iconFiberFade); #ifndef DIFFUSION_IMAGING_EXTENDED int size = m_Controls->m_AdditionalScaling->count(); for(int t=0; tm_AdditionalScaling->itemText(t).toStdString() == "Scale by ASR") { m_Controls->m_AdditionalScaling->removeItem(t); } } #endif m_Controls->m_ScalingFrame->setVisible(false); m_Controls->m_NormalizationFrame->setVisible(false); m_Controls->m_Crosshair->setVisible(false); } } void QmitkControlVisualizationPropertiesView::SetFocus() { m_Controls->m_TSMenu->setFocus(); } void QmitkControlVisualizationPropertiesView::SliceRotation(const itk::EventObject&) { // test if plane rotated if( m_GlyIsOn_T || m_GlyIsOn_C || m_GlyIsOn_S ) { if( this->IsPlaneRotated() ) { // show label m_Controls->m_lblRotatedPlanesWarning->show(); } else { //hide label m_Controls->m_lblRotatedPlanesWarning->hide(); } } } void QmitkControlVisualizationPropertiesView::NodeRemoved(const mitk::DataNode* /*node*/) { } #include void QmitkControlVisualizationPropertiesView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_VisibleOdfsON_T), SIGNAL(clicked()), this, SLOT(VisibleOdfsON_T()) ); connect( (QObject*)(m_Controls->m_VisibleOdfsON_S), SIGNAL(clicked()), this, SLOT(VisibleOdfsON_S()) ); connect( (QObject*)(m_Controls->m_VisibleOdfsON_C), SIGNAL(clicked()), this, SLOT(VisibleOdfsON_C()) ); connect( (QObject*)(m_Controls->m_ShowMaxNumber), SIGNAL(editingFinished()), this, SLOT(ShowMaxNumberChanged()) ); connect( (QObject*)(m_Controls->m_NormalizationDropdown), SIGNAL(currentIndexChanged(int)), this, SLOT(NormalizationDropdownChanged(int)) ); connect( (QObject*)(m_Controls->m_ScalingFactor), SIGNAL(valueChanged(double)), this, SLOT(ScalingFactorChanged(double)) ); connect( (QObject*)(m_Controls->m_AdditionalScaling), SIGNAL(currentIndexChanged(int)), this, SLOT(AdditionalScaling(int)) ); connect( (QObject*)(m_Controls->m_ScalingCheckbox), SIGNAL(clicked()), this, SLOT(ScalingCheckbox()) ); connect((QObject*) m_Controls->m_ResetColoring, SIGNAL(clicked()), (QObject*) this, SLOT(BundleRepresentationResetColoring())); connect((QObject*) m_Controls->m_FiberFading2D, SIGNAL(clicked()), (QObject*) this, SLOT( Fiber2DfadingEFX() ) ); connect((QObject*) m_Controls->m_FiberThicknessSlider, SIGNAL(sliderReleased()), (QObject*) this, SLOT( FiberSlicingThickness2D() ) ); connect((QObject*) m_Controls->m_FiberThicknessSlider, SIGNAL(valueChanged(int)), (QObject*) this, SLOT( FiberSlicingUpdateLabel(int) )); connect((QObject*) m_Controls->m_Crosshair, SIGNAL(clicked()), (QObject*) this, SLOT(SetInteractor())); connect((QObject*) m_Controls->m_LineWidth, SIGNAL(editingFinished()), (QObject*) this, SLOT(LineWidthChanged())); connect((QObject*) m_Controls->m_TubeWidth, SIGNAL(editingFinished()), (QObject*) this, SLOT(TubeRadiusChanged())); connect( (QObject*) m_Controls->m_EllipsoidViewRadioButton, SIGNAL(toggled(bool)), (QObject*) this, SLOT(OnTensorViewChanged() ) ); connect( (QObject*) m_Controls->m_colouriseRainbowRadioButton, SIGNAL(toggled(bool)), (QObject*) this, SLOT(OnColourisationModeChanged() ) ); connect( (QObject*) m_Controls->m_randomModeRadioButton, SIGNAL(toggled(bool)), (QObject*) this, SLOT(OnRandomModeChanged() ) ); } } // set diffusion image channel to b0 volume void QmitkControlVisualizationPropertiesView::NodeAdded(const mitk::DataNode *node) { mitk::DataNode* notConst = const_cast(node); bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(node->GetData())) ); if (isDiffusionImage) { mitk::Image::Pointer dimg = dynamic_cast(notConst->GetData()); // if there is no b0 image in the dataset, the GetB0Indices() returns a vector of size 0 // and hence we cannot set the Property directly to .front() int displayChannelPropertyValue = 0; mitk::BValueMapProperty* bmapproperty = static_cast (dimg->GetProperty(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ); mitk::DiffusionPropertyHelper::BValueMapType map = bmapproperty->GetBValueMap(); if( map[0].size() > 0) { displayChannelPropertyValue = map[0].front(); } notConst->SetIntProperty("DisplayChannel", displayChannelPropertyValue ); } } /* OnSelectionChanged is registered to SelectionService, therefore no need to implement SelectionService Listener explicitly */ void QmitkControlVisualizationPropertiesView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { m_Controls->m_BundleControlsFrame->setVisible(false); m_Controls->m_ImageControlsFrame->setVisible(false); if (nodes.size()>1) // only do stuff if one node is selected return; m_Controls->m_NumberGlyphsFrame->setVisible(false); m_Controls->m_GlyphFrame->setVisible(false); m_Controls->m_TSMenu->setVisible(false); m_SelectedNode = nullptr; int numOdfImages = 0; for (mitk::DataNode::Pointer node: nodes) { if(node.IsNull()) continue; mitk::BaseData* nodeData = node->GetData(); if(nodeData == nullptr) continue; m_SelectedNode = node; if (dynamic_cast(nodeData)) { // handle fiber bundle property observers if (m_Color.IsNotNull()) { m_Color->RemoveObserver(m_FiberBundleObserverTag); } itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::SetFiberBundleCustomColor ); m_Color = dynamic_cast(node->GetProperty("color", nullptr)); if (m_Color.IsNotNull()) m_FiberBundleObserverTag = m_Color->AddObserver( itk::ModifiedEvent(), command ); if (m_Opacity.IsNotNull()) { m_Opacity->RemoveObserver(m_FiberBundleObserveOpacityTag); } itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::SetFiberBundleOpacity ); m_Opacity = dynamic_cast(node->GetProperty("opacity", nullptr)); if (m_Opacity.IsNotNull()) { m_FiberBundleObserveOpacityTag = m_Opacity->AddObserver( itk::ModifiedEvent(), command2 ); } m_Controls->m_BundleControlsFrame->setVisible(true); if(m_CurrentPickingNode != 0 && node.GetPointer() != m_CurrentPickingNode) { m_Controls->m_Crosshair->setEnabled(false); } else { m_Controls->m_Crosshair->setEnabled(true); } int width; node->GetIntProperty("shape.linewidth", width); m_Controls->m_LineWidth->setValue(width); float radius; node->GetFloatProperty("shape.tuberadius", radius); m_Controls->m_TubeWidth->setValue(radius); float range; node->GetFloatProperty("Fiber2DSliceThickness",range); mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); mitk::BaseGeometry::Pointer geo = fib->GetGeometry(); mitk::ScalarType max = geo->GetExtentInMM(0); max = std::max(max, geo->GetExtentInMM(1)); max = std::max(max, geo->GetExtentInMM(2)); m_Controls->m_FiberThicknessSlider->setMaximum(max * 10); m_Controls->m_FiberThicknessSlider->setValue(range * 10); } else if(dynamic_cast(nodeData) || dynamic_cast(nodeData)) { m_Controls->m_ImageControlsFrame->setVisible(true); m_Controls->m_NumberGlyphsFrame->setVisible(true); m_Controls->m_GlyphFrame->setVisible(true); m_Controls->m_NormalizationFrame->setVisible(true); if(m_NodeUsedForOdfVisualization.IsNotNull()) { m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_S", false); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_C", false); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_T", false); } m_NodeUsedForOdfVisualization = node; m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_S", m_GlyIsOn_S); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_C", m_GlyIsOn_C); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_T", m_GlyIsOn_T); int val; node->GetIntProperty("ShowMaxNumber", val); m_Controls->m_ShowMaxNumber->setValue(val); m_Controls->m_NormalizationDropdown ->setCurrentIndex(dynamic_cast(node->GetProperty("Normalization")) ->GetValueAsId()); float fval; node->GetFloatProperty("Scaling",fval); m_Controls->m_ScalingFactor->setValue(fval); m_Controls->m_AdditionalScaling ->setCurrentIndex(dynamic_cast(node->GetProperty("ScaleBy"))->GetValueAsId()); bool switchTensorViewValue = false; node->GetBoolProperty( "DiffusionCore.Rendering.OdfVtkMapper.SwitchTensorView", switchTensorViewValue ); if( dynamic_cast(nodeData) ) { m_Controls-> m_EllipsoidViewRadioButton-> setEnabled( true ); m_Controls-> m_EllipsoidViewRadioButton-> setChecked( switchTensorViewValue ); } else { m_Controls-> m_EllipsoidViewRadioButton-> setEnabled( false ); m_Controls-> m_EllipsoidViewRadioButton-> setChecked( false ); } bool colourisationModeBit = false; node-> GetBoolProperty( "DiffusionCore.Rendering.OdfVtkMapper.ColourisationModeBit", colourisationModeBit ); m_Controls-> m_colouriseSimpleRadioButton-> setChecked( colourisationModeBit ); bool randomModeBit = false; node-> GetBoolProperty( "DiffusionCore.Rendering.OdfVtkMapper.RandomModeBit", randomModeBit ); m_Controls-> m_randomModeRadioButton-> setChecked( randomModeBit ); numOdfImages++; } else if(dynamic_cast(nodeData)) { PlanarFigureFocus(); } else if( dynamic_cast(nodeData) ) { m_Controls->m_ImageControlsFrame->setVisible(true); m_Controls->m_TSMenu->setVisible(true); } } if( nodes.empty() ) { return; } mitk::DataNode::Pointer node = nodes.at(0); if( node.IsNull() ) { return; } QMenu *myMenu = m_MyMenu; myMenu->clear(); QActionGroup* thickSlicesActionGroup = new QActionGroup(myMenu); thickSlicesActionGroup->setExclusive(true); int currentTSMode = 0; { mitk::ResliceMethodProperty::Pointer m = dynamic_cast(node->GetProperty( "reslice.thickslices" )); if( m.IsNotNull() ) currentTSMode = m->GetValueAsId(); } int maxTS = 30; for (auto node: nodes) { mitk::Image* image = dynamic_cast(node->GetData()); if (image) { int size = std::max(image->GetDimension(0), std::max(image->GetDimension(1), image->GetDimension(2))); if (size>maxTS) { maxTS=size; } } } maxTS /= 2; int currentNum = 0; { mitk::IntProperty::Pointer m = dynamic_cast(node->GetProperty( "reslice.thickslices.num" )); if( m.IsNotNull() ) { currentNum = m->GetValue(); if(currentNum < 0) { currentNum = 0; } if(currentNum > maxTS) { currentNum = maxTS; } } } if(currentTSMode==0) { currentNum=0; } QSlider *m_TSSlider = new QSlider(myMenu); m_TSSlider->setMinimum(0); m_TSSlider->setMaximum(maxTS-1); m_TSSlider->setValue(currentNum); m_TSSlider->setOrientation(Qt::Horizontal); connect( m_TSSlider, SIGNAL( valueChanged(int) ), this, SLOT( OnTSNumChanged(int) ) ); QHBoxLayout* _TSLayout = new QHBoxLayout; _TSLayout->setContentsMargins(4,4,4,4); _TSLayout->addWidget(m_TSSlider); _TSLayout->addWidget(m_TSLabel=new QLabel(QString::number(currentNum*2+1),myMenu)); QWidget* _TSWidget = new QWidget; _TSWidget->setLayout(_TSLayout); QActionGroup* thickSliceModeActionGroup = new QActionGroup(myMenu); thickSliceModeActionGroup->setExclusive(true); QWidgetAction *m_TSSliderAction = new QWidgetAction(myMenu); m_TSSliderAction->setDefaultWidget(_TSWidget); myMenu->addAction(m_TSSliderAction); QAction* mipThickSlicesAction = new QAction(myMenu); mipThickSlicesAction->setActionGroup(thickSliceModeActionGroup); mipThickSlicesAction->setText("MIP (max. intensity proj.)"); mipThickSlicesAction->setCheckable(true); mipThickSlicesAction->setChecked(currentThickSlicesMode==1); mipThickSlicesAction->setData(1); myMenu->addAction( mipThickSlicesAction ); QAction* sumThickSlicesAction = new QAction(myMenu); sumThickSlicesAction->setActionGroup(thickSliceModeActionGroup); sumThickSlicesAction->setText("SUM (sum intensity proj.)"); sumThickSlicesAction->setCheckable(true); sumThickSlicesAction->setChecked(currentThickSlicesMode==2); sumThickSlicesAction->setData(2); myMenu->addAction( sumThickSlicesAction ); QAction* weightedThickSlicesAction = new QAction(myMenu); weightedThickSlicesAction->setActionGroup(thickSliceModeActionGroup); weightedThickSlicesAction->setText("WEIGHTED (gaussian proj.)"); weightedThickSlicesAction->setCheckable(true); weightedThickSlicesAction->setChecked(currentThickSlicesMode==3); weightedThickSlicesAction->setData(3); myMenu->addAction( weightedThickSlicesAction ); connect( thickSliceModeActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(OnThickSlicesModeSelected(QAction*)) ); } void QmitkControlVisualizationPropertiesView::VisibleOdfsON_S() { m_GlyIsOn_S = m_Controls->m_VisibleOdfsON_S->isChecked(); if (m_NodeUsedForOdfVisualization.IsNull()) { MITK_WARN << "ODF visualization activated but m_NodeUsedForOdfVisualization is nullptr"; return; } m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_S", m_GlyIsOn_S); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::VisibleOdfsON_T() { m_GlyIsOn_T = m_Controls->m_VisibleOdfsON_T->isChecked(); if (m_NodeUsedForOdfVisualization.IsNull()) { MITK_WARN << "ODF visualization activated but m_NodeUsedForOdfVisualization is nullptr"; return; } m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_T", m_GlyIsOn_T); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::VisibleOdfsON_C() { m_GlyIsOn_C = m_Controls->m_VisibleOdfsON_C->isChecked(); if (m_NodeUsedForOdfVisualization.IsNull()) { MITK_WARN << "ODF visualization activated but m_NodeUsedForOdfVisualization is nullptr"; return; } m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_C", m_GlyIsOn_C); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } bool QmitkControlVisualizationPropertiesView::IsPlaneRotated() { mitk::Image* currentImage = dynamic_cast( m_NodeUsedForOdfVisualization->GetData() ); if( currentImage == nullptr ) { MITK_ERROR << " Casting problems. Returning false"; return false; } mitk::Vector3D imageNormal0 = currentImage->GetSlicedGeometry()->GetAxisVector(0); mitk::Vector3D imageNormal1 = currentImage->GetSlicedGeometry()->GetAxisVector(1); mitk::Vector3D imageNormal2 = currentImage->GetSlicedGeometry()->GetAxisVector(2); imageNormal0.Normalize(); imageNormal1.Normalize(); imageNormal2.Normalize(); auto renderWindowPart = this->GetRenderWindowPart(); double eps = 0.000001; // for all 2D renderwindows of the render window part check alignment { mitk::PlaneGeometry::ConstPointer displayPlane = dynamic_cast ( renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()->GetCurrentWorldPlaneGeometry() ); if (displayPlane.IsNull()) { return false; } mitk::Vector3D normal = displayPlane->GetNormal(); normal.Normalize(); int test = 0; if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal0.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal1.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal2.GetVnlVector()))-1) > eps ) { test++; } if (test==3) { return true; } } { mitk::PlaneGeometry::ConstPointer displayPlane = dynamic_cast ( renderWindowPart->GetQmitkRenderWindow("sagittal")->GetRenderer()->GetCurrentWorldPlaneGeometry() ); if (displayPlane.IsNull()) { return false; } mitk::Vector3D normal = displayPlane->GetNormal(); normal.Normalize(); int test = 0; if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal0.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal1.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal2.GetVnlVector()))-1) > eps ) { test++; } if (test==3) { return true; } } { mitk::PlaneGeometry::ConstPointer displayPlane = dynamic_cast ( renderWindowPart->GetQmitkRenderWindow("coronal")->GetRenderer()->GetCurrentWorldPlaneGeometry() ); if (displayPlane.IsNull()) { return false; } mitk::Vector3D normal = displayPlane->GetNormal(); normal.Normalize(); int test = 0; if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal0.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal1.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal2.GetVnlVector()))-1) > eps ) { test++; } if (test==3) { return true; } } return false; } void QmitkControlVisualizationPropertiesView::ShowMaxNumberChanged() { int maxNr = m_Controls->m_ShowMaxNumber->value(); if ( maxNr < 1 ) { m_Controls->m_ShowMaxNumber->setValue( 1 ); maxNr = 1; } if ( dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) ) { m_SelectedNode->SetIntProperty("ShowMaxNumber", maxNr); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::NormalizationDropdownChanged(int normDropdown) { typedef mitk::OdfNormalizationMethodProperty PropType; PropType::Pointer normMeth = PropType::New(); switch(normDropdown) { case 0: normMeth->SetNormalizationToMinMax(); break; case 1: normMeth->SetNormalizationToMax(); break; case 2: normMeth->SetNormalizationToNone(); break; case 3: normMeth->SetNormalizationToGlobalMax(); break; default: normMeth->SetNormalizationToMinMax(); } if ( dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) ) { m_SelectedNode->SetProperty("Normalization", normMeth.GetPointer()); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::ScalingFactorChanged(double scalingFactor) { if ( dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) ) { m_SelectedNode->SetFloatProperty("Scaling", scalingFactor); } if (auto renderWindowPart = this->GetRenderWindowPart()) { renderWindowPart->RequestUpdate(); } } void QmitkControlVisualizationPropertiesView::AdditionalScaling(int additionalScaling) { typedef mitk::OdfScaleByProperty PropType; PropType::Pointer scaleBy = PropType::New(); switch(additionalScaling) { case 0: scaleBy->SetScaleByNothing(); break; case 1: scaleBy->SetScaleByGFA(); //m_Controls->params_frame->setVisible(true); break; #ifdef DIFFUSION_IMAGING_EXTENDED case 2: scaleBy->SetScaleByPrincipalCurvature(); // commented in for SPIE paper, Principle curvature scaling //m_Controls->params_frame->setVisible(true); break; #endif default: scaleBy->SetScaleByNothing(); } if ( dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) ) { m_SelectedNode->SetProperty("Normalization", scaleBy.GetPointer()); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::ScalingCheckbox() { m_Controls->m_ScalingFrame->setVisible( m_Controls->m_ScalingCheckbox->isChecked() ); if( ! m_Controls->m_ScalingCheckbox->isChecked() ) { m_Controls->m_AdditionalScaling->setCurrentIndex(0); m_Controls->m_ScalingFactor->setValue(1.0); } } void QmitkControlVisualizationPropertiesView::Fiber2DfadingEFX() { if (m_SelectedNode && dynamic_cast(m_SelectedNode->GetData()) ) { bool currentMode; m_SelectedNode->GetBoolProperty("Fiber2DfadeEFX", currentMode); m_SelectedNode->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(!currentMode)); dynamic_cast(m_SelectedNode->GetData())->RequestUpdate2D(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::FiberSlicingThickness2D() { if (m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { float fibThickness = m_Controls->m_FiberThicknessSlider->value() * 0.1; float currentThickness = 0; m_SelectedNode->GetFloatProperty("Fiber2DSliceThickness", currentThickness); if ( fabs(fibThickness-currentThickness) < 0.001 ) { return; } m_SelectedNode->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(fibThickness)); dynamic_cast(m_SelectedNode->GetData())->RequestUpdate2D(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::FiberSlicingUpdateLabel(int value) { QString label = "Range %1 mm"; label = label.arg(value * 0.1); m_Controls->label_range->setText(label); FiberSlicingThickness2D(); } void QmitkControlVisualizationPropertiesView::SetFiberBundleOpacity(const itk::EventObject& /*e*/) { if(m_SelectedNode) { mitk::FiberBundle::Pointer fib = dynamic_cast(m_SelectedNode->GetData()); fib->RequestUpdate(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::SetFiberBundleCustomColor(const itk::EventObject& /*e*/) { if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { float color[3]; m_SelectedNode->GetColor(color); mitk::FiberBundle::Pointer fib = dynamic_cast(m_SelectedNode->GetData()); fib->SetFiberColors(color[0]*255, color[1]*255, color[2]*255); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::BundleRepresentationResetColoring() { if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { mitk::FiberBundle::Pointer fib = dynamic_cast(m_SelectedNode->GetData()); fib->ColorFibersByOrientation(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::PlanarFigureFocus() { if(m_SelectedNode) { mitk::PlanarFigure* _PlanarFigure = 0; _PlanarFigure = dynamic_cast (m_SelectedNode->GetData()); if (_PlanarFigure && _PlanarFigure->GetPlaneGeometry()) { QmitkRenderWindow* selectedRenderWindow = 0; bool PlanarFigureInitializedWindow = false; auto renderWindowPart = this->GetRenderWindowPart(OPEN); QmitkRenderWindow* axialRenderWindow = renderWindowPart->GetQmitkRenderWindow("axial"); if (m_SelectedNode->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, axialRenderWindow->GetRenderer())) { selectedRenderWindow = axialRenderWindow; } QmitkRenderWindow* sagittalRenderWindow = renderWindowPart->GetQmitkRenderWindow("sagittal"); if (!selectedRenderWindow && m_SelectedNode->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, sagittalRenderWindow->GetRenderer())) { selectedRenderWindow = sagittalRenderWindow; } QmitkRenderWindow* coronalRenderWindow = renderWindowPart->GetQmitkRenderWindow("coronal"); if (!selectedRenderWindow && m_SelectedNode->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, coronalRenderWindow->GetRenderer())) { selectedRenderWindow = coronalRenderWindow; } QmitkRenderWindow* _3DRenderWindow = renderWindowPart->GetQmitkRenderWindow("3d"); if (!selectedRenderWindow && m_SelectedNode->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, _3DRenderWindow->GetRenderer())) { selectedRenderWindow = _3DRenderWindow; } const mitk::PlaneGeometry* _PlaneGeometry = _PlanarFigure->GetPlaneGeometry(); mitk::VnlVector normal = _PlaneGeometry->GetNormalVnl(); - mitk::Geometry2D::ConstPointer worldGeometry1 = + mitk::PlaneGeometry::ConstPointer worldGeometry1 = axialRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); mitk::PlaneGeometry::ConstPointer _Plane1 = dynamic_cast( worldGeometry1.GetPointer() ); mitk::VnlVector normal1 = _Plane1->GetNormalVnl(); - mitk::Geometry2D::ConstPointer worldGeometry2 = + mitk::PlaneGeometry::ConstPointer worldGeometry2 = sagittalRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); mitk::PlaneGeometry::ConstPointer _Plane2 = dynamic_cast( worldGeometry2.GetPointer() ); mitk::VnlVector normal2 = _Plane2->GetNormalVnl(); - mitk::Geometry2D::ConstPointer worldGeometry3 = + mitk::PlaneGeometry::ConstPointer worldGeometry3 = coronalRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); mitk::PlaneGeometry::ConstPointer _Plane3 = dynamic_cast( worldGeometry3.GetPointer() ); mitk::VnlVector normal3 = _Plane3->GetNormalVnl(); normal[0] = fabs(normal[0]); normal[1] = fabs(normal[1]); normal[2] = fabs(normal[2]); normal1[0] = fabs(normal1[0]); normal1[1] = fabs(normal1[1]); normal1[2] = fabs(normal1[2]); normal2[0] = fabs(normal2[0]); normal2[1] = fabs(normal2[1]); normal2[2] = fabs(normal2[2]); normal3[0] = fabs(normal3[0]); normal3[1] = fabs(normal3[1]); normal3[2] = fabs(normal3[2]); double ang1 = angle(normal, normal1); double ang2 = angle(normal, normal2); double ang3 = angle(normal, normal3); if(ang1 < ang2 && ang1 < ang3) { selectedRenderWindow = axialRenderWindow; } else { if(ang2 < ang3) { selectedRenderWindow = sagittalRenderWindow; } else { selectedRenderWindow = coronalRenderWindow; } } // make node visible if (selectedRenderWindow) { const mitk::Point3D& centerP = _PlaneGeometry->GetOrigin(); selectedRenderWindow->GetSliceNavigationController()->ReorientSlices( centerP, _PlaneGeometry->GetNormal()); } } // set interactor for new node (if not already set) mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(m_SelectedNode->GetDataInteractor().GetPointer()); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New(); us::Module* planarFigureModule = us::ModuleRegistry::GetModule( "MitkPlanarFigure" ); figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule ); figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule ); figureInteractor->SetDataNode( m_SelectedNode ); } m_SelectedNode->SetProperty("planarfigure.iseditable",mitk::BoolProperty::New(true)); } } void QmitkControlVisualizationPropertiesView::SetInteractor() { // BUG 19179 // typedef std::vector Container; // Container _NodeSet = this->GetDataManagerSelection(); // mitk::DataNode* node = 0; // mitk::FiberBundle* bundle = 0; // mitk::FiberBundleInteractor::Pointer bundleInteractor = 0; // // finally add all nodes to the model // for(Container::const_iterator it=_NodeSet.begin(); it!=_NodeSet.end() // ; it++) // { // node = const_cast(*it); // bundle = dynamic_cast(node->GetData()); // if(bundle) // { // bundleInteractor = dynamic_cast(node->GetInteractor()); // if(bundleInteractor.IsNotNull()) // mitk::GlobalInteraction::GetInstance()->RemoveInteractor(bundleInteractor); // if(!m_Controls->m_Crosshair->isChecked()) // { // m_Controls->m_Crosshair->setChecked(false); // this->GetActiveStdMultiWidget()->GetRenderWindow4()->setCursor(Qt::ArrowCursor); // m_CurrentPickingNode = 0; // } // else // { // m_Controls->m_Crosshair->setChecked(true); // bundleInteractor = mitk::FiberBundleInteractor::New("FiberBundleInteractor", node); // mitk::GlobalInteraction::GetInstance()->AddInteractor(bundleInteractor); // this->GetActiveStdMultiWidget()->GetRenderWindow4()->setCursor(Qt::CrossCursor); // m_CurrentPickingNode = node; // } // } // } } void QmitkControlVisualizationPropertiesView::TubeRadiusChanged() { if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { float newRadius = m_Controls->m_TubeWidth->value(); m_SelectedNode->SetFloatProperty("shape.tuberadius", newRadius); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::LineWidthChanged() { if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { int newWidth = m_Controls->m_LineWidth->value(); int currentWidth = 0; m_SelectedNode->GetIntProperty("shape.linewidth", currentWidth); if (currentWidth==newWidth) return; m_SelectedNode->SetIntProperty("shape.linewidth", newWidth); dynamic_cast(m_SelectedNode->GetData())->RequestUpdate(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::Welcome() { berry::PlatformUI::GetWorkbench()->GetIntroManager() ->ShowIntro(GetSite()->GetWorkbenchWindow(), false); } void QmitkControlVisualizationPropertiesView::OnTensorViewChanged() { if( m_NodeUsedForOdfVisualization.IsNotNull() ) { if( m_Controls-> m_EllipsoidViewRadioButton-> isChecked() ) { if ( m_SelectedNode and dynamic_cast( m_SelectedNode->GetData() ) ) { m_SelectedNode-> SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.SwitchTensorView", mitk::BoolProperty::New( true ) ); mitk::OdfNormalizationMethodProperty::Pointer normalizationProperty = mitk::OdfNormalizationMethodProperty::New( mitk::ODFN_MAX ); m_SelectedNode-> SetProperty( "Normalization", normalizationProperty ); // type OdfNormalizationMethodProperty m_Controls-> m_NormalizationDropdown->setCurrentIndex ( dynamic_cast( m_SelectedNode->GetProperty("Normalization") )->GetValueAsId() ); } else { m_SelectedNode-> SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.SwitchTensorView", mitk::BoolProperty::New( false ) ); m_Controls-> m_OdfViewRadioButton-> setChecked(true); m_Controls-> m_EllipsoidViewRadioButton-> setEnabled(false); } } else if( m_Controls-> m_OdfViewRadioButton-> isChecked() ) { m_SelectedNode-> SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.SwitchTensorView", mitk::BoolProperty::New( false ) ); } mitk::RenderingManager::GetInstance()-> RequestUpdateAll(); } else { MITK_DEBUG << "QmitkControlVisualizationPropertiesView::OnTensorViewChanged()" " was called but m_NodeUsedForOdfVisualization was Null."; } } void QmitkControlVisualizationPropertiesView::OnColourisationModeChanged() { if( m_SelectedNode and m_NodeUsedForOdfVisualization.IsNotNull() ) { if( m_Controls-> m_colouriseRainbowRadioButton-> isChecked() ) { m_SelectedNode-> SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.ColourisationModeBit", mitk::BoolProperty::New( false ) ); } else if ( m_Controls-> m_colouriseSimpleRadioButton-> isChecked() ) { m_SelectedNode-> SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.ColourisationModeBit", mitk::BoolProperty::New( true ) ); } mitk::RenderingManager::GetInstance()-> RequestUpdateAll(); } else { MITK_DEBUG << "QmitkControlVisualizationPropertiesView::OnColourisationModeChanged()" " was called but m_NodeUsedForOdfVisualization was Null."; } } void QmitkControlVisualizationPropertiesView::OnRandomModeChanged() { if( m_SelectedNode and m_NodeUsedForOdfVisualization.IsNotNull() ) { if( m_Controls-> m_randomModeRadioButton-> isChecked() ) { m_SelectedNode-> SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.RandomModeBit", mitk::BoolProperty::New( true ) ); } else if ( m_Controls-> m_orderedModeRadioButton-> isChecked() ) { m_SelectedNode-> SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.RandomModeBit", mitk::BoolProperty::New( false ) ); } mitk::RenderingManager::GetInstance()-> RequestUpdateAll(); } else { MITK_DEBUG << "QmitkControlVisualizationPropertiesView::OnRandomModeChanged()" " was called but m_NodeUsedForOdfVisualization was Null."; } }