diff --git a/Modules/Classification/CLActiveLearning/include/mitkAbstractClassifierPredictionFilter.h b/Modules/Classification/CLActiveLearning/include/mitkAbstractClassifierPredictionFilter.h index 3dd52b27fd..68f04eb615 100644 --- a/Modules/Classification/CLActiveLearning/include/mitkAbstractClassifierPredictionFilter.h +++ b/Modules/Classification/CLActiveLearning/include/mitkAbstractClassifierPredictionFilter.h @@ -1,72 +1,72 @@ /*=================================================================== 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 mitkAbstractClassifierPredictionFilter_h #define mitkAbstractClassifierPredictionFilter_h #include // ITK #include // MITK #include #include namespace mitk { /** \class AbstractClassifierPredictionFilter * \brief Filter that connects to a classifier and a data source and outputs the prediction for the data * * Inputs: * 0 - Training Data * 1 - A classifier that is based on mitk::AbstractClassifier * * Outputs: * 0 - Prediction * * Proper conversion of input data to Eigen::MatrixXd should be implemented via MakeTrainingData() */ class MITKCLACTIVELEARNING_EXPORT AbstractClassifierPredictionFilter : itk::ProcessObject { public: mitkClassMacroItkParent(AbstractClassifierPredictionFilter, itk::ProcessObject) // itkNewMacro(Self) protected: AbstractClassifierPredictionFilter(){} ~AbstractClassifierPredictionFilter(){} virtual Eigen::MatrixXd MakeMatrixData(itk::DataObject* /*inputData*/) = 0; Eigen::MatrixXd MakeMatrixData(const Eigen::MatrixXd &inputData){return inputData;} - virtual void GenerateData() override; + //virtual void GenerateData() override; private: // ITK examples do this... AbstractClassifierPredictionFilter(const Self&); void operator=(const Self&); }; } #endif diff --git a/Modules/Classification/CLActiveLearning/include/mitkActiveLearningSuggestRegionFilter.h b/Modules/Classification/CLActiveLearning/include/mitkActiveLearningSuggestRegionFilter.h index 9b9184644a..f34c04e960 100644 --- a/Modules/Classification/CLActiveLearning/include/mitkActiveLearningSuggestRegionFilter.h +++ b/Modules/Classification/CLActiveLearning/include/mitkActiveLearningSuggestRegionFilter.h @@ -1,169 +1,169 @@ /*=================================================================== 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 mitkActiveLearningSuggestRegionFilter_h #define mitkActiveLearningSuggestRegionFilter_h #include // ITK #include #include #include #include #include #include #include #include #include #include #include // MITK #include #include namespace mitk { /** \class ActiveLearningSuggestRegionFilter * \brief Filter that takes an image of prediction uncertainties and outputs an image (mask) containing only the most uncertain region * * This is just a composite filter using itkThresholdImageFilter and mitkSelectHighestUncertaintyRegionFilter */ template - class MITKCLACTIVELEARNING_EXPORT ActiveLearningSuggestRegionFilter : public itk::ImageToImageFilter + class ActiveLearningSuggestRegionFilter : public itk::ImageToImageFilter { public: typedef itk::ImageToImageFilter SuperClassName; mitkClassMacroItkParent(ActiveLearningSuggestRegionFilter, SuperClassName) itkNewMacro(Self) typedef typename InputImageType::PixelType InputImagePixelType; typedef typename OutputImageType::PixelType OutputImagePixelType; // We're not holding threshold as a member, so no set and get macro void SetThreshold(InputImagePixelType threshold) { if (m_ThresholdFilter->GetLowerThreshold() != threshold) { m_ThresholdFilter->SetLowerThreshold(threshold); this->Modified(); } } InputImagePixelType GetThreshold() const { return m_ThresholdFilter->GetLowerThreshold(); } protected: ActiveLearningSuggestRegionFilter() { m_GaussianFilter = itk::DiscreteGaussianImageFilter::New(); m_ThresholdFilter = itk::BinaryThresholdImageFilter::New(); m_CCFilter = itk::ConnectedComponentImageFilter::New(); m_ThresholdOutputFilter = itk::BinaryThresholdImageFilter::New(); // m_OpeningFilter = itk::BinaryMorphologicalOpeningImageFilter::New(); m_ThresholdFilter->SetLowerThreshold(0.5); m_ThresholdFilter->SetOutsideValue(0); m_ThresholdFilter->SetInsideValue(1); m_ThresholdOutputFilter->SetOutsideValue(0); m_ThresholdOutputFilter->SetInsideValue(1); } ~ActiveLearningSuggestRegionFilter(){} virtual void GenerateData() override { // Let this filter's input be threshold filter's input auto input = InputImageType::New(); input->Graft(const_cast(this->GetInput())); m_GaussianFilter->SetInput(input); m_GaussianFilter->Modified(); m_ThresholdFilter->SetInput(m_GaussianFilter->GetOutput()); m_ThresholdFilter->Modified(); // StructuringElementType structuringElement; // structuringElement.SetRadius(5); // structuringElement.CreateStructuringElement(); // m_OpeningFilter->SetKernel(structuringElement); // m_OpeningFilter->SetInput(m_ThresholdFilter->GetOutput()); // m_OpeningFilter->Modified(); // // Run pipeline to get image with connected components // m_CCFilter->SetInput(m_OpeningFilter->GetOutput()); // m_CCFilter->Update(); m_CCFilter->SetInput(m_ThresholdFilter->GetOutput()); m_CCFilter->Update(); // Find sum of uncertainties for all connected components int ccCount = static_cast(m_CCFilter->GetObjectCount()); std::map ccSize; for (int a=1; a<=ccCount; ++a) {ccSize[a] = 0.0;} auto inputIt = itk::ImageRegionConstIterator(input, input->GetLargestPossibleRegion()); auto outputIt = itk::ImageRegionConstIterator(m_CCFilter->GetOutput(), m_CCFilter->GetOutput()->GetLargestPossibleRegion()); while (!outputIt.IsAtEnd()) { OutputImagePixelType ccVal = outputIt.Get(); InputImagePixelType pixelVal = inputIt.Get(); if (ccVal != 0) {ccSize[ccVal] += pixelVal;} ++outputIt; ++inputIt; } // Find component with largest sum typedef typename std::map::value_type PairType; auto maxComponent = std::max_element(ccSize.begin(), ccSize.end(), [](const PairType& lhs, const PairType& rhs){return lhs.second < rhs.second;}); // Create mask m_ThresholdOutputFilter->SetLowerThreshold(maxComponent->first); m_ThresholdOutputFilter->SetUpperThreshold(maxComponent->first); m_ThresholdOutputFilter->SetInput(m_CCFilter->GetOutput()); m_ThresholdOutputFilter->GraftOutput(this->GetOutput()); m_ThresholdOutputFilter->Update(); this->GraftOutput(m_ThresholdOutputFilter->GetOutput()); } // virtual void PrintSelf(std::ostream & os, itk::Indent indent) const // { // Superclass::PrintSelf(os, indent); // m_ThresholdFilter->PrintSelf(os, indent); // m_RegionFilter->PrintSelf(os, indent); // } private: // ITK examples do this... ActiveLearningSuggestRegionFilter(const Self&); void operator=(const Self&); typename itk::DiscreteGaussianImageFilter::Pointer m_GaussianFilter; typename itk::BinaryThresholdImageFilter::Pointer m_ThresholdFilter; typename itk::ConnectedComponentImageFilter::Pointer m_CCFilter; typename itk::BinaryThresholdImageFilter::Pointer m_ThresholdOutputFilter; - typedef itk::BinaryBallStructuringElement StructuringElementType; + typedef itk::BinaryBallStructuringElement StructuringElementType; typename itk::BinaryMorphologicalOpeningImageFilter::Pointer m_OpeningFilter; }; } #endif diff --git a/Modules/Classification/CLActiveLearning/include/mitkPredictionConfidenceFilter.h b/Modules/Classification/CLActiveLearning/include/mitkPredictionConfidenceFilter.h index 8315ab59a9..0716685cb3 100644 --- a/Modules/Classification/CLActiveLearning/include/mitkPredictionConfidenceFilter.h +++ b/Modules/Classification/CLActiveLearning/include/mitkPredictionConfidenceFilter.h @@ -1,65 +1,65 @@ /*=================================================================== 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 mitkPredictionConfidenceFilter_h #define mitkPredictionConfidenceFilter_h #include #include #include namespace mitk { template - class MITKCLACTIVELEARNING_EXPORT PredictionConfidenceFilter : public mitk::PredictionUncertaintyFilter + class PredictionConfidenceFilter : public mitk::PredictionUncertaintyFilter { public: typedef mitk::PredictionUncertaintyFilter SuperClassName; mitkClassMacro(PredictionConfidenceFilter, SuperClassName) itkNewMacro(Self) typedef typename InputImageType::PixelType InputImagePixelType; typedef typename OutputImageType::PixelType OutputImagePixelType; protected: OutputImagePixelType CalculateUncertainty(const InputImagePixelType& inputVector) override { InputImagePixelType maxValue(0); InputImagePixelType sum(0); // If input is not normalized // Is there a better way to find the maximum of a itk::VariableLengthVector? for (unsigned int i=0; i maxValue) maxValue = inputVector[i]; } // We could do something for non-normalized inputs, but this way a negative result indicates error return static_cast(1 - maxValue / static_cast(sum)); // Double to not lose information } private: // ITK examples do this... PredictionConfidenceFilter(const Self&); void operator=(const Self&); }; } #endif diff --git a/Modules/Classification/CLActiveLearning/include/mitkPredictionEntropyFilter.h b/Modules/Classification/CLActiveLearning/include/mitkPredictionEntropyFilter.h index 8672fe2f7d..3eae04bdea 100644 --- a/Modules/Classification/CLActiveLearning/include/mitkPredictionEntropyFilter.h +++ b/Modules/Classification/CLActiveLearning/include/mitkPredictionEntropyFilter.h @@ -1,74 +1,74 @@ /*=================================================================== 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 mitkPredictionEntropyFilter_h #define mitkPredictionEntropyFilter_h #include #include #include namespace mitk { template - class MITKCLACTIVELEARNING_EXPORT PredictionEntropyFilter : public mitk::PredictionUncertaintyFilter + class PredictionEntropyFilter : public mitk::PredictionUncertaintyFilter { public: typedef mitk::PredictionUncertaintyFilter SuperClassName; mitkClassMacro(PredictionEntropyFilter, SuperClassName) itkNewMacro(Self) typedef typename InputImageType::PixelType InputImagePixelType; typedef typename OutputImageType::PixelType OutputImagePixelType; protected: PredictionEntropyFilter(){} ~PredictionEntropyFilter(){} OutputImagePixelType CalculateUncertainty(const InputImagePixelType& inputVector) override { unsigned int N = inputVector.Size(); if (N == 1) {return 0;} OutputImagePixelType result(0); OutputImagePixelType sum(0); for (unsigned int i=0; i(inputVector[i]); // if (p < m_Epsilon) {p = m_Epsilon;} p = std::max(p, m_Epsilon); result -= p * std::log(p); // The result is supposed to be negative } result = result / static_cast(std::log(N / static_cast(sum)) * sum); // Normalize return result; } private: OutputImagePixelType m_Epsilon = 0.000001; // ITK examples do this... PredictionEntropyFilter(const Self&); void operator=(const Self&); }; } #endif diff --git a/Modules/Classification/CLActiveLearning/include/mitkPredictionMarginFilter.h b/Modules/Classification/CLActiveLearning/include/mitkPredictionMarginFilter.h index bafa6137f6..f72b0aa24e 100644 --- a/Modules/Classification/CLActiveLearning/include/mitkPredictionMarginFilter.h +++ b/Modules/Classification/CLActiveLearning/include/mitkPredictionMarginFilter.h @@ -1,72 +1,72 @@ /*=================================================================== 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 mitkPredictionMarginFilter_h #define mitkPredictionMarginFilter_h #include #include #include namespace mitk { template - class MITKCLACTIVELEARNING_EXPORT PredictionMarginFilter : public mitk::PredictionUncertaintyFilter + class PredictionMarginFilter : public mitk::PredictionUncertaintyFilter { public: typedef mitk::PredictionUncertaintyFilter SuperClassName; mitkClassMacro(PredictionMarginFilter, SuperClassName) itkNewMacro(Self) typedef typename InputImageType::PixelType InputImagePixelType; typedef typename OutputImageType::PixelType OutputImagePixelType; protected: OutputImagePixelType CalculateUncertainty(const InputImagePixelType& inputVector) override { InputImagePixelType firstMax(0); InputImagePixelType secondMax(0); InputImagePixelType sum(0); // If input is not normalized for (unsigned int i=0; i firstMax) { secondMax = firstMax; firstMax = inputVector[i]; } else if (inputVector[i] > secondMax) { secondMax = inputVector[i]; } return static_cast(1 - (firstMax - secondMax) / static_cast(sum)); // Double to not lose information } } private: // ITK examples do this... PredictionMarginFilter(const Self&); void operator=(const Self&); }; } #endif diff --git a/Modules/Classification/CLActiveLearning/include/mitkPredictionUncertaintyFilter.h b/Modules/Classification/CLActiveLearning/include/mitkPredictionUncertaintyFilter.h index 376da26e78..a2c6eac5dd 100644 --- a/Modules/Classification/CLActiveLearning/include/mitkPredictionUncertaintyFilter.h +++ b/Modules/Classification/CLActiveLearning/include/mitkPredictionUncertaintyFilter.h @@ -1,90 +1,90 @@ /*=================================================================== 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 mitkPredictionUncertaintyFilter_h #define mitkPredictionUncertaintyFilter_h #include #include // ITK #include #include #include #include #include namespace mitk { /** \class PredictionUncertaintyFilter * \brief Base class for filters that calculate an uncertainty measure on a vector image * * The input image should be a vector image. For each vector, the entries represent class * probabilities. From these an uncertainty is calculated, so that one vector of probabilities * will result in a scalar uncertainty. * Derivative classes will need to implement CalculateUncertainty. */ template - class MITKCLACTIVELEARNING_EXPORT PredictionUncertaintyFilter : public itk::ImageToImageFilter + class PredictionUncertaintyFilter : public itk::ImageToImageFilter { public: typedef itk::ImageToImageFilter SuperClassName; mitkClassMacroItkParent(PredictionUncertaintyFilter, SuperClassName) // itkNewMacro(Self) typedef typename InputImageType::PixelType InputImagePixelType; typedef typename OutputImageType::PixelType OutputImagePixelType; typedef typename OutputImageType::RegionType OutputImageRegionType; protected: PredictionUncertaintyFilter(){} ~PredictionUncertaintyFilter(){} virtual OutputImagePixelType CalculateUncertainty(const InputImagePixelType& inputVector) = 0; void GenerateData() override // virtual void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId) override { auto input = this->GetInput(); // const auto output = this->GetOutput(); // itk::ImageRegionConstIterator inputIt(input, outputRegionForThread); // itk::ImageRegionIterator outputIt(output, outputRegionForThread); itk::ImageRegionConstIterator inputIt(input, input->GetLargestPossibleRegion()); itk::ImageRegionIterator outputIt(output, output->GetLargestPossibleRegion()); while (!outputIt.IsAtEnd()) { outputIt.Set(CalculateUncertainty(inputIt.Get())); ++inputIt; ++outputIt; } } private: // ITK examples do this... PredictionUncertaintyFilter(const Self&); void operator=(const Self&); }; } #endif diff --git a/Modules/Classification/CLActiveLearning/include/mitkSelectHighestUncertaintyRegionFilter.h b/Modules/Classification/CLActiveLearning/include/mitkSelectHighestUncertaintyRegionFilter.h index 44a3912c24..c0f04bc201 100644 --- a/Modules/Classification/CLActiveLearning/include/mitkSelectHighestUncertaintyRegionFilter.h +++ b/Modules/Classification/CLActiveLearning/include/mitkSelectHighestUncertaintyRegionFilter.h @@ -1,82 +1,82 @@ /*=================================================================== 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 mitkSelectHighestUncertaintyRegionFilter_h #define mitkSelectHighestUncertaintyRegionFilter_h #include #include // ITK #include #include namespace mitk { /** \class SelectHighestUncertaintyRegionFilter * \brief This class will black out everything that is not part of the region with the highest uncertainty * * Expects an already thresholded image (i.e. values smaller threshold = 0). Will black out everything that does * not belong to the region with the highest sum of uncertainties. */ template - class MITKCLACTIVELEARNING_EXPORT SelectHighestUncertaintyRegionFilter : public itk::LabelShapeKeepNObjectsImageFilter + class SelectHighestUncertaintyRegionFilter : public itk::LabelShapeKeepNObjectsImageFilter { public: typedef itk::LabelShapeKeepNObjectsImageFilter SuperClassName; typedef typename itk::LabelShapeKeepNObjectsImageFilter::AttributeType AttributeType; mitkClassMacroItkParent(SelectHighestUncertaintyRegionFilter, SuperClassName) itkNewMacro(Self) // We want the attribute to be fixed void SetAttribute(AttributeType) override {} void SetAttribute(const std::string&){} protected: SelectHighestUncertaintyRegionFilter() { m_Attribute = Superclass::LabelObjectType::PHYSICAL_SIZE; Superclass::SetAttribute(m_Attribute); Superclass::SetBackgroundValue(0); Superclass::SetNumberOfObjects(1); Superclass::SetReverseOrdering(false); } ~SelectHighestUncertaintyRegionFilter(){} virtual void PrintSelf(std::ostream & os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "Attribute: " << "PhysicalSize" << std::endl; } private: // ITK examples do this... SelectHighestUncertaintyRegionFilter(const Self&); void operator=(const Self&); AttributeType m_Attribute; }; } #endif diff --git a/Modules/Classification/CLActiveLearning/test/mitkActiveLearningTest.cpp b/Modules/Classification/CLActiveLearning/test/mitkActiveLearningTest.cpp index 474f7d1d50..8ac576158c 100644 --- a/Modules/Classification/CLActiveLearning/test/mitkActiveLearningTest.cpp +++ b/Modules/Classification/CLActiveLearning/test/mitkActiveLearningTest.cpp @@ -1,267 +1,267 @@ /*=================================================================== 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. ===================================================================*/ // ITK #include #include #include #include #include #include #include #include // MITK #include #include #include #include // To be tested #include #include #include #include #include class mitkActiveLearningTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkActiveLearningTestSuite); MITK_TEST(PredictionEntropyFilterTest); MITK_TEST(ActiveLearningSuggestRegionFilterTest); CPPUNIT_TEST_SUITE_END(); public: typedef itk::Image ImageType; typedef itk::Image BinaryImageType; typedef itk::VectorImage VectorImageType; - typedef typename ImageType::PixelType PixelType; - typedef typename ImageType::IndexType IndexType; - typedef typename ImageType::RegionType RegionType; - typedef typename VectorImageType::IndexType VectorIndexType; + typedef ImageType::PixelType PixelType; + typedef ImageType::IndexType IndexType; + typedef ImageType::RegionType RegionType; + typedef VectorImageType::IndexType VectorIndexType; typedef itk::VariableLengthVector VectorType; void setUp() { // Create random test image int dim = 100; itk::Size<3> size; size.Fill(dim); auto randImageSource = itk::RandomImageSource::New(); randImageSource->SetNumberOfThreads(1); // so results are not random randImageSource->SetSize(size); randImageSource->Update(); m_TestImageRandom = randImageSource->GetOutput(); // Create gradient test image dim = 100; size.Fill(dim); RegionType region; region.SetSize(size); m_TestImageGradient = ImageType::New(); m_TestImageGradient->SetRegions(region); m_TestImageGradient->Allocate(); auto it = itk::ImageRegionIterator(m_TestImageGradient, m_TestImageGradient->GetLargestPossibleRegion()); PixelType val(0); while (!it.IsAtEnd()) { auto index = it.GetIndex(); float max = static_cast(dim); float sum = index[0] + index[1] + index[2]; // Linear gradient [0, 1] // val = sum / (3*max); // soft spheres if ((index[0] / max) > 0.5 && (index[1] / max) > 0.5 && (index[2] / max) > 0.5) { val = (-std::sin(2 * 3.14 * index[0] / max) * std::sin(2 * 3.14 * index[1] / max) * std::sin(2 * 3.14 * index[2] / max) + 1) / 2.; } else { val = (std::sin(4 * 3.14 * index[0] / max) * std::sin(4 * 3.14 * index[1] / max) * std::sin(4 * 3.14 * index[2] / max) + 1) / 2.; } it.Set(static_cast(val)); ++it; } // Create vector image & fill manually dim = 2; size.Fill(dim); region.SetSize(size); m_TestImageVector = VectorImageType::New(); m_TestImageVector->SetRegions(region); m_TestImageVector->SetVectorLength(3); m_TestImageVector->Allocate(); VectorIndexType index; VectorType vector; vector.SetSize(3); // Absolute certainty (should be 0.0) index[0] = 0; index[1] = 0; index[2] = 0; vector[0] = 1.0; vector[1] = 0.0; vector[2] = 0.0; m_TestImageVector->SetPixel(index, vector); // certain index[0] = 0; index[1] = 0; index[2] = 1; vector[0] = 0.9; vector[1] = 0.05; vector[2] = 0.05; m_TestImageVector->SetPixel(index, vector); // fairly certain index[0] = 0; index[1] = 1; index[2] = 0; vector[0] = 0.6; vector[1] = 0.3; vector[2] = 0.1; m_TestImageVector->SetPixel(index, vector); // zero margin index[0] = 0; index[1] = 1; index[2] = 1; vector[0] = 0.45; vector[1] = 0.45; vector[2] = 0.1; m_TestImageVector->SetPixel(index, vector); // absolute uncertainty (should be 1.0) index[0] = 1; index[1] = 0; index[2] = 0; vector[0] = 0.333; vector[1] = 0.333; vector[2] = 0.333; m_TestImageVector->SetPixel(index, vector); // normal not normalized index[0] = 1; index[1] = 0; index[2] = 1; vector[0] = 1.2; vector[1] = 0.6; vector[2] = 0.1; m_TestImageVector->SetPixel(index, vector); // error case... (should be 1.0) index[0] = 1; index[1] = 1; index[2] = 0; vector[0] = 0.0; vector[1] = 0.0; vector[2] = 0.0; m_TestImageVector->SetPixel(index, vector); // Absolute uncertainty & certainty (should be 1.0) index[0] = 1; index[1] = 1; index[2] = 1; vector[0] = 1.0; vector[1] = 1.0; vector[2] = 1.0; m_TestImageVector->SetPixel(index, vector); // Save gradient image auto writer = itk::ImageFileWriter::New(); writer->SetFileName("/home/jens/Desktop/ALtest/gradientImage.nrrd"); writer->SetInput(m_TestImageGradient); writer->Update(); auto writerVec = itk::ImageFileWriter::New(); writerVec->SetFileName("/home/jens/Desktop/ALtest/vectorImage.nrrd"); writerVec->SetInput(m_TestImageVector); writerVec->Update(); } void tearDown() { m_TestImageRandom = nullptr; m_TestImageGradient = nullptr; m_TestImageVector = nullptr; } void PredictionEntropyFilterTest() { auto entropyFilter = mitk::PredictionEntropyFilter::New(); entropyFilter->SetInput(m_TestImageVector); entropyFilter->Update(); auto writer = itk::ImageFileWriter::New(); writer->SetFileName("/home/jens/Desktop/ALtest/vectorImageEntropy.nrrd"); writer->SetInput(entropyFilter->GetOutput()); writer->Update(); } void ActiveLearningSuggestRegionFilterTest() { PixelType threshold = 0.7; // Threshold filter auto thresholdFilter = itk::BinaryThresholdImageFilter::New(); thresholdFilter->SetOutsideValue(0); thresholdFilter->SetInsideValue(1); thresholdFilter->SetLowerThreshold(threshold); thresholdFilter->SetInput(m_TestImageGradient); thresholdFilter->Update(); // Save thresholded image auto binaryWriter = itk::ImageFileWriter::New(); binaryWriter->SetFileName("/home/jens/Desktop/ALtest/gradientImageThresholded.nrrd"); binaryWriter->SetInput(thresholdFilter->GetOutput()); binaryWriter->Update(); // Connected component filter auto ccFilter = itk::ConnectedComponentImageFilter::New(); ccFilter->SetInput(thresholdFilter->GetOutput()); ccFilter->Update(); // Save image with connected components binaryWriter->SetFileName("/home/jens/Desktop/ALtest/gradientImageCC.nrrd"); binaryWriter->SetInput(ccFilter->GetOutput()); binaryWriter->Update(); // Select the one with greatest uncertainty sum int ccCount = static_cast(ccFilter->GetObjectCount()); MITK_INFO << "Number of components: " << ccCount; std::map componentSize; for (int a=1; a<=ccCount; ++a) {componentSize[a] = 0.0;} auto imageIterator = itk::ImageRegionConstIterator(m_TestImageGradient, m_TestImageGradient->GetLargestPossibleRegion()); auto binaryImageIterator = itk::ImageRegionConstIterator(ccFilter->GetOutput(), ccFilter->GetOutput()->GetLargestPossibleRegion()); while (!binaryImageIterator.IsAtEnd()) { unsigned short binVal = binaryImageIterator.Get(); float val = imageIterator.Get(); if (binVal != 0) {componentSize[binVal] += val;} ++binaryImageIterator; ++imageIterator; } - using PairType = decltype(componentSize)::value_type; + using PairType = std::map::value_type; auto maxComp = std::max_element(componentSize.begin(), componentSize.end(), [](const PairType& lhs, const PairType& rhs){return lhs.second < rhs.second;}); auto thresholdFilter2 = itk::BinaryThresholdImageFilter::New(); thresholdFilter2->SetOutsideValue(0); thresholdFilter2->SetInsideValue(1); thresholdFilter2->SetLowerThreshold(maxComp->first); thresholdFilter2->SetUpperThreshold(maxComp->first); thresholdFilter2->SetInput(ccFilter->GetOutput()); thresholdFilter2->Update(); // Save optimal region binaryWriter->SetFileName("/home/jens/Desktop/ALtest/gradientImageSuggestedRegionReference.nrrd"); binaryWriter->SetInput(thresholdFilter2->GetOutput()); binaryWriter->Update(); // Doe the same with suggestion filter auto suggestFilter = mitk::ActiveLearningSuggestRegionFilter::New(); suggestFilter->SetThreshold(threshold); suggestFilter->SetInput(m_TestImageGradient); suggestFilter->Update(); // Save suggested region binaryWriter->SetFileName("/home/jens/Desktop/ALtest/gradientImageSuggestedRegion.nrrd"); binaryWriter->SetInput(suggestFilter->GetOutput()); binaryWriter->Update(); } - typename ImageType::Pointer m_TestImageRandom; - typename ImageType::Pointer m_TestImageGradient; - typename VectorImageType::Pointer m_TestImageVector; + ImageType::Pointer m_TestImageRandom; + ImageType::Pointer m_TestImageGradient; + VectorImageType::Pointer m_TestImageVector; }; MITK_TEST_SUITE_REGISTRATION(mitkActiveLearning) diff --git a/Plugins/org.mitk.gui.qt.activelearning/src/internal/QmitkActiveLearning.cpp b/Plugins/org.mitk.gui.qt.activelearning/src/internal/QmitkActiveLearning.cpp index db32040810..1821ab718c 100644 --- a/Plugins/org.mitk.gui.qt.activelearning/src/internal/QmitkActiveLearning.cpp +++ b/Plugins/org.mitk.gui.qt.activelearning/src/internal/QmitkActiveLearning.cpp @@ -1,1429 +1,1429 @@ /*=================================================================== 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 // Qt #include #include #include #include #include #include // Qmitk #include "QmitkActiveLearning.h" // MITK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // ITK/VTK #include #include #include #include #include #include #include #include #include #include #include typedef ActiveLearning::FeaturePixelType FeaturePixelType; typedef ActiveLearning::AnnotationPixelType AnnotationPixelType; typedef ActiveLearning::LabelPixelType LabelPixelType; typedef ActiveLearning::FeatureMatrixType FeatureMatrixType; typedef ActiveLearning::LabelVectorType LabelVectorType; // Returns true if list has at least one entry and all entries are valid mitk::Images, otherwise false static bool SelectionAllImages(const QList& nodes) { if (nodes.empty()) { return false; } for (const auto& node : nodes) { if(!(node.IsNotNull() && dynamic_cast(node->GetData()) != nullptr)) return false; } return true; } // QColor to mitk::Color static mitk::Color QColorToMitkColor(const QColor& qcolor) { mitk::Color color; color.SetRed((float)qcolor.red() / 255); color.SetGreen((float)qcolor.green() / 255); color.SetBlue((float)qcolor.blue() / 255); return color; } // For debugging static void PrintAllLabels(mitk::LabelSetImage* image) { for (auto it=image->GetActiveLabelSet()->IteratorBegin(); it!=image->GetActiveLabelSet()->IteratorConstEnd(); ++it) { MITK_INFO << "Key: " << it->first << " - Name: " << it->second->GetName() << " - Value: " << it->second->GetValue() << " - Color: " << it->second->GetColor(); } } // Make values of labels a consistent range static void FillLabelValues(mitk::LabelSetImage* image) { int value(0); for (auto it=image->GetActiveLabelSet()->IteratorBegin(); it!=image->GetActiveLabelSet()->IteratorConstEnd(); ++it) { it->second->SetValue(value); value++; } image->GetActiveLabelSet()->SetActiveLabel(0); } // Fill image with zeros static void FillWithZeros(mitk::Image* image) { unsigned int size = image->GetPixelType().GetSize(); for (unsigned int i=0; iGetDimension(); i++) { size *= image->GetDimension(i); } for (unsigned int t=0; tGetTimeSteps(); t++) { mitk::ImageWriteAccessor accessor(image, image->GetVolumeData(0)); memset(accessor.GetData(), 0, size); } } template static Eigen::Matrix Transform(const std::vector images) { // Find size for output matrix [number of voxels, number of feature images] unsigned int size = images[0]->GetDimension(0); for (unsigned int i=1; i<3; ++i) { size *= images[0]->GetDimension(i); } Eigen::Matrix outputMatrix(size, images.size()); for (unsigned int i=0; i::Pointer imageItk; mitk::CastToItkImage(images[i], imageItk); outputMatrix.col(i) = Eigen::Matrix::Map(imageItk->GetBufferPointer(), size); } return outputMatrix; } template static mitk::Image::Pointer Transform(const Eigen::Matrix &inputMatrix, const mitk::Image::Pointer referenceImage) { typename itk::Image::Pointer imageItk; auto outputImage = mitk::Image::New(); outputImage->Initialize(mitk::MakeScalarPixelType(), *(referenceImage->GetTimeGeometry()->Clone())); mitk::CastToItkImage(outputImage, imageItk); auto it = itk::ImageRegionIterator>(imageItk, imageItk->GetLargestPossibleRegion()); int i = 0; while (!it.IsAtEnd()) { it.Set(inputMatrix(i, 0)); ++it; ++i; } mitk::GrabItkImageMemory(imageItk, outputImage); return outputImage; } template static std::vector Transform(const Eigen::Matrix &inputMatrix, const mitk::Image::Pointer referenceImage) { std::vector resultVector; for (int j=0; j::Pointer imageItk; auto outputImage = mitk::Image::New(); outputImage->Initialize(mitk::MakeScalarPixelType(), *(referenceImage->GetTimeGeometry()->Clone())); mitk::CastToItkImage(outputImage, imageItk); auto it = itk::ImageRegionIterator>(imageItk, imageItk->GetLargestPossibleRegion()); int i = 0; while (!it.IsAtEnd()) { it.Set(static_cast(inputMatrix(i, j))); ++it; ++i; } mitk::GrabItkImageMemory(imageItk, outputImage); resultVector.push_back(outputImage); } return resultVector; } template static void PrintMatrix(const Eigen::Matrix dataMatrix, int maxRows = 0) { if (maxRows == 0 || maxRows > dataMatrix.rows()) maxRows = dataMatrix.rows(); MITK_INFO << "---------------------"; for (int i=0; i static void PrintMatrix(const Eigen::Matrix dataMatrix, const Eigen::Matrix labelMatrix, int maxRows = 0) { if (labelMatrix.rows() < dataMatrix.rows()) return; if (maxRows == 0 || maxRows > dataMatrix.rows()) maxRows = dataMatrix.rows(); MITK_INFO << "---------------------"; for (int i=0; i static void GaussianSmoothing(const itk::Image* inputImage, const double sigma, mitk::Image::Pointer outputImage) { auto spacing = inputImage->GetSpacing(); float mean_spacing = (spacing[0] + spacing[1] + spacing[2]) / 3.; typedef itk::Image ImageType; typedef itk::Image FeatureImageType; auto filter = itk::DiscreteGaussianImageFilter::New(); filter->SetInput(inputImage); filter->SetVariance(sigma*sigma*mean_spacing*mean_spacing); filter->Update(); mitk::GrabItkImageMemory(filter->GetOutput(), outputImage); } template static void GaussianGradientMagnitude(const itk::Image* inputImage, const double sigma, mitk::Image::Pointer outputImage) { auto spacing = inputImage->GetSpacing(); float mean_spacing = (spacing[0] + spacing[1] + spacing[2]) / 3.; typedef itk::Image ImageType; typedef itk::Image FeatureImageType; auto filter = itk::GradientMagnitudeRecursiveGaussianImageFilter::New(); filter->SetInput(inputImage); filter->SetSigma(sigma*mean_spacing); filter->Update(); mitk::GrabItkImageMemory(filter->GetOutput(), outputImage); } template static void LaplacianOfGaussian(const itk::Image* inputImage, const double sigma, mitk::Image::Pointer outputImage) { auto spacing = inputImage->GetSpacing(); float mean_spacing = (spacing[0] + spacing[1] + spacing[2]) / 3.; typedef itk::Image ImageType; typedef itk::Image FeatureImageType; auto filter = itk::LaplacianRecursiveGaussianImageFilter::New(); filter->SetInput(inputImage); filter->SetSigma(sigma*mean_spacing); filter->Update(); mitk::GrabItkImageMemory(filter->GetOutput(), outputImage); } template static void StructureTensorEigenvalues(const itk::Image* inputImage, float sigma, std::vector outputImages) { // typedef itk::Image ImageType; // auto filter = itk::StructureTensorEigenvalueImageFilter::New(); // filter->SetInput(inputImage); // filter->SetInnerScale(sigma); // filter->SetOuterScale(sigma); // filter->Update(); // for (unsigned int i=0; iGetNumberOfOutputs(); i++) // { // mitk::GrabItkImageMemory(filter->GetOutput(i), outputImages[i]); // } auto spacing = inputImage->GetSpacing(); float mean_spacing = (spacing[0] + spacing[1] + spacing[2]) / 3.; typedef itk::Image ImageType; typedef itk::Image, imageDimension> TensorImageType; typename itk::StructureTensorImageFilter::Pointer filter = itk::StructureTensorImageFilter::New(); filter->SetInput(inputImage); filter->SetNoiseScale(sigma*mean_spacing); filter->SetFeatureScale(sigma*mean_spacing); filter->Update(); std::vector eigenValueImages; std::vector> eigenValueImageIterators; for (unsigned int i=0; iSetRegions(inputImage->GetLargestPossibleRegion()); image->Allocate(); eigenValueImages.push_back(image); itk::ImageRegionIterator it(image, image->GetLargestPossibleRegion()); eigenValueImageIterators.push_back(it); } itk::ImageRegionConstIterator tensorImageIterator(filter->GetOutput(), filter->GetOutput()->GetLargestPossibleRegion()); while (!tensorImageIterator.IsAtEnd()) { typename TensorImageType::PixelType::EigenValuesArrayType ev; tensorImageIterator.Get().ComputeEigenValues(ev); for (unsigned int i=0; i static void HessianEigenvalues(const itk::Image* inputImage, float sigma, std::vector outputImages) { auto spacing = inputImage->GetSpacing(); float mean_spacing = (spacing[0] + spacing[1] + spacing[2]) / 3.; typedef itk::Image ImageType; typedef itk::Image, imageDimension> TensorImageType; typename itk::HessianRecursiveGaussianImageFilter::Pointer filter = itk::HessianRecursiveGaussianImageFilter::New(); filter->SetInput(inputImage); filter->SetSigma(sigma*mean_spacing); filter->Update(); std::vector eigenValueImages; std::vector> eigenValueImageIterators; for (unsigned int i=0; iSetRegions(inputImage->GetLargestPossibleRegion()); image->Allocate(); eigenValueImages.push_back(image); itk::ImageRegionIterator it(image, image->GetLargestPossibleRegion()); eigenValueImageIterators.push_back(it); } itk::ImageRegionConstIterator tensorImageIterator(filter->GetOutput(), filter->GetOutput()->GetLargestPossibleRegion()); while (!tensorImageIterator.IsAtEnd()) { typename TensorImageType::PixelType::EigenValuesArrayType ev; tensorImageIterator.Get().ComputeEigenValues(ev); for (unsigned int i=0; i ImageType; // typedef itk::Image FeatureImageType; // auto filter = itk::HessianMatrixEigenvalueImageFilter::New(); // filter->SetInput(inputImage); // filter->SetSigma(sigma); // filter->Update(); // mitk::GrabItkImageMemory(filter->GetOutput(0), outputImages[0]); // mitk::GrabItkImageMemory(filter->GetOutput(1), outputImages[1]); // mitk::GrabItkImageMemory(filter->GetOutput(2), outputImages[2]); } /* ================================================================== * PUBLIC SLOTS * =============================================================== */ void ActiveLearning::Initialize() { // Get selected nodes and check again if these are all images m_Nodes = this->GetDataManagerSelection(); if (!SelectionAllImages(m_Nodes)) return; m_Controls.m_InitializePushButton->setDisabled(true); emit SignalSetProgressMaximum(m_Nodes.length() * 10 + 1); // 6 is number of features, shouldn't be hardcoded emit SignalResetProgress(); // Set names to the label (again) QString nameList = QString::fromStdString(m_Nodes[0]->GetName()); if (m_Nodes.length() >= 2) { for (int i=1; i"); nameList += QString::fromStdString(m_Nodes[i]->GetName()); } } m_Controls.m_InitializeLabel->setText(nameList); // ======================================= // SEGMENTATION IMAGE // ======================================= m_SegmentationImage = mitk::Image::New(); try { mitk::Image::Pointer referenceImage = dynamic_cast(m_Nodes[0]->GetData()); m_SegmentationImage->Initialize(mitk::MakeScalarPixelType(), *(referenceImage->GetTimeGeometry()->Clone())); } catch (mitk::Exception& e) { MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(m_Parent, "Error", "Could not initialize segmentation image"); return; } FillWithZeros(m_SegmentationImage); m_SegmentationNode = mitk::DataNode::New(); m_SegmentationNode->SetData(m_SegmentationImage); m_SegmentationNode->SetName("Segmentation"); m_SegmentationNode->SetColor(1., 1., 1.); m_SegmentationNode->SetBoolProperty("binary", false); m_SegmentationNode->SetProperty("reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_NEAREST)); this->GetDataStorage()->Add(m_SegmentationNode, m_Nodes[0]); // ======================================= // ANNOTATION IMAGE // ======================================= m_AnnotationImage = mitk::Image::New(); try { mitk::Image::Pointer referenceImage = dynamic_cast(m_Nodes[0]->GetData()); m_AnnotationImage->Initialize(mitk::MakeScalarPixelType(), *(referenceImage->GetTimeGeometry()->Clone())); } catch (mitk::Exception& e) { MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(m_Parent, "Error", "Could not initialize annotation image"); return; } FillWithZeros(m_AnnotationImage); m_AnnotationNode = mitk::DataNode::New(); m_AnnotationNode->SetData(m_AnnotationImage); m_AnnotationNode->SetName("Labels"); m_AnnotationNode->SetColor(1., 1., 1.); m_AnnotationNode->SetBoolProperty("binary", false); m_AnnotationNode->SetProperty("reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_NEAREST)); m_AnnotationNode->SetProperty("opacity", mitk::FloatProperty::New(1.0f)); this->GetDataStorage()->Add(m_AnnotationNode, m_Nodes[0]); // ======================================= // UNCERTAINTY NODE // ======================================= m_UncertaintyNode = mitk::DataNode::New(); m_UncertaintyNode->SetName("Uncertainty"); m_UncertaintyNode->SetColor(0., 1., 0.95); m_UncertaintyNode->SetBoolProperty("binary", false); m_UncertaintyNode->SetProperty("opacity", mitk::FloatProperty::New(0.6)); m_UncertaintyNode->SetVisibility(false); this->GetDataStorage()->Add(m_UncertaintyNode, m_Nodes[0]); // ======================================= // UNCERTAINTY REGION NODE // ======================================= m_UncertaintyRegionNode = mitk::DataNode::New(); m_UncertaintyRegionNode->SetName("Region"); m_UncertaintyRegionNode->SetColor(1., 1., 1.); m_UncertaintyRegionNode->SetBoolProperty("binary", false); m_UncertaintyRegionNode->SetProperty("opacity", mitk::FloatProperty::New(0.8)); m_UncertaintyRegionNode->SetVisibility(true); m_UncertaintyRegionNode->SetBoolProperty("fixedLayer", true); m_UncertaintyRegionNode->SetProperty("layer", mitk::IntProperty::New(99)); this->GetDataStorage()->Add(m_UncertaintyRegionNode, m_Nodes[0]); // Convert input images to FeaturePixelType for (auto node : m_Nodes) { mitk::Image::Pointer image = dynamic_cast(node->GetData()); auto itkImage = itk::Image::New(); mitk::CastToItkImage(image, itkImage); mitk::GrabItkImageMemory(itkImage, image); node->SetData(image); } emit SignalSetProgress(1); // Calculate features for (const auto node : m_Nodes) { mitk::Image::Pointer currentImage = dynamic_cast(node->GetData()); QFuture>> future; future = QtConcurrent::run(this, &ActiveLearning::CalculateFeatures, currentImage); auto futureWatcher = new QFutureWatcher>>(); futureWatcher->setFuture(future); connect(futureWatcher, SIGNAL(finished()), this, SLOT(OnInitializationFinished())); m_FeatureCalculationWatchers.push_back(futureWatcher); } // Interactor auto activeLearningLib = us::ModuleRegistry::GetModule("MitkCLActiveLearning"); m_Interactor = mitk::ActiveLearningInteractor::New(); m_Interactor->LoadStateMachine("Paint.xml", activeLearningLib); m_Interactor->SetEventConfig("PaintConfig.xml", activeLearningLib); m_Interactor->SetDataNode(m_AnnotationNode); // Automatically add first label OnAddLabelPushButtonClicked(); m_Active = true; } /* ================================================================== * PUBLIC * =============================================================== */ ActiveLearning::ActiveLearning() : m_Parent(nullptr), m_AnnotationImage(nullptr), m_AnnotationNode(nullptr), m_SegmentationImage(nullptr), m_SegmentationNode(nullptr), m_Active(false), m_Guidance(false), m_NumberOfTrees(50), m_MaximumTreeDepth(10), m_SamplesPerTree(0.66), m_PredictionMatrix(nullptr), m_Logger() { } ActiveLearning::~ActiveLearning() { } void ActiveLearning::CreateQtPartControl( QWidget *parent ) { m_Controls.setupUi(parent); m_Parent = parent; // Label model m_LabelListModel = new QStandardItemModel(0, 3, this); m_Controls.m_LabelTableView->setModel(m_LabelListModel); m_Controls.m_LabelTableView->horizontalHeader()->setDefaultSectionSize(20); m_Controls.m_LabelTableView->verticalHeader()->setDefaultSectionSize(20); NotEditableDelegate* itemDelegate = new NotEditableDelegate(parent); m_Controls.m_LabelTableView->setItemDelegateForColumn(1, itemDelegate); // Connects connect(m_Controls.m_LabelTableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnColorIconDoubleClicked(QModelIndex))); connect(m_Controls.m_LabelTableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(OnLabelListSelectionChanged(QItemSelection, QItemSelection))); connect(m_LabelListModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(OnLabelNameChanged(QModelIndex, QModelIndex))); connect(m_Controls.m_InitializePushButton, SIGNAL(clicked()), this, SLOT(Initialize())); connect(m_Controls.m_AddLabelPushButton, SIGNAL(clicked()), this, SLOT(OnAddLabelPushButtonClicked())); connect(m_Controls.m_RemoveLabelPushButton, SIGNAL(clicked()), this, SLOT(OnRemoveLabelPushButtonClicked())); connect(m_Controls.m_PaintToolButton, SIGNAL(clicked()), this, SLOT(OnPaintToolButtonClicked())); connect(m_Controls.m_EraseToolButton, SIGNAL(clicked()), this, SLOT(OnEraseToolButtonClicked())); connect(m_Controls.m_SaveSegmentationPushButton, SIGNAL(clicked()), this, SLOT(OnSaveSegmentationPushButtonClicked())); connect(m_Controls.m_SavePredictionsPushButton, SIGNAL(clicked()), this, SLOT(OnSavePredictionsPushButtonClicked())); connect(m_Controls.m_UpdatePredictionsPushButton, SIGNAL(clicked()), this, SLOT(OnUpdatePredictionsPushButtonClicked())); connect(this, SIGNAL(SignalIncrementProgress()), this, SLOT(OnSignalIncrementProgress())); connect(this, SIGNAL(SignalSetProgress(int)), this, SLOT(OnSignalSetProgress(int))); connect(this, SIGNAL(SignalResetProgress()), this, SLOT(OnSignalResetProgress())); connect(this, SIGNAL(SignalSetProgressMaximum(int)), this, SLOT(OnSignalSetProgressMaximum(int))); connect(m_Controls.m_BrushSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(OnBrushSizeSliderValueChanged(int))); connect(m_Controls.m_ActiveGuidanceCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnActiveGuidanceCheckBoxToggled(int))); connect(m_Controls.m_LoggerToolButton, SIGNAL(clicked()), this, SLOT(OnLoggerToolButtonClicked())); // Set start configuration m_Controls.m_LabelControlsFrame->setVisible(false); SetInitializeReady(false); } void ActiveLearning::ResetLabels() { for (int i=0; irowCount(); i++) { m_LabelListModel->item(i, 1)->setText(QString::number(i + 1)); } } std::vector > ActiveLearning::CalculateFeatures(const mitk::Image::Pointer inputImage) { std::vector> result; // TODO: Get features from preference page - std::vector sigmas = {0.7, 1.6}; + std::vector sigmas = {0.7f, 1.6f}; for (auto sigma : sigmas) { std::stringstream ss; auto gaussImage = mitk::Image::New(); AccessByItk_n(inputImage, GaussianSmoothing, (sigma, gaussImage)); gaussImage->SetClonedTimeGeometry(inputImage->GetTimeGeometry()); ss << "GaussianSmoothing (" << std::fixed << std::setprecision(2) << sigma << ")"; result.push_back(std::pair(gaussImage, ss.str())); ss.str(""); emit SignalIncrementProgress(); auto gradMagImage = mitk::Image::New(); AccessByItk_n(inputImage, GaussianGradientMagnitude, (sigma, gradMagImage)); gradMagImage->SetClonedTimeGeometry(inputImage->GetTimeGeometry()); ss << "GaussianGradientMagnitude (" << std::fixed << std::setprecision(2) << sigma << ")"; result.push_back(std::pair(gradMagImage, ss.str())); ss.str(""); emit SignalIncrementProgress(); auto logImage = mitk::Image::New(); AccessByItk_n(inputImage, LaplacianOfGaussian, (sigma, logImage)); logImage->SetClonedTimeGeometry(inputImage->GetTimeGeometry()); ss << "LaplacianOfGaussian (" << std::fixed << std::setprecision(2) << sigma << ")"; result.push_back(std::pair(logImage, ss.str())); ss.str(""); emit SignalIncrementProgress(); auto structImage1 = mitk::Image::New(); auto structImage2 = mitk::Image::New(); auto structImage3 = mitk::Image::New(); std::vector structImages = {structImage1, structImage2, structImage3}; AccessByItk_n(inputImage, StructureTensorEigenvalues, (sigma, structImages)); structImage1->SetClonedTimeGeometry(inputImage->GetTimeGeometry()); structImage2->SetClonedTimeGeometry(inputImage->GetTimeGeometry()); structImage3->SetClonedTimeGeometry(inputImage->GetTimeGeometry()); ss << "StructureTensorEV1 (" << std::fixed << std::setprecision(2) << sigma << ")"; result.push_back(std::pair(structImage1, ss.str())); ss.str(""); ss << "StructureTensorEV2 (" << std::fixed << std::setprecision(2) << sigma << ")"; result.push_back(std::pair(structImage2, ss.str())); ss.str(""); if (inputImage->GetDimension() == 3) { ss << "StructureTensorEV3 (" << std::fixed << std::setprecision(2) << sigma << ")"; result.push_back(std::pair(structImage3, ss.str())); ss.str(""); } emit SignalIncrementProgress(); auto hessianImage1 = mitk::Image::New(); auto hessianImage2 = mitk::Image::New(); auto hessianImage3 = mitk::Image::New(); std::vector hessianImages = {hessianImage1, hessianImage2, hessianImage3}; AccessByItk_n(inputImage, HessianEigenvalues, (sigma, hessianImages)); hessianImage1->SetClonedTimeGeometry(inputImage->GetTimeGeometry()); hessianImage2->SetClonedTimeGeometry(inputImage->GetTimeGeometry()); hessianImage3->SetClonedTimeGeometry(inputImage->GetTimeGeometry()); ss << "HessianEV1 (" << std::fixed << std::setprecision(2) << sigma << ")"; result.push_back(std::pair(hessianImage1, ss.str())); ss.str(""); ss << "HessianEV2 (" << std::fixed << std::setprecision(2) << sigma << ")"; result.push_back(std::pair(hessianImage2, ss.str())); ss.str(""); if (inputImage->GetDimension() == 3) { ss << "HessianEV3 (" << std::fixed << std::setprecision(2) << sigma << ")"; result.push_back(std::pair(hessianImage3, ss.str())); ss.str(""); } emit SignalIncrementProgress(); } return result; } std::pair> ActiveLearning::CalculatePrediction(const mitk::Image::Pointer annotationImage, const std::vector &featureImageVector, const mitk::Image::Pointer referenceImage, mitk::AbstractClassifier* classifier, std::shared_ptr predictionMatrix) { // Create prediction matrix if necessary if (predictionMatrix == nullptr) { FeatureMatrixType mat = Transform(featureImageVector); predictionMatrix = std::make_shared(mat); } emit SignalIncrementProgress(); // Get training data and train auto training = GetTrainingData(annotationImage, featureImageVector); classifier->Train(*training.second, *training.first); emit SignalIncrementProgress(); // Get result LabelVectorType segmentation = classifier->Predict(*predictionMatrix); emit SignalIncrementProgress(); FeatureMatrixType prediction = classifier->GetPointWiseProbabilities(); mitk::Image::Pointer segmentationImage = Transform(segmentation, referenceImage); std::vector predictionImages = Transform(prediction, referenceImage); emit SignalIncrementProgress(); std::pair> result = std::make_pair(segmentationImage, predictionImages); return result; } std::pair ActiveLearning::CalculateUncertainty(const std::vector &probabilityImageVector, const mitk::Image::Pointer referenceImage, bool guidance) { typedef itk::Image ImageType; std::vector itkImages; std::vector> iterators; for (auto image : probabilityImageVector) { - typename ImageType::Pointer itkImage; + ImageType::Pointer itkImage; mitk::CastToItkImage(image, itkImage); itkImages.push_back(itkImage); itk::ImageRegionConstIterator it(itkImage, itkImage->GetLargestPossibleRegion()); iterators.push_back(it); } auto outputImage = mitk::Image::New(); outputImage->Initialize(mitk::MakeScalarPixelType(), *(referenceImage->GetTimeGeometry()->Clone())); - typename ImageType::Pointer uncertaintyImage; + ImageType::Pointer uncertaintyImage; mitk::CastToItkImage(outputImage, uncertaintyImage); itk::ImageRegionIterator uit(uncertaintyImage, uncertaintyImage->GetLargestPossibleRegion()); while (!uit.IsAtEnd()) { FeaturePixelType value = 0; for (unsigned int i=0; iInitialize(mitk::MakeScalarPixelType(), *(referenceImage->GetTimeGeometry()->Clone())); auto regionFilter = mitk::ActiveLearningSuggestRegionFilter>::New(); regionFilter->SetInput(uncertaintyImage); regionFilter->SetThreshold(0.5); regionFilter->Update(); mitk::GrabItkImageMemory(regionFilter->GetOutput(), region); } mitk::GrabItkImageMemory(uncertaintyImage, outputImage); std::pair result = std::make_pair(outputImage, region); return result; } std::pair, std::shared_ptr> ActiveLearning::GetTrainingData(const mitk::Image::Pointer annotationImage, const std::vector &featureImageVector) { // Get indices and labels std::vector> indices; std::vector labels; itk::Image::Pointer annotationImageItk; mitk::CastToItkImage(annotationImage, annotationImageItk); itk::ImageRegionIteratorWithIndex> it(annotationImageItk, annotationImageItk->GetLargestPossibleRegion()); while (!it.IsAtEnd()) { if (it.Get() != 0) { indices.push_back(it.GetIndex()); labels.push_back(it.Get()); } ++it; } FeatureMatrixType trainingData(indices.size(), featureImageVector.size()); LabelVectorType trainingLabels = LabelVectorType::Map(labels.data(), labels.size()); int j = 0; for (mitk::Image::Pointer feature : featureImageVector) { int i = 0; mitk::ImagePixelReadAccessor access(feature, feature->GetVolumeData()); for (auto index : indices) { trainingData(i, j) = access.GetPixelByIndexSafe(index); i++; } j++; } auto trainingLabelsPtr = std::make_shared(trainingLabels); auto trainingDataPtr = std::make_shared(trainingData); std::pair, std::shared_ptr> result = std::make_pair(trainingLabelsPtr, trainingDataPtr); return result; } void ActiveLearning::UpdateLookupTables() { // Create new lookup table from list // Annotation type is int, but we only use a ushort lookup table auto lut = vtkSmartPointer::New(); int lowlim = std::numeric_limits::min(); int uplim = std::numeric_limits::max(); lut->SetNumberOfTableValues(uplim - lowlim + 1); lut->SetTableRange(lowlim, uplim); for (long i=0; i<(uplim-lowlim+1); ++i) { lut->SetTableValue(i, 0.0, 0.0, 0.0, 0.0); } for (int j=0; jrowCount(); ++j) { int value = m_LabelListModel->item(j, 1)->text().toInt(); const QColor color = m_LabelListModel->item(j, 0)->background().color(); lut->SetTableValue(value, color.redF(), color.greenF(), color.blueF(), 1.0); } auto lutMitk = mitk::LookupTable::New(); lutMitk->SetVtkLookupTable(lut); // Set to annotation image and segmentation image auto * lut_prop = dynamic_cast(m_AnnotationNode->GetProperty("LookupTable")); lut_prop->SetLookupTable(lutMitk); m_AnnotationNode->SetProperty("Image Rendering.Mode", mitk::RenderingModeProperty::New(mitk::RenderingModeProperty::LOOKUPTABLE_COLOR)); m_AnnotationNode->Modified(); lut_prop = dynamic_cast(m_SegmentationNode->GetProperty("LookupTable")); lut_prop->SetLookupTable(lutMitk); m_SegmentationNode->SetProperty("Image Rendering.Mode", mitk::RenderingModeProperty::New(mitk::RenderingModeProperty::LOOKUPTABLE_COLOR)); m_SegmentationNode->Modified(); } void ActiveLearning::UpdatePredictionNodes() { if (m_LabelListModel->rowCount() == 0) return; // Build lookup table vtkSmartPointer lut = vtkSmartPointer::New(); lut->SetTableRange (0, 1); lut->SetSaturationRange (0, 0); lut->SetHueRange (0, 0); lut->SetValueRange (0, 1); lut->SetAlphaRange (0, 1); lut->Build(); auto lutMitk = mitk::LookupTable::New(); lutMitk->SetVtkLookupTable(lut); for (int i=0; irowCount(); ++i) { auto property = mitk::NodePredicateProperty::New("segmentation_value", mitk::IntProperty::New(m_LabelListModel->item(i, 1)->text().toInt())); auto nodes = this->GetDataStorage()->GetDerivations(m_Nodes[0], property); if (nodes->Size() == 1) { auto node = nodes->GetElement(0); QString name = "Prediction "; name += m_LabelListModel->item(i, 2)->text(); node->SetName(name.toStdString()); auto * lut_prop = dynamic_cast(node->GetProperty("LookupTable")); lut_prop->SetLookupTable(lutMitk); node->SetProperty("Image Rendering.Mode", mitk::RenderingModeProperty::New(mitk::RenderingModeProperty::LOOKUPTABLE_COLOR)); node->SetColor(QColorToMitkColor(m_LabelListModel->item(i, 0)->background().color())); node->Modified(); } if (nodes->Size() > 1) mitkThrow(); } // Uncertainty image auto *lut_prop = dynamic_cast(m_UncertaintyNode->GetProperty("LookupTable")); if (lut_prop != nullptr) { lut_prop->SetLookupTable(lutMitk); m_UncertaintyNode->SetProperty("Image Rendering.Mode", mitk::RenderingModeProperty::New(mitk::RenderingModeProperty::LOOKUPTABLE_COLOR)); } vtkSmartPointer lut2 = vtkSmartPointer::New(); lut2->SetRampToLinear(); lut2->SetSaturationRange (0., 0.); lut2->SetHueRange (0., 0.); lut2->SetValueRange (0., 1.); lut2->SetAlphaRange (1., 0.); lut2->Build(); auto lutMitk2 = mitk::LookupTable::New(); lutMitk2->SetVtkLookupTable(lut2); lut_prop = dynamic_cast(m_UncertaintyRegionNode->GetProperty("LookupTable")); if (lut_prop != nullptr) { lut_prop->SetLookupTable(lutMitk2); m_UncertaintyRegionNode->SetProperty("Image Rendering.Mode", mitk::RenderingModeProperty::New(mitk::RenderingModeProperty::LOOKUPTABLE_COLOR)); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } const std::string ActiveLearning::VIEW_ID = "org.mitk.views.activelearning"; /* ================================================================== * PROTECTED SLOTS * =============================================================== */ void ActiveLearning::OnSignalIncrementProgress() { m_Controls.m_ProgressBar->setValue(m_Controls.m_ProgressBar->value() + 1); } void ActiveLearning::OnSignalSetProgress(int value) { m_Controls.m_ProgressBar->setValue(value); } void ActiveLearning::OnSignalResetProgress() { m_Controls.m_ProgressBar->setValue(0); } void ActiveLearning::OnSignalSetProgressMaximum(int value) { m_Controls.m_ProgressBar->setMaximum(value); } void ActiveLearning::OnAddLabelPushButtonClicked() { QString labelName = QString("Label ") + QString::number(m_LabelListModel->rowCount() + 1); QColor labelColor = Qt::GlobalColor(m_LabelListModel->rowCount() % 12 + 7); // We only want Qt default colors 7 to 18 // Create icon QStandardItem* colorSquare = new QStandardItem; colorSquare->setBackground(labelColor); colorSquare->setEditable(false); QPixmap colorPixmap(20, 20); colorPixmap.fill(labelColor); colorSquare->setIcon(QIcon(colorPixmap)); // Key is the highest existing key + 1 int value = 1; if (m_LabelListModel->rowCount() >= 1) { value = m_LabelListModel->item(m_LabelListModel->rowCount() - 1, 1)->text().toInt() + 1; } QStandardItem* valueItem = new QStandardItem; valueItem->setText(QString::number(value)); // Create label item QStandardItem* label = new QStandardItem(labelName); // Make list and insert QList list; list.append(colorSquare); list.append(valueItem); list.append(label); m_LabelListModel->appendRow(list); m_Controls.m_LabelTableView->selectRow(m_LabelListModel->rowCount() - 1); // If this is the first label, we activate the paint button // We also have to set the data node color for this one, because for 1 values that color seems to define the rendered color if (m_LabelListModel->rowCount() == 1) { OnPaintToolButtonClicked(); } // Update colors UpdateLookupTables(); } void ActiveLearning::OnRemoveLabelPushButtonClicked() { // can't remove last label if (m_LabelListModel->rowCount() <= 1) return; QItemSelectionModel* selection = m_Controls.m_LabelTableView->selectionModel(); if (selection->hasSelection()) { unsigned int removeIndex = selection->selectedRows().first().row(); QString removeMessage = QString("Remove label '") + m_LabelListModel->item(removeIndex, 2)->text() + QString("'?"); QMessageBox::StandardButton removeReply; removeReply = QMessageBox::question(m_Parent, "Remove Label", removeMessage, QMessageBox::Yes | QMessageBox::No); if (removeReply == QMessageBox::Yes) { AnnotationPixelType removeValue = m_LabelListModel->item(removeIndex, 1)->text().toInt(); m_LabelListModel->removeRow(removeIndex); if (!m_Interactor->IsUsed()) { ResetLabels(); } else { itk::Image::Pointer imageItk; mitk::CastToItkImage(m_AnnotationImage, imageItk); auto it = itk::ImageRegionIterator>(imageItk, imageItk->GetLargestPossibleRegion()); while (!it.IsAtEnd()) { if (it.Get() == removeValue) it.Set(0); ++it; } mitk::GrabItkImageMemory(imageItk, m_AnnotationImage); UpdateLookupTables(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } } void ActiveLearning::OnPaintToolButtonClicked() { m_Controls.m_PaintToolButton->setChecked(true); QItemSelectionModel* selection = m_Controls.m_LabelTableView->selectionModel(); int row(0); if (selection->hasSelection()) { row = selection->selectedRows().first().row(); } else { m_Controls.m_LabelTableView->selectRow(0); } m_Interactor->SetPaintingPixelValue(m_LabelListModel->item(row, 1)->text().toInt()); } void ActiveLearning::OnEraseToolButtonClicked() { m_Controls.m_EraseToolButton->setChecked(true); m_Interactor->SetPaintingPixelValue(0); } void ActiveLearning::OnSaveSegmentationPushButtonClicked() { auto newNode = mitk::DataNode::New(); newNode->SetName("Segmentation"); newNode->SetBoolProperty("binary", false); newNode->SetOpacity(1.0); newNode->SetVisibility(false); newNode->SetData(m_SegmentationImage->Clone()); this->GetDataStorage()->Add(newNode); } void ActiveLearning::OnSavePredictionsPushButtonClicked() { if (m_LabelListModel->rowCount() < 1) return; for (int i=0; irowCount(); ++i) { auto property = mitk::NodePredicateProperty::New("segmentation_value", mitk::IntProperty::New(m_LabelListModel->item(i, 1)->text().toInt())); auto nodes = this->GetDataStorage()->GetDerivations(m_Nodes[0], property); if (nodes->Size() == 1) { auto sourceNode = nodes->GetElement(0); mitk::Image::Pointer sourceImage = dynamic_cast(sourceNode->GetData()); auto newNode = mitk::DataNode::New(); QString name = "Prediction "; name += m_LabelListModel->item(i, 2)->text(); newNode->SetName(name.toStdString()); newNode->SetBoolProperty("binary", false); newNode->SetOpacity(1.0); newNode->SetVisibility(false); newNode->SetProperty("segmentation_value", mitk::IntProperty::New(m_LabelListModel->item(i, 1)->text().toInt())); newNode->SetData(sourceImage->Clone()); this->GetDataStorage()->Add(newNode); } if (nodes->Size() > 1) mitkThrow(); } } void ActiveLearning::OnActiveGuidanceCheckBoxToggled(int toggled) { m_Guidance = (toggled > 0); } void ActiveLearning::OnColorIconDoubleClicked(const QModelIndex& index) { // Check if click is really from color icon if (index.column() != 0) { return; } else { // Color change dialog QColor setColor = QColorDialog::getColor(m_LabelListModel->itemFromIndex(index)->background().color(), m_Parent, "Select Label Color"); if (setColor.isValid()) { m_LabelListModel->itemFromIndex(index)->setBackground(setColor); QPixmap colorPixmap(20, 20); colorPixmap.fill(setColor); m_LabelListModel->itemFromIndex(index)->setIcon(QIcon(colorPixmap)); UpdateLookupTables(); UpdatePredictionNodes(); } } } void ActiveLearning::OnLabelListSelectionChanged(const QItemSelection& selected, const QItemSelection& /*deselected*/) { if (selected.empty()) return; if (m_Controls.m_EraseToolButton->isChecked()) OnPaintToolButtonClicked(); // This assumes that only one item can be selected (single selection table view) try { int labelValue = m_LabelListModel->item(selected.indexes()[0].row(), 1)->text().toInt(); m_Interactor->SetPaintingPixelValue(labelValue); } catch (...) { m_Interactor->SetPaintingPixelValue(-1); } } void ActiveLearning::OnLabelNameChanged(const QModelIndex& topLeft, const QModelIndex& /*bottomRight*/) { UpdatePredictionNodes(); } void ActiveLearning::OnInitializationFinished() { // Check if all futures are finished for (auto watcher : m_FeatureCalculationWatchers) { if (watcher->isFinished() == false) {return;} } // Empty feature vector m_FeatureImageVector.clear(); // Insert features into feature vector and data storage for (unsigned int i=0; iresult(); for (unsigned int j=0; jSetData(result[j].first); node->SetName(result[j].second); node->SetBoolProperty("helper object", true); node->SetVisibility(false); this->GetDataStorage()->Add(node, m_Nodes[i]); } } // Show controls m_Controls.m_LabelControlsFrame->setVisible(true); m_Controls.m_InitializePushButton->setHidden(true); emit SignalResetProgress(); // Delete watchers for (auto watcher : m_FeatureCalculationWatchers) { delete watcher; } m_FeatureCalculationWatchers.clear(); } void ActiveLearning::OnLoggerToolButtonClicked() { QString directory = QFileDialog::getExistingDirectory(nullptr, QString("Select logging directory"), QDir::currentPath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (QDir(directory).exists()) { m_Logger.SetLoggingDirectory(directory); m_Controls.m_LoggerLabel->setText(directory); } } void ActiveLearning::OnUpdatePredictionsPushButtonClicked() { if (m_LabelListModel->rowCount() < 1) return; m_Controls.m_UpdatePredictionsPushButton->setDisabled(true); emit SignalSetProgressMaximum(4); // Clear old predictions for (int i=0; irowCount(); ++i) { auto property = mitk::NodePredicateProperty::New("segmentation_value", mitk::IntProperty::New(m_LabelListModel->item(i, 1)->text().toInt())); auto nodes = this->GetDataStorage()->GetDerivations(m_Nodes[0], property); if (nodes->Size() == 1) { this->GetDataStorage()->Remove(nodes); } if (nodes->Size() > 1) mitkThrow(); } // Classifier auto classifier = mitk::VigraRandomForestClassifier::New(); classifier->SetTreeCount(m_NumberOfTrees); classifier->SetMaximumTreeDepth(m_MaximumTreeDepth); classifier->SetSamplesPerTree(m_SamplesPerTree); mitk::Image::Pointer referenceImage = dynamic_cast(m_Nodes[0]->GetData()); QFuture>> future; future = QtConcurrent::run(this, &ActiveLearning::CalculatePrediction, m_AnnotationImage, m_FeatureImageVector, referenceImage, classifier, m_PredictionMatrix); m_PredictionCalculationWatcher = new QFutureWatcher>>(); m_PredictionCalculationWatcher->setFuture(future); connect(m_PredictionCalculationWatcher, SIGNAL(finished()), this, SLOT(OnPredictionCalculationFinished())); } void ActiveLearning::OnPredictionCalculationFinished() { auto result = m_PredictionCalculationWatcher->result(); m_SegmentationImage = result.first; m_SegmentationImage->Modified(); m_SegmentationNode->SetData(m_SegmentationImage); m_SegmentationNode->Modified(); for (unsigned int i=0; iitem(i, 2)->text(); node->SetName(name.toStdString()); node->SetBoolProperty("binary", false); node->SetVisibility(false); node->SetOpacity(0.3); node->SetColor(QColorToMitkColor(m_LabelListModel->item(i, 0)->background().color())); node->SetProperty("segmentation_value", mitk::IntProperty::New(m_LabelListModel->item(i, 1)->text().toInt())); node->SetData(result.second[i]); this->GetDataStorage()->Add(node, m_Nodes[0]); } // log current prediction and annotations std::vector> indices; std::vector labels; itk::Image::Pointer annotationImageItk; mitk::CastToItkImage(m_AnnotationImage, annotationImageItk); itk::ImageRegionIteratorWithIndex> it(annotationImageItk, annotationImageItk->GetLargestPossibleRegion()); while (!it.IsAtEnd()) { if (it.Get() != 0) { indices.push_back(it.GetIndex()); labels.push_back(it.Get()); } ++it; } QDateTime currentDateTime = QDateTime::currentDateTime(); m_Logger.WriteData(m_SegmentationImage, currentDateTime.toString("hh-mm-ss") + QString(".nrrd")); m_Logger.WriteData(indices, labels, currentDateTime.toString("hh-mm-ss") + QString(".csv")); QFuture> future; future = QtConcurrent::run(this, &ActiveLearning::CalculateUncertainty, result.second, m_SegmentationImage, m_Guidance); m_UncertaintyCalculationWatcher = new QFutureWatcher>(); m_UncertaintyCalculationWatcher->setFuture(future); connect(m_UncertaintyCalculationWatcher, SIGNAL(finished()), this, SLOT(OnUncertaintyCalculationFinished())); } void ActiveLearning::OnUncertaintyCalculationFinished() { m_UncertaintyImage = m_UncertaintyCalculationWatcher->result().first; m_UncertaintyImage->Modified(); m_UncertaintyNode->SetData(m_UncertaintyImage); m_UncertaintyNode->Modified(); if (m_UncertaintyCalculationWatcher->result().second.IsNotNull()) { m_UncertaintyRegion = m_UncertaintyCalculationWatcher->result().second; m_UncertaintyRegion->Modified(); m_UncertaintyRegionNode->SetData(m_UncertaintyRegion); m_UncertaintyRegionNode->Modified(); } UpdateLookupTables(); UpdatePredictionNodes(); emit SignalResetProgress(); m_Controls.m_UpdatePredictionsPushButton->setEnabled(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void ActiveLearning::OnBrushSizeSliderValueChanged(int value) { QString labelText = "Size "; labelText += QString::number(value); m_Controls.m_BrushSizeLabel->setText(labelText); m_Interactor->SetSize(value); } /* ================================================================== * PROTECTED * =============================================================== */ void ActiveLearning::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& nodes) { if (!SelectionAllImages(nodes)) { SetInitializeReady(false); return; } if (nodes.length() >= 2) { // First selection is the reference (could be any other) mitk::Image::Pointer referenceImage = dynamic_cast(nodes[0]->GetData()); mitk::BaseGeometry* referenceGeometry = referenceImage->GetTimeGeometry()->GetGeometryForTimeStep(0); // Adjust for multiple timesteps for (int i=1; i(nodes[i]->GetData()); mitk::BaseGeometry* currentGeometry = currentImage->GetTimeGeometry()->GetGeometryForTimeStep(0); // Adjust for multiple timesteps if (!mitk::Equal(*currentGeometry, *referenceGeometry, mitk::eps, true)) { SetInitializeReady(false); return; } } } // All nodes have the same geometry, allow init SetInitializeReady(true); } void ActiveLearning::SetFocus() { } /* ================================================================== * PRIVATE * =============================================================== */ void ActiveLearning::SetInitializeReady(bool ready) { if (ready) { // get selection, check again just to be sure auto nodes = this->GetDataManagerSelection(); if (!SelectionAllImages(nodes)) return; m_Controls.m_InitializePushButton->setEnabled(true); if (!m_Active) { QString nameList = QString::fromStdString(nodes[0]->GetName()); if (nodes.length() >= 2) { for (int i=1; i"); nameList += QString::fromStdString(nodes[i]->GetName()); } } m_Controls.m_InitializeLabel->setText(nameList); } } else { m_Controls.m_InitializePushButton->setDisabled(true); if (!m_Active) { m_Controls.m_InitializeLabel->setText("Selected images must have matching geometries"); } } }