vtkImageDilateErode3D.cxx 11.6 KB
Newer Older
Charles Law's avatar
Charles Law committed
1 2 3
/*=========================================================================

  Program:   Visualization Toolkit
4
  Module:    vtkImageDilateErode3D.cxx
Charles Law's avatar
Charles Law committed
5

6
  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 8
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
Will Schroeder's avatar
Will Schroeder committed
9

10 11
     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12
     PURPOSE.  See the above copyright notice for more information.
Charles Law's avatar
Charles Law committed
13 14

=========================================================================*/
15
#include "vtkImageDilateErode3D.h"
Brad King's avatar
Brad King committed
16
#include "vtkImageData.h"
Charles Law's avatar
Charles Law committed
17
#include "vtkImageEllipsoidSource.h"
18 19
#include "vtkInformation.h"
#include "vtkInformationVector.h"
20
#include "vtkObjectFactory.h"
21
#include "vtkStreamingDemandDrivenPipeline.h"
22

Brad King's avatar
Brad King committed
23
vtkStandardNewMacro(vtkImageDilateErode3D);
Charles Law's avatar
Charles Law committed
24 25

//----------------------------------------------------------------------------
26
// Construct an instance of vtkImageDilateErode3D fitler.
Charles Law's avatar
Charles Law committed
27
// By default zero values are dilated.
28
vtkImageDilateErode3D::vtkImageDilateErode3D()
Charles Law's avatar
Charles Law committed
29
{
Charles Law's avatar
Charles Law committed
30 31 32 33 34
  this->HandleBoundaries = 1;
  this->KernelSize[0] = 1;
  this->KernelSize[1] = 1;
  this->KernelSize[2] = 1;

Charles Law's avatar
Charles Law committed
35 36
  this->DilateValue = 0.0;
  this->ErodeValue = 255.0;
37

Charles Law's avatar
Charles Law committed
38 39 40 41 42 43 44 45 46 47 48 49 50
  this->Ellipse = vtkImageEllipsoidSource::New();
  // Setup the Ellipse to default size
  this->SetKernelSize(1, 1, 1);
}

//----------------------------------------------------------------------------
vtkImageDilateErode3D::~vtkImageDilateErode3D()
{
  if (this->Ellipse)
    {
    this->Ellipse->Delete();
    this->Ellipse = NULL;
    }
Charles Law's avatar
Charles Law committed
51 52
}

Charles Law's avatar
Charles Law committed
53
//----------------------------------------------------------------------------
54
void vtkImageDilateErode3D::PrintSelf(ostream& os, vtkIndent indent)
Charles Law's avatar
Charles Law committed
55
{
Brad King's avatar
Brad King committed
56
  this->Superclass::PrintSelf(os,indent);
57 58 59

  os << indent << "DilateValue: " << this->DilateValue << "\n";
  os << indent << "ErodeValue: " << this->ErodeValue << "\n";
Charles Law's avatar
Charles Law committed
60 61
}

Charles Law's avatar
Charles Law committed
62
//----------------------------------------------------------------------------
63
// This method sets the size of the neighborhood.  It also sets the
64
// default middle of the neighborhood and computes the eliptical foot print.
65 66 67
void vtkImageDilateErode3D::SetKernelSize(int size0, int size1, int size2)
{
  int modified = 0;
68

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
  if (this->KernelSize[0] != size0)
    {
    modified = 1;
    this->KernelSize[0] = size0;
    this->KernelMiddle[0] = size0 / 2;
    }
  if (this->KernelSize[1] != size1)
    {
    modified = 1;
    this->KernelSize[1] = size1;
    this->KernelMiddle[1] = size1 / 2;
    }
  if (this->KernelSize[2] != size2)
    {
    modified = 1;
    this->KernelSize[2] = size2;
    this->KernelMiddle[2] = size2 / 2;
    }

  if (modified)
    {
    this->Modified();
91 92
    this->Ellipse->SetWholeExtent(0, this->KernelSize[0]-1,
                                  0, this->KernelSize[1]-1,
93
                                  0, this->KernelSize[2]-1);
Francois Bertel's avatar
Francois Bertel committed
94 95 96 97 98 99
    this->Ellipse->SetCenter(static_cast<double>(this->KernelSize[0]-1)*0.5,
                             static_cast<double>(this->KernelSize[1]-1)*0.5,
                             static_cast<double>(this->KernelSize[2]-1)*0.5);
    this->Ellipse->SetRadius(static_cast<double>(this->KernelSize[0])*0.5,
                             static_cast<double>(this->KernelSize[1])*0.5,
                             static_cast<double>(this->KernelSize[2])*0.5);
100
    // make sure scalars have been allocated (needed if multithreaded is used)
101 102 103
    vtkInformation *ellipseOutInfo =
      this->Ellipse->GetExecutive()->GetOutputInformation(0);
    ellipseOutInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),
104 105
                        0, this->KernelSize[0]-1,
                        0, this->KernelSize[1]-1,
106
                        0, this->KernelSize[2]-1);
107
    this->Ellipse->Update();
Charles Law's avatar
Charles Law committed
108 109 110 111
    }
}

//----------------------------------------------------------------------------
Charles Law's avatar
Charles Law committed
112 113 114 115
// This templated function executes the filter on any region,
// whether it needs boundary checking or not.
// If the filter needs to be faster, the function could be duplicated
// for strictly center (no boundary ) processing.
Charles Law's avatar
Charles Law committed
116
template <class T>
Ken Martin's avatar
Ken Martin committed
117 118
void vtkImageDilateErode3DExecute(vtkImageDilateErode3D *self,
                                  vtkImageData *mask,
119 120
                                  vtkImageData *inData, T *inPtr,
                                  vtkImageData *outData, int *outExt,
121
                                  T *outPtr, int id, vtkInformation *inInfo)
Charles Law's avatar
Charles Law committed
122 123 124 125 126
{
  int *kernelMiddle, *kernelSize;
  // For looping though output (and input) pixels.
  int outMin0, outMax0, outMin1, outMax1, outMin2, outMax2;
  int outIdx0, outIdx1, outIdx2;
127 128
  vtkIdType inInc0, inInc1, inInc2;
  vtkIdType outInc0, outInc1, outInc2;
Charles Law's avatar
Charles Law committed
129 130
  T *inPtr0, *inPtr1, *inPtr2;
  T *outPtr0, *outPtr1, *outPtr2;
Charles Law's avatar
Charles Law committed
131
  int numComps, outIdxC;
Charles Law's avatar
Charles Law committed
132 133 134 135 136 137
  // For looping through hood pixels
  int hoodMin0, hoodMax0, hoodMin1, hoodMax1, hoodMin2, hoodMax2;
  int hoodIdx0, hoodIdx1, hoodIdx2;
  T *hoodPtr0, *hoodPtr1, *hoodPtr2;
  // For looping through the mask.
  unsigned char *maskPtr, *maskPtr0, *maskPtr1, *maskPtr2;
138
  vtkIdType maskInc0, maskInc1, maskInc2;
139
  // The extent of the whole input image
Charles Law's avatar
Charles Law committed
140 141
  int inImageMin0, inImageMin1, inImageMin2;
  int inImageMax0, inImageMax1, inImageMax2;
142
  int inImageExt[6];
Charles Law's avatar
Charles Law committed
143 144
  // dilate/erode
  T erodeValue, dilateValue;
145 146
  unsigned long count = 0;
  unsigned long target;
Charles Law's avatar
Charles Law committed
147

Charles Law's avatar
Charles Law committed
148
  // Get information to march through data
149 150 151 152 153 154 155 156 157
  inData->GetIncrements(inInc0, inInc1, inInc2);
  inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), inImageExt);
  inImageMin0 = inImageExt[0];
  inImageMax0 = inImageExt[1];
  inImageMin1 = inImageExt[2];
  inImageMax1 = inImageExt[3];
  inImageMin2 = inImageExt[4];
  inImageMax2 = inImageExt[5];
  outData->GetIncrements(outInc0, outInc1, outInc2);
Charles Law's avatar
Charles Law committed
158 159 160 161
  outMin0 = outExt[0];   outMax0 = outExt[1];
  outMin1 = outExt[2];   outMax1 = outExt[3];
  outMin2 = outExt[4];   outMax2 = outExt[5];
  numComps = outData->GetNumberOfScalarComponents();
162

Charles Law's avatar
Charles Law committed
163
  // Get ivars of this object (easier than making friends)
Francois Bertel's avatar
Francois Bertel committed
164 165
  erodeValue = static_cast<T>(self->GetErodeValue());
  dilateValue = static_cast<T>(self->GetDilateValue());
166 167
  kernelSize = self->GetKernelSize();
  kernelMiddle = self->GetKernelMiddle();
Charles Law's avatar
Charles Law committed
168 169 170 171 172 173 174 175
  hoodMin0 = - kernelMiddle[0];
  hoodMin1 = - kernelMiddle[1];
  hoodMin2 = - kernelMiddle[2];
  hoodMax0 = hoodMin0 + kernelSize[0] - 1;
  hoodMax1 = hoodMin1 + kernelSize[1] - 1;
  hoodMax2 = hoodMin2 + kernelSize[2] - 1;

  // Setup mask info
Francois Bertel's avatar
Francois Bertel committed
176
  maskPtr = static_cast<unsigned char *>(mask->GetScalarPointer());
177
  mask->GetIncrements(maskInc0, maskInc1, maskInc2);
178

Charles Law's avatar
Charles Law committed
179
  // in and out should be marching through corresponding pixels.
Francois Bertel's avatar
Francois Bertel committed
180
  inPtr = static_cast<T *>(inData->GetScalarPointer(outMin0, outMin1, outMin2));
Charles Law's avatar
Charles Law committed
181

Francois Bertel's avatar
Francois Bertel committed
182 183
  target = static_cast<unsigned long>(numComps*(outMax2-outMin2+1)*
                                      (outMax1-outMin1+1)/50.0);
184
  target++;
185

Charles Law's avatar
Charles Law committed
186 187
  // loop through components
  for (outIdxC = 0; outIdxC < numComps; ++outIdxC)
Charles Law's avatar
Charles Law committed
188
    {
Charles Law's avatar
Charles Law committed
189 190 191 192
    // loop through pixels of output
    outPtr2 = outPtr;
    inPtr2 = inPtr;
    for (outIdx2 = outMin2; outIdx2 <= outMax2; ++outIdx2)
Charles Law's avatar
Charles Law committed
193
      {
Charles Law's avatar
Charles Law committed
194 195
      outPtr1 = outPtr2;
      inPtr1 = inPtr2;
196
      for (outIdx1 = outMin1;
197 198
           !self->AbortExecute && outIdx1 <= outMax1; ++outIdx1)
        {
199
        if (!id)
200 201 202 203 204 205 206 207 208 209 210 211
          {
          if (!(count%target))
            {
            self->UpdateProgress(count/(50.0*target));
            }
          count++;
          }

        outPtr0 = outPtr1;
        inPtr0 = inPtr1;
        for (outIdx0 = outMin0; outIdx0 <= outMax0; ++outIdx0)
          {
212

213 214 215 216 217
          // Default behavior (copy input pixel)
          *outPtr0 = *inPtr0;
          if (*inPtr0 == erodeValue)
            {
            // loop through neighborhood pixels
218
            // as sort of a hack to handle boundaries,
219
            // input pointer will be marching through data that does not exist.
220
            hoodPtr2 = inPtr0 - kernelMiddle[0] * inInc0
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
              - kernelMiddle[1] * inInc1 - kernelMiddle[2] * inInc2;
            maskPtr2 = maskPtr;
            for (hoodIdx2 = hoodMin2; hoodIdx2 <= hoodMax2; ++hoodIdx2)
              {
              hoodPtr1 = hoodPtr2;
              maskPtr1 = maskPtr2;
              for (hoodIdx1 = hoodMin1; hoodIdx1 <= hoodMax1; ++hoodIdx1)
                {
                hoodPtr0 = hoodPtr1;
                maskPtr0 = maskPtr1;
                for (hoodIdx0 = hoodMin0; hoodIdx0 <= hoodMax0; ++hoodIdx0)
                  {
                  // A quick but rather expensive way to handle boundaries
                  if ( outIdx0 + hoodIdx0 >= inImageMin0 &&
                       outIdx0 + hoodIdx0 <= inImageMax0 &&
                       outIdx1 + hoodIdx1 >= inImageMin1 &&
                       outIdx1 + hoodIdx1 <= inImageMax1 &&
                       outIdx2 + hoodIdx2 >= inImageMin2 &&
                       outIdx2 + hoodIdx2 <= inImageMax2)
                    {
                    if (*hoodPtr0 == dilateValue && *maskPtr0)
                      {
                      *outPtr0 = dilateValue;
                      }
                    }
246

247 248 249 250 251 252 253 254 255 256
                  hoodPtr0 += inInc0;
                  maskPtr0 += maskInc0;
                  }
                hoodPtr1 += inInc1;
                maskPtr1 += maskInc1;
                }
              hoodPtr2 += inInc2;
              maskPtr2 += maskInc2;
              }
            }
257

258 259 260 261 262 263
          inPtr0 += inInc0;
          outPtr0 += outInc0;
          }
        inPtr1 += inInc1;
        outPtr1 += outInc1;
        }
Charles Law's avatar
Charles Law committed
264 265
      inPtr2 += inInc2;
      outPtr2 += outInc2;
Charles Law's avatar
Charles Law committed
266
      }
Charles Law's avatar
Charles Law committed
267 268
    ++inPtr;
    ++outPtr;
Charles Law's avatar
Charles Law committed
269 270 271
    }
}

Charles Law's avatar
Charles Law committed
272 273
//----------------------------------------------------------------------------
// This method contains the first switch statement that calls the correct
Charles Law's avatar
Charles Law committed
274
// templated function for the input and output Data types.
Charles Law's avatar
Charles Law committed
275
// It hanldes image boundaries, so the image does not shrink.
276 277 278 279 280
void vtkImageDilateErode3D::ThreadedRequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *vtkNotUsed(outputVector),
  vtkImageData ***inData,
281
  vtkImageData **outData,
282
  int outExt[6], int id)
Charles Law's avatar
Charles Law committed
283
{
284 285 286 287 288 289
  int inExt[6], wholeExt[6];
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), wholeExt);
  this->InternalRequestUpdateExtent(inExt,outExt,wholeExt);
  void *inPtr = inData[0][0]->GetScalarPointerForExtent(inExt);
  void *outPtr = outData[0]->GetScalarPointerForExtent(outExt);
Charles Law's avatar
Charles Law committed
290
  vtkImageData *mask;
Charles Law's avatar
Charles Law committed
291 292

  // Error checking on mask
293
  mask = this->Ellipse->GetOutput();
Charles Law's avatar
Charles Law committed
294
  if (mask->GetScalarType() != VTK_UNSIGNED_CHAR)
Charles Law's avatar
Charles Law committed
295
    {
Charles Law's avatar
Charles Law committed
296
    vtkErrorMacro(<< "Execute: mask has wrong scalar type");
Charles Law's avatar
Charles Law committed
297 298 299
    return;
    }

Charles Law's avatar
Charles Law committed
300
  // this filter expects the output type to be same as input
301
  if (outData[0]->GetScalarType() != inData[0][0]->GetScalarType())
Charles Law's avatar
Charles Law committed
302
    {
303
    vtkErrorMacro(<< "Execute: output ScalarType, "
304
      << vtkImageScalarTypeNameMacro(outData[0]->GetScalarType())
Charles Law's avatar
Charles Law committed
305
      << " must match input scalar type");
Charles Law's avatar
Charles Law committed
306 307
    return;
    }
Charles Law's avatar
Charles Law committed
308

309
  switch (inData[0][0]->GetScalarType())
Charles Law's avatar
Charles Law committed
310
    {
311 312
    vtkTemplateMacro(
      vtkImageDilateErode3DExecute(this, mask, inData[0][0],
Francois Bertel's avatar
Francois Bertel committed
313
                                   static_cast<VTK_TT *>(inPtr),outData[0],
314
                                   outExt,
Francois Bertel's avatar
Francois Bertel committed
315
                                   static_cast<VTK_TT *>(outPtr),id, inInfo));
Charles Law's avatar
Charles Law committed
316
    default:
Charles Law's avatar
Charles Law committed
317
      vtkErrorMacro(<< "Execute: Unknown ScalarType");
Charles Law's avatar
Charles Law committed
318 319 320
      return;
    }
}
321 322

//----------------------------------------------------------------------------
323
int vtkImageDilateErode3D::RequestData(vtkInformation *request,
324 325 326
                                        vtkInformationVector **inputVector,
                                        vtkInformationVector *outputVector)
{
327
  this->Ellipse->Update();
328
  return this->Superclass::RequestData(request, inputVector, outputVector);
329
}