diff --git a/Plugins/org.mitk.gui.qt.classificationsegmentation/src/internal/ClassificationRegionGrow.cpp b/Plugins/org.mitk.gui.qt.classificationsegmentation/src/internal/ClassificationRegionGrow.cpp index 8d5adc1c5f..1035ceeaed 100644 --- a/Plugins/org.mitk.gui.qt.classificationsegmentation/src/internal/ClassificationRegionGrow.cpp +++ b/Plugins/org.mitk.gui.qt.classificationsegmentation/src/internal/ClassificationRegionGrow.cpp @@ -1,630 +1,628 @@ /*=================================================================== 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. ===================================================================*/ // STD #include // Blueberry #include #include // Qmitk #include "ClassificationRegionGrow.h" // Qt #include #include #include //mitk image #include #include //#include //#include #include #include #include "mitkVigraRandomForestClassifier.h" #include "mitkCLUtil.h" #include "qboxlayout.h" #include #include "Eigen/Dense" #include #include #include #include #include #include #include #include #include #include -#include -#include #include #include //#include #include "mitkLabelSetImage.h" //#include #include #include #include #include #include //#include #include const std::string ClassificationRegionGrow::VIEW_ID = "org.mitk.views.ClassificationRegionGrow"; void ClassificationRegionGrow::SetFocus() { // m_Controls.buttonPerformImageProcessing->setFocus(); } void ClassificationRegionGrow::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); m_CalculateFeatures = true; m_BlockManualSegmentation = false; m_BlockPostProcessing = false; m_Controls.groupLearningParameter->setVisible(false); m_Controls.groupFeatureSelection->setVisible(false); QmitkDataStorageComboBox * cb_inputimage = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); QmitkDataStorageComboBox * cb_maskimage= new QmitkDataStorageComboBox(this->GetDataStorage(),mitk::TNodePredicateDataType::New()); QmitkDataStorageComboBox * cb_baseimage = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); m_Controls.m_InputImageLayout->addWidget(cb_inputimage); m_Controls.m_MaskImageLayout->addWidget(cb_maskimage); m_Controls.StartingPointLayout->addWidget(cb_baseimage); m_Controls.addInputButton->setIcon(QIcon::fromTheme("list-add")); m_Controls.removeInputButton->setIcon(QIcon::fromTheme("edit-delete")); connect( cb_inputimage, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnInitializeSession(const mitk::DataNode*))); connect( cb_maskimage, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnInitializeSession(const mitk::DataNode*))); connect(m_Controls.SelectAdvancedParameter, SIGNAL(toggled(bool)), m_Controls.groupLearningParameter, SLOT(setVisible(bool))); connect(m_Controls.SelectAdvancedParameter, SIGNAL(toggled(bool)), m_Controls.groupFeatureSelection, SLOT(setVisible(bool))); connect(m_Controls.SelectSimpleParameters, SIGNAL(toggled(bool)), m_Controls.parameterWidget, SLOT(setVisible(bool))); connect(m_Controls.m_DoAutomaticSecmentation, SIGNAL( clicked()), this, SLOT(DoAutomSegmentation())); connect(m_Controls.removeInputButton, SIGNAL(clicked()), this, SLOT(RemoveItemFromLabelList())); connect(m_Controls.addInputButton, SIGNAL(clicked()), this, SLOT(AddInputField())); connect(m_Controls.UseIntensity, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.Gauss1, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.Gauss2, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.Gauss3, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.Gauss4, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.Gauss5, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.DoG1, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.DoG2, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.DoG3, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.DoG4, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.DoG5, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.LoG1, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.LoG2, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.LoG3, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.LoG4, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.LoG5, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.HoG1, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.HoG2, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.HoG3, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.HoG4, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.HoG5, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.LH1, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.LH2, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.LH3, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); connect(m_Controls.LH4, SIGNAL(toggled(bool)), this, SLOT(OnFeatureSettingsChanged())); } void ClassificationRegionGrow::AddInputField() { QmitkDataStorageComboBox * cb_inputimage = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); //QPushButton * lockButton = new QPushButton(); //lockButton->setText(""); //lockButton->setMinimumWidth(40); //lockButton->setCheckable(true); //lockButton->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaStop)); QHBoxLayout *layout = new QHBoxLayout; layout->addWidget(cb_inputimage,100); //layout->addWidget(lockButton,1); m_Controls.m_InputImageLayout->addLayout(layout); connect(cb_inputimage, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnInitializeSession(const mitk::DataNode*))); } void ClassificationRegionGrow::RemoveItemFromLabelList() { auto numberOfElements = m_Controls.m_InputImageLayout->count(); auto lastItem = m_Controls.m_InputImageLayout->itemAt(numberOfElements-1); QHBoxLayout *layout = dynamic_cast(lastItem); while (QLayoutItem* item = layout->takeAt(0)) { if (QWidget* widget = item->widget()) widget->deleteLater(); delete item; } m_Controls.m_InputImageLayout->removeItem(lastItem); delete lastItem; } void ClassificationRegionGrow::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*source*/, const QList& nodes ) { // iterate all selected objects, adjust warning visibility foreach( mitk::DataNode::Pointer node, nodes ) { if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { return; } } } void ClassificationRegionGrow::OnInitializeSession(const mitk::DataNode *) { OnFeatureSettingsChanged(); } void ClassificationRegionGrow::ProcessFeatureImages(const mitk::Image::Pointer & raw_image) { // RAW if (m_Controls.UseIntensity->isChecked()) { m_FeatureImageVector.push_back(raw_image); } // GAUSS if (m_Controls.Gauss1->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::GaussianFilter(raw_image, smoothed, 1); m_FeatureImageVector.push_back(smoothed); } if (m_Controls.Gauss2->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::GaussianFilter(raw_image, smoothed, 2); m_FeatureImageVector.push_back(smoothed); } if (m_Controls.Gauss3->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::GaussianFilter(raw_image, smoothed, 3); m_FeatureImageVector.push_back(smoothed); } if (m_Controls.Gauss4->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::GaussianFilter(raw_image, smoothed, 4); m_FeatureImageVector.push_back(smoothed); } if (m_Controls.Gauss5->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::GaussianFilter(raw_image, smoothed, 5); m_FeatureImageVector.push_back(smoothed); } // Difference of Gaussian if (m_Controls.DoG1->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::DifferenceOfGaussianFilter(raw_image, smoothed, 1,0.8); m_FeatureImageVector.push_back(smoothed); } if (m_Controls.DoG2->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::DifferenceOfGaussianFilter(raw_image, smoothed, 2, 1.8); m_FeatureImageVector.push_back(smoothed); } if (m_Controls.DoG3->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::DifferenceOfGaussianFilter(raw_image, smoothed, 3, 2.6); m_FeatureImageVector.push_back(smoothed); } if (m_Controls.DoG4->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::DifferenceOfGaussianFilter(raw_image, smoothed, 4, 3.4); m_FeatureImageVector.push_back(smoothed); } if (m_Controls.DoG5->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::DifferenceOfGaussianFilter(raw_image, smoothed, 5, 4.3); m_FeatureImageVector.push_back(smoothed); } // Laplacian of Gaussian if (m_Controls.LoG1->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::LaplacianOfGaussianFilter(raw_image, smoothed, 1); m_FeatureImageVector.push_back(smoothed); } if (m_Controls.LoG2->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::LaplacianOfGaussianFilter(raw_image, smoothed, 2); m_FeatureImageVector.push_back(smoothed); } if (m_Controls.LoG3->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::LaplacianOfGaussianFilter(raw_image, smoothed, 3); m_FeatureImageVector.push_back(smoothed); } if (m_Controls.LoG4->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::LaplacianOfGaussianFilter(raw_image, smoothed, 4); m_FeatureImageVector.push_back(smoothed); } if (m_Controls.LoG5->isChecked()) { mitk::Image::Pointer smoothed; mitk::CLUtil::LaplacianOfGaussianFilter(raw_image, smoothed, 5); m_FeatureImageVector.push_back(smoothed); } // Hessian of Gaussian if (m_Controls.HoG1->isChecked()) { mitk::CLUtil::HessianOfGaussianFilter(raw_image, m_FeatureImageVector, 1); } if (m_Controls.HoG2->isChecked()) { mitk::CLUtil::HessianOfGaussianFilter(raw_image, m_FeatureImageVector, 2); } if (m_Controls.HoG3->isChecked()) { mitk::CLUtil::HessianOfGaussianFilter(raw_image, m_FeatureImageVector, 3); } if (m_Controls.HoG4->isChecked()) { mitk::CLUtil::HessianOfGaussianFilter(raw_image, m_FeatureImageVector, 4); } if (m_Controls.HoG5->isChecked()) { mitk::CLUtil::HessianOfGaussianFilter(raw_image, m_FeatureImageVector, 5); } // LocalHistogram if (m_Controls.LH1->isChecked()) { mitk::CLUtil::LocalHistogram(raw_image, m_FeatureImageVector, 5,3); } if (m_Controls.LH2->isChecked()) { mitk::CLUtil::LocalHistogram(raw_image, m_FeatureImageVector, 5, 5); } if (m_Controls.LH3->isChecked()) { mitk::CLUtil::LocalHistogram(raw_image, m_FeatureImageVector, 10, 3); } if (m_Controls.LH4->isChecked()) { mitk::CLUtil::LocalHistogram(raw_image, m_FeatureImageVector, 10, 5); } } void ClassificationRegionGrow::OnFeatureSettingsChanged() { MITK_INFO << "FeatureSettingsChanged"; m_CalculateFeatures = true; } void ClassificationRegionGrow::DoAutomSegmentation() { MITK_INFO << "Start Automatic Segmentation ..."; // Load Images from registration process QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls.m_InputImageLayout->itemAt(1)->widget()); QmitkDataStorageComboBox * cb_maskimage = dynamic_cast(m_Controls.m_MaskImageLayout->itemAt(1)->widget()); mitk::Image::Pointer raw_image; mitk::Image::Pointer mask_image; if ((cb_image != NULL) || (cb_maskimage != NULL)) { raw_image = dynamic_cast(cb_image->GetSelectedNode()->GetData()); mask_image = dynamic_cast(cb_maskimage->GetSelectedNode()->GetData()); } else { QMessageBox msgBox; msgBox.setText("Please specify the images that shlould be used."); msgBox.exec(); return; } if (raw_image.IsNull() || mask_image.IsNull()) { QMessageBox msgBox; msgBox.setText("Error during processing the specified images."); msgBox.exec(); return; } std::vector imageList; imageList.push_back(raw_image); for (int i = 2; i < m_Controls.m_InputImageLayout->count(); ++i) { QLayout* layout = dynamic_cast(m_Controls.m_InputImageLayout->itemAt(i)); MITK_INFO << layout; QmitkDataStorageComboBox * tmp_cb_image = dynamic_cast(layout->itemAt(0)->widget()); MITK_INFO << tmp_cb_image; if (tmp_cb_image) { mitk::Image::Pointer tmp_image = dynamic_cast(tmp_cb_image); if (tmp_image.IsNotNull()) { MITK_INFO << "Adding Image..."; imageList.push_back(tmp_image); } } } MITK_INFO << "Start Feature Calculation ..."; if(m_CalculateFeatures) { m_FeatureImageVector.clear(); for (auto img : imageList) { ProcessFeatureImages(img); } m_CalculateFeatures = false; if (m_Controls.checkAddFeaturesToDataManager->isChecked()) { for (std::size_t i = 0; i < m_FeatureImageVector.size(); ++i) { auto newName = "Feature_" + std::to_string(i); AddAsDataNode(m_FeatureImageVector[i].GetPointer(), newName); } } } MITK_INFO << "Start Classifier Training ..."; TrainClassifier(raw_image, mask_image); MITK_INFO << "Predict extended Segmentation ..."; PredictSegmentation(raw_image, mask_image); } void ClassificationRegionGrow::TrainClassifier(const mitk::Image::Pointer & raw_image, const mitk::Image::Pointer & mask_image) { typedef itk::Image DoubleImageType; typedef itk::Image ShortImageType; DoubleImageType::Pointer input; ShortImageType::Pointer mask; mitk::CastToItkImage(raw_image, input); mitk::CastToItkImage(mask_image, mask); int numberOfSegmentedVoxel = 0; int numberOfFeatures = m_FeatureImageVector.size(); auto maskIter = itk::ImageRegionConstIteratorWithIndex(mask, mask->GetLargestPossibleRegion()); m_SegmentedLocations.clear(); m_SegmentedOrganLocations.clear(); MITK_INFO << "Count Segmentation Size ..."; while ( ! maskIter.IsAtEnd()) { if (maskIter.Value() > 0) { m_SegmentedLocations.push_back(maskIter.GetIndex()); numberOfSegmentedVoxel++; if (maskIter.Value() > 1) { m_SegmentedOrganLocations.push_back(maskIter.GetIndex()); } } ++maskIter; } MITK_INFO << "Sizes: " << numberOfSegmentedVoxel << " " << m_SegmentedOrganLocations.size(); Eigen::MatrixXi Y_train = mitk::CLUtil::Transform(mask_image, mask_image); Eigen::MatrixXd X_train = Eigen::MatrixXd(numberOfSegmentedVoxel, numberOfFeatures); unsigned int index = 0; MITK_INFO << "Convert Training Data to Eigen Matrix ..."; for (const auto & image : m_FeatureImageVector) { X_train.col(index) = mitk::CLUtil::Transform(image, mask_image); ++index; } MITK_INFO << "Classifier Training ..."; m_Classifier = mitk::VigraRandomForestClassifier::New(); //this->m_Controls.Maximum m_Classifier->SetTreeCount(m_Controls.NumberOfTrees->value()); m_Classifier->SetSamplesPerTree(m_Controls.SamplesPerTree->value()); m_Classifier->SetMinimumSplitNodeSize(m_Controls.MinimumSamplesPerNode->value()); m_Classifier->SetMaximumTreeDepth(m_Controls.MaximumTreeDepth->value()); m_Classifier->Train(X_train, Y_train); } static void addNeighbours(std::stack > &stack, itk::Index<3> idx) { idx[0] -= 1; stack.push(idx); idx[0] += 2; stack.push(idx); idx[0] -= 1; idx[1] -= 1; stack.push(idx); idx[1] += 2; stack.push(idx); idx[1] -= 1; idx[2] -= 1; stack.push(idx); idx[2] += 2; stack.push(idx); } void ClassificationRegionGrow::PredictSegmentation(const mitk::Image::Pointer & raw_image, const mitk::Image::Pointer & mask_image) { typedef itk::Image DoubleImageType; typedef itk::Image ShortImageType; DoubleImageType::Pointer input; ShortImageType::Pointer mask; mitk::CastToItkImage(raw_image, input); mitk::CastToItkImage(mask_image, mask); std::vector featureImages; for (auto fimage : m_FeatureImageVector) { DoubleImageType::Pointer feature; mitk::CastToItkImage(fimage, feature); featureImages.push_back(feature); } ShortImageType::Pointer usedLocation = ShortImageType::New(); usedLocation->SetRegions(mask->GetLargestPossibleRegion()); usedLocation->Allocate(); usedLocation->FillBuffer(0); ShortImageType::Pointer resultSegmentation = ShortImageType::New(); if (m_Controls.UpdateImage->isChecked()) { QmitkDataStorageComboBox * cb_maskimage = dynamic_cast(m_Controls.StartingPointLayout->itemAt(2)->widget()); mitk::Image::Pointer base_image = dynamic_cast(cb_maskimage->GetSelectedNode()->GetData()); mitk::CastToItkImage(base_image, resultSegmentation); } else { resultSegmentation->SetRegions(mask->GetLargestPossibleRegion()); resultSegmentation->Allocate(); if (m_Controls.SegmentBackground->isChecked()) { resultSegmentation->FillBuffer(1); } else { resultSegmentation->FillBuffer(0); } } // Fill list of Stacks std::vector > > listOfStacks; while (m_SegmentedOrganLocations.size() > 0) { auto currentLocation = m_SegmentedOrganLocations.back(); m_SegmentedOrganLocations.pop_back(); std::size_t cValue = std::abs(mask->GetPixel(currentLocation)); resultSegmentation->SetPixel(currentLocation, cValue); usedLocation->SetPixel(currentLocation, 1000); while (listOfStacks.size() < cValue+1) { listOfStacks.push_back(std::stack >()); } addNeighbours(listOfStacks[cValue],currentLocation); } int countPredicted = 0; bool connectAllLabels = m_Controls.localGrowing->isChecked(); //m_SegmentedOrganLocations.reserve(10000); Eigen::MatrixXd currentX = Eigen::MatrixXd(1, featureImages.size()); vigra::MultiArrayView<2, double> X(vigra::Shape2(currentX.rows(), currentX.cols()), currentX.data()); auto outLabel = Eigen::MatrixXi(currentX.rows(), 1); vigra::MultiArrayView<2, int> Y(vigra::Shape2(currentX.rows(), 1), outLabel.data()); for (std::size_t i = 2; i < listOfStacks.size(); ++i) { while (listOfStacks[i].size() > 0) { auto currentLocation = listOfStacks[i].top(); listOfStacks[i].pop(); if (!mask->GetLargestPossibleRegion().IsInside(currentLocation)) { continue; } if (usedLocation->GetPixel(currentLocation) > i) { continue; } usedLocation->SetPixel(currentLocation, i+1); for (std::size_t f = 0; f < featureImages.size(); ++f) { currentX(0, f) = featureImages[f]->GetPixel(currentLocation); } m_Classifier->GetRandomForest().predictLabels(X, Y); ++countPredicted; if ((static_cast(Y(0, 0)) == i ) || ((Y(0, 0) > 1) && (connectAllLabels))) { resultSegmentation->SetPixel(currentLocation, std::abs(Y(0, 0))); addNeighbours(listOfStacks[i], currentLocation); } } } MITK_INFO << "Number of Predictions: " << countPredicted; MITK_INFO << "Finished Segmentation..."; mitk::Image::Pointer result; mitk::CastToMitkImage(resultSegmentation, result); result->SetOrigin(raw_image->GetGeometry()->GetOrigin()); result->SetSpacing(raw_image->GetGeometry()->GetSpacing()); mitk::LabelSetImage::Pointer labelResult = mitk::LabelSetImage::New(); labelResult->InitializeByLabeledImage(result); mitk::LabelSetImage::Pointer oldLabelSet = dynamic_cast(mask_image.GetPointer()); labelResult->AddLabelSetToLayer(labelResult->GetActiveLayer(),oldLabelSet->GetLabelSet()); MITK_INFO << "Passing Back..."; AddAsDataNode(labelResult.GetPointer(), "ResultSegmentation"); } mitk::DataNode::Pointer ClassificationRegionGrow::AddAsDataNode(const mitk::BaseData::Pointer & data_, const std::string & name ) { mitk::DataNode::Pointer node = nullptr; node = this->GetDataStorage()->GetNamedNode(name); if(node.IsNull()) { node = mitk::DataNode::New(); node->SetData(data_); node->SetName(name); this->GetDataStorage()->Add(node); }else{ if(dynamic_cast(node->GetData()) && dynamic_cast(data_.GetPointer())) { mitk::Image::Pointer target_image = dynamic_cast(node->GetData()); mitk::Image::Pointer source_image = dynamic_cast(data_.GetPointer()); mitk::ImageReadAccessor ra(source_image); target_image->SetImportVolume(const_cast(ra.GetData())); this->RequestRenderWindowUpdate(); } if(dynamic_cast(node->GetData()) && dynamic_cast(data_.GetPointer())) { node->SetData(data_); node->Modified(); } } return node; } diff --git a/Plugins/org.mitk.gui.qt.classificationsegmentation/src/internal/ClassificationSegmentation.cpp b/Plugins/org.mitk.gui.qt.classificationsegmentation/src/internal/ClassificationSegmentation.cpp index ef2ff1899c..14ed589883 100644 --- a/Plugins/org.mitk.gui.qt.classificationsegmentation/src/internal/ClassificationSegmentation.cpp +++ b/Plugins/org.mitk.gui.qt.classificationsegmentation/src/internal/ClassificationSegmentation.cpp @@ -1,981 +1,979 @@ /*=================================================================== 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 "ClassificationSegmentation.h" // Qt #include //mitk image #include #include #include #include #include #include #include "mitkVigraRandomForestClassifier.h" #include "mitkCLUtil.h" #include "qboxlayout.h" #include #include "Eigen/Dense" #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 ClassificationSegmentation::VIEW_ID = "org.mitk.views.classificationsegmentation"; void ClassificationSegmentation::SetFocus() { // m_Controls.buttonPerformImageProcessing->setFocus(); } void ClassificationSegmentation::OnButtonCSFToggle(bool checked) { // m_PointListWidget->SetPointSet(dynamic_cast(m_PointSetList[0]->GetData())); if(checked) m_PointSetDataInteractor->SetDataNode(m_PointSetList[0]); else m_PointSetDataInteractor->SetDataNode(nullptr); } void ClassificationSegmentation::OnButtonLESToggle(bool checked) { // m_PointListWidget->SetPointSet(dynamic_cast(m_PointSetList[1]->GetData())); if(checked) m_PointSetDataInteractor->SetDataNode(m_PointSetList[1]); else m_PointSetDataInteractor->SetDataNode(nullptr); } void ClassificationSegmentation::OnButtonBRAToggle(bool checked) { // m_PointListWidget->SetPointSet(dynamic_cast(m_PointSetList[2]->GetData())); if(checked) m_PointSetDataInteractor->SetDataNode(m_PointSetList[2]); else m_PointSetDataInteractor->SetDataNode(nullptr); } void ClassificationSegmentation::OnButtonNoInteractionToggle(bool checked) { if(checked) m_PointSetDataInteractor->SetDataNode(nullptr); } void ClassificationSegmentation::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); m_CalculateFeatures = true; m_BlockManualSegmentation = false; m_BlockPostProcessing = false; QmitkDataStorageComboBox * cb_inputimage = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); QmitkDataStorageComboBox * cb_maskimage= new QmitkDataStorageComboBox(this->GetDataStorage(),mitk::TNodePredicateDataType::New()); QmitkDataStorageComboBox * cb_classifer= new QmitkDataStorageComboBox(this->GetDataStorage(),mitk::TNodePredicateDataType::New()); m_Controls.m_InputImageLayout->addWidget(cb_inputimage); m_Controls.m_MaskImageLayout->addWidget(cb_maskimage); m_Controls.m_ClassifierLayout->addWidget(cb_classifer); m_Controls.m_ParameterLayout->layout()->addWidget(new QLabel("Gauss Sigma")); m_GaussSlider = new ctkSliderWidget(); m_GaussSlider->setMinimum(0); m_GaussSlider->setMaximum(10); m_GaussSlider->setValue(1); m_Controls.m_ParameterLayout->layout()->addWidget(m_GaussSlider); m_Controls.m_ParameterLayout->layout()->addWidget(new QLabel("Hessian Sigma")); m_HessianSlider = new ctkSliderWidget(); m_HessianSlider->setMinimum(0); m_HessianSlider->setMaximum(10); m_HessianSlider->setValue(3); m_Controls.m_ParameterLayout->layout()->addWidget(m_HessianSlider); m_Controls.m_ParameterLayout->layout()->addWidget(new QLabel("Structure Tensor Inner and Outer Scale")); m_STInnerSlider = new ctkSliderWidget(); m_STInnerSlider->setMinimum(0); m_STInnerSlider->setMaximum(10); m_STInnerSlider->setValue(1.5); m_Controls.m_ParameterLayout->layout()->addWidget(m_STInnerSlider); m_STOuterSlider = new ctkSliderWidget(); m_STOuterSlider->setMinimum(0); m_STOuterSlider->setMaximum(10); m_STOuterSlider->setValue(3); m_Controls.m_ParameterLayout->layout()->addWidget(m_STOuterSlider); m_Controls.m_PostProcessingLayout->layout()->addWidget(new QLabel("Probability map smoothing")); m_GaussCSFSlider = new ctkSliderWidget; m_GaussCSFSlider->setMinimum(0); m_GaussCSFSlider->setMaximum(10); m_GaussCSFSlider->setValue(1.5); m_Controls.m_PostProcessingLayout->layout()->addWidget(m_GaussCSFSlider); m_GaussLESSlider = new ctkSliderWidget; m_GaussLESSlider->setMinimum(0); m_GaussLESSlider->setMaximum(10); m_GaussLESSlider->setValue(3); m_Controls.m_PostProcessingLayout->layout()->addWidget(m_GaussLESSlider); m_GaussBRASlider = new ctkSliderWidget; m_GaussBRASlider->setMinimum(0); m_GaussBRASlider->setMaximum(10); m_GaussBRASlider->setValue(0.5); m_Controls.m_PostProcessingLayout->layout()->addWidget(m_GaussBRASlider); m_Controls.m_PostProcessingLayout->layout()->addWidget(new QLabel("Probability map weighting")); m_WeightCSFSlider = new ctkSliderWidget; m_WeightCSFSlider->setMinimum(0.0); m_WeightCSFSlider->setMaximum(2.0); m_WeightCSFSlider->setValue(1.0); m_WeightCSFSlider->setSingleStep(0.1); m_Controls.m_PostProcessingLayout->layout()->addWidget(m_WeightCSFSlider); m_WeightLESSlider = new ctkSliderWidget; m_WeightLESSlider->setMinimum(0.0); m_WeightLESSlider->setMaximum(2.0); m_WeightLESSlider->setValue(1.0); m_WeightLESSlider->setSingleStep(0.1); m_Controls.m_PostProcessingLayout->layout()->addWidget(m_WeightLESSlider); m_WeightBRASlider = new ctkSliderWidget; m_WeightBRASlider->setMinimum(0.0); m_WeightBRASlider->setMaximum(2.0); m_WeightBRASlider->setValue(1.0); m_WeightBRASlider->setSingleStep(0.1); m_Controls.m_PostProcessingLayout->layout()->addWidget(m_WeightBRASlider); m_PointSetDataInteractor = mitk::PointSetDataInteractor::New(); m_PointSetDataInteractor->LoadStateMachine("PointSet.xml"); m_PointSetDataInteractor->SetEventConfig("PointSetConfig.xml"); connect( cb_inputimage, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnInitializeSession(const mitk::DataNode*))); connect( cb_maskimage, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnInitializeSession(const mitk::DataNode*))); connect( m_Controls.m_SavePointsButton, SIGNAL(clicked(bool)), this, SLOT(DoSavePointsAsMask())); connect( m_Controls.m_ButtonCSFToggle, SIGNAL(toggled(bool)), this, SLOT(OnButtonCSFToggle(bool))); connect( m_Controls.m_ButtonLESToggle, SIGNAL(toggled(bool)), this, SLOT(OnButtonLESToggle(bool))); connect( m_Controls.m_ButtonBRAToggle, SIGNAL(toggled(bool)), this, SLOT(OnButtonBRAToggle(bool))); connect( m_Controls.m_ButtonNoInteraction, SIGNAL(toggled(bool)), this, SLOT(OnButtonNoInteractionToggle(bool))); connect( &m_ManualSegmentationFutureWatcher, SIGNAL(finished()), this, SLOT(ManualSegmentationFinished())); connect( &m_PostProcessingFutureWatcher, SIGNAL(finished()), this, SLOT(PostProcessingFinished())); //connect( m_Controls.m_AddPointSets, SIGNAL(clicked()),this, SLOT(OnAddPointSets()) ); connect( m_GaussSlider, SIGNAL(valueChanged(double)), this, SLOT(OnFeatureSettingsChanged())); connect( m_HessianSlider, SIGNAL(valueChanged(double)), this, SLOT(OnFeatureSettingsChanged())); connect( m_STInnerSlider, SIGNAL(valueChanged(double)), this, SLOT(OnFeatureSettingsChanged())); connect( m_STOuterSlider, SIGNAL(valueChanged(double)), this, SLOT(OnFeatureSettingsChanged())); connect( m_GaussCSFSlider, SIGNAL(valueChanged(double)), this, SLOT(OnPostProcessingSettingsChanged())); connect( m_GaussLESSlider, SIGNAL(valueChanged(double)), this, SLOT(OnPostProcessingSettingsChanged())); connect( m_GaussBRASlider, SIGNAL(valueChanged(double)), this, SLOT(OnPostProcessingSettingsChanged())); connect( m_WeightCSFSlider, SIGNAL(valueChanged(double)), this, SLOT(OnPostProcessingSettingsChanged())); connect( m_WeightLESSlider, SIGNAL(valueChanged(double)), this, SLOT(OnPostProcessingSettingsChanged())); connect( m_WeightBRASlider, SIGNAL(valueChanged(double)), this, SLOT(OnPostProcessingSettingsChanged())); connect(m_Controls.m_DoAutomaticSecmentation, SIGNAL(clicked(bool)), this, SLOT(DoAutomSegmentation())); connect(m_Controls.m_AddForestToDataManager, SIGNAL(clicked(bool)), this, SLOT(OnAddForestToDataManager())); mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New(); pointSetNode->SetName("CSF_Points."); pointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true)); pointSetNode->SetProperty("layer", mitk::IntProperty::New(1024)); pointSetNode->SetColor(0,1.0,0); pointSetNode->SetDataInteractor(m_PointSetDataInteractor.GetPointer()); m_PointSetList.push_back(pointSetNode); GetDataStorage()->Add(pointSetNode); pointSetNode = mitk::DataNode::New(); pointSetNode->SetName("LES_Points."); pointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true)); pointSetNode->SetProperty("layer", mitk::IntProperty::New(1024)); pointSetNode->SetColor(1.0,0,0); pointSetNode->SetDataInteractor(m_PointSetDataInteractor.GetPointer()); m_PointSetList.push_back(pointSetNode); GetDataStorage()->Add(pointSetNode); pointSetNode = mitk::DataNode::New(); pointSetNode->SetName("BRA_Points."); pointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true)); pointSetNode->SetProperty("layer", mitk::IntProperty::New(1024)); pointSetNode->SetColor(0,0,1.0); pointSetNode->SetDataInteractor(m_PointSetDataInteractor.GetPointer()); m_PointSetList.push_back(pointSetNode); GetDataStorage()->Add(pointSetNode); m_Controls.m_PostProcessingLayout->hide(); m_Controls.m_ParameterLayout->hide(); } void ClassificationSegmentation::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*source*/, const QList& nodes ) { // iterate all selected objects, adjust warning visibility foreach( mitk::DataNode::Pointer node, nodes ) { if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { // m_Controls.labelWarning->setVisible( false ); // m_Controls.buttonPerformImageProcessing->setEnabled( true ); return; } } // m_Controls.labelWarning->setVisible( true ); // m_Controls.buttonPerformImageProcessing->setEnabled( false ); } void ClassificationSegmentation::OnAddForestToDataManager() { AddAsDataNode(m_TempClassifier.GetPointer(),"ManualSegmentation_Classifier"); } void ClassificationSegmentation::OnInitializeSession(const mitk::DataNode *) { MITK_WARN << "Data selection changed! New session initialized."; m_PointSetDataInteractor->SetDataNode(nullptr); /// CSF POINTSET mitk::PointSet::Pointer pntset = mitk::PointSet::New(); m_PointSetList[0]->SetData(pntset); itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &ClassificationSegmentation::ManualSegmentationTrigger); pntset->AddObserver( mitk::PointSetAddEvent(), command ); pntset->AddObserver( mitk::PointSetRemoveEvent(), command ); pntset->AddObserver( mitk::PointSetMoveEvent(), command ); /// LES POINTSET pntset = mitk::PointSet::New(); m_PointSetList[1]->SetData(pntset); command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &ClassificationSegmentation::ManualSegmentationTrigger); pntset->AddObserver( mitk::PointSetAddEvent(), command ); pntset->AddObserver( mitk::PointSetRemoveEvent(), command ); pntset->AddObserver( mitk::PointSetMoveEvent(), command ); /// BRA POINTSET pntset = mitk::PointSet::New(); m_PointSetList[2]->SetData(pntset); command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &ClassificationSegmentation::ManualSegmentationTrigger); pntset->AddObserver( mitk::PointSetAddEvent(), command ); pntset->AddObserver( mitk::PointSetRemoveEvent(), command ); pntset->AddObserver( mitk::PointSetMoveEvent(), command ); } void ClassificationSegmentation::DoSavePointsAsMask() { mitk::Image::Pointer sampled_image = nullptr; QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls.m_InputImageLayout->itemAt(1)->widget()); mitk::Image::Pointer raw_image = dynamic_cast(cb_image->GetSelectedNode()->GetData()); int label = 1; for( auto datanode : m_PointSetList) { mitk::PointSet::Pointer point_set = dynamic_cast(datanode->GetData()); mitk::Image::Pointer temp_img; SampleClassMaskByPointSet(raw_image, point_set,temp_img); mitk::CLUtil::InsertLabel(temp_img,sampled_image,label++); QmitkIOUtil::Save(datanode->GetData(),QString("PointSet.mps")); } QmitkIOUtil::Save(sampled_image,QString("PointSetMask.nrrd")); } void ClassificationSegmentation::ProcessFeatureImages(const mitk::Image::Pointer & raw_image, const mitk::Image::Pointer & brain_mask) { typedef itk::Image DoubleImageType; typedef itk::Image ShortImageType; typedef itk::ConstNeighborhoodIterator NeighborhoodType; // Neighborhood iterator to access image typedef itk::Functor::NeighborhoodFirstOrderStatistics FunctorType; typedef itk::NeighborhoodFunctorImageFilter FOSFilerType; m_FeatureImageVector.clear(); // RAW m_FeatureImageVector.push_back(raw_image); // GAUSS mitk::Image::Pointer smoothed; mitk::CLUtil::GaussianFilter(raw_image,smoothed,m_GaussSlider->value()); m_FeatureImageVector.push_back(smoothed); // Calculate Probability maps (parameters used from literatur) // CSF mitk::Image::Pointer csf_prob = mitk::Image::New(); mitk::CLUtil::ProbabilityMap(smoothed,13.9, 8.3,csf_prob); m_FeatureImageVector.push_back(csf_prob); // Lesion mitk::Image::Pointer les_prob = mitk::Image::New(); mitk::CLUtil::ProbabilityMap(smoothed,59, 11.6,les_prob); m_FeatureImageVector.push_back(les_prob); // Barin (GM/WM) mitk::Image::Pointer brain_prob = mitk::Image::New(); mitk::CLUtil::ProbabilityMap(smoothed,32, 5.6,brain_prob); m_FeatureImageVector.push_back(brain_prob); std::vector FOS_sizes; FOS_sizes.push_back(1); DoubleImageType::Pointer input; ShortImageType::Pointer mask; mitk::CastToItkImage(smoothed, input); mitk::CastToItkImage(brain_mask, mask); for(unsigned int i = 0 ; i < FOS_sizes.size(); i++) { FOSFilerType::Pointer filter = FOSFilerType::New(); filter->SetNeighborhoodSize(FOS_sizes[i]); filter->SetInput(input); filter->SetMask(mask); filter->Update(); FOSFilerType::DataObjectPointerArray array = filter->GetOutputs(); for( unsigned int i = 0; i < FunctorType::OutputCount; i++) { mitk::Image::Pointer featureimage; mitk::CastToMitkImage(dynamic_cast(array[i].GetPointer()),featureimage); m_FeatureImageVector.push_back(featureimage); // AddImageAsDataNode(featureimage,FunctorType::GetFeatureName(i))->SetVisibility(show_nodes); } } { itk::HessianMatrixEigenvalueImageFilter< DoubleImageType >::Pointer filter = itk::HessianMatrixEigenvalueImageFilter< DoubleImageType >::New(); filter->SetInput(input); filter->SetImageMask(mask); filter->SetSigma(m_HessianSlider->value()); filter->Update(); mitk::Image::Pointer o1,o2,o3; mitk::CastToMitkImage(filter->GetOutput(0),o1); mitk::CastToMitkImage(filter->GetOutput(1),o2); mitk::CastToMitkImage(filter->GetOutput(2),o3); m_FeatureImageVector.push_back(o1); m_FeatureImageVector.push_back(o2); m_FeatureImageVector.push_back(o3); // AddImageAsDataNode(o1,"HE_1")->SetVisibility(show_nodes); // AddImageAsDataNode(o2,"HE_2")->SetVisibility(show_nodes); // AddImageAsDataNode(o3,"HE_3")->SetVisibility(show_nodes); } { itk::StructureTensorEigenvalueImageFilter< DoubleImageType >::Pointer filter = itk::StructureTensorEigenvalueImageFilter< DoubleImageType >::New(); filter->SetInput(input); filter->SetImageMask(mask); filter->SetInnerScale(m_STInnerSlider->value()); filter->SetOuterScale(m_STOuterSlider->value()); filter->Update(); mitk::Image::Pointer o1,o2,o3; mitk::CastToMitkImage(filter->GetOutput(0),o1); mitk::CastToMitkImage(filter->GetOutput(1),o2); mitk::CastToMitkImage(filter->GetOutput(2),o3); m_FeatureImageVector.push_back(o1); m_FeatureImageVector.push_back(o2); m_FeatureImageVector.push_back(o3); // AddImageAsDataNode(o1,"ST_1")->SetVisibility(show_nodes); // AddImageAsDataNode(o2,"ST_2")->SetVisibility(show_nodes); // AddImageAsDataNode(o3,"ST_3")->SetVisibility(show_nodes); } { itk::LineHistogramBasedMassImageFilter< DoubleImageType >::Pointer filter = itk::LineHistogramBasedMassImageFilter< DoubleImageType >::New(); filter->SetInput(input); filter->SetImageMask(mask); filter->Update(); mitk::Image::Pointer o1; mitk::CastToMitkImage(filter->GetOutput(0),o1); m_FeatureImageVector.push_back(o1); } } void ClassificationSegmentation::OnFeatureSettingsChanged() { MITK_INFO << "FeatureSettingsChanged"; m_CalculateFeatures = true; ManualSegmentationTrigger(); } void ClassificationSegmentation::OnPostProcessingSettingsChanged() { MITK_INFO << "PostProcessingSettigsChanged"; PostProcessingTrigger(); } void ClassificationSegmentation::DoAutomSegmentation() { QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls.m_InputImageLayout->itemAt(1)->widget()); mitk::Image::Pointer raw_image = dynamic_cast(cb_image->GetSelectedNode()->GetData()); QmitkDataStorageComboBox * cb_maskimage = dynamic_cast(m_Controls.m_MaskImageLayout->itemAt(1)->widget()); QmitkDataStorageComboBox * cb_rf = dynamic_cast(m_Controls.m_ClassifierLayout->itemAt(1)->widget()); mitk::Image::Pointer mask_image = dynamic_cast(cb_maskimage->GetSelectedNode()->GetData()); mitk::VigraRandomForestClassifier::Pointer classifier = dynamic_cast(cb_rf->GetSelectedNode()->GetData()); if(m_CalculateFeatures) { ProcessFeatureImages(raw_image,mask_image); m_CalculateFeatures = false; } Eigen::MatrixXd X_test; unsigned int count_test = 0; mitk::CLUtil::CountVoxel(mask_image, count_test); X_test = Eigen::MatrixXd(count_test, m_FeatureImageVector.size()); unsigned int index = 0; for( const auto & image : m_FeatureImageVector) { X_test.col(index) = mitk::CLUtil::Transform(image,mask_image); ++index; } Eigen::MatrixXi Y_test = classifier->Predict(X_test); mitk::Image::Pointer result_mask = mitk::CLUtil::Transform(Y_test,mask_image); auto node = AddAsDataNode(result_mask.GetPointer(),"Autom-ResultMask"); auto lut = mitk::LookupTable::New(); lut->SetType(mitk::LookupTable::PET_20); auto * lut_prop = dynamic_cast(node->GetProperty("LookupTable")); lut_prop->SetLookupTable(lut); mitk::LevelWindow lw(1,3); node->SetLevelWindow(lw); node->SetOpacity(0.3); std::map perlabelvoxelcount; mitk::CLUtil::CountVoxel(result_mask, perlabelvoxelcount); double voxel_volume = result_mask->GetGeometry()->GetSpacing().GetVnlVector().inf_norm(); QString newtext; newtext += "Name\tVolume\tUnit\n"; for(const auto & pair: perlabelvoxelcount) { newtext += "Label" + QString::number(pair.first) + "\t" + QString::number(pair.second*voxel_volume* 0.001) + "\tml\n"; } m_Controls.m_ResultTextEdit->setText(newtext); } std::vector ClassificationSegmentation::ManualSegmentationCallback() { QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls.m_InputImageLayout->itemAt(1)->widget()); QmitkDataStorageComboBox * cb_maskimage = dynamic_cast(m_Controls.m_MaskImageLayout->itemAt(1)->widget()); mitk::Image::Pointer raw_image = dynamic_cast(cb_image->GetSelectedNode()->GetData()); mitk::Image::Pointer mask_image = dynamic_cast(cb_maskimage->GetSelectedNode()->GetData()); if(raw_image.IsNull() || mask_image.IsNull()) { MITK_WARN << "Please provide input iamge and mask image"; //return nullptr; } if(m_CalculateFeatures) { ProcessFeatureImages(raw_image,mask_image); m_CalculateFeatures = false; } mitk::Image::Pointer sampled_image = nullptr; int label = 1; for( auto datanode : m_PointSetList) { mitk::PointSet::Pointer point_set = dynamic_cast(datanode->GetData()); mitk::Image::Pointer temp_img; SampleClassMaskByPointSet(raw_image, point_set,temp_img); mitk::CLUtil::InsertLabel(temp_img,sampled_image,label++); } m_TempClassifier = mitk::VigraRandomForestClassifier::New(); m_TempClassifier->SetTreeCount(50); m_TempClassifier->SetSamplesPerTree(0.66); Eigen::MatrixXd X_train; Eigen::MatrixXd X_test; unsigned int count_train = 0; unsigned int count_test = 0; mitk::CLUtil::CountVoxel(sampled_image, count_train); mitk::CLUtil::CountVoxel(mask_image, count_test); X_train = Eigen::MatrixXd(count_train, m_FeatureImageVector.size() ); X_test = Eigen::MatrixXd(count_test, m_FeatureImageVector.size()); unsigned int index = 0; for( const auto & image : m_FeatureImageVector) { X_train.col(index) = mitk::CLUtil::Transform(image,sampled_image); X_test.col(index) = mitk::CLUtil::Transform(image,mask_image); ++index; } Eigen::MatrixXi Y = mitk::CLUtil::Transform(sampled_image,sampled_image); m_TempClassifier->Train(X_train,Y); Eigen::MatrixXi Y_test = m_TempClassifier->Predict(X_test); Eigen::MatrixXd Yp_test = m_TempClassifier->GetPointWiseProbabilities(); // mitk::Image::Pointer result_mask = mitk::CLUtil::Transform(Y_test,mask_image); std::vector resultvector; resultvector.push_back( mitk::CLUtil::Transform(Y_test,mask_image) ); resultvector.push_back( mitk::CLUtil::Transform(Yp_test.col(0),mask_image) ); resultvector.push_back( mitk::CLUtil::Transform(Yp_test.col(1),mask_image) ); resultvector.push_back( mitk::CLUtil::Transform(Yp_test.col(2),mask_image) ); return resultvector; } void ClassificationSegmentation::ManualSegmentationFinished() { // Receive Future result m_ResultImageVector = m_ManualSegmentationFutureWatcher.result(); // Add result to Datastorage mitk::DataNode::Pointer node = AddAsDataNode(m_ResultImageVector[0].GetPointer(),"Manual-ResultMask"); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType(mitk::LookupTable::PET_20); mitk::LookupTableProperty * lut_prop = dynamic_cast(node->GetProperty("LookupTable")); lut_prop->SetLookupTable(lut); mitk::LevelWindow lw(1,3); node->SetLevelWindow(lw); node->SetOpacity(0.3); m_BlockManualSegmentation = false; this->PostProcessingTrigger(); // Update Volume data std::map perlabelvoxelcount; mitk::CLUtil::CountVoxel(m_ResultImageVector[0], perlabelvoxelcount); double voxel_volume = m_ResultImageVector[0]->GetGeometry()->GetSpacing().GetVnlVector().inf_norm(); QString newtext; newtext += "Name\tVolume\tUnit\n"; for(const auto & pair: perlabelvoxelcount) newtext += "Label" + QString::number(pair.first) + "\t" + QString::number(pair.second*voxel_volume* 0.001) + "\tml\n"; m_Controls.m_ResultTextEdit->setText(newtext); } void ClassificationSegmentation::ManualSegmentationTrigger() { unsigned int samplecounter = 0; for( auto datanode : m_PointSetList) { mitk::PointSet::Pointer point_set = dynamic_cast(datanode->GetData()); samplecounter += point_set->GetSize(); } if(samplecounter < 10) return; if(!m_BlockManualSegmentation){ // Start GUI Thread m_ManualSegmentationFutureWatcher.setFuture( QtConcurrent::run(this, &ClassificationSegmentation::ManualSegmentationCallback)); // on finish call OnManualSegmentationFinished(); m_BlockManualSegmentation = true; } } void ClassificationSegmentation::SampleClassMaskByPointSet(const mitk::Image::Pointer & ref_img, mitk::PointSet::Pointer & pointset, mitk::Image::Pointer & outimage) { outimage = ref_img->Clone(); itk::Image::Pointer itk_out; mitk::CastToItkImage(outimage,itk_out); itk_out->FillBuffer(0); typedef itk::ImageRegionIteratorWithIndex > IteratorType; IteratorType oit(itk_out, itk_out->GetLargestPossibleRegion()); for(int i = 0 ; i < pointset->GetSize(); ++i) { IteratorType::IndexType index; ref_img->GetGeometry()->WorldToIndex(pointset->GetPoint(i), index); oit.SetIndex(index); oit.Set(1); } mitk::CastToMitkImage(itk_out,outimage); } // old version //void ClassificationSegmentation::DoImageProcessing() //{ // QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls.m_InputImageLayout->itemAt(1)->widget()); // QmitkDataStorageComboBox * cb_maskimage = dynamic_cast(m_Controls.m_MaskImageLayout->itemAt(1)->widget()); // QmitkDataStorageComboBox * cb_classifier = dynamic_cast(m_Controls.m_RandomForestLayout->itemAt(1)->widget()); // if (cb_image == nullptr || cb_classifier == nullptr || cb_maskimage == nullptr) // { // QMessageBox::information( nullptr, "Template", "Please load and select an image before starting image processing."); // return; // } // mitk::VigraRandomForestClassifier::Pointer rf = dynamic_cast(cb_classifier->GetSelectedNode()->GetData()); // mitk::Image::Pointer image = dynamic_cast(cb_image->GetSelectedNode()->GetData()); // mitk::Image::Pointer mask = dynamic_cast(cb_maskimage->GetSelectedNode()->GetData()); // unsigned int n_samples = 0; // mitk::CLUtil::CountVoxel(mask, n_samples); // unsigned int n_features = 13; // InputImage, PROBA_CSF, PROBA_LES, PROBA_BRA, FOS_MEAN,FOS_VARIANCE,FOS_SKEWNESS, FOS_KURTOSIS, FOS_MIN, FOS_MAX, HE_1, HE_2, HE_3 // Eigen::MatrixXd feature_matrix = Eigen::MatrixXd(n_samples, n_features); // MITK_INFO << "Remove voxels outside the mask"; // // mitk::CLUtil::LogicalAndImages(image,brain_mask,image); // feature_matrix.block(0,0,n_samples,1) = mitk::CLUtil::Transform(image,mask); // AddImageAsDataNode(image, "UI_InputImage"); // mitk::Image::Pointer csf_prob = mitk::Image::New(); // mitk::CLUtil::ProbabilityMap(image,13.9, 8.3,csf_prob); // feature_matrix.block(0,1,n_samples,1) = mitk::CLUtil::Transform(csf_prob,mask); // AddImageAsDataNode(csf_prob, "UI_CSFProb"); // mitk::Image::Pointer les_prob = mitk::Image::New(); // mitk::CLUtil::ProbabilityMap(image,59, 11.6,les_prob); // feature_matrix.block(0,2,n_samples,1) = mitk::CLUtil::Transform(les_prob,mask); // AddImageAsDataNode(les_prob, "UI_LESProb"); // mitk::Image::Pointer brain_prob = mitk::Image::New(); // mitk::CLUtil::ProbabilityMap(image,32, 5.6,brain_prob); // feature_matrix.block(0,3,n_samples,1) = mitk::CLUtil::Transform(brain_prob,mask); // AddImageAsDataNode(brain_prob, "UI_BRAProb"); // int n = 0; // std::vector res; // DoFirstOrderFeatureCalculation(image, mask, 1, res); // for( const auto & img: res) // { // feature_matrix.block(0,3+(++n),n_samples,1) = mitk::CLUtil::Transform(img,mask); // std::string name; // img->GetPropertyList()->GetStringProperty("name", name); // AddImageAsDataNode(img.GetPointer(), name ); // } // res.clear(); // DoHessianEigenvaluesFeatureCalculation(image, mask, 3.0, res); // for( const auto & img: res) // { // feature_matrix.block(0,3+(++n),n_samples,1) = mitk::CLUtil::Transform(img,mask); // std::string name; // img->GetPropertyList()->GetStringProperty("name", name); // AddImageAsDataNode(img.GetPointer(), name ); // } // MITK_INFO << "Start Prediction"; // rf->Predict(feature_matrix); // MITK_INFO << "End Prediction"; // mitk::Image::Pointer result_image = mitk::CLUtil::Transform(rf->GetLabels(),mask); // mitk::Image::Pointer proba1_image = mitk::CLUtil::Transform(rf->GetPointWiseProbabilities().col(0),mask); // mitk::Image::Pointer proba2_image = mitk::CLUtil::Transform(rf->GetPointWiseProbabilities().col(1),mask); // mitk::Image::Pointer proba3_image = mitk::CLUtil::Transform(rf->GetPointWiseProbabilities().col(2),mask); // AddImageAsDataNode(result_image, "ClassificationResult"); // AddImageAsDataNode(proba1_image, "CSF_Proba_CL"); // AddImageAsDataNode(proba2_image, "LES_Proba_CL"); // AddImageAsDataNode(proba3_image, "BRA_Proba_CL"); // PostProcessing(rf,mask); //} mitk::DataNode::Pointer ClassificationSegmentation::AddAsDataNode(const mitk::BaseData::Pointer & data_, const std::string & name ) { mitk::DataNode::Pointer node = nullptr; node = this->GetDataStorage()->GetNamedNode(name); if(node.IsNull()) { node = mitk::DataNode::New(); node->SetData(data_); node->SetName(name); this->GetDataStorage()->Add(node); }else{ if(dynamic_cast(node->GetData()) && dynamic_cast(data_.GetPointer())) { mitk::Image::Pointer target_image = dynamic_cast(node->GetData()); mitk::Image::Pointer source_image = dynamic_cast(data_.GetPointer()); mitk::ImageReadAccessor ra(source_image); target_image->SetImportVolume(const_cast(ra.GetData())); this->RequestRenderWindowUpdate(); } if(dynamic_cast(node->GetData()) && dynamic_cast(data_.GetPointer())) { node->SetData(data_); node->Modified(); } } return node; } void ClassificationSegmentation::PostProcessingTrigger() { if(m_ResultImageVector.empty() || m_ResultImageVector.size() < 4) { MITK_ERROR("PostProcessingCallback") << "Result image vector not initialized!"; return; } if(!m_BlockPostProcessing){ m_PostProcessingFutureWatcher.setFuture( QtConcurrent::run(this, &ClassificationSegmentation::PostProcessingCallback)); // on finish call OnManualSegmentationFinished(); m_BlockPostProcessing = true; } } void ClassificationSegmentation::PostProcessingFinished() { // Receive Future result m_PostProcessingImageVector = m_PostProcessingFutureWatcher.result(); // Add result to Datastorage mitk::DataNode::Pointer node = AddAsDataNode(m_PostProcessingImageVector[0].GetPointer(),"Manual-ResultMask-PostProcessing"); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType(mitk::LookupTable::PET_20); mitk::LookupTableProperty * lut_prop = dynamic_cast(node->GetProperty("LookupTable")); lut_prop->SetLookupTable(lut); mitk::LevelWindow lw(1,3); node->SetLevelWindow(lw); node->SetOpacity(0.3); m_BlockPostProcessing = false; } std::vector ClassificationSegmentation::PostProcessingCallback() { std::vector resultvector; mitk::Image::Pointer CSF_PMap = m_ResultImageVector[1]->Clone(); mitk::Image::Pointer LES_PMap = m_ResultImageVector[2]->Clone(); mitk::Image::Pointer BRA_PMap = m_ResultImageVector[3]->Clone(); mitk::Image::Pointer mask = m_ResultImageVector[0]->Clone(); MITK_INFO("PostProcessingCallback") << "ProbabilityMap merg strat ..."; { mitk::Image::Pointer resultmask = mask->Clone(); mitk::CLUtil::GaussianFilter(CSF_PMap, CSF_PMap, m_GaussCSFSlider->value()); mitk::CLUtil::GaussianFilter(LES_PMap, LES_PMap, m_GaussLESSlider->value()); mitk::CLUtil::GaussianFilter(BRA_PMap, BRA_PMap, m_GaussBRASlider->value()); itk::Image::Pointer itk_csf, itk_les, itk_bra; itk::Image::Pointer itk_result; mitk::CastToItkImage(CSF_PMap, itk_csf); mitk::CastToItkImage(LES_PMap, itk_les); mitk::CastToItkImage(BRA_PMap, itk_bra); mitk::CastToItkImage(resultmask, itk_result); itk::ImageRegionIterator > it_csf(itk_csf,itk_csf->GetLargestPossibleRegion()); itk::ImageRegionIterator > it_les(itk_les,itk_les->GetLargestPossibleRegion()); itk::ImageRegionIterator > it_bra(itk_bra,itk_bra->GetLargestPossibleRegion()); itk::ImageRegionIterator > it_res(itk_result,itk_result->GetLargestPossibleRegion()); while (!it_csf.IsAtEnd()) { double csf = it_csf.Value() * m_WeightCSFSlider->value(); double les = it_les.Value() * m_WeightLESSlider->value(); double bra = it_bra.Value() * m_WeightBRASlider->value(); if(csf > les && csf > bra) it_res.Set(1); if(les > csf && les > bra) it_res.Set(2); if(bra > les && bra > csf) it_res.Set(3); ++it_csf; ++it_les; ++it_bra; ++it_res; } mitk::CastToMitkImage(itk_result, resultmask); { std::map mergeinstruction ; mergeinstruction[1] = 1; mergeinstruction[2] = 1; mergeinstruction[3] = 1; mergeinstruction[4] = 1; mergeinstruction[5] = 1; mergeinstruction[6] = 1; // {{1,1},{2,1},{3,1},{4,1},{5,1},{6,1}}; mitk::Image::Pointer brain_mask = mask->Clone(); mitk::CLUtil::MergeLabels(brain_mask, mergeinstruction); mitk::CLUtil::ClosingBinary(brain_mask,brain_mask,2,mitk::CLUtil::All); mitk::CLUtil::LogicalAndImages(resultmask, brain_mask, resultmask); } MITK_INFO("PostProcessingCallback") << "ProbabilityMap merg end!"; resultvector.push_back(resultmask); } return resultvector; // { // MITK_INFO << "Morphological processing strat ..."; // mitk::Image::Pointer resultmask = mask->Clone(); // mitk::Image::Pointer csf_mask; // mitk::CLUtil::GrabLabel(resultmask, csf_mask, 1); // mitk::CLUtil::ClosingBinary(csf_mask,csf_mask,1,mitk::CLUtil::Axial); // mitk::CLUtil::ErodeBinary(csf_mask, csf_mask, 2, mitk::CLUtil::Axial); // mitk::CLUtil::DilateBinary(csf_mask, csf_mask, 1, mitk::CLUtil::Axial); // std::map merge_instruction = {{0,0},{1,3},{2,2},{3,3}}; // mitk::CLUtil::MergeLabels(resultmask, merge_instruction); // mitk::CLUtil::InsertLabel(resultmask, csf_mask, 1/*as csf mask*/); // add morpological manipulated csf_mask // // ------------ // mitk::Image::Pointer les_mask; // mitk::CLUtil::GrabLabel(resultmask, les_mask, 2); // mitk::CLUtil::ClosingBinary(les_mask,les_mask,1,mitk::CLUtil::Axial); // mitk::Image::Pointer les_cc_mask; unsigned int num = 0; // mitk::CLUtil::ConnectedComponentsImage(les_mask, mask, les_cc_mask, num); // std::map map; // mitk::CLUtil::CountVoxel(les_cc_mask,map); // unsigned int counter = 0; // while(map.size() > 2) // { // mitk::CLUtil::ErodeBinary(les_mask, les_mask, 1, mitk::CLUtil::Axial); // mitk::CLUtil::LogicalAndImages(les_cc_mask,les_mask,les_cc_mask); // map.clear(); // mitk::CLUtil::CountVoxel(les_cc_mask,map); // MITK_INFO("PostProcessing") << map.size(); // counter++; // } // while(counter != 0) // { // mitk::CLUtil::DilateBinary(les_mask, les_mask, 1, mitk::CLUtil::Axial); // counter--; // } // merge_instruction = {{0,0},{1,1},{2,3},{3,3}}; // mitk::CLUtil::MergeLabels(resultmask, merge_instruction); // mitk::CLUtil::InsertLabel(resultmask, les_mask, 2/*as les mask*/); // MITK_INFO << "Morphological processing end"; // // ------------ // mitk::CLUtil::LogicalAndImages(resultmask,mask,resultmask); // AddImageAsDataNode(resultmask,"SmoothedMaskMorphed"); // } } // mitk::Image::Pointer r= mitk::Image::New(),g= mitk::Image::New(),b = mitk::Image::New(); // unsigned int* m_ImageDimensions; // m_ImageDimensions = new unsigned int[3]; // m_ImageDimensions[0] = raw_image->GetDimensions()[0]; // m_ImageDimensions[1] = raw_image->GetDimensions()[1]; // m_ImageDimensions[2] = 1; // r->Initialize( mitk::MakePixelType() ,3,m_ImageDimensions); // g->Initialize( mitk::MakePixelType() ,3,m_ImageDimensions); // b->Initialize( mitk::MakePixelType() ,3,m_ImageDimensions); // mitk::ImageReadAccessor inputAccForRGB(raw_image, raw_image->GetSliceData(0,0,0)); // unsigned char* rbgSlice = (unsigned char*)inputAccForRGB.GetData(); // mitk::ImageReadAccessor inputAcc(r, r->GetSliceData(0,0,0)); // unsigned char* rData = (unsigned char*)inputAcc.GetData(); // mitk::ImageReadAccessor inputAcc2(g, g->GetSliceData(0,0,0)); // unsigned char* gData = (unsigned char*)inputAcc2.GetData(); // mitk::ImageReadAccessor inputAcc3(b, b->GetSliceData(0,0,0)); // unsigned char* // bData = (unsigned char*)inputAcc3.GetData(); // for(int i = 0; i < m_ImageDimensions[0] * m_ImageDimensions[1]*3; i+=3) // { // rData[i/3] = rbgSlice[i]; // gData[i/3] = rbgSlice[i+1]; // bData[i/3] = rbgSlice[i+2]; // } // m_FeatureImageVector.push_back(r); // m_FeatureImageVector.push_back(g); // m_FeatureImageVector.push_back(b); // AddImageAsDataNode(r,"r"); // AddImageAsDataNode(g,"g"); // AddImageAsDataNode(b,"b");