Vous avez reçu un message "Your GitLab account has been locked ..." ? Pas d'inquiétude : lisez cet article https://docs.gricad-pages.univ-grenoble-alpes.fr/help/unlock/

Commit fcf67865 authored by cfouard's avatar cfouard
Browse files

ADDED now a NEEDS_ACTION in action_macro (to make an action depend from another action)

FIXED no more filter_implementation files replaced by filter.impl
FIXED same thing in the Wizard
IMPROVED Multipicking it is now easier to interact with the selected points and the widget can be exported and used by other actions
ADDED an Itk Region Growing Filter using Multipicking

git-svn-id: svn+ssh://scm.forge.imag.fr/var/lib/gforge/chroot/scmrepos/svn/camitk/trunk/camitk@177 ec899d31-69d1-42ba-9299-647d76f65fb3
parent d30776eb
......@@ -74,7 +74,7 @@ void MedianFilter::process(ImageComponent * comp) {
}
#include "MedianFilter_implementation"
#include "MedianFilter.impl"
// ITK filter implementation
template <class InputPixelType, class OutputPixelType, const int dim>
......
......@@ -82,7 +82,7 @@ void MorphologicalOperators::process(ImageComponent * comp) {
}
#include "MorphologicalOperators_implementation"
#include "MorphologicalOperators.impl"
// ITK filter implementation
template <class InputPixelType, class OutputPixelType, const int dim>
......
......@@ -58,7 +58,7 @@ void SobelEdgeDetection::process(ImageComponent * comp) {
}
#include "SobelEdgeDetection_implementation"
#include "SobelEdgeDetection.impl"
// ITK filter implementation
template <class InputPixelType, class OutputPixelType, const int dim>
......
action_extension(
NEEDS_ITK
LIBRARIES ITKBasicFilters ITKCommon ITKIO
NEEDS_ACTION_EXTENSION multipicking
LIBRARIES ITKBasicFilters ITKCommon ITKIO multipicking
)
......@@ -2,7 +2,7 @@
// include generated actions headers
#include "OtsuFilter.h"
#include "ManualThreshold.h"
//#include "RegionGrowing.h"
#include "RegionGrowing.h"
// --------------- declare the extension -------------------
Q_EXPORT_PLUGIN2(itksegmentationextension, ITKSegmentationExtension);
......@@ -11,7 +11,7 @@ Q_EXPORT_PLUGIN2(itksegmentationextension, ITKSegmentationExtension);
void ITKSegmentationExtension::init() {
registerNewAction(OtsuFilter);
registerNewAction(ManualThreshold);
// registerNewAction(RegionGrowing);
registerNewAction(RegionGrowing);
}
......@@ -61,7 +61,7 @@ void ManualThreshold::process(ImageComponent * comp) {
}
#include "ManualThreshold_implementation"
#include "ManualThreshold.impl"
// ITK filter implementation
template <class InputPixelType, class OutputPixelType, const int dim>
......
......@@ -66,7 +66,7 @@ void OtsuFilter::process(ImageComponent * comp) {
}
#include "OtsuFilter_implementation"
#include "OtsuFilter.impl"
// ITK filter implementation
template <class InputPixelType, class OutputPixelType, const int dim>
......
#include "RegionGrowing.h"
// includes from Qt
#include <QMessageBox>
#include <QString>
#include <QTextStream>
#include <QVBoxLayout>
// includes from CamiTK
#include <Application.h>
#include <ItkProgressObserver.h>
#include <itkImageToVTKImageFilter.h>
#include <itkVTKImageToImageFilter.h>
// includes from Itk
#include <itkConnectedThresholdImageFilter.h>
#include <itkCurvatureFlowImageFilter.h>
#include <itkCastImageFilter.h>
// local includes
#include "RegionGrowingWidget.h"
using namespace camitk;
// --------------- constructor -------------------
RegionGrowing::RegionGrowing(ActionExtension * extension) : Action(extension) {
// Setting name, description and input component
setName("Region Growing Segmentation");
setDescription(" This filter segments volume images using region growing approach. It starts from a seed point that is considered to be inside the object to be segmented. The pixels neighboring this seed point are evaluated to determine if they should also be considered part of the object. If so, they are added to the region and the process continues as long as new pixels are added to the region. For connected threshold filter, the criterion is based on the intensity of the neighboring pixels. They are considered as part of the object if theyr value is between a lower and an upper threshold. ");
setComponent("ImageComponent");
setEmbedded(true);
// Setting classification family and tags
this->setFamily("ITK Segmentation");
this->addTag("Threshold");
this->addTag("Manal");
this->addTag("Classification");
this->addTag("Growing Region");
this->addTag("Seed Point");
// Setting the widget containing the parameters
theWidget = NULL;
}
// --------------- destructor -------------------
RegionGrowing::~RegionGrowing() {
// do not delete the widget has it might have been used in the ActionViewer (i.e. the ownership might have been taken by the stacked widget)
}
// --------------- getWidget --------------
QWidget * RegionGrowing::getWidget() {
RegionGrowingWidget * rgWidget = dynamic_cast<RegionGrowingWidget *> (theWidget);
//-- create the widget if needed
if (!rgWidget) {
theWidget = new RegionGrowingWidget(this);
rgWidget = dynamic_cast<RegionGrowingWidget *> (theWidget);
}
//-- update the widget with a PickedPixelMap param
rgWidget->updateComponent (dynamic_cast<ImageComponent *> (getTargets().last()));
return theWidget;
}
// --------------- apply -------------------
Action::ApplyStatus RegionGrowing::apply() {
// check the widget
RegionGrowingWidget * rgWidget = dynamic_cast<RegionGrowingWidget *> (theWidget);
// Get the image
ImageComponent * input = dynamic_cast<ImageComponent *> (getTargets().last());
// this call works only with a GUI (i.e. if theWidget exists)
if ((input == NULL) || (rgWidget == NULL))
return ABORTED;
// Get the parameters
filterBefore = rgWidget->isSmoothingChecked();
nbIterations = rgWidget->getNumberOfIterations();
timeStep = rgWidget->getTimeStep();
lowThreshold = rgWidget->getLowThreshold();
highThreshold = rgWidget->getHighThreshold();
seedPoints = rgWidget->getSeedPoints(input);
process(input);
return SUCCESS;
}
Action::ApplyStatus RegionGrowing::apply(int lowThreshold, int highThreshold, QList<QVector3D> * seedPoints,
bool filterBefore, int nbIterations, double timeStep) {
// Get the image
ImageComponent * input = dynamic_cast<ImageComponent *> (getTargets().last());
// Get the parameters
this->lowThreshold = lowThreshold;
this->highThreshold = highThreshold;
this->seedPoints = seedPoints;
this->filterBefore = filterBefore;
this->nbIterations = nbIterations;
this->timeStep = timeStep;
process(input);
return SUCCESS;
}
void RegionGrowing::process(ImageComponent * comp) {
// ITK filter implementation using templates
vtkSmartPointer<vtkImageData> inputImage = comp->getImageData();
vtkSmartPointer<vtkImageData> outputImage = implementProcess (inputImage);
QString newName;
QTextStream(&newName) << comp->getName() << "_segmented";
new ImageComponent(outputImage, newName);
Application::refresh();
}
#include "RegionGrowing.impl"
// ITK filter implementation
template <class InputPixelType, class OutputPixelType, const int dim>
vtkSmartPointer<vtkImageData> RegionGrowing::itkProcess(vtkSmartPointer<vtkImageData> img)
{
vtkSmartPointer<vtkImageData> result = vtkSmartPointer<vtkImageData>::New();
// --------------------- Filters declaration and creation ----------------------
// Define ITK input and output image types with respect to the instanciation
// types of the tamplate.
typedef itk::Image< InputPixelType, dim > InputImageType;
typedef itk::Image< double, dim > DoubleImageType;
typedef itk::Image< OutputPixelType, dim > OutputImageType;
// Convert the image from CamiTK in VTK format to ITK format to use ITK filters.
typedef itk::VTKImageToImageFilter<InputImageType> vtkToItkFilterType;
typename vtkToItkFilterType::Pointer vtkToItkFilter = vtkToItkFilterType::New();
// Convert the input image as a DoubleImageType to be able to perform filtering
typedef itk::CastImageFilter<InputImageType, DoubleImageType> CastFilterInType;
typename CastFilterInType::Pointer castFilter = CastFilterInType::New();
// Smoothing filter
typedef itk::CurvatureFlowImageFilter<DoubleImageType, DoubleImageType> CurvatureFlowImageFilterType;
typename CurvatureFlowImageFilterType::Pointer smoothingFilter = CurvatureFlowImageFilterType::New();
// Rgion Growing filter
typedef itk::ConnectedThresholdImageFilter<DoubleImageType, OutputImageType> ConnectedFilterType;
typename ConnectedFilterType::Pointer connectedThreshold = ConnectedFilterType::New();
// In the same way, once the image is filtered, we need to convert it again to
// VTK format to give it to CamiTK.
typedef itk::ImageToVTKImageFilter<OutputImageType> itkToVtkFilterType;
typename itkToVtkFilterType::Pointer itkToVtkFilter = itkToVtkFilterType::New();
// Connecting the pipeline ...
// To update CamiTK progress bar while filtering, add an ITK observer to the filters.
ItkProgressObserver::Pointer observer = ItkProgressObserver::New();
// ITK observers generally give values between 0 and 1, and CamiTK progress bar
// wants values between 0 and 100...
observer->SetCoef(100.0);
// From VTK to ITK
vtkToItkFilter->SetInput(img);
// From input type to double type
castFilter->SetInput(vtkToItkFilter->GetOutput());
castFilter->AddObserver(itk::ProgressEvent(), observer);
castFilter->Update();
observer->Reset();
// Smoothing
if (filterBefore) {
smoothingFilter->SetInput(castFilter->GetOutput());
smoothingFilter->SetNumberOfIterations(nbIterations);
smoothingFilter->SetTimeStep(timeStep);
smoothingFilter->AddObserver(itk::ProgressEvent(), observer);
smoothingFilter->Update();
observer->Reset();
connectedThreshold->SetInput(smoothingFilter->GetOutput());
}
else {
connectedThreshold->SetInput(castFilter->GetOutput());
}
connectedThreshold->AddObserver(itk::ProgressEvent(), observer);
connectedThreshold->SetLower(lowThreshold);
connectedThreshold->SetUpper(highThreshold);
connectedThreshold->SetReplaceValue(255);
// set the initial seeds
for (int i = 0; i < seedPoints->size(); i++) {
InputImageType::IndexType seed;
seed[0] = seedPoints->at(i).x();
seed[1] = seedPoints->at(i).y();
if (dim == 3) {
seed[2] = seedPoints->at(i).z();
}
connectedThreshold->AddSeed(seed);
}
connectedThreshold->Update();
observer->Reset();
itkToVtkFilter->SetInput(connectedThreshold->GetOutput());
itkToVtkFilter->Update();
observer->Reset();
// --------------------- Create and return a copy (the filters will be deleted)--
vtkImageData * resultImage = itkToVtkFilter->GetOutput();
int extent[6];
resultImage->GetExtent(extent);
result->SetExtent(extent);
result->DeepCopy(resultImage);
result->Update();
return result;
}
#ifndef CONNECTEDTHRESHOLD_H
#define CONNECTEDTHRESHOLD_H
#include <QObject>
#include <QMap>
#include <Action.h>
#include <ImageComponent.h>
#include <QFrame>
using namespace camitk;
class RegionGrowing : public Action {
public:
/// Default Constructor
RegionGrowing(ActionExtension * extension);
/// Default Destructor
virtual ~RegionGrowing();
/// Returns the widget that allows to modify the action parameters
virtual QWidget * getWidget();
public slots:
/** this method is automatically called when the action is triggered.
* !!! This method works only if theWidget has been instantiated
* (i.e. if getWidget has been called at least once, this is the case when there is a GUI)
* if not, please use the apply method with the parameters...
*/
virtual ApplyStatus apply();
/// Same method to be called manually with the parameters
virtual ApplyStatus apply(int lowThreshold, int highThreshold, QList<QVector3D> * seedPoints, bool filterBefore=false, int nbIterations = 5, double timeStep = 0.120);
private:
/// helper method to simplify the target component processing
virtual void process(ImageComponent * comp);
vtkSmartPointer<vtkImageData> implementProcess(vtkSmartPointer<vtkImageData> img);
template <class InputPixelType, class OutputPixelType, const int dim>
vtkSmartPointer<vtkImageData> itkProcess(vtkSmartPointer<vtkImageData> img);
protected:
/// The widget will be filled with parameters
QWidget * theWidget;
/** Parameters @{ */
/// Should a smoothing filter be applied before region growing ?
bool filterBefore;
/// number of iterations of this smoothing filter
int nbIterations;
/// time step of this smoothing filter
double timeStep;
/// low threshold for region growing
int lowThreshold;
/// high threshold for region growing
int highThreshold;
/// list of seed points
QList<QVector3D> * seedPoints;
};
#endif // CONNECTEDTHRESHOLD_H
vtkSmartPointer<vtkImageData> RegionGrowing::implementProcess(vtkSmartPointer<vtkImageData> img)
{
vtkSmartPointer<vtkImageData> result = NULL;
if (img == NULL)
return result;
int * dims = img->GetDimensions();
int dim = 0;
if (dims[2] == 0)
dim = 2;
else
dim = 3;
int scalarType = img->GetScalarType();
switch (scalarType)
{
case VTK_CHAR :
if (dim == 2)
result = itkProcess<char, unsigned char, 2>(img);
else // if dim == 3
result = itkProcess<char, unsigned char, 3>(img);
break;
case VTK_UNSIGNED_CHAR :
if (dim == 2)
result = itkProcess<unsigned char, unsigned char, 2>(img);
else // if dim == 3
result = itkProcess<unsigned char, unsigned char, 3>(img);
break;
case VTK_SIGNED_CHAR :
if (dim == 2)
result = itkProcess<signed char, unsigned char, 2>(img);
else // if dim == 3
result = itkProcess<signed char, unsigned char, 3>(img);
break;
case VTK_SHORT :
if (dim == 2)
result = itkProcess<short, unsigned char, 2>(img);
else // if dim == 3
result = itkProcess<short, unsigned char, 3>(img);
break;
case VTK_UNSIGNED_SHORT :
if (dim == 2)
result = itkProcess<unsigned short, unsigned char, 2>(img);
else // if dim == 3
result = itkProcess<unsigned short, unsigned char, 3>(img);
break;
case VTK_INT :
if (dim == 2)
result = itkProcess<int, unsigned char, 2>(img);
else // if dim == 3
result = itkProcess<int, unsigned char, 3>(img);
break;
case VTK_UNSIGNED_INT :
if (dim == 2)
result = itkProcess<unsigned int, unsigned char, 2>(img);
else // if dim == 3
result = itkProcess<unsigned int, unsigned char, 3>(img);
break;
case VTK_LONG :
if (dim == 2)
result = itkProcess<long, unsigned char, 2>(img);
else // if dim == 3
result = itkProcess<long, unsigned char, 3>(img);
break;
case VTK_UNSIGNED_LONG :
if (dim == 2)
result = itkProcess<unsigned long, unsigned char, 2>(img);
else // if dim == 3
result = itkProcess<unsigned long, unsigned char, 3>(img);
break;
case VTK_FLOAT :
if (dim == 2)
result = itkProcess<float, unsigned char, 2>(img);
else // if dim == 3
result = itkProcess<float, unsigned char, 3>(img);
break;
case VTK_DOUBLE :
if (dim == 2)
result = itkProcess<double, unsigned char, 2>(img);
else // if dim == 3
result = itkProcess<double, unsigned char, 3>(img);
break;
default :
break;
}
return result;
}
#include <QMessageBox>
#include <QFileDialog>
#include <QList>
#include <QVector3D>
#include <PickedPixelMap.h>
#include <Application.h>
#include "RegionGrowingWidget.h"
RegionGrowingWidget::RegionGrowingWidget(Action * action)
: QWidget()
{
this->myAction = action;
ui.setupUi(this);
pickingW = new MultiPickingWidget(this);
ui.seedPointGroupBox->layout()->addWidget(pickingW);
QObject::connect(ui.applyButton, SIGNAL(clicked()), myAction, SLOT(apply()));
}
RegionGrowingWidget::~RegionGrowingWidget() {
}
bool RegionGrowingWidget::isSmoothingChecked() {
return ui.smoothingGroupBox->isChecked();
}
int RegionGrowingWidget::getNumberOfIterations() {
return ui.numberOfIterationsSpinBox->value();
}
double RegionGrowingWidget::getTimeStep() {
return ui.timeStepDoubleSpinBox->value();
}
int RegionGrowingWidget::getLowThreshold() {
return ui.lowThresholdSpinBox->value();
}
int RegionGrowingWidget::getHighThreshold() {
return ui.highThresholdSpinBox->value();
}
QList<QVector3D> * RegionGrowingWidget::getSeedPoints(ImageComponent * image) {
return pickingW->getPickedPixelMap(image)->getPixelIndexList();
}
void RegionGrowingWidget::updateComponent (ImageComponent * image) {
ui.componentName->setText(image->getName());
pickingW->updateComponent(image);
}
#ifndef REGIONGROWINGWIDGET_H
#define REGIONGROWINGWIDGET_H
#include <QWidget>
#include <ImageComponent.h>
#include <MultiPickingWidget.h>
#include <Action.h>
#include "ui_RegionGrowingWidget.h"
using namespace camitk;
using namespace std;
class RegionGrowingWidget : public QWidget {
Q_OBJECT
public:
/// Default construtor
RegionGrowingWidget(Action* action);
/// destructor
~RegionGrowingWidget();
/// Update the widget with the correct PickedPixelMap (ImageComponent + Qlist of the selected points)
void updateComponent(ImageComponent * image);
/** Accessors to all parameters
* @{
*/
/// Do the user want smoothing ?
bool isSmoothingChecked();
/// number of iterations for smoothing
int getNumberOfIterations();
/// time step for smoothing
double getTimeStep();
/// low threshold for region growing
int getLowThreshold();
/// high threshold for region growing
int getHighThreshold();
/// List of seed points
QList<QVector3D> * getSeedPoints(ImageComponent * image);
/** @} */
protected:
Ui::RegionGrowingWidget ui;
/// Multiple picking widget
MultiPickingWidget * pickingW;
/// Connected Action
Action * myAction;
};
#endif // REGIONGROWINGWIDGET_H
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RegionGrowingWidget</class>
<widget class="QWidget" name="RegionGrowingWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>423</width>