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://www.centreleonberard.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 ===========================================================================**/
20 #include "vvToolSegmentation.h"
21 #include "vvSlicerManager.h"
23 #include "vvToolInputSelectorWidget.h"
24 #include "vvImageWriter.h"
27 #include "clitkConnectedComponentLabeling_ggo.h"
28 #include "clitkConnectedComponentLabelingGenericFilter.h"
31 #include <QFileDialog>
32 #include <QMessageBox>
35 #include "vtkImageContinuousErode3D.h"
36 #include "vtkImageContinuousDilate3D.h"
37 #include "vtkRenderWindow.h"
39 //------------------------------------------------------------------------------
40 // Create the tool and automagically (I like this word) insert it in
41 // the main window menu.
42 ADD_TOOL(vvToolSegmentation);
43 //------------------------------------------------------------------------------
46 //------------------------------------------------------------------------------
47 void vvToolSegmentation::Initialize()
49 SetToolName("Segmentation");
50 SetToolMenuName("Interactive Segmentation");
51 SetToolIconFilename(":/common/icons/ducky.ico");
52 SetToolTip("Image interactive segmentation (trial).");
53 SetToolExperimental(true);
55 //------------------------------------------------------------------------------
58 //------------------------------------------------------------------------------
59 vvToolSegmentation::vvToolSegmentation(vvMainWindowBase * parent, Qt::WindowFlags f)
60 :vvToolWidgetBase(parent,f),
61 vvToolBase<vvToolSegmentation>(parent),
62 Ui::vvToolSegmentation()
65 Ui_vvToolSegmentation::setupUi(mToolWidget);
66 setAttribute(Qt::WA_DeleteOnClose);
68 // Set how many inputs are needed for this tool
69 AddInputSelector("Select one image");
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"
80 //------------------------------------------------------------------------------
83 //------------------------------------------------------------------------------
84 vvToolSegmentation::~vvToolSegmentation()
88 //------------------------------------------------------------------------------
91 //------------------------------------------------------------------------------
92 bool vvToolSegmentation::close()
95 if (mRefMaskActor) mRefMaskActor->RemoveActors();
97 if (mCurrentMaskActor) mCurrentMaskActor->RemoveActors();
98 for(int i=0; i<mCurrentCCLActors.size(); i++) {
100 if (mCurrentCCLActors[i]) mCurrentCCLActors[i]->RemoveActors();
104 mCurrentSlicerManager->Render();
107 //------------------------------------------------------------------------------
110 //------------------------------------------------------------------------------
111 void vvToolSegmentation::InputIsSelected(vvSlicerManager * m)
113 DD("InputIsSelected");
114 mCurrentSlicerManager = m;
115 mCurrentImage = mCurrentSlicerManager->GetImage();
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"));
125 //mLabelInputInfo->setText(QString("%1").arg(m->GetFileName().c_str()));
131 if (mRefMaskActor == NULL) {
137 mToolInputSelectionWidget->hide();
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)));
145 //------------------------------------------------------------------------------
148 //------------------------------------------------------------------------------
149 void vvToolSegmentation::apply()
153 //------------------------------------------------------------------------------
156 //------------------------------------------------------------------------------
157 void vvToolSegmentation::OpenBinaryImage()
159 DD("OpenBinaryImage");
161 // Load browser and select image
162 QString Extensions = "Images files ( *.mha *.mhd *.hdr *.his)";
163 Extensions += ";;All Files (*)";
165 QFileDialog::getOpenFileName(this,tr("Open binary image"),
166 mMainWindowBase->GetInputPathName(),Extensions);
167 DD(filename.toStdString());
168 if (filename.size() == 0) return;
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();
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);
187 mRefMaskImage = reader->GetOutput();
188 int dim = mRefMaskImage->GetNumberOfDimensions();
190 QMessageBox::information(this,tr("Sorry only 3D yet"), tr("Sorry only 3D yet"));
195 reader = vvImageReader::New();
196 reader->SetInputFilenames(filenames);
197 reader->Update(vvImageReader::IMAGE);
198 mCurrentMaskImage = reader->GetOutput();
200 // Add a new roi actor for the current mask
201 mCurrentMaskActor = CreateMaskActor(mCurrentMaskImage, 1, 0, false);
202 mCurrentMaskActor->Update(); // default color is red
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();
212 //------------------------------------------------------------------------------
215 //------------------------------------------------------------------------------
216 void vvToolSegmentation::KeyPressed(std::string KeyPress)
218 if (KeyPress == "e") {
221 if (KeyPress == "d") {
222 Dilate(); // FIXME -> extend image BB !!
224 if (KeyPress == "L") {
227 if (KeyPress == "m") {
230 if (KeyPress == "s") { // Supress "Remove" one label
231 if (mCurrentState == State_CCL) RemoveLabel();
233 if (KeyPress == "t") { // display remove ref contour
234 mRefMaskActor->SetContourVisible(!mRefMaskActor->IsContourVisible());
235 mRefMaskActor->UpdateColor();
236 mCurrentSlicerManager->Render();
238 if (KeyPress == "w") {
239 vvImageWriter::Pointer writer = vvImageWriter::New();
240 writer->SetOutputFileName("a.mha");
241 writer->SetInput(mCurrentMaskImage);
245 //------------------------------------------------------------------------------
248 //------------------------------------------------------------------------------
249 void vvToolSegmentation::Merge()
251 if (mCurrentState != State_CCL) return;
255 for(int i=0; i<mCurrentCCLActors.size(); i++) {
256 if (mCurrentCCLActors[i]) {
257 mCurrentCCLActors[i]->SetVisible(false);
258 mCurrentCCLActors[i]->RemoveActors();
261 mCurrentCCLActors.clear();
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
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;
281 //------------------------------------------------------------------------------
284 //------------------------------------------------------------------------------
285 void vvToolSegmentation::Erode()
287 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
288 // Merge labels if needed
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);
296 image->DeepCopy(erode->GetOutput());
298 UpdateAndRenderNewMask();
300 QApplication::restoreOverrideCursor();
302 //------------------------------------------------------------------------------
305 //------------------------------------------------------------------------------
306 void vvToolSegmentation::Dilate()
308 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
309 // Merge labels if needed
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);
317 image->DeepCopy(dilate->GetOutput());
319 UpdateAndRenderNewMask();
321 QApplication::restoreOverrideCursor();
323 //------------------------------------------------------------------------------
326 //------------------------------------------------------------------------------
327 void vvToolSegmentation::UpdateAndRenderNewMask()
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);
337 mCurrentSlicerManager->Render();
339 //------------------------------------------------------------------------------
341 //------------------------------------------------------------------------------
342 void vvToolSegmentation::Labelize()
344 if (mCurrentState == State_CCL) return; // Do nothing in this case
347 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
348 mCurrentMaskActor->SetVisible(false);
351 vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
352 typedef args_info_clitkConnectedComponentLabeling ArgsInfoType;
354 cmdline_parser_clitkConnectedComponentLabeling_init(&a);
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);
364 DD(filter->GetOriginalNumberOfObjects());
365 DD(filter->GetSizeOfObjectsInPixels().size());
366 mCurrentCCLImage = filter->GetOutputVVImage();
367 DDV(filter->GetSizeOfObjectsInPixels(), filter->GetSizeOfObjectsInPixels().size());
372 vvImageWriter::Pointer writer = vvImageWriter::New();
373 writer->SetInput(mCurrentCCLImage);
374 writer->SetOutputFileName("bidon-ccl.mha");
376 DD(mCurrentCCLImage->IsScalarTypeInteger());
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 );
387 // mCurrentMaskActor->Update();
388 mCurrentSlicerManager->Render();
390 // UpdateAndRender();
391 mCurrentState = State_CCL;
392 QApplication::restoreOverrideCursor();
394 //------------------------------------------------------------------------------
396 //------------------------------------------------------------------------------
397 QSharedPointer<vvROIActor> vvToolSegmentation::CreateMaskActor(vvImage::Pointer image, int i, int colorID, bool BGMode)
399 static int 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"));
410 actor->SetBGMode(true);
413 roi->SetForegroundValueLabelImage(i); // FG mode
414 actor->SetBGMode(false); // FG mode
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);
423 //------------------------------------------------------------------------------
426 //------------------------------------------------------------------------------
427 void vvToolSegmentation::MousePositionChanged(int slicer)
429 if (mCurrentState == State_Default) return; // Do nothing in this case
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];
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);
453 // DD("out of mask");
454 mCurrentLabelUnderMousePointer = 0;
456 // DD(mCurrentLabelUnderMousePointer);
458 //------------------------------------------------------------------------------
461 //------------------------------------------------------------------------------
462 void vvToolSegmentation::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();
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;
477 //------------------------------------------------------------------------------