#ifndef _vvSegmentationDialog_CXX #define _vvSegmentationDialog_CXX /*========================================================================= Program: vv Module: $RCSfile: vvSegmentationDialog.cxx,v $ Language: C++ Date: $Date: 2010/01/06 13:31:58 $ Version: $Revision: 1.1 $ Author : David Sarrut (david.sarrut@gmail.com) Copyright (C) 2008 Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr CREATIS-LRMN http://www.creatis.insa-lyon.fr This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . =========================================================================*/ #include #include #include "vvSegmentationDialog.h" #include "vvProgressDialog.h" #include "vvImageWriter.h" #include "vvLandmarks.h" #include "vvInteractorStyleNavigator.h" #include "vvSlicer.h" #include "vtkMarchingCubes.h" #include "vtkMarchingSquares.h" #include "vtkImageClip.h" #include "vtkCamera.h" #include "vtkRenderer.h" #include "vtkProperty.h" #include "vtkLookupTable.h" #include "vtkClipPolyData.h" #include "vtkImageToPolyDataFilter.h" #include "vtkLookupTable.h" #include "vtkDoubleArray.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkImageMapToWindowLevelColors.h" #include "vtkImageContinuousErode3D.h" #include "vtkImageContinuousDilate3D.h" #include "vtkImageLogic.h" #include "vtkInteractorStyleTrackballCamera.h" #include "vtkImageSeedConnectivity.h" #include "vtkConnectivityFilter.h" #include "vtkPolyData.h" #include #include #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkStreamingDemandDrivenPipeline.h" #include #include //==================================================================== vvSegmentationDialog::vvSegmentationDialog(QWidget * parent, Qt::WindowFlags f) :QDialog(parent,f), Ui::vvSegmentationDialog() { // initialization setupUi(this); mManager = new vvSlicerManager(1); mClipper = vtkImageClip::New(); mSquares1 = vtkMarchingSquares::New(); mSquaresMapper1 = vtkPolyDataMapper::New(); mSquaresActor1 = vtkActor::New(); mSquares2 = vtkMarchingSquares::New(); mSquaresMapper2 = vtkPolyDataMapper::New(); mSquaresActor2 = vtkActor::New(); //m3DMapper = vtkPolyDataMapper::New(); //m3DActor = vtkActor::New(); m3DExtractor = vtkMarchingCubes::New(); m3DMappers.clear(); m3DActors.clear(); mBinaireImages.clear(); mKernelValue = 2; connect(clipping1Slider,SIGNAL(valueChanged(int)),this,SLOT(clippingvaluechanged(int))); connect(clipping2Slider,SIGNAL(valueChanged(int)),this,SLOT(clippingvaluechanged(int))); connect(binaryButton,SIGNAL(clicked()),this,SLOT(BinariseSurface())); connect(saveButton,SIGNAL(clicked()),this,SLOT(Save())); connect(erodeButton,SIGNAL(clicked()),this,SLOT(Erode())); connect(dilateButton,SIGNAL(clicked()),this,SLOT(Dilate())); connect(dimButton,SIGNAL(clicked()),this,SLOT(ChangeDimRendering())); connect(kernelSpinBox,SIGNAL(valueChanged(int)),this,SLOT(KernelValueChanged(int))); binaryButton->setEnabled(0); erodeButton->setEnabled(0); dilateButton->setEnabled(0); infoLabel->setText("Select Up and Down threshold before clicking binarise !"); } vvSegmentationDialog::~vvSegmentationDialog() { mClipper->Delete(); mSquaresActor1->Delete(); mSquaresMapper1->Delete(); mSquares1->Delete(); mSquaresActor2->Delete(); mSquaresMapper2->Delete(); mSquares2->Delete(); //m3DMapper->Delete(); //m3DActor->Delete(); m3DExtractor->Delete(); for (unsigned int i = 0; i < mBinaireImages.size(); i++) mBinaireImages[i]->Delete(); for (unsigned int i = 0; i < m3DActors.size(); i++) m3DActors[i]->Delete(); for (unsigned int i = 0; i < m3DMappers.size(); i++) m3DMappers[i]->Delete(); delete mManager; } //---------------------------------------------------------------------------- // This templated function executes the filter for any type of data. // Handles the one input operations template void vvImageBinarize(vtkImageData *in1Data, T *in1Ptr, int outExt[6],int clampMin, int clampMax) { int idxR, idxY, idxZ; int maxY, maxZ; vtkIdType inIncX, inIncY, inIncZ; int rowLength; // find the region to loop over rowLength = (outExt[1] - outExt[0]+1)*in1Data->GetNumberOfScalarComponents(); // What a pain. Maybe I should just make another filter. maxY = outExt[3] - outExt[2]; maxZ = outExt[5] - outExt[4]; // Get increments to march through data in1Data->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ); for (idxZ = 0; idxZ <= maxZ; idxZ++) { for (idxY = 0; idxY <= maxY; idxY++) { for (idxR = 0; idxR < rowLength; idxR++) { if (static_cast(*in1Ptr) > clampMin && static_cast(*in1Ptr) <= clampMax) *in1Ptr = static_cast(1); else *in1Ptr = static_cast(0); in1Ptr++; } in1Ptr += inIncY; } in1Ptr += inIncZ; } } void vvSegmentationDialog::SetImage(vvImage::Pointer image) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); mManager->SetImage(image); mManager->SetSlicerWindow(0,viewWidget->GetRenderWindow()); vvInteractorStyleNavigator* style = vvInteractorStyleNavigator::New(); mManager->SetInteractorStyleNavigator(0,style); style->Delete(); double range[2]; mManager->GetImage()->GetScalarRange(range); mManager->GetSlicer(0)->SetColorWindow(range[1]-range[0]); mManager->GetSlicer(0)->SetColorLevel((range[1]+range[0])/2); clipping1Slider->setMinimum(range[0]); clipping1Slider->setMaximum(range[1]); clipping2Slider->setMinimum(range[0]); clipping2Slider->setMaximum(range[1]); clipping1Slider->setValue(range[0]); clipping2Slider->setValue(range[1]); mClipper->SetInput(mManager->GetSlicer(0)->GetInput()); mSquares1->SetValue(0,clipping1Slider->value()); mSquares2->SetValue(0,clipping2Slider->value()); mSquares1->SetInput(mClipper->GetOutput()); mSquares2->SetInput(mClipper->GetOutput()); mSquaresMapper1->SetInput(mSquares1->GetOutput()); mSquaresMapper2->SetInput(mSquares2->GetOutput()); mSquaresMapper1->ScalarVisibilityOff(); mSquaresMapper2->ScalarVisibilityOff(); mSquaresActor1->SetMapper(mSquaresMapper1); mSquaresActor2->SetMapper(mSquaresMapper2); mSquaresActor1->GetProperty()->SetColor(1.0,0,0); mSquaresActor2->GetProperty()->SetColor(0,0,1.0); mSquaresActor1->SetPickable(0); mSquaresActor2->SetPickable(0); mManager->GetSlicer(0)->GetRenderer()->AddActor(mSquaresActor1); mManager->GetSlicer(0)->GetRenderer()->AddActor(mSquaresActor2); mSquares1->Update(); mSquares2->Update(); UpdateSlice(0,mManager->GetSlicer(0)->GetSlice()); connect(mManager,SIGNAL(UpdateTSlice(int,int)),this,SLOT(UpdateSlice(int, int))); connect(mManager,SIGNAL(UpdateSlice(int,int)),this,SLOT(UpdateSlice(int, int))); connect(mManager,SIGNAL(UpdateSliceRange(int,int,int,int,int)),this,SLOT(UpdateSlice(int, int))); connect(mManager,SIGNAL(LandmarkAdded()),this,SLOT(InsertSeed())); QApplication::restoreOverrideCursor(); } void vvSegmentationDialog::UpdateSlice(int slicer,int slices) { int slice = mManager->GetSlicer(0)->GetSlice(); int tslice = mManager->GetSlicer(0)->GetTSlice(); mClipper->SetInput(mManager->GetSlicer(0)->GetInput()); int* extent = mManager->GetSlicer(0)->GetImageActor()->GetDisplayExtent(); mClipper->SetOutputWholeExtent(extent[0],extent[1],extent[2],extent[3],extent[4],extent[5]); int i; for (i = 0; i < 6;i = i+2) { if (extent[i] == extent[i+1]) { break; } } switch (i) { case 0: if (mManager->GetSlicer(0)->GetRenderer()->GetActiveCamera()->GetPosition()[0] > slice) { mSquaresActor1->SetPosition(1,0,0); mSquaresActor2->SetPosition(1,0,0); } else { mSquaresActor1->SetPosition(-1,0,0); mSquaresActor2->SetPosition(-1,0,0); } break; case 2: if (mManager->GetSlicer(0)->GetRenderer()->GetActiveCamera()->GetPosition()[1] > slice) { mSquaresActor1->SetPosition(0,1,0); mSquaresActor2->SetPosition(0,1,0); } else { mSquaresActor1->SetPosition(0,-1,0); mSquaresActor2->SetPosition(0,-1,0); } break; case 4: if (mManager->GetSlicer(0)->GetRenderer()->GetActiveCamera()->GetPosition()[2] > slice) { mSquaresActor1->SetPosition(0,0,1); mSquaresActor2->SetPosition(0,0,1); } else { mSquaresActor1->SetPosition(0,0,-1); mSquaresActor2->SetPosition(0,0,-1); } break; } mSquares1->Update(); mSquares2->Update(); if (m3DActors.size()) { for (unsigned int i =0; i < m3DActors.size(); i++) { if (m3DActors[i]->GetVisibility()) { m3DActors[i]->VisibilityOff(); } } std::cout << "display " << tslice << " on " << m3DActors.size() << std::endl; m3DActors[tslice]->VisibilityOn(); } mManager->Render(); } void vvSegmentationDialog::clippingvaluechanged(int value) { binaryButton->setEnabled(1); int min = (clipping1Slider->value() < clipping2Slider->value() ) ? clipping1Slider->value():clipping2Slider->value(); int max = (clipping1Slider->value() > clipping2Slider->value() ) ? clipping1Slider->value():clipping2Slider->value(); mSquares1->SetValue(0,min); mSquares2->SetValue(0,max); QString textMin = " Min : "; textMin += QString::number(min); QString textMax = "\n Max : "; textMax += QString::number(max); minLabel->setText(textMin); maxLabel->setText(textMax); if (mSquares1->GetInput()) { mSquares1->Update(); mSquares2->Update(); mManager->Render(); } } void vvSegmentationDialog::BinariseSurface() { infoLabel->setText("Click erode then space on desired organ !"); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); int clampMin = (clipping1Slider->value() < clipping2Slider->value() ) ? clipping1Slider->value():clipping2Slider->value(); int clampMax = (clipping1Slider->value() > clipping2Slider->value() ) ? clipping1Slider->value():clipping2Slider->value(); vtkImageData* outputImage = vtkImageData::New(); for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) { vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage]; int ext[6]; image->GetWholeExtent(ext); void *in1Ptr; in1Ptr = image->GetScalarPointerForExtent(ext); switch (image->GetScalarType()) { vtkTemplateMacro( vvImageBinarize(image, static_cast(in1Ptr), ext,clampMin,clampMax)); default: std::cerr << "Error, unknown pixel format : " << image->GetScalarTypeAsString() << std::endl; return; } outputImage->Initialize(); outputImage->SetExtent(ext); outputImage->SetOrigin(image->GetOrigin()); outputImage->SetSpacing(image->GetSpacing()); outputImage->SetScalarTypeToUnsignedChar(); outputImage->CopyAndCastFrom(image,ext); outputImage->Update(); image->DeepCopy(outputImage); image->UpdateInformation(); image->PropagateUpdateExtent(); vtkImageData* imageBin = vtkImageData::New(); imageBin->DeepCopy(image); imageBin->Update(); mBinaireImages.push_back(imageBin); } outputImage->Delete(); erodeButton->setEnabled(1); QApplication::restoreOverrideCursor(); mManager->SetColorWindow(2); mManager->SetColorLevel(0.5); mManager->Render(); } void vvSegmentationDialog::Erode() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); vtkImageContinuousErode3D* erode = vtkImageContinuousErode3D::New(); erode->SetKernelSize(mKernelValue,mKernelValue,mKernelValue); for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) { vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage]; erode->SetInput(image); erode->Update(); image->DeepCopy(erode->GetOutput()); image->Update(); } erode->Delete(); dilateButton->setEnabled(1); mManager->Render(); QApplication::restoreOverrideCursor(); } void vvSegmentationDialog::Dilate() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); vtkImageContinuousDilate3D* dilate = vtkImageContinuousDilate3D::New(); vtkImageLogic* And = vtkImageLogic::New(); And->SetOperationToAnd(); dilate->SetKernelSize(mKernelValue,mKernelValue,mKernelValue); for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) { vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage]; dilate->SetInput(image); vtkImageData* mask = mBinaireImages[numImage]; And->SetInput1(dilate->GetOutput()); And->SetInput2(mask); And->Update(); image->DeepCopy(And->GetOutput()); image->Update(); } And->Delete(); dilate->Delete(); mManager->Render(); QApplication::restoreOverrideCursor(); } void vvSegmentationDialog::InsertSeed() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); int point4D[4]; point4D[0] = mManager->GetLandmarks()->GetCoordinates( mManager->GetLandmarks()->GetNumberOfPoints()-1)[0]; point4D[1] = mManager->GetLandmarks()->GetCoordinates( mManager->GetLandmarks()->GetNumberOfPoints()-1)[1]; point4D[2] = mManager->GetLandmarks()->GetCoordinates( mManager->GetLandmarks()->GetNumberOfPoints()-1)[2]; point4D[3] = mManager->GetLandmarks()->GetCoordinates( mManager->GetLandmarks()->GetNumberOfPoints()-1)[3]; point4D[0] = point4D[0]/mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetSpacing()[0]; point4D[1] = point4D[1]/mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetSpacing()[1]; point4D[2] = point4D[2]/mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetSpacing()[2]; vtkImageSeedConnectivity* seed = vtkImageSeedConnectivity::New(); seed->SetInputConnectValue(1); seed->SetOutputConnectedValue(1); seed->SetOutputUnconnectedValue(0); seed->AddSeed(point4D[0],point4D[1],point4D[2]); for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) { vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage]; seed->SetInput(image); seed->Update(); image->DeepCopy(seed->GetOutput()); image->Update(); } seed->Delete(); QApplication::restoreOverrideCursor(); } void vvSegmentationDialog::ChangeDimRendering() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (dimButton->text() == "3D") { if (m3DActors.size() == 0) { m3DExtractor->SetValue(0,0.5); for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) { vtkActor* actor = vtkActor::New(); m3DExtractor->SetInput(mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage]); m3DExtractor->Update(); vtkPolyDataMapper* mapper = vtkPolyDataMapper::New(); mapper->SetInput(m3DExtractor->GetOutput()); m3DMappers.push_back(mapper); actor->SetMapper(mapper); actor->GetProperty()->SetColor(1.0,0.7,0.2); actor->VisibilityOff(); mManager->GetSlicer(0)->GetRenderer()->AddActor(actor); m3DActors.push_back(actor); } } mManager->GetSlicer(0)->GetRenderer()->SetBackground(0.5,0.6,0.9); m3DActors[0]->VisibilityOn(); vtkInteractorStyleTrackballCamera* style = vtkInteractorStyleTrackballCamera::New(); mManager->SetInteractorStyleNavigator(0,style); style->Delete(); mManager->GetSlicer(0)->GetImageActor()->VisibilityOff(); mSquaresActor1->VisibilityOff(); mSquaresActor2->VisibilityOff(); mManager->Render(); dimButton->setText("2D"); } else { mManager->GetSlicer(0)->GetRenderer()->SetBackground(0.0,0.0,0.0); vvInteractorStyleNavigator* style = vvInteractorStyleNavigator::New(); mManager->SetInteractorStyleNavigator(0,style); style->Delete(); mManager->GetSlicer(0)->SetSliceOrientation(2); m3DActors[mManager->GetSlicer(0)->GetTSlice()]->VisibilityOff(); mManager->GetSlicer(0)->GetImageActor()->VisibilityOn(); mSquaresActor1->VisibilityOn(); mSquaresActor2->VisibilityOn(); dimButton->setText("3D"); } QApplication::restoreOverrideCursor(); } void vvSegmentationDialog::KernelValueChanged(int kernel) { mKernelValue = kernel; } void vvSegmentationDialog::Save() { if (dimButton->text() == "2D") //If in *3D* mode, save the mesh { QString fileName = QFileDialog::getSaveFileName(this, tr("Save Mesh As"), QDir::home().dirName(), "Mesh Files (*.vtk *.vtp)"); if (!fileName.isEmpty()) { vtkSmartPointer w = vtkSmartPointer::New(); w->SetInput(m3DExtractor->GetOutput()); w->SetFileName(fileName.toStdString().c_str()); w->Write(); } } else { QStringList OutputListeFormat; OutputListeFormat.clear(); int dimension = mManager->GetDimension(); if (dimension == 1) { OutputListeFormat.push_back(".mhd"); } if (dimension == 2) { OutputListeFormat.push_back(".bmp"); OutputListeFormat.push_back(".png"); OutputListeFormat.push_back(".jpeg"); OutputListeFormat.push_back(".tif"); OutputListeFormat.push_back(".mhd"); OutputListeFormat.push_back(".hdr"); OutputListeFormat.push_back(".vox"); } else if (dimension == 3) { OutputListeFormat.push_back(".mhd"); OutputListeFormat.push_back(".hdr"); OutputListeFormat.push_back(".vox"); } else if (dimension == 4) { OutputListeFormat.push_back(".mhd"); } QString Extensions = "AllFiles(*.*)"; for (int i = 0; i < OutputListeFormat.count(); i++) { Extensions += ";;Images ( *"; Extensions += OutputListeFormat[i]; Extensions += ")"; } QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), QDir::home().dirName(), Extensions); if (!fileName.isEmpty()) { std::string fileformat = vtksys::SystemTools::GetFilenameLastExtension(fileName.toStdString()); if (OutputListeFormat.contains( fileformat.c_str())) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); vvProgressDialog progress("Saving "+fileName.toStdString()); qApp->processEvents(); vvImageWriter *writer = new vvImageWriter; writer->SetOutputFileName(fileName.toStdString()); writer->SetInput(mManager->GetSlicer(0)->GetImage()); writer->Update(dimension,"unsigned_char"); QApplication::restoreOverrideCursor(); if (writer->GetLastError().size()) { QString error = "Saving did not succeed\n"; error += writer->GetLastError().c_str(); QMessageBox::information(this,tr("Saving Problem"),error); Save(); } } else { QString error = fileformat.c_str(); if (error.isEmpty()) error += "no file format specified !"; else error += " format unknown !!!\n"; QMessageBox::information(this,tr("Saving Problem"),error); Save(); } } } } #endif /* end #define _vvSegmentationDialog_CXX */