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"
38 //------------------------------------------------------------------------------
39 // Create the tool and automagically (I like this word) insert it in
40 // the main window menu.
41 ADD_TOOL(vvToolSegmentation);
42 //------------------------------------------------------------------------------
45 //------------------------------------------------------------------------------
46 void vvToolSegmentation::Initialize()
48 SetToolName("Segmentation");
49 SetToolMenuName("Interactive Segmentation");
50 SetToolIconFilename(":/common/icons/ducky.ico");
51 SetToolTip("Image interactive segmentation (trial).");
52 SetToolExperimental(true);
54 //------------------------------------------------------------------------------
57 //------------------------------------------------------------------------------
58 vvToolSegmentation::vvToolSegmentation(vvMainWindowBase * parent, Qt::WindowFlags f)
59 :vvToolWidgetBase(parent,f),
60 vvToolBase<vvToolSegmentation>(parent),
61 Ui::vvToolSegmentation()
64 Ui_vvToolSegmentation::setupUi(mToolWidget);
65 setAttribute(Qt::WA_DeleteOnClose);
67 // Set how many inputs are needed for this tool
68 AddInputSelector("Select one image");
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"
79 //------------------------------------------------------------------------------
82 //------------------------------------------------------------------------------
83 vvToolSegmentation::~vvToolSegmentation()
87 //------------------------------------------------------------------------------
90 //------------------------------------------------------------------------------
91 bool vvToolSegmentation::close()
94 mRefMaskActor->RemoveActors();
96 mCurrentMaskActor->RemoveActors();
100 mCurrentSlicerManager->Render();
103 //------------------------------------------------------------------------------
106 //------------------------------------------------------------------------------
107 void vvToolSegmentation::InputIsSelected(vvSlicerManager * m)
109 DD("InputIsSelected");
110 mCurrentSlicerManager = m;
111 mCurrentImage = mCurrentSlicerManager->GetImage();
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"));
121 //mLabelInputInfo->setText(QString("%1").arg(m->GetFileName().c_str()));
127 if (mRefMaskActor == NULL) {
133 mToolInputSelectionWidget->hide();
135 // Connect mouse position
136 connect(mCurrentSlicerManager, SIGNAL(MousePositionUpdatedSignal(int)),
137 this, SLOT(MousePositionChanged(int)));
139 //------------------------------------------------------------------------------
142 //------------------------------------------------------------------------------
143 void vvToolSegmentation::apply()
147 //------------------------------------------------------------------------------
150 //------------------------------------------------------------------------------
151 void vvToolSegmentation::OpenBinaryImage()
153 DD("OpenBinaryImage");
155 // Load browser and select image
156 QString Extensions = "Images files ( *.mha *.mhd *.hdr *.his)";
157 Extensions += ";;All Files (*)";
159 QFileDialog::getOpenFileName(this,tr("Open binary image"),
160 mMainWindowBase->GetInputPathName(),Extensions);
161 DD(filename.toStdString());
162 if (filename.size() == 0) return;
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();
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);
181 mRefMaskImage = reader->GetOutput();
182 int dim = mRefMaskImage->GetNumberOfDimensions();
184 QMessageBox::information(this,tr("Sorry only 3D yet"), tr("Sorry only 3D yet"));
189 reader = vvImageReader::New();
190 reader->SetInputFilenames(filenames);
191 reader->Update(vvImageReader::IMAGE);
192 mCurrentMaskImage = reader->GetOutput();
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();
202 mCurrentMaskActor = CreateMaskActor(mCurrentMaskImage, 1, 1, false);
203 mCurrentMaskActor->SetOverlayColor(1,0,0); // red roi
204 mRefMaskActor->UpdateColor();
205 mCurrentMaskActor->Update();
207 // Prepare widget to get keyboard event. With this method, the key
208 // only work when the mouse focus is on the dialog
210 this->installEventFilter(this);
213 //------------------------------------------------------------------------------
216 //------------------------------------------------------------------------------
217 //void vvToolSegmentation::keyPressEvent(QKeyEvent * event)
218 bool vvToolSegmentation::eventFilter(QObject *object, QEvent * e)
221 //vvToolWidgetBase::keyPressEvent(event);
223 if (/*object == form &&*/ e->type() == QEvent::KeyPress) {
224 QKeyEvent * event = static_cast<QKeyEvent *>(e);
226 if (event->text() == "e") {
229 if (event->text() == "d") {
230 Dilate(); // FIXME -> extend image BB !!
232 if (event->text() == "l") {
235 if (event->text() == "r") { // "Remove" one label
236 if (mCurrentMode == Mode_CCL) RemoveLabel();
238 if (event->text() == "s") {
239 vvImageWriter::Pointer writer = vvImageWriter::New();
240 writer->SetOutputFileName("a.mha");
241 writer->SetInput(mCurrentMaskImage);
244 //mMainWindow->keyPressEvent(event);
245 vvToolWidgetBase::keyPressEvent(event);
247 return QObject::eventFilter(object, e);
249 //------------------------------------------------------------------------------
252 //------------------------------------------------------------------------------
253 void vvToolSegmentation::Erode()
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);
261 image->DeepCopy(erode->GetOutput());
263 UpdateAndRenderNewMask();
265 QApplication::restoreOverrideCursor();
267 //------------------------------------------------------------------------------
270 //------------------------------------------------------------------------------
271 void vvToolSegmentation::Dilate()
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);
279 image->DeepCopy(dilate->GetOutput());
281 UpdateAndRenderNewMask();
283 QApplication::restoreOverrideCursor();
285 //------------------------------------------------------------------------------
288 //------------------------------------------------------------------------------
289 void vvToolSegmentation::UpdateAndRenderNewMask()
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);
299 mCurrentSlicerManager->Render();
301 //------------------------------------------------------------------------------
303 //------------------------------------------------------------------------------
304 void vvToolSegmentation::Labelize()
308 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
311 vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
312 typedef args_info_clitkConnectedComponentLabeling ArgsInfoType;
314 cmdline_parser_clitkConnectedComponentLabeling_init(&a);
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);
324 DD(filter->GetOriginalNumberOfObjects());
325 DD(filter->GetSizeOfObjectsInPixels().size());
326 mCurrentCCLImage = filter->GetOutputVVImage();
327 DDV(filter->GetSizeOfObjectsInPixels(), filter->GetSizeOfObjectsInPixels().size());
332 vvImageWriter::Pointer writer = vvImageWriter::New();
333 writer->SetInput(mCurrentCCLImage);
334 writer->SetOutputFileName("bidon-ccl.mha");
336 DD(mCurrentCCLImage->IsScalarTypeInteger());
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
343 QSharedPointer<vvROIActor> actor = CreateMaskActor(mCurrentCCLImage, i, i+1, false);
344 mCurrentCCLActors.push_back( actor );
347 mCurrentMaskActor->SetVisible(false);
348 mCurrentMaskActor->Update();
349 mCurrentSlicerManager->Render();
351 // UpdateAndRender();
352 mCurrentMode = Mode_CCL;
353 QApplication::restoreOverrideCursor();
355 //------------------------------------------------------------------------------
357 //------------------------------------------------------------------------------
358 QSharedPointer<vvROIActor> vvToolSegmentation::CreateMaskActor(vvImage::Pointer image, int i, int colorID, bool BGMode)
360 static int 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"));
371 actor->SetBGMode(true);
375 roi->SetForegroundValueLabelImage(i); // FG mode
376 actor->SetBGMode(false); // FG mode
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);
385 //------------------------------------------------------------------------------
388 //------------------------------------------------------------------------------
389 void vvToolSegmentation::MousePositionChanged(int slicer)
391 if (mCurrentMode == Mode_Default) return; // Do nothing in this case
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];
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]) {
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);
415 // DD("out of mask");
419 //------------------------------------------------------------------------------
422 //------------------------------------------------------------------------------
423 void vvToolSegmentation::RemoveLabel() {
426 //------------------------------------------------------------------------------