]> Creatis software - clitk.git/blob - vv/vvToolSegmentation.cxx
First version with Merge and remove label
[clitk.git] / vv / vvToolSegmentation.cxx
1 /*=========================================================================
2   Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
3
4   Authors belong to:
5   - University of LYON              http://www.universite-lyon.fr/
6   - Léon Bérard cancer center       http://www.centreleonberard.fr
7   - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
8
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.
12
13   It is distributed under dual licence
14
15   - BSD        See included LICENSE.txt file
16   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17   ===========================================================================**/
18
19 // vv
20 #include "vvToolSegmentation.h"
21 #include "vvSlicerManager.h"
22 #include "vvSlicer.h"
23 #include "vvToolInputSelectorWidget.h"
24 #include "vvImageWriter.h"
25
26 // clitk
27 #include "clitkConnectedComponentLabeling_ggo.h"
28 #include "clitkConnectedComponentLabelingGenericFilter.h"
29
30 // Qt
31 #include <QFileDialog>
32 #include <QMessageBox>
33
34 // vtk
35 #include "vtkImageContinuousErode3D.h"
36 #include "vtkImageContinuousDilate3D.h"
37 #include "vtkRenderWindow.h"
38
39 //------------------------------------------------------------------------------
40 // Create the tool and automagically (I like this word) insert it in
41 // the main window menu.
42 ADD_TOOL(vvToolSegmentation);
43 //------------------------------------------------------------------------------
44
45
46 //------------------------------------------------------------------------------
47 void vvToolSegmentation::Initialize()
48 {
49   SetToolName("Segmentation");
50   SetToolMenuName("Interactive Segmentation");
51   SetToolIconFilename(":/common/icons/ducky.ico");
52   SetToolTip("Image interactive segmentation (trial).");
53   SetToolExperimental(true);
54 }
55 //------------------------------------------------------------------------------
56
57
58 //------------------------------------------------------------------------------
59 vvToolSegmentation::vvToolSegmentation(vvMainWindowBase * parent, Qt::WindowFlags f)
60   :vvToolWidgetBase(parent,f),
61    vvToolBase<vvToolSegmentation>(parent),
62    Ui::vvToolSegmentation()
63 {
64   // GUI Initialization
65   Ui_vvToolSegmentation::setupUi(mToolWidget);
66   setAttribute(Qt::WA_DeleteOnClose);
67
68   // Set how many inputs are needed for this tool
69   AddInputSelector("Select one image");
70   
71   // Init
72   mRefMaskImage = NULL;
73   mCurrentState = State_Default;
74   mKernelValue = 3; // FIXME must be odd. If even -> not symmetrical
75   mDefaultLUTColor = vtkSmartPointer<vtkLookupTable>::New();
76   mDefaultLUTColor->SetNumberOfTableValues(256);
77 #include "vvDefaultLut.h"
78   
79 }
80 //------------------------------------------------------------------------------
81
82
83 //------------------------------------------------------------------------------
84 vvToolSegmentation::~vvToolSegmentation()
85 {
86   DD("destructor");
87 }
88 //------------------------------------------------------------------------------
89
90
91 //------------------------------------------------------------------------------
92 bool vvToolSegmentation::close()
93 {
94   DD("remo ref");
95   if (mRefMaskActor) mRefMaskActor->RemoveActors();
96   DD("remo mask");
97   if (mCurrentMaskActor) mCurrentMaskActor->RemoveActors();
98   for(int i=0; i<mCurrentCCLActors.size(); i++) {
99     DD(i);
100     if (mCurrentCCLActors[i]) mCurrentCCLActors[i]->RemoveActors();
101   }
102   DD("wclose");
103   QWidget::close();  
104   mCurrentSlicerManager->Render();
105   return true;
106 }
107 //------------------------------------------------------------------------------
108
109
110 //------------------------------------------------------------------------------
111 void vvToolSegmentation::InputIsSelected(vvSlicerManager * m)
112 {
113   DD("InputIsSelected");
114   mCurrentSlicerManager = m;
115   mCurrentImage = mCurrentSlicerManager->GetImage();
116
117   // Refuse if non 3D image
118   if (mCurrentImage->GetNumberOfDimensions() != 3) {
119     QMessageBox::information(this,tr("Sorry only 3D yet"), tr("Sorry only 3D yet"));
120     close();
121     return;
122   }
123
124   // Change gui
125   //mLabelInputInfo->setText(QString("%1").arg(m->GetFileName().c_str()));
126
127   // Open mask
128   OpenBinaryImage();
129   
130   // If cancel: stop
131   if (mRefMaskActor == NULL) {
132     close();
133     return;
134   }
135
136   // Update gui
137   mToolInputSelectionWidget->hide();
138
139   // Connect mouse position
140   connect(mCurrentSlicerManager, SIGNAL(MousePositionUpdatedSignal(int)),
141           this, SLOT(MousePositionChanged(int)));
142   connect(mCurrentSlicerManager, SIGNAL(KeyPressedSignal(std::string)),
143           this, SLOT(KeyPressed(std::string)));
144 }
145 //------------------------------------------------------------------------------
146
147
148 //------------------------------------------------------------------------------
149 void vvToolSegmentation::apply()
150 {
151   DD("apply");
152 }
153 //------------------------------------------------------------------------------
154
155
156 //------------------------------------------------------------------------------
157 void vvToolSegmentation::OpenBinaryImage()
158 {
159   DD("OpenBinaryImage");
160
161   // Load browser and select image
162   QString Extensions = "Images files ( *.mha *.mhd *.hdr *.his)";
163   Extensions += ";;All Files (*)";
164   QString filename =
165     QFileDialog::getOpenFileName(this,tr("Open binary image"),
166                                  mMainWindowBase->GetInputPathName(),Extensions);
167   DD(filename.toStdString());
168   if (filename.size() == 0) return;
169   
170   // Open Image
171   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
172   vvImageReader::Pointer reader = vvImageReader::New();
173   std::vector<std::string> filenames;
174   filenames.push_back(filename.toStdString());
175   reader->SetInputFilenames(filenames);
176   reader->Update(vvImageReader::IMAGE);
177   QApplication::restoreOverrideCursor();
178   
179   if (reader->GetLastError().size() != 0) {
180     std::cerr << "Error while reading " << filename.toStdString() << std::endl;
181     QString error = "Cannot open file \n";
182     error += reader->GetLastError().c_str();
183     QMessageBox::information(this,tr("Reading problem"),error);
184     return;
185   }
186
187   mRefMaskImage = reader->GetOutput();
188   int dim = mRefMaskImage->GetNumberOfDimensions();
189   if (dim != 3 ) {
190     QMessageBox::information(this,tr("Sorry only 3D yet"), tr("Sorry only 3D yet"));
191     close();
192     return;
193   }
194
195   reader = vvImageReader::New();
196   reader->SetInputFilenames(filenames);
197   reader->Update(vvImageReader::IMAGE);
198   mCurrentMaskImage = reader->GetOutput();
199
200   // Add a new roi actor for the current mask
201   mCurrentMaskActor = CreateMaskActor(mCurrentMaskImage, 1, 0, false);
202   mCurrentMaskActor->Update(); // default color is red
203
204   // Add a mask actor for the reference
205   mRefMaskActor = CreateMaskActor(mRefMaskImage, 0, 1, true);
206   mRefMaskActor->SetContourVisible(true);
207   mRefMaskActor->SetVisible(false);
208   mRefMaskActor->SetContourColor(0,1,0); // green contour
209   mRefMaskActor->UpdateColor();
210   mRefMaskActor->Update();
211 }
212 //------------------------------------------------------------------------------
213
214
215 //------------------------------------------------------------------------------
216 void vvToolSegmentation::KeyPressed(std::string KeyPress)
217
218   if (KeyPress == "e") {
219     Erode();
220   }
221   if (KeyPress == "d") {
222     Dilate(); // FIXME -> extend image BB !!
223   }
224   if (KeyPress == "L") {
225     Labelize(); 
226   }
227   if (KeyPress == "m") {
228     Merge(); 
229   }
230   if (KeyPress == "s") { // Supress "Remove" one label
231     if (mCurrentState == State_CCL) RemoveLabel();
232   }
233   if (KeyPress == "t") { // display remove ref contour
234     mRefMaskActor->SetContourVisible(!mRefMaskActor->IsContourVisible());
235     mRefMaskActor->UpdateColor();
236     mCurrentSlicerManager->Render();
237   }
238   if (KeyPress == "w") {
239     vvImageWriter::Pointer writer = vvImageWriter::New();
240     writer->SetOutputFileName("a.mha");
241     writer->SetInput(mCurrentMaskImage);
242     writer->Update();
243   }
244 }
245 //------------------------------------------------------------------------------
246
247
248 //------------------------------------------------------------------------------
249 void vvToolSegmentation::Merge()
250 {
251   if (mCurrentState != State_CCL) return;
252   
253   DD("Merge");
254   // Remove actors
255   for(int i=0; i<mCurrentCCLActors.size(); i++) {
256     if (mCurrentCCLActors[i]) {
257       mCurrentCCLActors[i]->SetVisible(false);
258       mCurrentCCLActors[i]->RemoveActors();
259     }
260   }
261   mCurrentCCLActors.clear();
262
263   // Compute new mask
264   vtkImageData * ccl  = mCurrentCCLImage->GetFirstVTKImageData();
265   vtkImageData * mask = mCurrentMaskImage->GetFirstVTKImageData();
266   int * pCCL = (int*)ccl->GetScalarPointer();
267   char * pPix = (char*)mask->GetScalarPointer();
268   for(uint i=0; i<ccl->GetNumberOfPoints(); i++) {
269     if (pCCL[i] == 0) pPix[i] = 0; // copy BG
270   }
271
272   // Display new mask and remove ccl
273   mCurrentCCLImage->Reset();
274   mCurrentMaskActor->RemoveActors(); // kill it
275   mCurrentMaskActor = CreateMaskActor(mCurrentMaskImage, 1, 0, false); // renew
276   mCurrentMaskActor->Update();
277   mCurrentMaskActor->SetVisible(true); 
278   mCurrentSlicerManager->Render();
279   mCurrentState = State_Default;
280 }
281 //------------------------------------------------------------------------------
282
283
284 //------------------------------------------------------------------------------
285 void vvToolSegmentation::Erode()
286 {
287   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
288   // Merge labels if needed
289   Merge();
290   // Get image and start erosion
291   vtkImageContinuousErode3D* erode = vtkImageContinuousErode3D::New();
292   erode->SetKernelSize(mKernelValue,mKernelValue,mKernelValue);
293   vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
294   erode->SetInput(image);
295   erode->Update();
296   image->DeepCopy(erode->GetOutput());
297   image->Update();
298   UpdateAndRenderNewMask();
299   erode->Delete();
300   QApplication::restoreOverrideCursor();
301 }
302 //------------------------------------------------------------------------------
303
304
305 //------------------------------------------------------------------------------
306 void vvToolSegmentation::Dilate()
307 {
308   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
309   // Merge labels if needed
310   Merge();
311   // Get image and start dilatation
312   vtkImageContinuousDilate3D* dilate = vtkImageContinuousDilate3D::New();
313   dilate->SetKernelSize(mKernelValue,mKernelValue,mKernelValue);
314   vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
315   dilate->SetInput(image);
316   dilate->Update();
317   image->DeepCopy(dilate->GetOutput());
318   image->Update();
319   UpdateAndRenderNewMask();
320   dilate->Delete();
321   QApplication::restoreOverrideCursor();
322 }
323 //------------------------------------------------------------------------------
324
325
326 //------------------------------------------------------------------------------
327 void vvToolSegmentation::UpdateAndRenderNewMask()
328 {
329   bool visible = mCurrentMaskActor->IsVisible();
330   bool cvisible = mCurrentMaskActor->IsContourVisible();
331   mCurrentMaskActor->SetVisible(false);
332   mCurrentMaskActor->SetContourVisible(false);
333   mCurrentMaskActor->UpdateImage();
334   mCurrentMaskActor->SetVisible(visible);
335   mCurrentMaskActor->SetContourVisible(cvisible);
336
337   mCurrentSlicerManager->Render();
338 }
339 //------------------------------------------------------------------------------
340
341 //------------------------------------------------------------------------------
342 void vvToolSegmentation::Labelize()
343 {
344   if (mCurrentState == State_CCL) return; // Do nothing in this case
345   DD("Labelize");
346   // Waiting cursos
347   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
348   mCurrentMaskActor->SetVisible(false);
349   
350   // Build CCL filter
351   vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
352   typedef args_info_clitkConnectedComponentLabeling ArgsInfoType;
353   ArgsInfoType a;
354   cmdline_parser_clitkConnectedComponentLabeling_init(&a);
355   a.inputBG_arg = 0;
356   a.full_flag = false;  // FIXME set by gui
357   a.minSize_arg = 100;  // FIXME set by gui 
358   typedef clitk::ConnectedComponentLabelingGenericFilter<ArgsInfoType> FilterType;
359   FilterType::Pointer filter = FilterType::New();
360   filter->SetArgsInfo(a);
361   filter->SetInputVVImage(mCurrentMaskImage); // FIXME Check type is ok ? convert float ?
362   filter->SetIOVerbose(true);  
363   filter->Update();
364   DD(filter->GetOriginalNumberOfObjects());
365   DD(filter->GetSizeOfObjectsInPixels().size());
366   mCurrentCCLImage = filter->GetOutputVVImage();
367   DDV(filter->GetSizeOfObjectsInPixels(), filter->GetSizeOfObjectsInPixels().size());
368   DD("filter done");
369
370   /*
371   // DEBUG
372   vvImageWriter::Pointer writer = vvImageWriter::New();
373   writer->SetInput(mCurrentCCLImage);
374   writer->SetOutputFileName("bidon-ccl.mha");
375   writer->Update(); 
376   DD(mCurrentCCLImage->IsScalarTypeInteger());
377   */
378   
379   // Create actors 
380   int n = filter->GetSizeOfObjectsInPixels().size();
381   mCurrentCCLActors.clear();
382   for(int i=1; i<=std::min(n,10); i++) { // Start at 1 because 0 is BG. FIXME max by gui
383     QSharedPointer<vvROIActor> actor = CreateMaskActor(mCurrentCCLImage, i, i+1, false); 
384     mCurrentCCLActors.push_back( actor );
385     actor->Update();    
386   }
387   //  mCurrentMaskActor->Update();
388   mCurrentSlicerManager->Render();
389   
390   // UpdateAndRender();
391   mCurrentState = State_CCL;
392   QApplication::restoreOverrideCursor();
393 }
394 //------------------------------------------------------------------------------
395
396 //------------------------------------------------------------------------------
397 QSharedPointer<vvROIActor> vvToolSegmentation::CreateMaskActor(vvImage::Pointer image, int i, int colorID, bool BGMode)
398 {
399   static int depth = 1;
400   depth += 1;
401   QSharedPointer<vvROIActor> actor = QSharedPointer<vvROIActor>(new vvROIActor);
402   double * color = mDefaultLUTColor->GetTableValue(colorID % mDefaultLUTColor->GetNumberOfTableValues ());
403   std::vector<double> c;
404   c.push_back(color[0]);
405   c.push_back(color[1]);
406   c.push_back(color[2]);
407   clitk::DicomRT_ROI::Pointer roi = clitk::DicomRT_ROI::New();
408   roi->SetFromBinaryImage(image, i, std::string("toto"), c, std::string("titi"));
409   if (BGMode) {
410     actor->SetBGMode(true);
411   }
412   else {
413     roi->SetForegroundValueLabelImage(i); // FG mode
414     actor->SetBGMode(false); // FG mode
415   }
416   actor->SetROI(roi);
417   actor->SetSlicerManager(mCurrentSlicerManager);
418   actor->Initialize(depth+i, true); // +1 to start at 1 not 0
419   actor->SetContourVisible(false);
420   actor->SetVisible(true);
421   return actor;
422 }
423 //------------------------------------------------------------------------------
424
425
426 //------------------------------------------------------------------------------
427 void vvToolSegmentation::MousePositionChanged(int slicer)
428 {
429   if (mCurrentState == State_Default) return; // Do nothing in this case
430
431   double x = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[0];
432   double y = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[1];
433   double z = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[2];
434   vtkImageData * image = mCurrentCCLImage->GetFirstVTKImageData();
435   double Xover = (x - image->GetOrigin()[0]) / image->GetSpacing()[0];
436   double Yover = (y - image->GetOrigin()[1]) / image->GetSpacing()[1];
437   double Zover = (z - image->GetOrigin()[2]) / image->GetSpacing()[2];
438   int ix, iy, iz;
439   
440   if (Xover >= image->GetWholeExtent()[0] &&
441       Xover <= image->GetWholeExtent()[1] &&
442       Yover >= image->GetWholeExtent()[2] &&
443       Yover <= image->GetWholeExtent()[3] &&
444       Zover >= image->GetWholeExtent()[4] &&
445       Zover <= image->GetWholeExtent()[5]) {
446     mCurrentLabelUnderMousePointer = 
447       mCurrentSlicerManager->GetSlicer(0)->GetScalarComponentAsDouble(image, Xover, Yover, Zover, ix, iy, iz, 0);
448     // DD(Xover); DD(Yover); DD(Zover);
449     // DD(ix); DD(iy); DD(iz);
450     // DD(valueOver);
451   }
452   else {
453     // DD("out of mask");
454     mCurrentLabelUnderMousePointer = 0;
455   }
456   // DD(mCurrentLabelUnderMousePointer);
457 }
458 //------------------------------------------------------------------------------
459
460
461 //------------------------------------------------------------------------------
462 void vvToolSegmentation::RemoveLabel() {
463   DD("RemoveLabel");
464   if (mCurrentLabelUnderMousePointer == 0) return;
465   // First actor=0 and is label 1. Label 0 is not an actor, it is BG
466   int actorNumber = mCurrentLabelUnderMousePointer-1; 
467   // Set actor invisible
468   mCurrentCCLActors[actorNumber]->SetVisible(false);
469   mCurrentSlicerManager->Render();
470   // Set image label
471   vtkImageData * image = mCurrentCCLImage->GetFirstVTKImageData();
472   int * pPix = (int*)image->GetScalarPointer();
473   for(uint i=0; i<image->GetNumberOfPoints(); i++) {
474     if (pPix[i] == mCurrentLabelUnderMousePointer) pPix[i] = 0;
475   }
476 }
477 //------------------------------------------------------------------------------