/*========================================================================= medInria Copyright (c) INRIA 2013 - 2019. All rights reserved. See LICENSE.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =========================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mseg { class VarSegToolBoxPrivate { public: vtkLandmarkSegmentationController *controller; medAbstractLayeredView *currentView; QList medViews; QList *views2D; QList *views3D; QPushButton *segButton; QPushButton *binaryImageButton; QPushButton *applyMaskButton; QPushButton *mprMode; dtkSmartPointer originalInput; dtkSmartPointer output; int inputSize[3]; bool segOn; dtkSmartPointer process; }; VarSegToolBox::VarSegToolBox(QWidget *parent ) : medAbstractSelectableToolBox(parent) , d(new VarSegToolBoxPrivate) { QWidget *displayWidget = new QWidget(this); this->addWidget(displayWidget); QVBoxLayout *layout = new QVBoxLayout(displayWidget); QLabel *inside = new QLabel(QString("Inside VOI: \n\tShift + right mouse button"), displayWidget); QLabel *outside = new QLabel(QString("On VOI: \n\tShift + left mouse button"), displayWidget); QLabel *on = new QLabel(QString("Outside VOI: \n\tShift + Ctrl + right mouse button \n\tor Shift + middle mouse button"), displayWidget); QLabel *deleteLabel = new QLabel(QString("To delete a landmark: \n\tCtrl + left mouse button on the landmark"), displayWidget); d->segButton = new QPushButton(tr("Start Segmentation"), displayWidget); d->segButton->setCheckable(true); d->segButton->setObjectName("segButton"); d->binaryImageButton = new QPushButton(tr("Save Mask"), displayWidget); d->binaryImageButton->setToolTip("Import the current mask to the non persistent database"); d->binaryImageButton->setObjectName("binaryImageButton"); d->applyMaskButton = new QPushButton(tr("Apply and Save Segmentation"), displayWidget); d->applyMaskButton->setToolTip("Apply the mask to the image, save the segmentation"); d->applyMaskButton->setObjectName("applyMaskButton"); enableButtons(false); layout->addWidget(d->segButton); layout->addWidget(inside); layout->addWidget(outside); layout->addWidget(on); layout->addWidget(deleteLabel); layout->addWidget(d->binaryImageButton); layout->addWidget(d->applyMaskButton); connect(d->segButton, SIGNAL(toggled(bool)), this, SLOT(segmentation(bool)), Qt::UniqueConnection); connect(d->binaryImageButton, SIGNAL(clicked()), this, SLOT(addBinaryImage()), Qt::UniqueConnection); connect(d->applyMaskButton, SIGNAL(clicked()), this, SLOT(applyMaskToImage()), Qt::UniqueConnection); d->controller = vtkLandmarkSegmentationController::New(); d->output = medAbstractDataFactory::instance()->createSmartPointer("itkDataImageUChar3"); d->currentView = nullptr; d->segOn = false; d->views2D = new QList(); d->views3D = new QList(); } VarSegToolBox::~VarSegToolBox() { d->controller->Delete(); delete d; } //static medAbstractSelectableToolBox *VarSegToolBox::createInstance(QWidget *parent) { return new VarSegToolBox(parent); } QString VarSegToolBox::s_description() { static const QString desc = "Variational Segmentation Tool"; return desc; } QString VarSegToolBox::s_identifier() { static const QString id = "mseg::VarSegToolBox"; return id; } QString VarSegToolBox::s_name() { return "Variational Segmentation"; } dtkPlugin* VarSegToolBox::plugin() { return medPluginManager::instance().plugin("Variational Segmentation"); } void VarSegToolBox::updateLandmarksRenderer(QString key, QString value) { if (key != "Orientation") { return; } medAbstractView *v = qobject_cast(this->sender()); if (v != d->currentView || !d->controller) { return; } vtkRenderWindowInteractor *interactor = static_cast(v->backend())->renWin->GetInteractor(); vtkCollection *landmarks = d->controller->GetTotalLandmarkCollection(); landmarks->InitTraversal(); vtkLandmarkWidget *l = vtkLandmarkWidget::SafeDownCast(landmarks->GetNextItemAsObject()); while(l) { if (!d->controller->RemoveConstraint (l)) { if ( (l->GetInteractor() == interactor)) { if (value=="3D") { l->On(); } else if (d->controller->getMode3D()) // test if previous orientation was 3d { if (l->GetCurrentRenderer()) { l->Off(); } } } } l = vtkLandmarkWidget::SafeDownCast(landmarks->GetNextItemAsObject()); } if (value == "3D") { d->controller->setMode3D(true); } else { d->controller->setMode3D(false); } landmarks->InitTraversal(); l = vtkLandmarkWidget::SafeDownCast(landmarks->GetNextItemAsObject()); while(l) { l->showOrHide2DWidget(); l = vtkLandmarkWidget::SafeDownCast(landmarks->GetNextItemAsObject()); } } void VarSegToolBox::addBinaryImage() { typedef itk::Image binaryType; binaryType::Pointer img = d->controller->GetBinaryImage(); if (img) { d->output->setData(img); medUtilities::setDerivedMetaData(d->output, d->originalInput, "VarSegMask"); medDataManager::instance().importData(d->output, false); } } void VarSegToolBox::applyMaskToImage() { if (d->currentView) { this->setToolBoxOnWaitStatus(); d->process = qobject_cast(dtkAbstractProcessFactory::instance()->create("medMaskApplication")); typedef itk::Image binaryType; binaryType::Pointer img = d->controller->GetBinaryImage(); if (img) { medAbstractData *maskData = medAbstractDataFactory::instance()->create( "itkDataImageUChar3" ); maskData->setData(img); d->process->setInput(maskData, 0); d->process->setInput(static_cast(d->currentView->layerData(0)), 1); medRunnableProcess *runProcess = new medRunnableProcess; runProcess->setProcess (d->process); connect (runProcess, SIGNAL (success (QObject*)), this, SLOT(displayOutput()), Qt::UniqueConnection); this->addConnectionsAndStartJob(runProcess); enableOnProcessSuccessImportOutput(runProcess, false); } else { this->displayMessageError("The input data is empty"); this->setToolBoxOnReadyToUse(); } } } void VarSegToolBox::displayOutput() { medUtilities::setDerivedMetaData(d->process->output(), d->originalInput, "VarSegApplied"); medDataManager::instance().importData(d->process->output(), false); typedef itk::Image binaryType; binaryType::Pointer img = d->controller->GetBinaryImage(); if (img) { d->output->setData(img); medUtilities::setDerivedMetaData(d->output, d->originalInput, "VarSegMask"); } medTabbedViewContainers *tabbedViewContainers = getWorkspace()->tabbedViewContainers(); medViewContainer *viewContainer = tabbedViewContainers->containersInTab(tabbedViewContainers->currentIndex()).at(0); viewContainer->removeView(); viewContainer->setMultiLayered(true); viewContainer->addData(d->process->output()); } void VarSegToolBox::updateView() { medAbstractView *view = this->getWorkspace()->tabbedViewContainers()->getFirstSelectedContainerView(); medAbstractLayeredView *layeredView = qobject_cast(view); if (layeredView && !d->segOn) { // if the segmentation is activated we do not change the currentView. // The currentView is supposed to be the view in which the segmentation is being done. d->currentView = layeredView; // Toolbox does not work with meshes or vector images for (unsigned int i=0; icurrentView->layersCount(); ++i) { medAbstractData *data = d->currentView->layerData(i); if(!data || data->identifier().contains("vtkDataMesh") || !data->identifier().contains("itkDataImage") //avoid medVtkFibersData also || data->identifier().contains("itkDataImageVector") || (qobject_cast(data)->Dimension() != 3)) { handleDisplayError(medAbstractProcessLegacy::DIMENSION_3D); d->currentView = nullptr; return; } } } else { d->currentView = nullptr; } } void VarSegToolBox::clear() { endSegmentation(); } void VarSegToolBox::startSegmentation() { if (!d->currentView) { d->segButton->setChecked(false); this->displayMessageError("A data is needed in the view"); return; } d->medViews.clear(); d->views2D->clear(); d->views3D->clear(); connect(d->currentView, SIGNAL(propertySet(QString,QString)), this, SLOT(updateLandmarksRenderer(QString,QString)), Qt::UniqueConnection); connect(d->currentView, SIGNAL(closed()), this, SLOT(manageClosingView()), Qt::UniqueConnection); vtkCollection *interactorcollection = vtkCollection::New(); interactorcollection->AddItem(static_cast(d->currentView->backend())->renWin->GetInteractor()); d->controller->SetInteractorCollection(interactorcollection); interactorcollection->Delete(); d->controller->EnabledOn(); typedef vtkLandmarkSegmentationController::ImageType ImageType; ImageType::Pointer image; d->originalInput = d->currentView->layerData(0); if (!d->originalInput) return; if (d->originalInput->identifier() == "itkDataImageShort3") { image = castImageToType(d->originalInput); } else if (d->originalInput->identifier() == "itkDataImageUShort3") { image = castImageToType(d->originalInput); } else if (d->originalInput->identifier() == "itkDataImageDouble3") { image = castImageToType(d->originalInput); } else if (d->originalInput->identifier() == "itkDataImageFloat3") { image = castImageToType(d->originalInput); } else if (d->originalInput->identifier() == "itkDataImageInt3") { image = castImageToType(d->originalInput); } else if (d->originalInput->identifier() == "itkDataImageUChar3") { image = castImageToType(d->originalInput); } else { handleDisplayError(medAbstractProcessLegacy::PIXEL_TYPE); endSegmentation(); return; } ImageType::Pointer smallerImage; ImageType::SizeType imageSize = image->GetLargestPossibleRegion().GetSize(); ; ImageType::SpacingType imageSpacing = image->GetSpacing(); double res = 25; ImageType::IndexType corner = {{0,0,0}}; double smallestSpacing = std::min(imageSpacing[0], std::min(imageSpacing[1], imageSpacing[2])); double mSpacing[3]; for (unsigned int i = 0; i < 3; i++) { mSpacing[i] = 100 * smallestSpacing / res; } int mDim[3]; for (unsigned int i = 0; i < 3; i++) { mDim[i] = (int) (imageSize[i] * imageSpacing[i] / mSpacing[i]); d->inputSize[i]=imageSize[i]; } d->controller->setOutputSize(d->inputSize[0], d->inputSize[1], d->inputSize[2]); ImageType::SpacingType NewSpacing; ImageType::SizeType NewSize; NewSpacing[0] = mSpacing[0]; NewSpacing[1] = mSpacing[1]; NewSpacing[2] = mSpacing[2]; NewSize[0] = mDim[0]; NewSize[1] = mDim[1]; NewSize[2] = mDim[2]; ImageType::RegionType region(corner,NewSize); smallerImage = ImageType::New(); smallerImage->SetRegions(region); smallerImage->Allocate(); smallerImage->SetDirection(image->GetDirection()); smallerImage->SetOrigin(image->GetOrigin()); smallerImage->SetSpacing(NewSpacing); d->controller->SetInput(smallerImage); d->medViews.append(d->currentView); d->views2D->append(static_cast(d->currentView->backend())->view2D); d->views3D->append(static_cast(d->currentView->backend())->view3D); for (int i = 0; imedViews.size(); i++) { d->views2D->at(i)->AddDataSet (d->controller->GetOutput()); d->views3D->at(i)->AddDataSet (d->controller->GetOutput()); } d->controller->setViews2D(d->views2D); d->controller->setViews3D(d->views3D); enableButtons(true); d->segOn = true; } template typename vtkLandmarkSegmentationController::ImageType::Pointer VarSegToolBox::castImageToType(medAbstractData *inputData) { typedef itk::Image InputImage; typename InputImage::Pointer imgData = dynamic_cast< InputImage*>((itk::Object*)(inputData->data())); typedef itk::CastImageFilter< InputImage, vtkLandmarkSegmentationController::ImageType > CasterType; typename CasterType::Pointer caster = CasterType::New(); caster->SetInput(imgData); caster->Update(); return caster->GetOutput(); } void VarSegToolBox::manageClosingView() { d->currentView = nullptr; d->medViews.clear(); endSegmentation(); } void VarSegToolBox::enableButtons(bool isEnabled) { d->binaryImageButton->setEnabled(isEnabled); d->applyMaskButton->setEnabled(isEnabled); } void VarSegToolBox::endSegmentation() { if (d->segButton->isChecked()) { d->segButton->setChecked(false); } d->segButton->setText("Start Segmentation"); d->segOn = false; if (d->controller) { for (int i = 0; imedViews.size(); i++) { if(d->currentView) { d->views2D->at(i)->RemoveDataSet (d->controller->GetOutput()); d->views3D->at(i)->RemoveDataSet (d->controller->GetOutput()); } } d->controller->EnabledOff(); d->controller->DeleteAllLandmarks(); d->controller->Delete(); d->controller = vtkLandmarkSegmentationController::New(); updateView(); enableButtons(false); medAbstractView *view = this->getWorkspace()->tabbedViewContainers()->getFirstSelectedContainerView(); if (view && (view->count()>0)) { view->render(); } } } void VarSegToolBox::segmentation(bool checked) { if (checked) { d->segButton->setText("End Segmentation"); startSegmentation(); } else { endSegmentation(); } } medAbstractData* VarSegToolBox::processOutput() { return d->output; } } // namespace mseg