diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.cpp index 4afbb2be02..9992684b8e 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.cpp @@ -1,226 +1,277 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkContourModelToImageWidget.h" #include "mitkImage.h" #include "../../Common/QmitkDataSelectionWidget.h" #include #include #include #include #include #include #include #include +#include #include static const char* const HelpText = "Select a binary image and a contour(set)"; QmitkContourModelToImageWidget::QmitkContourModelToImageWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) : QmitkSegmentationUtilityWidget(timeNavigationController, parent) { m_Controls.setupUi(this); m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::SegmentationPredicate); m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::ContourModelPredicate); m_Controls.dataSelectionWidget->SetHelpText(HelpText); this->EnableButtons(false); connect (m_Controls.btnProcess, SIGNAL(pressed()), this, SLOT(OnProcessPressed())); connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); if( m_Controls.dataSelectionWidget->GetSelection(0).IsNotNull() && m_Controls.dataSelectionWidget->GetSelection(1).IsNotNull() ) { this->OnSelectionChanged( 0, m_Controls.dataSelectionWidget->GetSelection(0)); } } QmitkContourModelToImageWidget::~QmitkContourModelToImageWidget() { } void QmitkContourModelToImageWidget::OnSelectionChanged(unsigned int index, const mitk::DataNode* selection) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node0 = dataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer node1 = dataSelectionWidget->GetSelection(1); if (node0.IsNull() || node1.IsNull() ) { this->EnableButtons(false); } else { this->SelectionControl(index, selection); } } void QmitkContourModelToImageWidget::SelectionControl(unsigned int index, const mitk::DataNode* /*selection*/) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(index); //TODO check if contours are inside the image! dataSelectionWidget->SetHelpText(""); this->EnableButtons(); } void QmitkContourModelToImageWidget::EnableButtons(bool enable) { m_Controls.btnProcess->setEnabled(enable); } void QmitkContourModelToImageWidget::OnProcessPressed() { - //Disable Buttons during calculation and initialize Progressbar - this->EnableButtons(false); - mitk::ProgressBar::GetInstance()->AddStepsToDo(4); - mitk::ProgressBar::GetInstance()->Progress(); - QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; - //create result image, get mask node and reference image - mitk::Image::Pointer resultImage(0); mitk::DataNode::Pointer segmentationNode = dataSelectionWidget->GetSelection(0); + + if (segmentationNode.IsNull()) + { + MITK_ERROR<<"Error writing contours into binary image! No image selected!"; + return; + } + mitk::Image::Pointer segmentationImage = static_cast(segmentationNode->GetData()); - //TODO Use one ContourModelSet!!! - //TODO Extract logic to somewhere - std::vector contourList; + if (segmentationImage.IsNull()) + { + MITK_ERROR<<"Error writing contours into binary image! Invalid image data selected!"; + return; + } + + unsigned int timeStep = this->GetTimeNavigationController()->GetTime()->GetPos(); + + m_SegmentationImage = segmentationImage; + m_SegmentationImageGeometry = segmentationImage->GetTimeGeometry()->GetGeometryForTimeStep(timeStep); + + mitk::ContourModelSet::Pointer contourSet; mitk::DataNode::Pointer contourNode = dataSelectionWidget->GetSelection(1); - mitk::ContourModel::Pointer contour = static_cast(contourNode->GetData()); + mitk::ContourModel::Pointer contour = dynamic_cast(contourNode->GetData()); if (contour.IsNotNull()) { - contourList.push_back(contour); + contourSet = mitk::ContourModelSet::New(); + contourSet->AddContourModel(contour); } else { - // TODO move to utils! - mitk::ContourModelSet::Pointer contourSet = static_cast(contourNode->GetData()); - mitk::ContourModelSet::ContourModelSetIterator it = contourSet->Begin(); - while (it != contourSet->End()) + contourSet = static_cast(contourNode->GetData()); + if (contourSet.IsNull()) { - contourList.push_back(*it); - ++it; + MITK_ERROR<<"Error writing contours into binary image! Invalid contour data selected!"; + return; } } - // Do actual filling - mitk::Geometry3D::Pointer segmentationGeometry = segmentationImage->GetGeometry(); - mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); - mitk::Point3D point3D; - mitk::Vector3D normal; + //Disable Buttons during calculation and initialize Progressbar + this->EnableButtons(false); + unsigned int num_contours = contourSet->GetContourModelList()->size(); + mitk::ProgressBar::GetInstance()->AddStepsToDo(num_contours); + mitk::ProgressBar::GetInstance()->Progress(); - mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(); - mitk::Image::Pointer slice; + // Do actual filling mitk::ContourModel::Pointer projectedContour; - - unsigned int timeStep = this->GetTimeNavigationController()->GetTime()->GetPos(); - int sliceIndex; - bool isFrontside = true; - bool isRotated = false; - - foreach (mitk::ContourModel::Pointer contour, contourList) + mitk::ContourModelSet::ContourModelSetIterator it = contourSet->Begin(); + mitk::ContourModelSet::ContourModelSetIterator end = contourSet->End(); + while (it != end) { + mitk::ContourModel* contour = it->GetPointer(); + //Check Controls - // BUG save project with contours not working!! -// contour->GetGeometry()->Print(std::cout); - - // 1. construct geometry -> extract slice - // TODO Detect contour orientation - point3D = contour->GetVertexAt(0)->Coordinates; - segmentationGeometry->WorldToIndex(point3D, point3D); - plane->InitializeStandardPlane(segmentationGeometry, mitk::PlaneGeometry::Axial, point3D[2], isFrontside, isRotated); - point3D = plane->GetOrigin(); - normal = plane->GetNormal(); - normal.Normalize(); - point3D += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 - plane->SetOrigin(point3D); - - // 2. fill into it - extractor->SetInput( segmentationImage ); -// extractor->SetTimeStep( timeStep ); - extractor->SetWorldGeometry( plane ); - extractor->SetVtkOutputRequest(false); - extractor->SetResliceTransformByGeometry( segmentationImage->GetTimeGeometry()->GetGeometryForTimeStep( timeStep ) ); - extractor->Modified(); - extractor->Update(); + // 1. Get corresponding image slice + mitk::Image::Pointer slice = this->GetSliceForContour(contour, timeStep); - slice = extractor->GetOutput(); + // 2. Fill contour into slice projectedContour = mitk::ContourModelUtils::ProjectContourTo2DSlice(slice, contour, true, false); mitk::ContourModelUtils::FillContourInSlice(projectedContour, slice); - mitk::DataNode::Pointer filled = mitk::DataNode::New(); - filled->SetName("FILLED"); - filled->SetData(slice); - dataSelectionWidget->GetDataStorage()->Add(filled); +// mitk::DataNode::Pointer filled = mitk::DataNode::New(); +// filled->SetName("FILLED"); +// filled->SetData(slice); +// dataSelectionWidget->GetDataStorage()->Add(filled); + // 3. Write slice back into image volume + if (slice.IsNotNull()) + { + this->WriteBackSlice(slice, timeStep); + } + else + { + MITK_ERROR<<"Contour to image failed!"; + } + mitk::ProgressBar::GetInstance()->Progress(); + ++it; } if(segmentationNode.IsNull() || contourNode.IsNull() ) { MITK_ERROR << "Selection does not contain valid data"; QMessageBox::information( this, "Contour To Image", "Selection does not contain valid data, please select a binary image and a contour(set)", QMessageBox::Ok ); m_Controls.btnProcess->setEnabled(false); return; } + this->EnableButtons(); +} - //Do Image-Masking - mitk::ProgressBar::GetInstance()->Progress(); +mitk::Image::Pointer QmitkContourModelToImageWidget::GetSliceForContour(mitk::ContourModel::Pointer contour, unsigned int timestep) +{ + mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); + mitk::Point3D point3D, tempPoint; + mitk::Vector3D normal; - // Do contour filling + mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(); + mitk::Image::Pointer slice; - mitk::ProgressBar::GetInstance()->Progress(); + int sliceIndex; + bool isFrontside = true; + bool isRotated = false; - if( resultImage.IsNull() ) + point3D = contour->GetVertexAt(0)->Coordinates; + tempPoint = contour->GetVertexAt(contour->GetNumberOfVertices()*0.5)->Coordinates; + mitk::Vector3D vec = point3D - tempPoint; + vec.Normalize(); +// MITK_INFO<GetIndexToWorldTransform()->GetMatrix(); + m_SegmentationImageGeometry->WorldToIndex(point3D, point3D); + mitk::PlaneGeometry::PlaneOrientation orientation; + if (mitk::Equal(vec[0], 0)) { - MITK_ERROR << "Contour To Image failed"; - QMessageBox::information( this, "Contour To Image", "Failed to write contours into image. For more information please see logging window.", QMessageBox::Ok ); - this->EnableButtons(); - mitk::ProgressBar::GetInstance()->Progress(4); - return; + orientation = mitk::PlaneGeometry::Sagittal; + sliceIndex = point3D[0]; + } + else if (mitk::Equal(vec[1], 0)) + { + orientation = mitk::PlaneGeometry::Frontal; + sliceIndex = point3D[1]; + } + else if (mitk::Equal(vec[2], 0)) + { + orientation = mitk::PlaneGeometry::Axial; + sliceIndex = point3D[2]; + } + else + { + // Maybe rotate geometry to extract slice? + MITK_ERROR<<"Cannot detect correct slice number! Only axial, sagittal and frontal oriented contours are supported!"; + return 0; } - //Add result to data storage - this->AddToDataStorage( - dataSelectionWidget->GetDataStorage(), - resultImage, - dataSelectionWidget->GetSelection(0)->GetName() + "_" + dataSelectionWidget->GetSelection(1)->GetName(), - dataSelectionWidget->GetSelection(0)); + plane->InitializeStandardPlane(m_SegmentationImageGeometry, orientation, sliceIndex, isFrontside, isRotated); + point3D = plane->GetOrigin(); + normal = plane->GetNormal(); + normal.Normalize(); + point3D += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 + plane->SetOrigin(point3D); - this->EnableButtons(); + m_CurrentPlane = plane; - mitk::ProgressBar::GetInstance()->Progress(); -} + // 2. fill into it + extractor->SetInput( m_SegmentationImage ); +// extractor->SetTimeStep( timeStep ); + extractor->SetWorldGeometry( plane ); + extractor->SetVtkOutputRequest(false); + extractor->SetResliceTransformByGeometry( m_SegmentationImageGeometry ); + + extractor->Modified(); + extractor->Update(); + slice = extractor->GetOutput(); + return slice; +} -void QmitkContourModelToImageWidget::AddToDataStorage(mitk::DataStorage::Pointer dataStorage, mitk::Image::Pointer segmentation, const std::string& name, mitk::DataNode::Pointer parent ) +void QmitkContourModelToImageWidget::WriteBackSlice(mitk::Image::Pointer slice, unsigned int timestep) { - mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); + //Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk reslicer + vtkSmartPointer reslice = vtkSmartPointer::New(); + + //Set the slice as 'input' + reslice->SetInputSlice(slice->GetVtkImageData()); + + //set overwrite mode to true to write back to the image volume + reslice->SetOverwriteMode(true); + reslice->Modified(); + + mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); + extractor->SetInput( m_SegmentationImage ); + extractor->SetTimeStep( timestep ); + extractor->SetWorldGeometry( m_CurrentPlane ); + extractor->SetVtkOutputRequest(true); + extractor->SetResliceTransformByGeometry( m_SegmentationImage->GetGeometry( timestep ) ); - dataNode->SetName(name); - dataNode->SetData(segmentation); + extractor->Modified(); + extractor->Update(); - dataStorage->Add(dataNode, parent); + m_SegmentationImage->Modified(); + m_SegmentationImage->GetVtkImageData()->Modified(); } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.h index 15b9e8bcbe..76afb38f08 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.h @@ -1,86 +1,92 @@ /*=================================================================== 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 QmitkContourModelToImageWidget_h #define QmitkContourModelToImageWidget_h #include "../QmitkSegmentationUtilityWidget.h" #include -#include - namespace mitk { class Image; class ContourModelSet; class ContourModel; + class Geometry3D; + class PlaneGeometry; } /*! \brief QmitkContourModelToImageWidget Tool masks an image with a binary image or a surface. The Method requires an image and a binary image mask or a surface. The input image and the binary image mask must be of the same size. Masking with a surface creates first a binary image of the surface and then use this for the masking of the input image. */ class QmitkContourModelToImageWidget : public QmitkSegmentationUtilityWidget { Q_OBJECT public: /** @brief Default constructor, including creation of GUI elements and signals/slots connections. */ explicit QmitkContourModelToImageWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent = NULL); /** @brief Defaul destructor. */ ~QmitkContourModelToImageWidget(); private slots: /** @brief This slot is called if the selection in the workbench is changed. */ void OnSelectionChanged(unsigned int index, const mitk::DataNode* selection); // /** @brief This slot is called if user activates the radio button for masking an image with a binary image mask. */ // void OnContourModelToImageToggled(bool); // /** @brief This slot is called if user activates the radio button for masking an image with a surface. */ // void OnSurfaceMaskingToggled(bool); /** @brief This slot is called if user activates the button to mask an image. */ void OnProcessPressed(); private: /** @brief Check if selections is valid. */ void SelectionControl( unsigned int index, const mitk::DataNode* selection); /** @brief Enable buttons if data selction is valid. */ void EnableButtons(bool enable = true); + /** @brief Extracts the slice which correspond to the position of the contour*/ + itk::SmartPointer GetSliceForContour(itk::SmartPointer contour, unsigned int timestep); + + /** @brief Extracts the slice which correspond to the position of the contour*/ + void WriteBackSlice (itk::SmartPointer slice, unsigned int timestep); + /** @brief Fills a mitk::ContourModel into a given segmentation image */ itk::SmartPointer ContourModelToImage(itk::SmartPointer segmenationImage, itk::SmartPointer contour ); /** @brief Fills a whole ContourModelSet into a given segmentation image */ itk::SmartPointer ContourModelSetToImage( itk::SmartPointer segmenationImage, itk::SmartPointer contourSet ); - /** @brief Adds a new data object to the DataStorage.*/ - void AddToDataStorage(mitk::DataStorage::Pointer dataStorage, itk::SmartPointer segmentation, - const std::string& name, mitk::DataNode::Pointer parent = NULL); - Ui::QmitkContourModelToImageWidgetControls m_Controls; + + itk::SmartPointer m_SegmentationImage; + mitk::Geometry3D::Pointer m_SegmentationImageGeometry; + itk::SmartPointer m_CurrentPlane; }; #endif