1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
5 - University of LYON http://www.universite-lyon.fr/
6 - Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr
7 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the copyright notices for more information.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ======================================================================-====*/
18 #ifndef _vvSegmentationDialog_CXX
19 #define _vvSegmentationDialog_CXX
23 #include "vvSegmentationDialog.h"
24 #include "vvProgressDialog.h"
25 #include "vvImageWriter.h"
26 #include "vvLandmarks.h"
27 #include "vvInteractorStyleNavigator.h"
30 #include "vtkMarchingCubes.h"
31 #include "vtkMarchingSquares.h"
32 #include "vtkImageClip.h"
33 #include "vtkCamera.h"
34 #include "vtkRenderer.h"
35 #include "vtkProperty.h"
36 #include "vtkLookupTable.h"
37 #include "vtkClipPolyData.h"
38 #include "vtkImageToPolyDataFilter.h"
39 #include "vtkLookupTable.h"
40 #include "vtkDoubleArray.h"
41 #include "vtkPointData.h"
42 #include "vtkCellData.h"
43 #include "vtkImageMapToWindowLevelColors.h"
44 #include "vtkImageContinuousErode3D.h"
45 #include "vtkImageContinuousDilate3D.h"
46 #include "vtkImageLogic.h"
47 #include "vtkInteractorStyleTrackballCamera.h"
48 #include "vtkImageSeedConnectivity.h"
49 #include "vtkConnectivityFilter.h"
50 #include "vtkPolyData.h"
51 #include <vtkPolyDataMapper.h>
52 #include <vtkImageData.h>
53 #include "vtkInformation.h"
54 #include "vtkInformationVector.h"
55 #include "vtkStreamingDemandDrivenPipeline.h"
56 #include <vtkPolyDataWriter.h>
58 #include <QMessageBox>
60 //====================================================================
61 vvSegmentationDialog::vvSegmentationDialog(QWidget * parent, Qt::WindowFlags f)
62 :QDialog(parent,f), Ui::vvSegmentationDialog() {
66 mManager = new vvSlicerManager(1);
68 mClipper = vtkImageClip::New();
69 mSquares1 = vtkMarchingSquares::New();
70 mSquaresMapper1 = vtkPolyDataMapper::New();
71 mSquaresActor1 = vtkActor::New();
73 mSquares2 = vtkMarchingSquares::New();
74 mSquaresMapper2 = vtkPolyDataMapper::New();
75 mSquaresActor2 = vtkActor::New();
77 //m3DMapper = vtkPolyDataMapper::New();
78 //m3DActor = vtkActor::New();
79 m3DExtractor = vtkMarchingCubes::New();
83 mBinaireImages.clear();
86 connect(clipping1Slider,SIGNAL(valueChanged(int)),this,SLOT(clippingvaluechanged(int)));
87 connect(clipping2Slider,SIGNAL(valueChanged(int)),this,SLOT(clippingvaluechanged(int)));
88 connect(binaryButton,SIGNAL(clicked()),this,SLOT(BinariseSurface()));
89 connect(saveButton,SIGNAL(clicked()),this,SLOT(Save()));
90 connect(erodeButton,SIGNAL(clicked()),this,SLOT(Erode()));
91 connect(dilateButton,SIGNAL(clicked()),this,SLOT(Dilate()));
92 connect(dimButton,SIGNAL(clicked()),this,SLOT(ChangeDimRendering()));
93 connect(kernelSpinBox,SIGNAL(valueChanged(int)),this,SLOT(KernelValueChanged(int)));
95 binaryButton->setEnabled(0);
96 erodeButton->setEnabled(0);
97 dilateButton->setEnabled(0);
98 infoLabel->setText("Select Up and Down threshold before clicking binarise !");
101 vvSegmentationDialog::~vvSegmentationDialog()
105 mSquaresActor1->Delete();
106 mSquaresMapper1->Delete();
109 mSquaresActor2->Delete();
110 mSquaresMapper2->Delete();
113 //m3DMapper->Delete();
114 //m3DActor->Delete();
115 m3DExtractor->Delete();
117 for (unsigned int i = 0; i < mBinaireImages.size(); i++)
118 mBinaireImages[i]->Delete();
120 for (unsigned int i = 0; i < m3DActors.size(); i++)
121 m3DActors[i]->Delete();
123 for (unsigned int i = 0; i < m3DMappers.size(); i++)
124 m3DMappers[i]->Delete();
129 //----------------------------------------------------------------------------
130 // This templated function executes the filter for any type of data.
131 // Handles the one input operations
133 void vvImageBinarize(vtkImageData *in1Data, T *in1Ptr,
134 int outExt[6],int clampMin, int clampMax)
136 int idxR, idxY, idxZ;
138 vtkIdType inIncX, inIncY, inIncZ;
141 // find the region to loop over
143 (outExt[1] - outExt[0]+1)*in1Data->GetNumberOfScalarComponents();
144 // What a pain. Maybe I should just make another filter.
146 maxY = outExt[3] - outExt[2];
147 maxZ = outExt[5] - outExt[4];
149 // Get increments to march through data
150 in1Data->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ);
152 for (idxZ = 0; idxZ <= maxZ; idxZ++)
154 for (idxY = 0; idxY <= maxY; idxY++)
156 for (idxR = 0; idxR < rowLength; idxR++)
158 if (static_cast<double>(*in1Ptr) > clampMin && static_cast<double>(*in1Ptr) <= clampMax)
159 *in1Ptr = static_cast<T>(1);
161 *in1Ptr = static_cast<T>(0);
170 void vvSegmentationDialog::SetImage(vvImage::Pointer image)
173 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
174 mManager->SetImage(image);
175 mManager->SetSlicerWindow(0,viewWidget->GetRenderWindow());
176 vvInteractorStyleNavigator* style = vvInteractorStyleNavigator::New();
177 mManager->SetInteractorStyleNavigator(0,style);
181 mManager->GetImage()->GetScalarRange(range);
182 mManager->GetSlicer(0)->SetColorWindow(range[1]-range[0]);
183 mManager->GetSlicer(0)->SetColorLevel((range[1]+range[0])/2);
185 clipping1Slider->setMinimum(range[0]);
186 clipping1Slider->setMaximum(range[1]);
187 clipping2Slider->setMinimum(range[0]);
188 clipping2Slider->setMaximum(range[1]);
189 clipping1Slider->setValue(range[0]);
190 clipping2Slider->setValue(range[1]);
192 mClipper->SetInput(mManager->GetSlicer(0)->GetInput());
193 mSquares1->SetValue(0,clipping1Slider->value());
194 mSquares2->SetValue(0,clipping2Slider->value());
195 mSquares1->SetInput(mClipper->GetOutput());
196 mSquares2->SetInput(mClipper->GetOutput());
198 mSquaresMapper1->SetInput(mSquares1->GetOutput());
199 mSquaresMapper2->SetInput(mSquares2->GetOutput());
200 mSquaresMapper1->ScalarVisibilityOff();
201 mSquaresMapper2->ScalarVisibilityOff();
203 mSquaresActor1->SetMapper(mSquaresMapper1);
204 mSquaresActor2->SetMapper(mSquaresMapper2);
205 mSquaresActor1->GetProperty()->SetColor(1.0,0,0);
206 mSquaresActor2->GetProperty()->SetColor(0,0,1.0);
207 mSquaresActor1->SetPickable(0);
208 mSquaresActor2->SetPickable(0);
210 mManager->GetSlicer(0)->GetRenderer()->AddActor(mSquaresActor1);
211 mManager->GetSlicer(0)->GetRenderer()->AddActor(mSquaresActor2);
216 UpdateSlice(0,mManager->GetSlicer(0)->GetSlice());
218 connect(mManager,SIGNAL(UpdateTSlice(int,int)),this,SLOT(UpdateSlice(int, int)));
219 connect(mManager,SIGNAL(UpdateSlice(int,int)),this,SLOT(UpdateSlice(int, int)));
220 connect(mManager,SIGNAL(UpdateSliceRange(int,int,int,int,int)),this,SLOT(UpdateSlice(int, int)));
221 connect(mManager,SIGNAL(LandmarkAdded()),this,SLOT(InsertSeed()));
222 QApplication::restoreOverrideCursor();
225 void vvSegmentationDialog::UpdateSlice(int slicer,int slices)
227 int slice = mManager->GetSlicer(0)->GetSlice();
228 int tslice = mManager->GetSlicer(0)->GetTSlice();
229 mClipper->SetInput(mManager->GetSlicer(0)->GetInput());
230 int* extent = mManager->GetSlicer(0)->GetImageActor()->GetDisplayExtent();
231 mClipper->SetOutputWholeExtent(extent[0],extent[1],extent[2],extent[3],extent[4],extent[5]);
233 for (i = 0; i < 6;i = i+2)
235 if (extent[i] == extent[i+1])
244 if (mManager->GetSlicer(0)->GetRenderer()->GetActiveCamera()->GetPosition()[0] > slice)
246 mSquaresActor1->SetPosition(1,0,0);
247 mSquaresActor2->SetPosition(1,0,0);
251 mSquaresActor1->SetPosition(-1,0,0);
252 mSquaresActor2->SetPosition(-1,0,0);
256 if (mManager->GetSlicer(0)->GetRenderer()->GetActiveCamera()->GetPosition()[1] > slice)
258 mSquaresActor1->SetPosition(0,1,0);
259 mSquaresActor2->SetPosition(0,1,0);
263 mSquaresActor1->SetPosition(0,-1,0);
264 mSquaresActor2->SetPosition(0,-1,0);
268 if (mManager->GetSlicer(0)->GetRenderer()->GetActiveCamera()->GetPosition()[2] > slice)
270 mSquaresActor1->SetPosition(0,0,1);
271 mSquaresActor2->SetPosition(0,0,1);
275 mSquaresActor1->SetPosition(0,0,-1);
276 mSquaresActor2->SetPosition(0,0,-1);
283 if (m3DActors.size())
285 for (unsigned int i =0; i < m3DActors.size(); i++)
287 if (m3DActors[i]->GetVisibility())
289 m3DActors[i]->VisibilityOff();
292 std::cout << "display " << tslice << " on " << m3DActors.size() << std::endl;
293 m3DActors[tslice]->VisibilityOn();
300 void vvSegmentationDialog::clippingvaluechanged(int value)
302 binaryButton->setEnabled(1);
303 int min = (clipping1Slider->value() < clipping2Slider->value() ) ?
304 clipping1Slider->value():clipping2Slider->value();
305 int max = (clipping1Slider->value() > clipping2Slider->value() ) ?
306 clipping1Slider->value():clipping2Slider->value();
307 mSquares1->SetValue(0,min);
308 mSquares2->SetValue(0,max);
310 QString textMin = "<b> Min : </b>";
311 textMin += QString::number(min);
312 QString textMax = "\n <b> Max : </b>";
313 textMax += QString::number(max);
314 minLabel->setText(textMin);
315 maxLabel->setText(textMax);
317 if (mSquares1->GetInput())
326 void vvSegmentationDialog::BinariseSurface()
328 infoLabel->setText("Click erode then space on desired organ !");
330 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
331 int clampMin = (clipping1Slider->value() < clipping2Slider->value() ) ?
332 clipping1Slider->value():clipping2Slider->value();
333 int clampMax = (clipping1Slider->value() > clipping2Slider->value() ) ?
334 clipping1Slider->value():clipping2Slider->value();
335 vtkImageData* outputImage = vtkImageData::New();
337 for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++)
339 vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage];
341 image->GetWholeExtent(ext);
343 in1Ptr = image->GetScalarPointerForExtent(ext);
345 switch (image->GetScalarType())
348 vvImageBinarize(image, static_cast<VTK_TT *>(in1Ptr),
349 ext,clampMin,clampMax));
351 std::cerr << "Error, unknown pixel format : " << image->GetScalarTypeAsString() << std::endl;
355 outputImage->Initialize();
356 outputImage->SetExtent(ext);
357 outputImage->SetOrigin(image->GetOrigin());
358 outputImage->SetSpacing(image->GetSpacing());
359 outputImage->SetScalarTypeToUnsignedChar();
360 outputImage->CopyAndCastFrom(image,ext);
361 outputImage->Update();
363 image->DeepCopy(outputImage);
364 image->UpdateInformation();
365 image->PropagateUpdateExtent();
367 vtkImageData* imageBin = vtkImageData::New();
368 imageBin->DeepCopy(image);
370 mBinaireImages.push_back(imageBin);
373 outputImage->Delete();
374 erodeButton->setEnabled(1);
375 QApplication::restoreOverrideCursor();
376 mManager->SetColorWindow(2);
377 mManager->SetColorLevel(0.5);
381 void vvSegmentationDialog::Erode()
383 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
384 vtkImageContinuousErode3D* erode = vtkImageContinuousErode3D::New();
385 erode->SetKernelSize(mKernelValue,mKernelValue,mKernelValue);
386 for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++)
388 vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage];
389 erode->SetInput(image);
391 image->DeepCopy(erode->GetOutput());
395 dilateButton->setEnabled(1);
397 QApplication::restoreOverrideCursor();
400 void vvSegmentationDialog::Dilate()
402 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
403 vtkImageContinuousDilate3D* dilate = vtkImageContinuousDilate3D::New();
404 vtkImageLogic* And = vtkImageLogic::New();
405 And->SetOperationToAnd();
406 dilate->SetKernelSize(mKernelValue,mKernelValue,mKernelValue);
407 for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++)
409 vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage];
410 dilate->SetInput(image);
411 vtkImageData* mask = mBinaireImages[numImage];
412 And->SetInput1(dilate->GetOutput());
413 And->SetInput2(mask);
415 image->DeepCopy(And->GetOutput());
421 QApplication::restoreOverrideCursor();
424 void vvSegmentationDialog::InsertSeed()
426 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
428 point4D[0] = mManager->GetLandmarks()->GetCoordinates(
429 mManager->GetLandmarks()->GetNumberOfPoints()-1)[0];
430 point4D[1] = mManager->GetLandmarks()->GetCoordinates(
431 mManager->GetLandmarks()->GetNumberOfPoints()-1)[1];
432 point4D[2] = mManager->GetLandmarks()->GetCoordinates(
433 mManager->GetLandmarks()->GetNumberOfPoints()-1)[2];
434 point4D[3] = mManager->GetLandmarks()->GetCoordinates(
435 mManager->GetLandmarks()->GetNumberOfPoints()-1)[3];
437 point4D[0] = point4D[0]/mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetSpacing()[0];
438 point4D[1] = point4D[1]/mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetSpacing()[1];
439 point4D[2] = point4D[2]/mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetSpacing()[2];
441 vtkImageSeedConnectivity* seed = vtkImageSeedConnectivity::New();
442 seed->SetInputConnectValue(1);
443 seed->SetOutputConnectedValue(1);
444 seed->SetOutputUnconnectedValue(0);
445 seed->AddSeed(point4D[0],point4D[1],point4D[2]);
447 for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++)
449 vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage];
450 seed->SetInput(image);
452 image->DeepCopy(seed->GetOutput());
457 QApplication::restoreOverrideCursor();
460 void vvSegmentationDialog::ChangeDimRendering()
462 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
464 if (dimButton->text() == "3D")
466 if (m3DActors.size() == 0)
468 m3DExtractor->SetValue(0,0.5);
469 for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++)
471 vtkActor* actor = vtkActor::New();
472 m3DExtractor->SetInput(mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage]);
473 m3DExtractor->Update();
475 vtkPolyDataMapper* mapper = vtkPolyDataMapper::New();
476 mapper->SetInput(m3DExtractor->GetOutput());
477 m3DMappers.push_back(mapper);
479 actor->SetMapper(mapper);
480 actor->GetProperty()->SetColor(1.0,0.7,0.2);
481 actor->VisibilityOff();
483 mManager->GetSlicer(0)->GetRenderer()->AddActor(actor);
484 m3DActors.push_back(actor);
488 mManager->GetSlicer(0)->GetRenderer()->SetBackground(0.5,0.6,0.9);
489 m3DActors[0]->VisibilityOn();
491 vtkInteractorStyleTrackballCamera* style = vtkInteractorStyleTrackballCamera::New();
492 mManager->SetInteractorStyleNavigator(0,style);
495 mManager->GetSlicer(0)->GetImageActor()->VisibilityOff();
496 mSquaresActor1->VisibilityOff();
497 mSquaresActor2->VisibilityOff();
499 dimButton->setText("2D");
503 mManager->GetSlicer(0)->GetRenderer()->SetBackground(0.0,0.0,0.0);
504 vvInteractorStyleNavigator* style = vvInteractorStyleNavigator::New();
505 mManager->SetInteractorStyleNavigator(0,style);
508 mManager->GetSlicer(0)->SetSliceOrientation(2);
509 m3DActors[mManager->GetSlicer(0)->GetTSlice()]->VisibilityOff();
511 mManager->GetSlicer(0)->GetImageActor()->VisibilityOn();
512 mSquaresActor1->VisibilityOn();
513 mSquaresActor2->VisibilityOn();
514 dimButton->setText("3D");
516 QApplication::restoreOverrideCursor();
519 void vvSegmentationDialog::KernelValueChanged(int kernel)
521 mKernelValue = kernel;
524 void vvSegmentationDialog::Save()
526 if (dimButton->text() == "2D") //If in *3D* mode, save the mesh
528 QString fileName = QFileDialog::getSaveFileName(this,
530 QDir::home().dirName(),
531 "Mesh Files (*.vtk *.vtp)");
532 if (!fileName.isEmpty())
534 vtkSmartPointer<vtkPolyDataWriter> w = vtkSmartPointer<vtkPolyDataWriter>::New();
535 w->SetInput(m3DExtractor->GetOutput());
536 w->SetFileName(fileName.toStdString().c_str());
541 QStringList OutputListeFormat;
542 OutputListeFormat.clear();
543 int dimension = mManager->GetDimension();
546 OutputListeFormat.push_back(".mhd");
550 OutputListeFormat.push_back(".bmp");
551 OutputListeFormat.push_back(".png");
552 OutputListeFormat.push_back(".jpeg");
553 OutputListeFormat.push_back(".tif");
554 OutputListeFormat.push_back(".mhd");
555 OutputListeFormat.push_back(".hdr");
556 OutputListeFormat.push_back(".vox");
558 else if (dimension == 3)
560 OutputListeFormat.push_back(".mhd");
561 OutputListeFormat.push_back(".hdr");
562 OutputListeFormat.push_back(".vox");
564 else if (dimension == 4)
566 OutputListeFormat.push_back(".mhd");
568 QString Extensions = "AllFiles(*.*)";
569 for (int i = 0; i < OutputListeFormat.count(); i++)
571 Extensions += ";;Images ( *";
572 Extensions += OutputListeFormat[i];
575 QString fileName = QFileDialog::getSaveFileName(this,
577 QDir::home().dirName(),
579 if (!fileName.isEmpty())
581 std::string fileformat = vtksys::SystemTools::GetFilenameLastExtension(fileName.toStdString());
582 if (OutputListeFormat.contains(
585 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
586 vvProgressDialog progress("Saving "+fileName.toStdString());
587 qApp->processEvents();
588 vvImageWriter *writer = new vvImageWriter;
589 writer->SetOutputFileName(fileName.toStdString());
590 writer->SetInput(mManager->GetSlicer(0)->GetImage());
591 writer->Update(dimension,"unsigned_char");
592 QApplication::restoreOverrideCursor();
593 if (writer->GetLastError().size())
595 QString error = "Saving did not succeed\n";
596 error += writer->GetLastError().c_str();
597 QMessageBox::information(this,tr("Saving Problem"),error);
603 QString error = fileformat.c_str();
605 error += "no file format specified !";
607 error += " format unknown !!!\n";
608 QMessageBox::information(this,tr("Saving Problem"),error);
615 #endif /* end #define _vvSegmentationDialog_CXX */