- BSD See included LICENSE.txt file
- CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-===========================================================================**/
+ ===========================================================================**/
// vv
#include "vvToolSegmentation.h"
// clitk
#include "clitkConnectedComponentLabeling_ggo.h"
#include "clitkConnectedComponentLabelingGenericFilter.h"
+#include "clitkRegionGrowing_ggo.h"
+#include "clitkRegionGrowingGenericFilter.h"
// Qt
#include <QFileDialog>
#include <QMessageBox>
// vtk
+#include <vtkVersion.h>
+#include <vtkStreamingDemandDrivenPipeline.h>
+#include <vtkInformation.h>
#include "vtkImageContinuousErode3D.h"
#include "vtkImageContinuousDilate3D.h"
+#include "vtkRenderWindow.h"
//------------------------------------------------------------------------------
// Create the tool and automagically (I like this word) insert it in
AddInputSelector("Select one image");
// Init
+ mCurrentLabelUnderMousePointer = 0.0;
+ mCurrentMousePositionInMM.resize(3);
+ // mCurrentMousePositionInPixel.resize(3);
mRefMaskImage = NULL;
- mCurrentMode = Mode_Default;
+ mCurrentState = State_Default;
mKernelValue = 3; // FIXME must be odd. If even -> not symmetrical
mDefaultLUTColor = vtkSmartPointer<vtkLookupTable>::New();
mDefaultLUTColor->SetNumberOfTableValues(256);
//------------------------------------------------------------------------------
bool vvToolSegmentation::close()
{
- DD("close");
- mRefMaskActor->RemoveActors();
- DD("la");
- mCurrentMaskActor->RemoveActors();
- DD("here");
+ DD("remo ref");
+ if (mRefMaskActor) mRefMaskActor->RemoveActors();
+ DD("remo mask");
+ if (mCurrentMaskActor) mCurrentMaskActor->RemoveActors();
+ for(int i=0; i<mCurrentCCLActors.size(); i++) {
+ if (mCurrentCCLActors[i]) mCurrentCCLActors[i]->RemoveActors();
+ }
+ DD("wclose");
QWidget::close();
- DD("toto");
mCurrentSlicerManager->Render();
return true;
}
// Connect mouse position
connect(mCurrentSlicerManager, SIGNAL(MousePositionUpdatedSignal(int)),
this, SLOT(MousePositionChanged(int)));
+ connect(mCurrentSlicerManager, SIGNAL(KeyPressedSignal(std::string)),
+ this, SLOT(KeyPressed(std::string)));
}
//------------------------------------------------------------------------------
reader->Update(vvImageReader::IMAGE);
mCurrentMaskImage = reader->GetOutput();
- // Add a new roi actor
- mRefMaskActor = CreateMaskActor(mRefMaskImage, 0, 0, true);
+ // Add a new roi actor for the current mask
+ mCurrentMaskActor = CreateMaskActor(mCurrentMaskImage, 1, 0, false);
+ mCurrentMaskActor->Update(); // default color is red
+ UpdateMaskSize(mCurrentMaskImage, mCurrentMaskSizeInPixels, mCurrentMaskSizeInCC);
+
+ // Add a mask actor for the reference
+ mRefMaskActor = CreateMaskActor(mRefMaskImage, 0, 1, true);
mRefMaskActor->SetContourVisible(true);
mRefMaskActor->SetVisible(false);
mRefMaskActor->SetContourColor(0,1,0); // green contour
mRefMaskActor->UpdateColor();
mRefMaskActor->Update();
+ UpdateMaskSize(mRefMaskImage, mRefMaskSizeInPixels, mRefMaskSizeInCC);
+
+ // Update GUI
+ UpdateMaskSizeLabels();
+}
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+void vvToolSegmentation::UpdateMaskSizeLabels()
+{
+ QString s("%1 pix (%2 cm3)");
+ s = s.arg(mRefMaskSizeInPixels).arg(mRefMaskSizeInCC);
+ mRefMaskSizeLabel->setText(s);
+ QString s2("%1 pix (%2 cm3)");
+ s2 = s2.arg(mCurrentMaskSizeInPixels).arg(mCurrentMaskSizeInCC);
+ mCurrentMaskSizeLabel->setText(s2);
+}
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+void vvToolSegmentation::UpdateMaskSize(vvImage::Pointer image, long & pix, double & cc)
+{
+ pix = ComputeNumberOfPixels(image, GetForegroundValue());
+ double vol = image->GetSpacing()[0]*image->GetSpacing()[1]*image->GetSpacing()[2];
+ cc = pix * vol / (10*10*10);
+}
+//------------------------------------------------------------------------------
- mCurrentMaskActor = CreateMaskActor(mCurrentMaskImage, 1, 1, false);
- mCurrentMaskActor->SetOverlayColor(1,0,0); // red roi
- mRefMaskActor->UpdateColor();
- mCurrentMaskActor->Update();
- // Prepare widget to get keyboard event. With this method, the key
- // only work when the mouse focus is on the dialog
- DD("here installe");
- this->installEventFilter(this);
- //grabKeyboard();
+//------------------------------------------------------------------------------
+long vvToolSegmentation::ComputeNumberOfPixels(vvImage::Pointer image, double value)
+{
+ int n=0;
+ vtkImageData * im = image->GetFirstVTKImageData();
+ char * pPix = (char*)im->GetScalarPointer(); // FIXME char ?
+ for(uint i=0; i<im->GetNumberOfPoints(); i++) {
+ if (pPix[i] == value) n++;
+ }
+ DD(n);
+ return n;
+}
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+void vvToolSegmentation::KeyPressed(std::string KeyPress)
+{
+ if (KeyPress == "G") {
+ RegionGrowing();
+ }
+ if (KeyPress == "e") {
+ Erode();
+ }
+ if (KeyPress == "d") {
+ Dilate(); // FIXME -> extend image BB !!
+ }
+ if (KeyPress == "L") {
+ Labelize();
+ }
+ if (KeyPress == "m") {
+ Merge();
+ UpdateAndRenderNewMask();
+ }
+ if (KeyPress == "s") { // Supress "Remove" one label
+ if (mCurrentState == State_CCL) RemoveLabel();
+ }
+ if (KeyPress == "t") { // display remove ref contour
+ mRefMaskActor->SetContourVisible(!mRefMaskActor->IsContourVisible());
+ mRefMaskActor->UpdateColor();
+ mCurrentSlicerManager->Render();
+ }
+ if (KeyPress == "w") {
+ vvImageWriter::Pointer writer = vvImageWriter::New();
+ writer->SetOutputFileName("a.mha");
+ writer->SetInput(mCurrentMaskImage);
+ writer->Update();
+ }
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
-//void vvToolSegmentation::keyPressEvent(QKeyEvent * event)
-bool vvToolSegmentation::eventFilter(QObject *object, QEvent * e)
+void vvToolSegmentation::RegionGrowing()
{
- // DD("key");
- //vvToolWidgetBase::keyPressEvent(event);
+ DD("RegionGrowing");
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ // Merge labels if needed
+ Merge();
+ // Get mouse location
+ DD(mCurrentLabelUnderMousePointer);
+ DDV(mCurrentMousePositionInMM, 3);
+ // DDV(mCurrentMousePositionInPixel, 3);
+
+ // Build RG filter parameters
+ typedef args_info_clitkRegionGrowing ArgsInfoType;
+ ArgsInfoType a;
+ cmdline_parser_clitkRegionGrowing_init(&a);
+ // FIXME parameters
+ a.type_arg = 4; // FIXME set by gui
+ DD(a.lower_arg);
+ a.lower_arg = 200;
+ a.upper_arg = 3000;
+ a.seed_given = 3;
+ a.seed_arg = new int[3];
+
+ DDV(mCurrentMousePositionInMM, 3);
+ vtkImageData * image = mCurrentImage->GetFirstVTKImageData();
+ double x = (mCurrentMousePositionInMM[0] - image->GetOrigin()[0]) / image->GetSpacing()[0];
+ double y = (mCurrentMousePositionInMM[1] - image->GetOrigin()[1]) / image->GetSpacing()[1];
+ double z = (mCurrentMousePositionInMM[2] - image->GetOrigin()[2]) / image->GetSpacing()[2];
+ a.seed_arg[0] = x;
+ a.seed_arg[1] = y;
+ a.seed_arg[2] = z;
+ a.verbose_flag = 1;
+
+ // Build RG filter parameters
+ typedef clitk::RegionGrowingGenericFilter<args_info_clitkRegionGrowing> FilterType;
+ FilterType::Pointer filter = FilterType::New();
+ filter->SetArgsInfo(a);
+ filter->SetInputVVImage(mCurrentImage);
+ filter->SetIOVerbose(true);
+ filter->Update();
+ mCurrentMaskImage = filter->GetOutputVVImage();
+ DD("filter done");
+
+ mCurrentMaskActor->RemoveActors();
+ mCurrentMaskActor = CreateMaskActor(mCurrentMaskImage, 1, 0, false);
+ mCurrentMaskActor->Update(); // default color is red
+ UpdateAndRenderNewMask();
+ UpdateMaskSizeLabels();
+ DD("end");
- if (/*object == form &&*/ e->type() == QEvent::KeyPress) {
- QKeyEvent * event = static_cast<QKeyEvent *>(e);
-
- if (event->text() == "e") {
- Erode();
- }
- if (event->text() == "d") {
- Dilate(); // FIXME -> extend image BB !!
- }
- if (event->text() == "l") {
- Labelize();
- }
- if (event->text() == "r") { // "Remove" one label
- if (mCurrentMode == Mode_CCL) RemoveLabel();
- }
- if (event->text() == "s") {
- vvImageWriter::Pointer writer = vvImageWriter::New();
- writer->SetOutputFileName("a.mha");
- writer->SetInput(mCurrentMaskImage);
- writer->Update();
+ // mouse pointer
+ QApplication::restoreOverrideCursor();
+}
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+void vvToolSegmentation::Merge()
+{
+ if (mCurrentState != State_CCL) return;
+
+ DD("Merge");
+ // Remove actors
+ for(int i=0; i<mCurrentCCLActors.size(); i++) {
+ if (mCurrentCCLActors[i]) {
+ mCurrentCCLActors[i]->SetVisible(false);
+ mCurrentCCLActors[i]->RemoveActors();
}
- //mMainWindow->keyPressEvent(event);
- vvToolWidgetBase::keyPressEvent(event);
- }
- return QObject::eventFilter(object, e);
+ }
+ mCurrentCCLActors.clear();
+
+ // Compute new mask
+ vtkImageData * ccl = mCurrentCCLImage->GetFirstVTKImageData();
+ vtkImageData * mask = mCurrentMaskImage->GetFirstVTKImageData();
+ int * pCCL = (int*)ccl->GetScalarPointer();
+ char * pPix = (char*)mask->GetScalarPointer();
+ for(uint i=0; i<ccl->GetNumberOfPoints(); i++) {
+ if (pCCL[i] == 0) pPix[i] = GetBackgroundValue(); // copy BG. In CCL BG is always 0
+ }
+
+ // Display new mask and remove ccl
+ mCurrentCCLImage->Reset();
+ mCurrentMaskActor->RemoveActors(); // kill it
+ mCurrentMaskActor = CreateMaskActor(mCurrentMaskImage, 1, 0, false); // renew
+ mCurrentMaskActor->Update();
+ mCurrentMaskActor->SetVisible(true);
+ // mCurrentSlicerManager->Render();
+ mCurrentState = State_Default;
}
//------------------------------------------------------------------------------
void vvToolSegmentation::Erode()
{
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ // Merge labels if needed
+ Merge();
+ // Get image and start erosion
vtkImageContinuousErode3D* erode = vtkImageContinuousErode3D::New();
erode->SetKernelSize(mKernelValue,mKernelValue,mKernelValue);
vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
+#if VTK_MAJOR_VERSION <= 5
erode->SetInput(image);
+#else
+ erode->SetInputData(image);
+#endif
erode->Update();
image->DeepCopy(erode->GetOutput());
+#if VTK_MAJOR_VERSION <= 5
image->Update();
+#else
+ //image->Update();
+#endif
UpdateAndRenderNewMask();
erode->Delete();
QApplication::restoreOverrideCursor();
void vvToolSegmentation::Dilate()
{
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ // Merge labels if needed
+ Merge();
+ // Get image and start dilatation
vtkImageContinuousDilate3D* dilate = vtkImageContinuousDilate3D::New();
dilate->SetKernelSize(mKernelValue,mKernelValue,mKernelValue);
vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
+#if VTK_MAJOR_VERSION <= 5
dilate->SetInput(image);
+#else
+ dilate->SetInputData(image);
+#endif
dilate->Update();
image->DeepCopy(dilate->GetOutput());
+#if VTK_MAJOR_VERSION <= 5
image->Update();
+#else
+ //image->Update();
+#endif
UpdateAndRenderNewMask();
dilate->Delete();
QApplication::restoreOverrideCursor();
mCurrentMaskActor->SetContourVisible(cvisible);
mCurrentSlicerManager->Render();
+ UpdateMaskSize(mCurrentMaskImage, mCurrentMaskSizeInPixels, mCurrentMaskSizeInCC);
+ UpdateMaskSizeLabels();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void vvToolSegmentation::Labelize()
{
+ if (mCurrentState == State_CCL) return; // Do nothing in this case
DD("Labelize");
// Waiting cursos
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ mCurrentMaskActor->SetVisible(false);
// Build CCL filter
vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
typedef args_info_clitkConnectedComponentLabeling ArgsInfoType;
ArgsInfoType a;
cmdline_parser_clitkConnectedComponentLabeling_init(&a);
- a.inputBG_arg = 0;
+ a.inputBG_arg = GetBackgroundValue();
a.full_flag = false; // FIXME set by gui
a.minSize_arg = 100; // FIXME set by gui
typedef clitk::ConnectedComponentLabelingGenericFilter<ArgsInfoType> FilterType;
FilterType::Pointer filter = FilterType::New();
filter->SetArgsInfo(a);
- filter->SetInputVVImage(mCurrentMaskImage);
+ filter->SetInputVVImage(mCurrentMaskImage); // FIXME Check type is ok ? convert float ?
filter->SetIOVerbose(true);
filter->Update();
DD(filter->GetOriginalNumberOfObjects());
// Create actors
int n = filter->GetSizeOfObjectsInPixels().size();
- for(int i=1; i<std::min(n,10); i++) { // Start at 1 because 0 is BG. FIXME max 10
- DD(i);
+ mCurrentCCLActors.clear();
+ for(int i=1; i<=std::min(n,10); i++) { // Start at 1 because 0 is BG. FIXME max by gui
QSharedPointer<vvROIActor> actor = CreateMaskActor(mCurrentCCLImage, i, i+1, false);
mCurrentCCLActors.push_back( actor );
actor->Update();
}
- mCurrentMaskActor->SetVisible(false);
- mCurrentMaskActor->Update();
+ // mCurrentMaskActor->Update();
mCurrentSlicerManager->Render();
// UpdateAndRender();
- mCurrentMode = Mode_CCL;
+ mCurrentState = State_CCL;
QApplication::restoreOverrideCursor();
}
//------------------------------------------------------------------------------
actor->SetBGMode(true);
}
else {
- DD("FG mode");
roi->SetForegroundValueLabelImage(i); // FG mode
actor->SetBGMode(false); // FG mode
}
//------------------------------------------------------------------------------
void vvToolSegmentation::MousePositionChanged(int slicer)
{
- if (mCurrentMode == Mode_Default) return; // Do nothing in this case
-
+ // DD("MousePositionChanged ");
+ // DD(slicer);
double x = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[0];
double y = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[1];
double z = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[2];
- vtkImageData * image = mCurrentCCLImage->GetFirstVTKImageData();
+ mCurrentMousePositionInMM[0] = x;
+ mCurrentMousePositionInMM[1] = y;
+ mCurrentMousePositionInMM[2] = z;
+ // DDV(mCurrentMousePositionInMM, 3);
+
+ // vtkImageData * image = mCurrentCCLImage->GetFirstVTKImageData();
+ vtkImageData * image = mCurrentMaskImage->GetFirstVTKImageData();
double Xover = (x - image->GetOrigin()[0]) / image->GetSpacing()[0];
double Yover = (y - image->GetOrigin()[1]) / image->GetSpacing()[1];
double Zover = (z - image->GetOrigin()[2]) / image->GetSpacing()[2];
int ix, iy, iz;
+ // mCurrentMousePositionInPixel[0] = Xover;
+ // mCurrentMousePositionInPixel[1] = Yover;
+ // mCurrentMousePositionInPixel[2] = Zover;
+ // DDV(mCurrentMousePositionInPixel, 3);
+#if VTK_MAJOR_VERSION <= 5
if (Xover >= image->GetWholeExtent()[0] &&
Xover <= image->GetWholeExtent()[1] &&
Yover >= image->GetWholeExtent()[2] &&
Yover <= image->GetWholeExtent()[3] &&
Zover >= image->GetWholeExtent()[4] &&
Zover <= image->GetWholeExtent()[5]) {
- double valueOver =
- mCurrentSlicerManager->GetSlicer(0)->GetScalarComponentAsDouble(image, Xover, Yover, Zover, ix, iy, iz, 0);
- // DD(Xover); DD(Yover); DD(Zover);
- // DD(ix); DD(iy); DD(iz);
- // DD(valueOver);
+ if (mCurrentState == State_Default) { // inside the mask
+ mCurrentLabelUnderMousePointer = 1;
+ return;
+ }
+ else { // inside the label image
+ vtkImageData * image = mCurrentCCLImage->GetFirstVTKImageData();
+ mCurrentLabelUnderMousePointer =
+ mCurrentSlicerManager->GetSlicer(0)->GetScalarComponentAsDouble(image, Xover, Yover, Zover, ix, iy, iz, 0);
+ return;
+ }
}
else {
// DD("out of mask");
+ mCurrentLabelUnderMousePointer = 0; // BG is always 0 in CCL
}
-
+#else
+ if (Xover >= image->GetInformation()->Get(vtkDataObject::DATA_EXTENT())[0] &&
+ Xover <= image->GetInformation()->Get(vtkDataObject::DATA_EXTENT())[1] &&
+ Yover >= image->GetInformation()->Get(vtkDataObject::DATA_EXTENT())[2] &&
+ Yover <= image->GetInformation()->Get(vtkDataObject::DATA_EXTENT())[3] &&
+ Zover >= image->GetInformation()->Get(vtkDataObject::DATA_EXTENT())[4] &&
+ Zover <= image->GetInformation()->Get(vtkDataObject::DATA_EXTENT())[5]) {
+ if (mCurrentState == State_Default) { // inside the mask
+ mCurrentLabelUnderMousePointer = 1;
+ return;
+ }
+ else { // inside the label image
+ vtkImageData * image = mCurrentCCLImage->GetFirstVTKImageData();
+ mCurrentLabelUnderMousePointer =
+ mCurrentSlicerManager->GetSlicer(0)->GetScalarComponentAsDouble(image, Xover, Yover, Zover, ix, iy, iz, 0);
+ return;
+ }
+ }
+ else {
+ // DD("out of mask");
+ mCurrentLabelUnderMousePointer = 0; // BG is always 0 in CCL
+ }
+#endif
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void vvToolSegmentation::RemoveLabel() {
DD("RemoveLabel");
+ if (mCurrentLabelUnderMousePointer == 0) return;
+ // First actor=0 and is label 1. Label 0 is not an actor, it is BG
+ int actorNumber = mCurrentLabelUnderMousePointer-1;
+ // Set actor invisible
+ mCurrentCCLActors[actorNumber]->SetVisible(false);
+ mCurrentSlicerManager->Render();
+ // Set image label
+ vtkImageData * image = mCurrentCCLImage->GetFirstVTKImageData();
+ int * pPix = (int*)image->GetScalarPointer();
+ int n = 0;
+ for(uint i=0; i<image->GetNumberOfPoints(); i++) {
+ if (pPix[i] == mCurrentLabelUnderMousePointer) pPix[i] = 0;
+ if (pPix[i] != 0) n++; // count the number of pixels in the foreground
+ }
+ // Update mask size
+ mCurrentMaskSizeInPixels = n;
+ mCurrentMaskSizeInCC = mCurrentMaskImage->GetSpacing()[0] * mCurrentMaskImage->GetSpacing()[1] * mCurrentMaskImage->GetSpacing()[2] * n / (10*10*10);
+ UpdateMaskSizeLabels();
}
//------------------------------------------------------------------------------