MeanFilter.cpp 8.54 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
5
 * (c) 2001-2016 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/
saubatn's avatar
saubatn committed
25
// CamiTK includes
26
#include "MeanFilter.h"
27 28
#include <Application.h>
#include <ItkProgressObserver.h>
saubatn's avatar
saubatn committed
29 30 31
#include <Property.h>

// Qt includes
32 33 34
#include <QMessageBox>
#include <QString>
#include <QTextStream>
saubatn's avatar
saubatn committed
35 36

// Itk includes
37 38
#include <itkImageToVTKImageFilter.h>
#include <itkVTKImageToImageFilter.h>
39 40 41 42 43 44 45
#include <itkMeanImageFilter.h>

using namespace camitk;


// --------------- constructor -------------------
MeanFilter::MeanFilter(ActionExtension * extension) : Action(extension) {
46
    // Setting name, description and input component
47 48
    setName("Mean Filter");
    setDescription("<br>\
saubatn's avatar
saubatn committed
49 50 51 52 53 54 55 56 57 58 59 60
The <b>mean</b> filter is commonly used for noise reduction. <br/><br/> \
This filter computes the value of each output pixel by finding the statistical mean of the neighborhood of the corresponding input pixel. The following figure illustrates the local effect of the <b>mean</b> filter in 2D case.<br/>\
______________ <br/> \
| 28 | 26 | 50 | <br/> \
|-----|-----|------| <br/> \
| 27 | 25 | 29 |  -> 30.22 -> 30<br/> \
|-----|-----|------| <br/> \
| 25 | 30 | 32 | <br/> \
-------------------- <br/> \
<i>Note that this algorithm is sensitive to the presence of outliers in the neighborhood. </i><br/>\
<br/> \
The <b>parameters</b> are the size of the neighborhood along X, Y and Z directions. <br/>The value on each direction is used as the semi-size of a rectangular box. For example in <i>2D</i> a size of 1 in X direction and 2 in Y direction results in a 3x5 neighborhood.<br/> \
61 62 63
");
    setComponent("ImageComponent");

64
    // Setting classification family and tags
65 66 67 68 69 70
    this->setFamily("ITK Filter");
    this->addTag("Mean");
    this->addTag("Smoothing");
    this->addTag("Neighborhood Filter");

    // Setting parameters default values
saubatn's avatar
saubatn committed
71 72 73 74 75 76 77
    Property* halfNeighborhoodSizeProp_X = new Property(tr("Half neighborhood size along X"), 1, tr("Half the size of the X direction of the neighborhood taken into account for the mean computation. \nFor instance, a value of 2 will create a windows of size 4 along the X direction."), "");
    halfNeighborhoodSizeProp_X->setAttribute("minimum", 1);
    halfNeighborhoodSizeProp_X->setAttribute("maximum", 100);
    halfNeighborhoodSizeProp_X->setAttribute("singleStep", 1);
    addParameter(halfNeighborhoodSizeProp_X);

    Property* halfNeighborhoodSizeProp_Y = new Property(tr("Half neighborhood size along Y"), 1, tr("Half the size of the Y direction of the neighborhood taken into account for the mean computation. \nFor instance, a value of 2 will create a windows of size 4 along the Y direction."), "");
saubatn's avatar
saubatn committed
78 79 80
    halfNeighborhoodSizeProp_Y->setAttribute("minimum", 1);
    halfNeighborhoodSizeProp_Y->setAttribute("maximum", 100);
    halfNeighborhoodSizeProp_Y->setAttribute("singleStep", 1);
saubatn's avatar
saubatn committed
81 82 83
    addParameter(halfNeighborhoodSizeProp_Y);

    Property* halfNeighborhoodSizeProp_Z = new Property(tr("Half neighborhood size along Z"), 1, tr("Half the size of the Z direction of the neighborhood taken into account for the mean computation. \nFor instance, a value of 2 will create a windows of size 4 along the Z direction."), "");
saubatn's avatar
saubatn committed
84 85 86
    halfNeighborhoodSizeProp_Z->setAttribute("minimum", 1);
    halfNeighborhoodSizeProp_Z->setAttribute("maximum", 100);
    halfNeighborhoodSizeProp_Z->setAttribute("singleStep", 1);
saubatn's avatar
saubatn committed
87
    addParameter(halfNeighborhoodSizeProp_Z);
88 89 90 91 92 93 94 95
}

// --------------- destructor -------------------
MeanFilter::~MeanFilter() {
    // 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)
}

// --------------- apply -------------------
96 97
Action::ApplyStatus MeanFilter::apply() {
    foreach (Component *comp, getTargets()) {
98
        ImageComponent * input = dynamic_cast<ImageComponent *> ( comp );
99
        process(input);
100
    }
101
    return SUCCESS;
102 103 104 105
}

void MeanFilter::process(ImageComponent * comp) {
    // Get the parameters
saubatn's avatar
saubatn committed
106 107 108
    this->halfNeighborhoodSizeX = property("Half neighborhood size along X").toInt();
    this->halfNeighborhoodSizeY = property("Half neighborhood size along Y").toInt();
    this->halfNeighborhoodSizeZ = property("Half neighborhood size along Z").toInt();
109 110
    // ITK filter implementation using templates
    vtkSmartPointer<vtkImageData> inputImage = comp->getImageData();
111
    vtkSmartPointer<vtkImageData> outputImage = implementProcess (inputImage);
112 113
    QString newName;
    QTextStream(&newName) << comp->getName() << "_mean";
114

saubatn's avatar
saubatn committed
115
    ImageComponent* outputComp = new ImageComponent(outputImage, newName);
116

saubatn's avatar
saubatn committed
117 118
    // consider frame policy on new image created
    Action::applyTargetPosition(comp, outputComp);
119

120
    Application::refresh();
121 122 123

}

124
#include "MeanFilter.impl"
125 126

// ITK filter implementation
127 128 129 130 131 132 133 134 135 136 137 138
template <class InputPixelType, class OutputPixelType, const int dim>
vtkSmartPointer<vtkImageData> MeanFilter::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< OutputPixelType, dim > OutputImageType;

    // Convert the image from CamiTK in VTK format to ITK format to use ITK filters.
    typedef itk::VTKImageToImageFilter<InputImageType> vtkToItkFilterType;
139 140
    typename vtkToItkFilterType::Pointer vtkToItkFilter = vtkToItkFilterType::New();

141 142 143
    // Declare and create your own private ITK filter here...
    typedef itk::MeanImageFilter<InputImageType, OutputImageType> FilterType;
    typename FilterType::Pointer filter = FilterType::New();
144

145 146 147 148
    // 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();
149

150 151 152
    // 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
153
    //    wants values between 0 and 100...
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
    observer->SetCoef(100.0);

    // --------------------- Plug filters and parameters ---------------------------
    // From VTK to ITK
    vtkToItkFilter->SetInput(img);
    vtkToItkFilter->AddObserver(itk::ProgressEvent(), observer);
    vtkToItkFilter->Update();
    observer->Reset();

    typename InputImageType::SizeType indexRadius;
    indexRadius[0] = halfNeighborhoodSizeX;
    indexRadius[1] = halfNeighborhoodSizeY;
    if (dim == 3)
        indexRadius[2] = halfNeighborhoodSizeZ;

    filter->SetInput(vtkToItkFilter->GetOutput());
    filter->SetRadius(indexRadius);
    filter->AddObserver(itk::ProgressEvent(), observer);
    filter->Update();
    observer->Reset();

    // From ITK to VTK
176
    // Change the following line to put your filter instead of vtkToItkFilter
177 178
    itkToVtkFilter->SetInput(filter->GetOutput());
    itkToVtkFilter->AddObserver(itk::ProgressEvent(), observer);
179

180 181
    // --------------------- Actually execute all filters parts --------------------
    itkToVtkFilter->Update();
182 183

    // --------------------- Create and return a copy (the filters will be deleted)--
184
    vtkSmartPointer<vtkImageData> resultImage = itkToVtkFilter->GetOutput();
185
    int extent[6];
186 187 188
    resultImage->GetExtent(extent);
    result->SetExtent(extent);
    result->DeepCopy(resultImage);
189

190
    // Set CamiTK progress bar back to zero (the processing filter is over)
191 192
    observer->Reset();

193 194
    return result;
}
195