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");
72 mCurrentLabelUnderMousePointer = 0.0;
73 mCurrentMousePosition.resize(3);
75 mCurrentState = State_Default;
76 mKernelValue = 3; // FIXME must be odd. If even -> not symmetrical
77 mDefaultLUTColor = vtkSmartPointer<vtkLookupTable>::New();
78 mDefaultLUTColor->SetNumberOfTableValues(256);
79 #include "vvDefaultLut.h"
82 //------------------------------------------------------------------------------
85 //------------------------------------------------------------------------------
86 vvToolSegmentation::~vvToolSegmentation()
90 //------------------------------------------------------------------------------
93 //------------------------------------------------------------------------------
94 bool vvToolSegmentation::close()
97 if (mRefMaskActor) mRefMaskActor->RemoveActors();
99 if (mCurrentMaskActor) mCurrentMaskActor->RemoveActors();
100 for(int i=0; i<mCurrentCCLActors.size(); i++) {
101 if (mCurrentCCLActors[i]) mCurrentCCLActors[i]->RemoveActors();
105 mCurrentSlicerManager->Render();
108 //------------------------------------------------------------------------------
111 //------------------------------------------------------------------------------
112 void vvToolSegmentation::InputIsSelected(vvSlicerManager * m)
114 DD("InputIsSelected");
115 mCurrentSlicerManager = m;
116 mCurrentImage = mCurrentSlicerManager->GetImage();
118 // Refuse if non 3D image
119 if (mCurrentImage->GetNumberOfDimensions() != 3) {
120 QMessageBox::information(this,tr("Sorry only 3D yet"), tr("Sorry only 3D yet"));
126 //mLabelInputInfo->setText(QString("%1").arg(m->GetFileName().c_str()));
132 if (mRefMaskActor == NULL) {
138 mToolInputSelectionWidget->hide();
140 // Connect mouse position
141 connect(mCurrentSlicerManager, SIGNAL(MousePositionUpdatedSignal(int)),
142 this, SLOT(MousePositionChanged(int)));
143 connect(mCurrentSlicerManager, SIGNAL(KeyPressedSignal(std::string)),
144 this, SLOT(KeyPressed(std::string)));
146 //------------------------------------------------------------------------------
149 //------------------------------------------------------------------------------
150 void vvToolSegmentation::apply()
154 //------------------------------------------------------------------------------
157 //------------------------------------------------------------------------------
158 void vvToolSegmentation::OpenBinaryImage()
160 DD("OpenBinaryImage");
162 // Load browser and select image
163 QString Extensions = "Images files ( *.mha *.mhd *.hdr *.his)";
164 Extensions += ";;All Files (*)";
166 QFileDialog::getOpenFileName(this,tr("Open binary image"),
167 mMainWindowBase->GetInputPathName(),Extensions);
168 DD(filename.toStdString());
169 if (filename.size() == 0) return;
172 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
173 vvImageReader::Pointer reader = vvImageReader::New();
174 std::vector<std::string> filenames;
175 filenames.push_back(filename.toStdString());
176 reader->SetInputFilenames(filenames);
177 reader->Update(vvImageReader::IMAGE);
178 QApplication::restoreOverrideCursor();
180 if (reader->GetLastError().size() != 0) {
181 std::cerr << "Error while reading " << filename.toStdString() << std::endl;
182 QString error = "Cannot open file \n";
183 error += reader->GetLastError().c_str();
184 QMessageBox::information(this,tr("Reading problem"),error);
188 mRefMaskImage = reader->GetOutput();
189 int dim = mRefMaskImage->GetNumberOfDimensions();
191 QMessageBox::information(this,tr("Sorry only 3D yet"), tr("Sorry only 3D yet"));
196 reader = vvImageReader::New();
197 reader->SetInputFilenames(filenames);
198 reader->Update(vvImageReader::IMAGE);
199 mCurrentMaskImage = reader->GetOutput();
201 // Add a new roi actor for the current mask
202 mCurrentMaskActor = CreateMaskActor(mCurrentMaskImage, 1, 0, false);
203 mCurrentMaskActor->Update(); // default color is red
204 UpdateMaskSize(mCurrentMaskImage, mCurrentMaskSizeInPixels, mCurrentMaskSizeInCC);
206 // Add a mask actor for the reference
207 mRefMaskActor = CreateMaskActor(mRefMaskImage, 0, 1, true);
208 mRefMaskActor->SetContourVisible(true);
209 mRefMaskActor->SetVisible(false);
210 mRefMaskActor->SetContourColor(0,1,0); // green contour
211 mRefMaskActor->UpdateColor();
212 mRefMaskActor->Update();
213 UpdateMaskSize(mRefMaskImage, mRefMaskSizeInPixels, mRefMaskSizeInCC);
216 UpdateMaskSizeLabels();
218 //------------------------------------------------------------------------------
221 //------------------------------------------------------------------------------
222 void vvToolSegmentation::UpdateMaskSizeLabels()
224 QString s("%1 pix (%2 cm3)");
225 s = s.arg(mRefMaskSizeInPixels).arg(mRefMaskSizeInCC);
226 mRefMaskSizeLabel->setText(s);
227 QString s2("%1 pix (%2 cm3)");
228 s2 = s2.arg(mCurrentMaskSizeInPixels).arg(mCurrentMaskSizeInCC);
229 mCurrentMaskSizeLabel->setText(s2);
231 //------------------------------------------------------------------------------
234 //------------------------------------------------------------------------------
235 void vvToolSegmentation::UpdateMaskSize(vvImage::Pointer image, long & pix, double & cc)
237 pix = ComputeNumberOfPixels(image, GetForegroundValue());
238 double vol = image->GetSpacing()[0]*image->GetSpacing()[1]*image->GetSpacing()[2];
239 cc = pix * vol / (10*10*10);
241 //------------------------------------------------------------------------------
244 //------------------------------------------------------------------------------
245 long vvToolSegmentation::ComputeNumberOfPixels(vvImage::Pointer image, double value)
248 vtkImageData * im = image->GetFirstVTKImageData();
249 char * pPix = (char*)im->GetScalarPointer(); // FIXME char ?
250 for(uint i=0; i<im->GetNumberOfPoints(); i++) {
251 if (pPix[i] == value) n++;
256 //------------------------------------------------------------------------------
259 //------------------------------------------------------------------------------
260 void vvToolSegmentation::KeyPressed(std::string KeyPress)
262 if (KeyPress == "g") {
265 if (KeyPress == "e") {
268 if (KeyPress == "d") {
269 Dilate(); // FIXME -> extend image BB !!
271 if (KeyPress == "L") {
274 if (KeyPress == "m") {
276 UpdateAndRenderNewMask();
278 if (KeyPress == "s") { // Supress "Remove" one label
279 if (mCurrentState == State_CCL) RemoveLabel();
281 if (KeyPress == "t") { // display remove ref contour
282 mRefMaskActor->SetContourVisible(!mRefMaskActor->IsContourVisible());
283 mRefMaskActor->UpdateColor();
284 mCurrentSlicerManager->Render();
286 if (KeyPress == "w") {
287 vvImageWriter::Pointer writer = vvImageWriter::New();
288 writer->SetOutputFileName("a.mha");
289 writer->SetInput(mCurrentMaskImage);
293 //------------------------------------------------------------------------------
296 //------------------------------------------------------------------------------
297 void vvToolSegmentation::RegionGrowing()
300 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
301 // Merge labels if needed
303 // Get mouse location
304 DD(mCurrentLabelUnderMousePointer);
305 DDV(mCurrentMousePosition, 3);
311 clitk.private/deprecated/./mv_to_public.sh ~/src/clitk/clitk.private/tests_dav/ ~/src/clitk/clitk/segmentation/ clitkRegionGrowing.cxx
313 clitk.private/deprecated/./mv_to_public.sh ~/src/clitk/clitk.private/tests_dav/ ~/src/clitk/clitk/segmentation/ clitkRegionGrowing.cxx
316 git format-patch --stdout --root -- clitkRegionGrowing.cxx >/tmp/patch
317 git rm clitkRegionGrowing.cxx
318 git commit clitkRegionGrowing.cxx -m "Moved from repository tests_dav to segmentation"
319 /home/dsarrut/src/clitk/clitk/segmentation
323 git mv clitkRegionGrowing.cxx /home/dsarrut/src/clitk/clitk/segmentation//clitkRegionGrowing.cxx
324 git commit clitkRegionGrowing.cxx /home/dsarrut/src/clitk/clitk/segmentation//clitkRegionGrowing.cxx -m Moved from repository tests_dav to segmentation
328 typedef args_info_clitkConnectedComponentLabeling ArgsInfoType;
330 cmdline_parser_clitkConnectedComponentLabeling_init(&a);
331 a.inputBG_arg = GetBackgroundValue();
332 a.full_flag = false; // FIXME set by gui
333 a.minSize_arg = 100; // FIXME set by gui
334 typedef clitk::ConnectedComponentLabelingGenericFilter<ArgsInfoType> FilterType;
335 FilterType::Pointer filter = FilterType::New();
336 filter->SetArgsInfo(a);
337 filter->SetInputVVImage(mCurrentMaskImage); // FIXME Check type is ok ? convert float ?
338 filter->SetIOVerbose(true);
340 DD(filter->GetOriginalNumberOfObjects());
341 DD(filter->GetSizeOfObjectsInPixels().size());
342 mCurrentCCLImage = filter->GetOutputVVImage();
343 DDV(filter->GetSizeOfObjectsInPixels(), filter->GetSizeOfObjectsInPixels().size());
346 //------------------------------------------------------------------------------
349 //------------------------------------------------------------------------------
350 void vvToolSegmentation::Merge()
352 if (mCurrentState != State_CCL) return;
356 for(int i=0; i<mCurrentCCLActors.size(); i++) {
357 if (mCurrentCCLActors[i]) {
358 mCurrentCCLActors[i]->SetVisible(false);
359 mCurrentCCLActors[i]->RemoveActors();
362 mCurrentCCLActors.clear();
365 vtkImageData * ccl = mCurrentCCLImage->GetFirstVTKImageData();
366 vtkImageData * mask = mCurrentMaskImage->GetFirstVTKImageData();
367 int * pCCL = (int*)ccl->GetScalarPointer();
368 char * pPix = (char*)mask->GetScalarPointer();
369 for(uint i=0; i<ccl->GetNumberOfPoints(); i++) {
370 if (pCCL[i] == 0) pPix[i] = GetBackgroundValue(); // copy BG. In CCL BG is always 0
373 // Display new mask and remove ccl
374 mCurrentCCLImage->Reset();
375 mCurrentMaskActor->RemoveActors(); // kill it
376 mCurrentMaskActor = CreateMaskActor(mCurrentMaskImage, 1, 0, false); // renew
377 mCurrentMaskActor->Update();
378 mCurrentMaskActor->SetVisible(true);
379 // mCurrentSlicerManager->Render();
380 mCurrentState = State_Default;
382 //------------------------------------------------------------------------------
385 //------------------------------------------------------------------------------
386 void vvToolSegmentation::Erode()
388 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
389 // Merge labels if needed
391 // Get image and start erosion
392 vtkImageContinuousErode3D* erode = vtkImageContinuousErode3D::New();
393 erode->SetKernelSize(mKernelValue,mKernelValue,mKernelValue);
394 vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
395 erode->SetInput(image);
397 image->DeepCopy(erode->GetOutput());
399 UpdateAndRenderNewMask();
401 QApplication::restoreOverrideCursor();
403 //------------------------------------------------------------------------------
406 //------------------------------------------------------------------------------
407 void vvToolSegmentation::Dilate()
409 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
410 // Merge labels if needed
412 // Get image and start dilatation
413 vtkImageContinuousDilate3D* dilate = vtkImageContinuousDilate3D::New();
414 dilate->SetKernelSize(mKernelValue,mKernelValue,mKernelValue);
415 vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
416 dilate->SetInput(image);
418 image->DeepCopy(dilate->GetOutput());
420 UpdateAndRenderNewMask();
422 QApplication::restoreOverrideCursor();
424 //------------------------------------------------------------------------------
427 //------------------------------------------------------------------------------
428 void vvToolSegmentation::UpdateAndRenderNewMask()
430 bool visible = mCurrentMaskActor->IsVisible();
431 bool cvisible = mCurrentMaskActor->IsContourVisible();
432 mCurrentMaskActor->SetVisible(false);
433 mCurrentMaskActor->SetContourVisible(false);
434 mCurrentMaskActor->UpdateImage();
435 mCurrentMaskActor->SetVisible(visible);
436 mCurrentMaskActor->SetContourVisible(cvisible);
438 mCurrentSlicerManager->Render();
439 UpdateMaskSize(mCurrentMaskImage, mCurrentMaskSizeInPixels, mCurrentMaskSizeInCC);
440 UpdateMaskSizeLabels();
442 //------------------------------------------------------------------------------
444 //------------------------------------------------------------------------------
445 void vvToolSegmentation::Labelize()
447 if (mCurrentState == State_CCL) return; // Do nothing in this case
450 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
451 mCurrentMaskActor->SetVisible(false);
454 vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
455 typedef args_info_clitkConnectedComponentLabeling ArgsInfoType;
457 cmdline_parser_clitkConnectedComponentLabeling_init(&a);
458 a.inputBG_arg = GetBackgroundValue();
459 a.full_flag = false; // FIXME set by gui
460 a.minSize_arg = 100; // FIXME set by gui
461 typedef clitk::ConnectedComponentLabelingGenericFilter<ArgsInfoType> FilterType;
462 FilterType::Pointer filter = FilterType::New();
463 filter->SetArgsInfo(a);
464 filter->SetInputVVImage(mCurrentMaskImage); // FIXME Check type is ok ? convert float ?
465 filter->SetIOVerbose(true);
467 DD(filter->GetOriginalNumberOfObjects());
468 DD(filter->GetSizeOfObjectsInPixels().size());
469 mCurrentCCLImage = filter->GetOutputVVImage();
470 DDV(filter->GetSizeOfObjectsInPixels(), filter->GetSizeOfObjectsInPixels().size());
475 vvImageWriter::Pointer writer = vvImageWriter::New();
476 writer->SetInput(mCurrentCCLImage);
477 writer->SetOutputFileName("bidon-ccl.mha");
479 DD(mCurrentCCLImage->IsScalarTypeInteger());
483 int n = filter->GetSizeOfObjectsInPixels().size();
484 mCurrentCCLActors.clear();
485 for(int i=1; i<=std::min(n,10); i++) { // Start at 1 because 0 is BG. FIXME max by gui
486 QSharedPointer<vvROIActor> actor = CreateMaskActor(mCurrentCCLImage, i, i+1, false);
487 mCurrentCCLActors.push_back( actor );
490 // mCurrentMaskActor->Update();
491 mCurrentSlicerManager->Render();
493 // UpdateAndRender();
494 mCurrentState = State_CCL;
495 QApplication::restoreOverrideCursor();
497 //------------------------------------------------------------------------------
499 //------------------------------------------------------------------------------
500 QSharedPointer<vvROIActor> vvToolSegmentation::CreateMaskActor(vvImage::Pointer image, int i, int colorID, bool BGMode)
502 static int depth = 1;
504 QSharedPointer<vvROIActor> actor = QSharedPointer<vvROIActor>(new vvROIActor);
505 double * color = mDefaultLUTColor->GetTableValue(colorID % mDefaultLUTColor->GetNumberOfTableValues ());
506 std::vector<double> c;
507 c.push_back(color[0]);
508 c.push_back(color[1]);
509 c.push_back(color[2]);
510 clitk::DicomRT_ROI::Pointer roi = clitk::DicomRT_ROI::New();
511 roi->SetFromBinaryImage(image, i, std::string("toto"), c, std::string("titi"));
513 actor->SetBGMode(true);
516 roi->SetForegroundValueLabelImage(i); // FG mode
517 actor->SetBGMode(false); // FG mode
520 actor->SetSlicerManager(mCurrentSlicerManager);
521 actor->Initialize(depth+i, true); // +1 to start at 1 not 0
522 actor->SetContourVisible(false);
523 actor->SetVisible(true);
526 //------------------------------------------------------------------------------
529 //------------------------------------------------------------------------------
530 void vvToolSegmentation::MousePositionChanged(int slicer)
532 double x = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[0];
533 double y = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[1];
534 double z = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[2];
535 vtkImageData * image = mCurrentCCLImage->GetFirstVTKImageData();
536 double Xover = (x - image->GetOrigin()[0]) / image->GetSpacing()[0];
537 double Yover = (y - image->GetOrigin()[1]) / image->GetSpacing()[1];
538 double Zover = (z - image->GetOrigin()[2]) / image->GetSpacing()[2];
541 mCurrentMousePosition[0] = Xover;
542 mCurrentMousePosition[1] = Yover;
543 mCurrentMousePosition[2] = Zover;
545 if (Xover >= image->GetWholeExtent()[0] &&
546 Xover <= image->GetWholeExtent()[1] &&
547 Yover >= image->GetWholeExtent()[2] &&
548 Yover <= image->GetWholeExtent()[3] &&
549 Zover >= image->GetWholeExtent()[4] &&
550 Zover <= image->GetWholeExtent()[5]) {
551 if (mCurrentState == State_Default) { // inside the mask
552 mCurrentLabelUnderMousePointer = 1;
555 else { // inside the label image
556 mCurrentLabelUnderMousePointer =
557 mCurrentSlicerManager->GetSlicer(0)->GetScalarComponentAsDouble(image, Xover, Yover, Zover, ix, iy, iz, 0);
562 // DD("out of mask");
563 mCurrentLabelUnderMousePointer = 0; // BG is always 0 in CCL
566 //------------------------------------------------------------------------------
569 //------------------------------------------------------------------------------
570 void vvToolSegmentation::RemoveLabel() {
572 if (mCurrentLabelUnderMousePointer == 0) return;
573 // First actor=0 and is label 1. Label 0 is not an actor, it is BG
574 int actorNumber = mCurrentLabelUnderMousePointer-1;
575 // Set actor invisible
576 mCurrentCCLActors[actorNumber]->SetVisible(false);
577 mCurrentSlicerManager->Render();
579 vtkImageData * image = mCurrentCCLImage->GetFirstVTKImageData();
580 int * pPix = (int*)image->GetScalarPointer();
582 for(uint i=0; i<image->GetNumberOfPoints(); i++) {
583 if (pPix[i] == mCurrentLabelUnderMousePointer) pPix[i] = 0;
584 if (pPix[i] != 0) n++; // count the number of pixels in the foreground
587 mCurrentMaskSizeInPixels = n;
588 mCurrentMaskSizeInCC = mCurrentMaskImage->GetSpacing()[0] * mCurrentMaskImage->GetSpacing()[1] * mCurrentMaskImage->GetSpacing()[2] * n / (10*10*10);
589 UpdateMaskSizeLabels();
591 //------------------------------------------------------------------------------