]> Creatis software - clitk.git/blob - vv/vvToolSegmentation.cxx
Merge branch 'master' of git.creatis.insa-lyon.fr:clitk
[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
38 //------------------------------------------------------------------------------
39 // Create the tool and automagically (I like this word) insert it in
40 // the main window menu.
41 ADD_TOOL(vvToolSegmentation);
42 //------------------------------------------------------------------------------
43
44
45 //------------------------------------------------------------------------------
46 void vvToolSegmentation::Initialize()
47 {
48   SetToolName("Segmentation");
49   SetToolMenuName("Interactive Segmentation");
50   SetToolIconFilename(":/common/icons/ducky.ico");
51   SetToolTip("Image interactive segmentation (trial).");
52   SetToolExperimental(true);
53 }
54 //------------------------------------------------------------------------------
55
56
57 //------------------------------------------------------------------------------
58 vvToolSegmentation::vvToolSegmentation(vvMainWindowBase * parent, Qt::WindowFlags f)
59   :vvToolWidgetBase(parent,f),
60    vvToolBase<vvToolSegmentation>(parent),
61    Ui::vvToolSegmentation()
62 {
63   // GUI Initialization
64   Ui_vvToolSegmentation::setupUi(mToolWidget);
65   setAttribute(Qt::WA_DeleteOnClose);
66
67   // Set how many inputs are needed for this tool
68   AddInputSelector("Select one image");
69   
70   // Init
71   mRefMaskImage = NULL;
72   mCurrentMode = Mode_Default;
73   mKernelValue = 3; // FIXME must be odd. If even -> not symmetrical
74   mDefaultLUTColor = vtkSmartPointer<vtkLookupTable>::New();
75   mDefaultLUTColor->SetNumberOfTableValues(256);
76 #include "vvDefaultLut.h"
77   
78 }
79 //------------------------------------------------------------------------------
80
81
82 //------------------------------------------------------------------------------
83 vvToolSegmentation::~vvToolSegmentation()
84 {
85   DD("destructor");
86 }
87 //------------------------------------------------------------------------------
88
89
90 //------------------------------------------------------------------------------
91 bool vvToolSegmentation::close()
92 {
93   DD("close");
94   mRefMaskActor->RemoveActors();
95   DD("la");
96   mCurrentMaskActor->RemoveActors();
97   DD("here");
98   QWidget::close();  
99   DD("toto");
100   mCurrentSlicerManager->Render();
101   return true;
102 }
103 //------------------------------------------------------------------------------
104
105
106 //------------------------------------------------------------------------------
107 void vvToolSegmentation::InputIsSelected(vvSlicerManager * m)
108 {
109   DD("InputIsSelected");
110   mCurrentSlicerManager = m;
111   mCurrentImage = mCurrentSlicerManager->GetImage();
112
113   // Refuse if non 3D image
114   if (mCurrentImage->GetNumberOfDimensions() != 3) {
115     QMessageBox::information(this,tr("Sorry only 3D yet"), tr("Sorry only 3D yet"));
116     close();
117     return;
118   }
119
120   // Change gui
121   //mLabelInputInfo->setText(QString("%1").arg(m->GetFileName().c_str()));
122
123   // Open mask
124   OpenBinaryImage();
125   
126   // If cancel: stop
127   if (mRefMaskActor == NULL) {
128     close();
129     return;
130   }
131
132   // Update gui
133   mToolInputSelectionWidget->hide();
134
135   // Connect mouse position
136   connect(mCurrentSlicerManager, SIGNAL(MousePositionUpdatedSignal(int)),
137           this, SLOT(MousePositionChanged(int)));
138 }
139 //------------------------------------------------------------------------------
140
141
142 //------------------------------------------------------------------------------
143 void vvToolSegmentation::apply()
144 {
145   DD("apply");
146 }
147 //------------------------------------------------------------------------------
148
149
150 //------------------------------------------------------------------------------
151 void vvToolSegmentation::OpenBinaryImage()
152 {
153   DD("OpenBinaryImage");
154
155   // Load browser and select image
156   QString Extensions = "Images files ( *.mha *.mhd *.hdr *.his)";
157   Extensions += ";;All Files (*)";
158   QString filename =
159     QFileDialog::getOpenFileName(this,tr("Open binary image"),
160                                  mMainWindowBase->GetInputPathName(),Extensions);
161   DD(filename.toStdString());
162   if (filename.size() == 0) return;
163   
164   // Open Image
165   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
166   vvImageReader::Pointer reader = vvImageReader::New();
167   std::vector<std::string> filenames;
168   filenames.push_back(filename.toStdString());
169   reader->SetInputFilenames(filenames);
170   reader->Update(vvImageReader::IMAGE);
171   QApplication::restoreOverrideCursor();
172   
173   if (reader->GetLastError().size() != 0) {
174     std::cerr << "Error while reading " << filename.toStdString() << std::endl;
175     QString error = "Cannot open file \n";
176     error += reader->GetLastError().c_str();
177     QMessageBox::information(this,tr("Reading problem"),error);
178     return;
179   }
180
181   mRefMaskImage = reader->GetOutput();
182   int dim = mRefMaskImage->GetNumberOfDimensions();
183   if (dim != 3 ) {
184     QMessageBox::information(this,tr("Sorry only 3D yet"), tr("Sorry only 3D yet"));
185     close();
186     return;
187   }
188
189   reader = vvImageReader::New();
190   reader->SetInputFilenames(filenames);
191   reader->Update(vvImageReader::IMAGE);
192   mCurrentMaskImage = reader->GetOutput();
193
194   // Add a new roi actor
195   mRefMaskActor = CreateMaskActor(mRefMaskImage, 0, 0, true);
196   mRefMaskActor->SetContourVisible(true);
197   mRefMaskActor->SetVisible(false);
198   mRefMaskActor->SetContourColor(0,1,0); // green contour
199   mRefMaskActor->UpdateColor();
200   mRefMaskActor->Update();
201
202   mCurrentMaskActor = CreateMaskActor(mCurrentMaskImage, 1, 1, false);
203   mCurrentMaskActor->SetOverlayColor(1,0,0); // red roi
204   mRefMaskActor->UpdateColor();
205   mCurrentMaskActor->Update();
206
207   // Prepare widget to get keyboard event. With this method, the key
208   //  only work when the mouse focus is on the dialog
209   DD("here installe");
210   this->installEventFilter(this);
211   //grabKeyboard();
212 }
213 //------------------------------------------------------------------------------
214
215
216 //------------------------------------------------------------------------------
217 //void vvToolSegmentation::keyPressEvent(QKeyEvent * event)
218 bool vvToolSegmentation::eventFilter(QObject *object, QEvent * e)
219 {
220   // DD("key");
221   //vvToolWidgetBase::keyPressEvent(event);
222   
223   if (/*object == form &&*/ e->type() == QEvent::KeyPress) {
224     QKeyEvent * event = static_cast<QKeyEvent *>(e);
225     
226     if (event->text() == "e") {
227       Erode();
228     }
229     if (event->text() == "d") {
230       Dilate(); // FIXME -> extend image BB !!
231     }
232     if (event->text() == "l") {
233       Labelize(); 
234     }
235     if (event->text() == "r") { // "Remove" one label
236       if (mCurrentMode == Mode_CCL) RemoveLabel();
237     }
238     if (event->text() == "s") {
239       vvImageWriter::Pointer writer = vvImageWriter::New();
240       writer->SetOutputFileName("a.mha");
241       writer->SetInput(mCurrentMaskImage);
242       writer->Update();
243     }
244     //mMainWindow->keyPressEvent(event);
245     vvToolWidgetBase::keyPressEvent(event);
246   }         
247   return QObject::eventFilter(object, e);
248 }
249 //------------------------------------------------------------------------------
250
251
252 //------------------------------------------------------------------------------
253 void vvToolSegmentation::Erode()
254 {
255   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
256   vtkImageContinuousErode3D* erode = vtkImageContinuousErode3D::New();
257   erode->SetKernelSize(mKernelValue,mKernelValue,mKernelValue);
258   vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
259   erode->SetInput(image);
260   erode->Update();
261   image->DeepCopy(erode->GetOutput());
262   image->Update();
263   UpdateAndRenderNewMask();
264   erode->Delete();
265   QApplication::restoreOverrideCursor();
266 }
267 //------------------------------------------------------------------------------
268
269
270 //------------------------------------------------------------------------------
271 void vvToolSegmentation::Dilate()
272 {
273   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
274   vtkImageContinuousDilate3D* dilate = vtkImageContinuousDilate3D::New();
275   dilate->SetKernelSize(mKernelValue,mKernelValue,mKernelValue);
276   vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
277   dilate->SetInput(image);
278   dilate->Update();
279   image->DeepCopy(dilate->GetOutput());
280   image->Update();
281   UpdateAndRenderNewMask();
282   dilate->Delete();
283   QApplication::restoreOverrideCursor();
284 }
285 //------------------------------------------------------------------------------
286
287
288 //------------------------------------------------------------------------------
289 void vvToolSegmentation::UpdateAndRenderNewMask()
290 {
291   bool visible = mCurrentMaskActor->IsVisible();
292   bool cvisible = mCurrentMaskActor->IsContourVisible();
293   mCurrentMaskActor->SetVisible(false);
294   mCurrentMaskActor->SetContourVisible(false);
295   mCurrentMaskActor->UpdateImage();
296   mCurrentMaskActor->SetVisible(visible);
297   mCurrentMaskActor->SetContourVisible(cvisible);
298
299   mCurrentSlicerManager->Render();
300 }
301 //------------------------------------------------------------------------------
302
303 //------------------------------------------------------------------------------
304 void vvToolSegmentation::Labelize()
305 {
306   DD("Labelize");
307   // Waiting cursos
308   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
309   
310   // Build CCL filter
311   vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
312   typedef args_info_clitkConnectedComponentLabeling ArgsInfoType;
313   ArgsInfoType a;
314   cmdline_parser_clitkConnectedComponentLabeling_init(&a);
315   a.inputBG_arg = 0;
316   a.full_flag = false;  // FIXME set by gui
317   a.minSize_arg = 100;  // FIXME set by gui 
318   typedef clitk::ConnectedComponentLabelingGenericFilter<ArgsInfoType> FilterType;
319   FilterType::Pointer filter = FilterType::New();
320   filter->SetArgsInfo(a);
321   filter->SetInputVVImage(mCurrentMaskImage);
322   filter->SetIOVerbose(true);  
323   filter->Update();
324   DD(filter->GetOriginalNumberOfObjects());
325   DD(filter->GetSizeOfObjectsInPixels().size());
326   mCurrentCCLImage = filter->GetOutputVVImage();
327   DDV(filter->GetSizeOfObjectsInPixels(), filter->GetSizeOfObjectsInPixels().size());
328   DD("filter done");
329
330   /*
331   // DEBUG
332   vvImageWriter::Pointer writer = vvImageWriter::New();
333   writer->SetInput(mCurrentCCLImage);
334   writer->SetOutputFileName("bidon-ccl.mha");
335   writer->Update(); 
336   DD(mCurrentCCLImage->IsScalarTypeInteger());
337   */
338   
339   // Create actors 
340   int n = filter->GetSizeOfObjectsInPixels().size();
341   for(int i=1; i<std::min(n,10); i++) { // Start at 1 because 0 is BG. FIXME max 10
342     DD(i);
343     QSharedPointer<vvROIActor> actor = CreateMaskActor(mCurrentCCLImage, i, i+1, false); 
344     mCurrentCCLActors.push_back( actor );
345     actor->Update();    
346   }
347   mCurrentMaskActor->SetVisible(false);
348   mCurrentMaskActor->Update();
349   mCurrentSlicerManager->Render();
350   
351   // UpdateAndRender();
352   mCurrentMode = Mode_CCL;
353   QApplication::restoreOverrideCursor();
354 }
355 //------------------------------------------------------------------------------
356
357 //------------------------------------------------------------------------------
358 QSharedPointer<vvROIActor> vvToolSegmentation::CreateMaskActor(vvImage::Pointer image, int i, int colorID, bool BGMode)
359 {
360   static int depth = 1;
361   depth += 1;
362   QSharedPointer<vvROIActor> actor = QSharedPointer<vvROIActor>(new vvROIActor);
363   double * color = mDefaultLUTColor->GetTableValue(colorID % mDefaultLUTColor->GetNumberOfTableValues ());
364   std::vector<double> c;
365   c.push_back(color[0]);
366   c.push_back(color[1]);
367   c.push_back(color[2]);
368   clitk::DicomRT_ROI::Pointer roi = clitk::DicomRT_ROI::New();
369   roi->SetFromBinaryImage(image, i, std::string("toto"), c, std::string("titi"));
370   if (BGMode) {
371     actor->SetBGMode(true);
372   }
373   else {
374     DD("FG mode");
375     roi->SetForegroundValueLabelImage(i); // FG mode
376     actor->SetBGMode(false); // FG mode
377   }
378   actor->SetROI(roi);
379   actor->SetSlicerManager(mCurrentSlicerManager);
380   actor->Initialize(depth+i, true); // +1 to start at 1 not 0
381   actor->SetContourVisible(false);
382   actor->SetVisible(true);
383   return actor;
384 }
385 //------------------------------------------------------------------------------
386
387
388 //------------------------------------------------------------------------------
389 void vvToolSegmentation::MousePositionChanged(int slicer)
390 {
391   if (mCurrentMode == Mode_Default) return; // Do nothing in this case
392
393   double x = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[0];
394   double y = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[1];
395   double z = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[2];
396   vtkImageData * image = mCurrentCCLImage->GetFirstVTKImageData();
397   double Xover = (x - image->GetOrigin()[0]) / image->GetSpacing()[0];
398   double Yover = (y - image->GetOrigin()[1]) / image->GetSpacing()[1];
399   double Zover = (z - image->GetOrigin()[2]) / image->GetSpacing()[2];
400   int ix, iy, iz;
401   
402   if (Xover >= image->GetWholeExtent()[0] &&
403       Xover <= image->GetWholeExtent()[1] &&
404       Yover >= image->GetWholeExtent()[2] &&
405       Yover <= image->GetWholeExtent()[3] &&
406       Zover >= image->GetWholeExtent()[4] &&
407       Zover <= image->GetWholeExtent()[5]) {
408     double valueOver = 
409       mCurrentSlicerManager->GetSlicer(0)->GetScalarComponentAsDouble(image, Xover, Yover, Zover, ix, iy, iz, 0);
410     // DD(Xover); DD(Yover); DD(Zover);
411     // DD(ix); DD(iy); DD(iz);
412     // DD(valueOver);
413   }
414   else {
415     // DD("out of mask");
416   }
417
418 }
419 //------------------------------------------------------------------------------
420
421
422 //------------------------------------------------------------------------------
423 void vvToolSegmentation::RemoveLabel() {
424   DD("RemoveLabel");
425 }
426 //------------------------------------------------------------------------------