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()
67 mManager = new vvSlicerManager(1);
69 mClipper = vtkImageClip::New();
70 mSquares1 = vtkMarchingSquares::New();
71 mSquaresMapper1 = vtkPolyDataMapper::New();
72 mSquaresActor1 = vtkActor::New();
74 mSquares2 = vtkMarchingSquares::New();
75 mSquaresMapper2 = vtkPolyDataMapper::New();
76 mSquaresActor2 = vtkActor::New();
78 //m3DMapper = vtkPolyDataMapper::New();
79 //m3DActor = vtkActor::New();
80 m3DExtractor = vtkMarchingCubes::New();
81 m3DExtractor->ComputeScalarsOff();
85 mBinaireImages.clear();
88 connect(clipping1Slider,SIGNAL(valueChanged(int)),this,SLOT(clippingvaluechanged(int)));
89 connect(clipping2Slider,SIGNAL(valueChanged(int)),this,SLOT(clippingvaluechanged(int)));
90 connect(binaryButton,SIGNAL(clicked()),this,SLOT(BinariseSurface()));
91 connect(saveButton,SIGNAL(clicked()),this,SLOT(Save()));
92 connect(erodeButton,SIGNAL(clicked()),this,SLOT(Erode()));
93 connect(dilateButton,SIGNAL(clicked()),this,SLOT(Dilate()));
94 connect(dimButton,SIGNAL(clicked()),this,SLOT(ChangeDimRendering()));
95 connect(kernelSpinBox,SIGNAL(valueChanged(int)),this,SLOT(KernelValueChanged(int)));
97 binaryButton->setEnabled(0);
98 erodeButton->setEnabled(0);
99 dilateButton->setEnabled(0);
100 infoLabel->setText("Select Up and Down threshold before clicking binarise !");
103 vvSegmentationDialog::~vvSegmentationDialog()
107 mSquaresActor1->Delete();
108 mSquaresMapper1->Delete();
111 mSquaresActor2->Delete();
112 mSquaresMapper2->Delete();
115 //m3DMapper->Delete();
116 //m3DActor->Delete();
117 m3DExtractor->Delete();
119 for (unsigned int i = 0; i < mBinaireImages.size(); i++)
120 mBinaireImages[i]->Delete();
122 for (unsigned int i = 0; i < m3DActors.size(); i++)
123 m3DActors[i]->Delete();
125 for (unsigned int i = 0; i < m3DMappers.size(); i++)
126 m3DMappers[i]->Delete();
131 //----------------------------------------------------------------------------
132 // This templated function executes the filter for any type of data.
133 // Handles the one input operations
135 void vvImageBinarize(vtkImageData *in1Data, T *in1Ptr,
136 int outExt[6],int clampMin, int clampMax)
138 int idxR, idxY, idxZ;
140 vtkIdType inIncX, inIncY, inIncZ;
143 // find the region to loop over
145 (outExt[1] - outExt[0]+1)*in1Data->GetNumberOfScalarComponents();
146 // What a pain. Maybe I should just make another filter.
148 maxY = outExt[3] - outExt[2];
149 maxZ = outExt[5] - outExt[4];
151 // Get increments to march through data
152 in1Data->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ);
154 for (idxZ = 0; idxZ <= maxZ; idxZ++) {
155 for (idxY = 0; idxY <= maxY; idxY++) {
156 for (idxR = 0; idxR < rowLength; idxR++) {
157 if (static_cast<double>(*in1Ptr) > clampMin && static_cast<double>(*in1Ptr) <= clampMax)
158 *in1Ptr = static_cast<T>(1);
160 *in1Ptr = static_cast<T>(0);
169 void vvSegmentationDialog::SetImage(vvImage::Pointer image)
172 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
173 mManager->SetImage(image);
174 mManager->SetSlicerWindow(0,viewWidget->GetRenderWindow());
175 vvInteractorStyleNavigator* style = vvInteractorStyleNavigator::New();
176 mManager->SetInteractorStyleNavigator(0,style);
180 mManager->GetImage()->GetScalarRange(range);
181 mManager->GetSlicer(0)->SetColorWindow(range[1]-range[0]);
182 mManager->GetSlicer(0)->SetColorLevel((range[1]+range[0])/2);
184 clipping1Slider->setMinimum(range[0]);
185 clipping1Slider->setMaximum(range[1]);
186 clipping2Slider->setMinimum(range[0]);
187 clipping2Slider->setMaximum(range[1]);
188 clipping1Slider->setValue(range[0]);
189 clipping2Slider->setValue(range[1]);
191 mClipper->SetInput(mManager->GetSlicer(0)->GetInput());
192 mSquares1->SetValue(0,clipping1Slider->value());
193 mSquares2->SetValue(0,clipping2Slider->value());
194 mSquares1->SetInput(mClipper->GetOutput());
195 mSquares2->SetInput(mClipper->GetOutput());
197 mSquaresMapper1->SetInput(mSquares1->GetOutput());
198 mSquaresMapper2->SetInput(mSquares2->GetOutput());
199 mSquaresMapper1->ScalarVisibilityOff();
200 mSquaresMapper2->ScalarVisibilityOff();
202 mSquaresActor1->SetMapper(mSquaresMapper1);
203 mSquaresActor2->SetMapper(mSquaresMapper2);
204 mSquaresActor1->GetProperty()->SetColor(1.0,0,0);
205 mSquaresActor2->GetProperty()->SetColor(0,0,1.0);
206 mSquaresActor1->SetPickable(0);
207 mSquaresActor2->SetPickable(0);
209 mManager->GetSlicer(0)->GetRenderer()->AddActor(mSquaresActor1);
210 mManager->GetSlicer(0)->GetRenderer()->AddActor(mSquaresActor2);
215 UpdateSlice(0,mManager->GetSlicer(0)->GetSlice());
217 connect(mManager,SIGNAL(UpdateTSlice(int,int)),this,SLOT(UpdateSlice(int, int)));
218 connect(mManager,SIGNAL(UpdateSlice(int,int)),this,SLOT(UpdateSlice(int, int)));
219 connect(mManager,SIGNAL(UpdateSliceRange(int,int,int,int,int)),this,SLOT(UpdateSlice(int, int)));
220 connect(mManager,SIGNAL(LandmarkAdded()),this,SLOT(InsertSeed()));
221 QApplication::restoreOverrideCursor();
224 void vvSegmentationDialog::UpdateSlice(int slicer,int slices)
226 int slice = mManager->GetSlicer(0)->GetSlice();
227 int tslice = mManager->GetSlicer(0)->GetTSlice();
228 mClipper->SetInput(mManager->GetSlicer(0)->GetInput());
229 int* extent = mManager->GetSlicer(0)->GetImageActor()->GetDisplayExtent();
230 mClipper->SetOutputWholeExtent(extent[0],extent[1],extent[2],extent[3],extent[4],extent[5]);
232 for (i = 0; i < 6; i = i+2) {
233 if (extent[i] == extent[i+1]) {
240 if (mManager->GetSlicer(0)->GetRenderer()->GetActiveCamera()->GetPosition()[0] > slice) {
241 mSquaresActor1->SetPosition(1,0,0);
242 mSquaresActor2->SetPosition(1,0,0);
244 mSquaresActor1->SetPosition(-1,0,0);
245 mSquaresActor2->SetPosition(-1,0,0);
249 if (mManager->GetSlicer(0)->GetRenderer()->GetActiveCamera()->GetPosition()[1] > slice) {
250 mSquaresActor1->SetPosition(0,1,0);
251 mSquaresActor2->SetPosition(0,1,0);
253 mSquaresActor1->SetPosition(0,-1,0);
254 mSquaresActor2->SetPosition(0,-1,0);
258 if (mManager->GetSlicer(0)->GetRenderer()->GetActiveCamera()->GetPosition()[2] > slice) {
259 mSquaresActor1->SetPosition(0,0,1);
260 mSquaresActor2->SetPosition(0,0,1);
262 mSquaresActor1->SetPosition(0,0,-1);
263 mSquaresActor2->SetPosition(0,0,-1);
270 if (m3DActors.size()) {
271 for (unsigned int i =0; i < m3DActors.size(); i++) {
272 if (m3DActors[i]->GetVisibility()) {
273 m3DActors[i]->VisibilityOff();
276 std::cout << "display " << tslice << " on " << m3DActors.size() << std::endl;
277 m3DActors[tslice]->VisibilityOn();
284 void vvSegmentationDialog::clippingvaluechanged(int value)
286 binaryButton->setEnabled(1);
287 int min = (clipping1Slider->value() < clipping2Slider->value() ) ?
288 clipping1Slider->value():clipping2Slider->value();
289 int max = (clipping1Slider->value() > clipping2Slider->value() ) ?
290 clipping1Slider->value():clipping2Slider->value();
291 mSquares1->SetValue(0,min);
292 mSquares2->SetValue(0,max);
294 QString textMin = "<b> Min : </b>";
295 textMin += QString::number(min);
296 QString textMax = "\n <b> Max : </b>";
297 textMax += QString::number(max);
298 minLabel->setText(textMin);
299 maxLabel->setText(textMax);
301 if (mSquares1->GetInput()) {
309 void vvSegmentationDialog::BinariseSurface()
311 infoLabel->setText("Click erode then space on desired organ !");
313 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
314 int clampMin = (clipping1Slider->value() < clipping2Slider->value() ) ?
315 clipping1Slider->value():clipping2Slider->value();
316 int clampMax = (clipping1Slider->value() > clipping2Slider->value() ) ?
317 clipping1Slider->value():clipping2Slider->value();
318 vtkImageData* outputImage = vtkImageData::New();
320 for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) {
321 vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage];
323 image->GetWholeExtent(ext);
325 in1Ptr = image->GetScalarPointerForExtent(ext);
327 switch (image->GetScalarType()) {
329 vvImageBinarize(image, static_cast<VTK_TT *>(in1Ptr),
330 ext,clampMin,clampMax));
332 std::cerr << "Error, unknown pixel format : " << image->GetScalarTypeAsString() << std::endl;
336 outputImage->Initialize();
337 outputImage->SetExtent(ext);
338 outputImage->SetOrigin(image->GetOrigin());
339 outputImage->SetSpacing(image->GetSpacing());
340 outputImage->SetScalarTypeToUnsignedChar();
341 outputImage->CopyAndCastFrom(image,ext);
342 outputImage->Update();
344 image->DeepCopy(outputImage);
345 image->UpdateInformation();
346 image->PropagateUpdateExtent();
348 vtkImageData* imageBin = vtkImageData::New();
349 imageBin->DeepCopy(image);
351 mBinaireImages.push_back(imageBin);
354 outputImage->Delete();
355 erodeButton->setEnabled(1);
356 QApplication::restoreOverrideCursor();
357 mManager->SetColorWindow(2);
358 mManager->SetColorLevel(0.5);
362 void vvSegmentationDialog::Erode()
364 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
365 vtkImageContinuousErode3D* erode = vtkImageContinuousErode3D::New();
366 erode->SetKernelSize(mKernelValue,mKernelValue,mKernelValue);
367 for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) {
368 vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage];
369 erode->SetInput(image);
371 image->DeepCopy(erode->GetOutput());
375 dilateButton->setEnabled(1);
377 QApplication::restoreOverrideCursor();
380 void vvSegmentationDialog::Dilate()
382 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
383 vtkImageContinuousDilate3D* dilate = vtkImageContinuousDilate3D::New();
384 vtkImageLogic* And = vtkImageLogic::New();
385 And->SetOperationToAnd();
386 dilate->SetKernelSize(mKernelValue,mKernelValue,mKernelValue);
387 for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) {
388 vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage];
389 dilate->SetInput(image);
390 vtkImageData* mask = mBinaireImages[numImage];
391 And->SetInput1(dilate->GetOutput());
392 And->SetInput2(mask);
394 image->DeepCopy(And->GetOutput());
400 QApplication::restoreOverrideCursor();
403 void vvSegmentationDialog::InsertSeed()
405 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
407 point4D[0] = mManager->GetLandmarks()->GetCoordinates(
408 mManager->GetLandmarks()->GetNumberOfPoints()-1)[0];
409 point4D[1] = mManager->GetLandmarks()->GetCoordinates(
410 mManager->GetLandmarks()->GetNumberOfPoints()-1)[1];
411 point4D[2] = mManager->GetLandmarks()->GetCoordinates(
412 mManager->GetLandmarks()->GetNumberOfPoints()-1)[2];
413 point4D[3] = mManager->GetLandmarks()->GetCoordinates(
414 mManager->GetLandmarks()->GetNumberOfPoints()-1)[3];
416 point4D[0] = (point4D[0]-mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetOrigin()[0])/mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetSpacing()[0];
417 point4D[1] = (point4D[1]-mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetOrigin()[1])/mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetSpacing()[1];
418 point4D[2] = (point4D[2]-mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetOrigin()[2])/mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetSpacing()[2];
420 vtkImageSeedConnectivity* seed = vtkImageSeedConnectivity::New();
421 seed->SetInputConnectValue(1);
422 seed->SetOutputConnectedValue(1);
423 seed->SetOutputUnconnectedValue(0);
424 seed->AddSeed(point4D[0],point4D[1],point4D[2]);
426 for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) {
427 vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage];
428 seed->SetInput(image);
430 image->DeepCopy(seed->GetOutput());
435 QApplication::restoreOverrideCursor();
438 void vvSegmentationDialog::ChangeDimRendering()
440 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
442 if (dimButton->text() == "3D") {
443 if (m3DActors.size() == 0) {
444 m3DExtractor->SetValue(0,0.5);
445 for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) {
446 vtkActor* actor = vtkActor::New();
447 m3DExtractor->SetInput(mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage]);
448 m3DExtractor->Update();
450 vtkPolyDataMapper* mapper = vtkPolyDataMapper::New();
451 mapper->SetInput(m3DExtractor->GetOutput());
452 m3DMappers.push_back(mapper);
454 actor->SetMapper(mapper);
455 actor->GetProperty()->SetColor(1.0,0.7,0.2);
456 actor->VisibilityOff();
458 mManager->GetSlicer(0)->GetRenderer()->AddActor(actor);
459 m3DActors.push_back(actor);
463 mManager->GetSlicer(0)->GetRenderer()->SetBackground(0.5,0.6,0.9);
464 m3DActors[0]->VisibilityOn();
466 vtkInteractorStyleTrackballCamera* style = vtkInteractorStyleTrackballCamera::New();
467 mManager->SetInteractorStyleNavigator(0,style);
470 mManager->GetSlicer(0)->GetImageActor()->VisibilityOff();
471 mSquaresActor1->VisibilityOff();
472 mSquaresActor2->VisibilityOff();
474 dimButton->setText("2D");
476 mManager->GetSlicer(0)->GetRenderer()->SetBackground(0.0,0.0,0.0);
477 vvInteractorStyleNavigator* style = vvInteractorStyleNavigator::New();
478 mManager->SetInteractorStyleNavigator(0,style);
481 mManager->GetSlicer(0)->SetSliceOrientation(2);
482 m3DActors[mManager->GetSlicer(0)->GetTSlice()]->VisibilityOff();
484 mManager->GetSlicer(0)->GetImageActor()->VisibilityOn();
485 mSquaresActor1->VisibilityOn();
486 mSquaresActor2->VisibilityOn();
487 dimButton->setText("3D");
489 QApplication::restoreOverrideCursor();
492 void vvSegmentationDialog::KernelValueChanged(int kernel)
494 mKernelValue = kernel;
497 void vvSegmentationDialog::Save()
499 if (dimButton->text() == "2D") { //If in *3D* mode, save the mesh
500 QString fileName = QFileDialog::getSaveFileName(this,
502 QDir::home().dirName(),
503 "Mesh Files (*.vtk *.vtp)");
504 if (!fileName.isEmpty()) {
505 vtkSmartPointer<vtkPolyDataWriter> w = vtkSmartPointer<vtkPolyDataWriter>::New();
506 w->SetInput(m3DExtractor->GetOutput());
507 w->SetFileName(fileName.toStdString().c_str());
511 QStringList OutputListeFormat;
512 OutputListeFormat.clear();
513 int dimension = mManager->GetDimension();
514 if (dimension == 1) {
515 OutputListeFormat.push_back(".mhd");
517 if (dimension == 2) {
518 OutputListeFormat.push_back(".bmp");
519 OutputListeFormat.push_back(".png");
520 OutputListeFormat.push_back(".jpeg");
521 OutputListeFormat.push_back(".tif");
522 OutputListeFormat.push_back(".mhd");
523 OutputListeFormat.push_back(".hdr");
524 OutputListeFormat.push_back(".vox");
525 } else if (dimension == 3) {
526 OutputListeFormat.push_back(".mhd");
527 OutputListeFormat.push_back(".hdr");
528 OutputListeFormat.push_back(".vox");
529 } else if (dimension == 4) {
530 OutputListeFormat.push_back(".mhd");
532 QString Extensions = "AllFiles(*.*)";
533 for (int i = 0; i < OutputListeFormat.count(); i++) {
534 Extensions += ";;Images ( *";
535 Extensions += OutputListeFormat[i];
538 QString fileName = QFileDialog::getSaveFileName(this,
540 QDir::home().dirName(),
542 if (!fileName.isEmpty()) {
543 std::string fileformat = vtksys::SystemTools::GetFilenameLastExtension(fileName.toStdString());
544 if (OutputListeFormat.contains(
545 fileformat.c_str())) {
546 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
547 vvProgressDialog progress("Saving "+fileName.toStdString());
548 qApp->processEvents();
549 vvImageWriter *writer = new vvImageWriter;
550 writer->SetOutputFileName(fileName.toStdString());
551 writer->SetInput(mManager->GetSlicer(0)->GetImage());
552 writer->Update(dimension,"unsigned_char");
553 QApplication::restoreOverrideCursor();
554 if (writer->GetLastError().size()) {
555 QString error = "Saving did not succeed\n";
556 error += writer->GetLastError().c_str();
557 QMessageBox::information(this,tr("Saving Problem"),error);
561 QString error = fileformat.c_str();
563 error += "no file format specified !";
565 error += " format unknown !!!\n";
566 QMessageBox::information(this,tr("Saving Problem"),error);
573 #endif /* end #define _vvSegmentationDialog_CXX */