ITK  4.1.0
Insight Segmentation and Registration Toolkit
itkBoxUtilities.h
Go to the documentation of this file.
00001 /*=========================================================================
00002  *
00003  *  Copyright Insight Software Consortium
00004  *
00005  *  Licensed under the Apache License, Version 2.0 (the "License");
00006  *  you may not use this file except in compliance with the License.
00007  *  You may obtain a copy of the License at
00008  *
00009  *         http://www.apache.org/licenses/LICENSE-2.0.txt
00010  *
00011  *  Unless required by applicable law or agreed to in writing, software
00012  *  distributed under the License is distributed on an "AS IS" BASIS,
00013  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  *  See the License for the specific language governing permissions and
00015  *  limitations under the License.
00016  *
00017  *=========================================================================*/
00018 #ifndef __itkBoxUtilities_h
00019 #define __itkBoxUtilities_h
00020 #include "itkProgressReporter.h"
00021 #include "itkShapedNeighborhoodIterator.h"
00022 #include "itkImageRegionIterator.h"
00023 #include "itkConstantBoundaryCondition.h"
00024 #include "itkImageRegionIteratorWithIndex.h"
00025 #include "itkImageRegionIterator.h"
00026 #include "itkOffset.h"
00027 #include "itkNeighborhoodAlgorithm.h"
00028 #include "itkShapedNeighborhoodIterator.h"
00029 #include "itkZeroFluxNeumannBoundaryCondition.h"
00030 
00031 /*
00032  *
00033  * This code was contributed in the Insight Journal paper:
00034  * "Efficient implementation of kernel filtering"
00035  * by Beare R., Lehmann G
00036  * http://hdl.handle.net/1926/555
00037  * http://www.insight-journal.org/browse/publication/160
00038  *
00039  */
00040 
00041 
00042 namespace itk
00043 {
00044 template< class TIterator >
00045 TIterator *
00046 setConnectivityEarlyBox(TIterator *it, bool fullyConnected = false)
00047 {
00048   // activate the "previous" neighbours
00049   typename TIterator::OffsetType offset;
00050   it->ClearActiveList();
00051   if ( !fullyConnected )
00052     {
00053     // only activate the neighbors that are face connected
00054     // to the current pixel. do not include the center pixel
00055     offset.Fill(0);
00056     for ( unsigned int d = 0; d < TIterator::Dimension; ++d )
00057       {
00058       offset[d] = -1;
00059       it->ActivateOffset(offset);
00060       offset[d] = 0;
00061       }
00062     }
00063   else
00064     {
00065     // activate all neighbors that are face+edge+vertex
00066     // connected to the current pixel. do not include the center pixel
00067     unsigned int centerIndex = it->GetCenterNeighborhoodIndex();
00068     for ( unsigned int d = 0; d < centerIndex; d++ )
00069       {
00070       offset = it->GetOffset(d);
00071       // check for positives in any dimension
00072       bool keep = true;
00073       for ( unsigned int i = 0; i < TIterator::Dimension; i++ )
00074         {
00075         if ( offset[i] > 0 )
00076           {
00077           keep = false;
00078           break;
00079           }
00080         }
00081       if ( keep )
00082         {
00083         it->ActivateOffset(offset);
00084         }
00085       }
00086     offset.Fill(0);
00087     it->DeactivateOffset(offset);
00088     }
00089   return it;
00090 }
00091 
00092 template< class TInputImage, class TOutputImage >
00093 void
00094 BoxAccumulateFunction(const TInputImage *inputImage,
00095                       const TOutputImage *outputImage,
00096                       typename TInputImage::RegionType inputRegion,
00097                       typename TOutputImage::RegionType outputRegion,
00098                       ProgressReporter & progress)
00099 {
00100   // typedefs
00101   typedef TInputImage                      InputImageType;
00102   typedef typename TInputImage::RegionType RegionType;
00103   typedef typename TInputImage::SizeType   SizeType;
00104   typedef typename TInputImage::IndexType  IndexType;
00105   typedef typename TInputImage::PixelType  PixelType;
00106   typedef typename TInputImage::OffsetType OffsetType;
00107   typedef TOutputImage                     OutputImageType;
00108   typedef typename TOutputImage::PixelType OutputPixelType;
00109   typedef typename TInputImage::PixelType  InputPixelType;
00110 
00111   typedef ImageRegionConstIterator< TInputImage > InputIterator;
00112   typedef ImageRegionIterator< TOutputImage >     OutputIterator;
00113 
00114   typedef ShapedNeighborhoodIterator< TOutputImage > NOutputIterator;
00115   InputIterator inIt(inputImage, inputRegion);
00116   typename TInputImage::SizeType kernelRadius;
00117   kernelRadius.Fill(1);
00118 
00119   NOutputIterator noutIt(kernelRadius, outputImage, outputRegion);
00120   // this iterator is fully connected
00121   setConnectivityEarlyBox(&noutIt, true);
00122 
00123   ConstantBoundaryCondition< OutputImageType > oBC;
00124   oBC.SetConstant(NumericTraits< OutputPixelType >::Zero);
00125   noutIt.OverrideBoundaryCondition(&oBC);
00126   // This uses several iterators. An alternative and probably better
00127   // approach would be to copy the input to the output and convolve
00128   // with the following weights (in 2D)
00129   //   -(dim - 1)  1
00130   //       1       1
00131   // The result of each convolution needs to get written back to the
00132   // image being convolved so that the accumulation propogates
00133   // This should be implementable with neighborhood operators.
00134 
00135   std::vector< int > Weights;
00136   typename NOutputIterator::ConstIterator sIt;
00137   for ( typename NOutputIterator::IndexListType::const_iterator idxIt = noutIt.GetActiveIndexList().begin();
00138         idxIt != noutIt.GetActiveIndexList().end();
00139         idxIt++ )
00140     {
00141     OffsetType offset = noutIt.GetOffset(*idxIt);
00142     int        w = -1;
00143     for ( unsigned int k = 0; k < InputImageType::ImageDimension; k++ )
00144       {
00145       if ( offset[k] != 0 )
00146         {
00147         w *= offset[k];
00148         }
00149       }
00150 //     std::cout << offset << "  " << w << std::endl;
00151     Weights.push_back(w);
00152     }
00153 
00154   for ( inIt.GoToBegin(), noutIt.GoToBegin(); !noutIt.IsAtEnd(); ++inIt, ++noutIt )
00155     {
00156     OutputPixelType Sum = 0;
00157     int             k;
00158     for ( k = 0, sIt = noutIt.Begin(); !sIt.IsAtEnd(); ++sIt, ++k )
00159       {
00160       Sum += sIt.Get() * Weights[k];
00161       }
00162     noutIt.SetCenterPixel( Sum + inIt.Get() );
00163     progress.CompletedPixel();
00164     }
00165 }
00166 
00167 // a function to generate corners of arbitary dimension box
00168 template< class ImType >
00169 std::vector< typename ImType::OffsetType > CornerOffsets(const ImType *im)
00170 {
00171   typedef ShapedNeighborhoodIterator< ImType > NIterator;
00172   typename ImType::SizeType unitradius;
00173   unitradius.Fill(1);
00174   NIterator    N1( unitradius, im, im->GetRequestedRegion() );
00175   unsigned int centerIndex = N1.GetCenterNeighborhoodIndex();
00176   typename NIterator::OffsetType offset;
00177   std::vector< typename ImType::OffsetType > result;
00178   for ( unsigned int d = 0; d < centerIndex * 2 + 1; d++ )
00179     {
00180     offset = N1.GetOffset(d);
00181     // check whether this is a corner - corners have no zeros
00182     bool corner = true;
00183     for ( unsigned int k = 0; k < ImType::ImageDimension; k++ )
00184       {
00185       if ( offset[k] == 0 )
00186         {
00187         corner = false;
00188         break;
00189         }
00190       }
00191     if ( corner )
00192       {
00193       result.push_back(offset);
00194       }
00195     }
00196   return ( result );
00197 }
00198 
00199 template< class TInputImage, class TOutputImage >
00200 void
00201 BoxMeanCalculatorFunction(const TInputImage *accImage,
00202                           TOutputImage *outputImage,
00203                           typename TInputImage::RegionType inputRegion,
00204                           typename TOutputImage::RegionType outputRegion,
00205                           typename TInputImage::SizeType Radius,
00206                           ProgressReporter & progress)
00207 {
00208   // typedefs
00209   typedef TInputImage                           InputImageType;
00210   typedef typename TInputImage::RegionType      RegionType;
00211   typedef typename TInputImage::SizeType        SizeType;
00212   typedef typename TInputImage::IndexType       IndexType;
00213   typedef typename TInputImage::PixelType       PixelType;
00214   typedef typename TInputImage::OffsetType      OffsetType;
00215   typedef TOutputImage                          OutputImageType;
00216   typedef typename TOutputImage::PixelType      OutputPixelType;
00217   typedef typename TInputImage::PixelType       InputPixelType;
00218   // use the face generator for speed
00219   typedef NeighborhoodAlgorithm::ImageBoundaryFacesCalculator< InputImageType > FaceCalculatorType;
00220   typedef typename FaceCalculatorType::FaceListType                             FaceListType;
00221   typedef typename FaceCalculatorType::FaceListType::iterator                   FaceListTypeIt;
00222   FaceCalculatorType faceCalculator;
00223 
00224   FaceListType                                    faceList;
00225   FaceListTypeIt                                  fit;
00226   ZeroFluxNeumannBoundaryCondition< TInputImage > nbc;
00227 
00228   // this process is actually slightly asymmetric because we need to
00229   // subtract rectangles that are next to our kernel, not overlapping it
00230   SizeType kernelSize;
00231   SizeType internalRadius;
00232   SizeType RegionLimit;
00233 
00234   IndexType RegionStart = inputRegion.GetIndex();
00235   for ( unsigned int i = 0; i < TInputImage::ImageDimension; i++ )
00236     {
00237     kernelSize[i] = Radius[i] * 2 + 1;
00238     internalRadius[i] = Radius[i] + 1;
00239     RegionLimit[i] = inputRegion.GetSize()[i] + RegionStart[i] - 1;
00240     }
00241 
00242   typedef typename NumericTraits< OutputPixelType >::RealType AccPixType;
00243   // get a set of offsets to corners for a unit hypercube in this image
00244   std::vector< OffsetType > UnitCorners = CornerOffsets< TInputImage >(accImage);
00245   std::vector< OffsetType > RealCorners;
00246   std::vector< AccPixType > Weights;
00247   // now compute the weights
00248   for ( unsigned int k = 0; k < UnitCorners.size(); k++ )
00249     {
00250     int        prod = 1;
00251     OffsetType ThisCorner;
00252     for ( unsigned int i = 0; i < TInputImage::ImageDimension; i++ )
00253       {
00254       prod *= UnitCorners[k][i];
00255       if ( UnitCorners[k][i] > 0 )
00256         {
00257         ThisCorner[i] = Radius[i];
00258         }
00259       else
00260         {
00261         ThisCorner[i] = -( Radius[i] + 1 );
00262         }
00263       }
00264     Weights.push_back( (AccPixType)prod );
00265     RealCorners.push_back(ThisCorner);
00266     }
00267 
00268   faceList = faceCalculator(accImage, outputRegion, internalRadius);
00269   // start with the body region
00270   for ( fit = faceList.begin(); fit != faceList.end(); ++fit )
00271     {
00272     if ( fit == faceList.begin() )
00273       {
00274       // this is the body region. This is meant to be an optimized
00275       // version that doesn't use neigborhood regions
00276       // compute the various offsets
00277       AccPixType pixelscount = 1;
00278       for ( unsigned int i = 0; i < TInputImage::ImageDimension; i++ )
00279         {
00280         pixelscount *= (AccPixType)( 2 * Radius[i] + 1 );
00281         }
00282 
00283       typedef ImageRegionIterator< OutputImageType >     OutputIteratorType;
00284       typedef ImageRegionConstIterator< InputImageType > InputIteratorType;
00285 
00286       typedef std::vector< InputIteratorType > CornerItVecType;
00287       CornerItVecType CornerItVec;
00288       // set up the iterators for each corner
00289       for ( unsigned int k = 0; k < RealCorners.size(); k++ )
00290         {
00291         typename InputImageType::RegionType tReg = ( *fit );
00292         tReg.SetIndex(tReg.GetIndex() + RealCorners[k]);
00293         InputIteratorType tempIt(accImage, tReg);
00294         tempIt.GoToBegin();
00295         CornerItVec.push_back(tempIt);
00296         }
00297       // set up the output iterator
00298       OutputIteratorType oIt(outputImage, *fit);
00299       // now do the work
00300       for ( oIt.GoToBegin(); !oIt.IsAtEnd(); ++oIt )
00301         {
00302         AccPixType Sum = 0;
00303         // check each corner
00304         for ( unsigned int k = 0; k < CornerItVec.size(); k++ )
00305           {
00306           Sum += Weights[k] * CornerItVec[k].Get();
00307           // increment each corner iterator
00308           ++( CornerItVec[k] );
00309           }
00310         oIt.Set( static_cast< OutputPixelType >( Sum / pixelscount ) );
00311         progress.CompletedPixel();
00312         }
00313       }
00314     else
00315       {
00316       // now we need to deal with the border regions
00317       typedef ImageRegionIteratorWithIndex< OutputImageType > OutputIteratorType;
00318       OutputIteratorType oIt(outputImage, *fit);
00319       // now do the work
00320       for ( oIt.GoToBegin(); !oIt.IsAtEnd(); ++oIt )
00321         {
00322         // figure out the number of pixels in the box by creating an
00323         // equivalent region and cropping - this could probably be
00324         // included in the loop below.
00325         RegionType currentKernelRegion;
00326         currentKernelRegion.SetSize(kernelSize);
00327         // compute the region's index
00328         IndexType kernelRegionIdx = oIt.GetIndex();
00329         IndexType CentIndex = kernelRegionIdx;
00330         for ( unsigned int i = 0; i < TInputImage::ImageDimension; i++ )
00331           {
00332           kernelRegionIdx[i] -= Radius[i];
00333           }
00334         currentKernelRegion.SetIndex(kernelRegionIdx);
00335         currentKernelRegion.Crop(inputRegion);
00336         OffsetValueType edgepixelscount = currentKernelRegion.GetNumberOfPixels();
00337         AccPixType Sum = 0;
00338         // rules are : for each corner,
00339         //               for each dimension
00340         //                  if dimension offset is positive -> this is
00341         //                  a leading edge. Crop if outside the input
00342         //                  region
00343         //                  if dimension offset is negative -> this is
00344         //                  a trailing edge. Ignore if it is outside
00345         //                  image region
00346         for ( unsigned int k = 0; k < RealCorners.size(); k++ )
00347           {
00348           IndexType ThisCorner = CentIndex + RealCorners[k];
00349           bool      IncludeCorner = true;
00350           for ( unsigned int j = 0; j < TInputImage::ImageDimension; j++ )
00351             {
00352             if ( UnitCorners[k][j] > 0 )
00353               {
00354               // leading edge - crop it
00355               if ( ThisCorner[j] > static_cast< OffsetValueType >( RegionLimit[j] ) )
00356                 {
00357                 ThisCorner[j] = static_cast< OffsetValueType >( RegionLimit[j] );
00358                 }
00359               }
00360             else
00361               {
00362               // trailing edge - check bounds
00363               if ( ThisCorner[j] < RegionStart[j] )
00364                 {
00365                 IncludeCorner = false;
00366                 break;
00367                 }
00368               }
00369             }
00370           if ( IncludeCorner )
00371             {
00372             Sum += accImage->GetPixel(ThisCorner) * Weights[k];
00373             }
00374           }
00375 
00376         oIt.Set( static_cast< OutputPixelType >( Sum / (AccPixType)edgepixelscount ) );
00377         progress.CompletedPixel();
00378         }
00379       }
00380     }
00381 }
00382 
00383 template< class TInputImage, class TOutputImage >
00384 void
00385 BoxSigmaCalculatorFunction(const TInputImage *accImage,
00386                            TOutputImage *outputImage,
00387                            typename TInputImage::RegionType inputRegion,
00388                            typename TOutputImage::RegionType outputRegion,
00389                            typename TInputImage::SizeType Radius,
00390                            ProgressReporter & progress)
00391 {
00392   // typedefs
00393   typedef TInputImage                           InputImageType;
00394   typedef typename TInputImage::RegionType      RegionType;
00395   typedef typename TInputImage::SizeType        SizeType;
00396   typedef typename TInputImage::IndexType       IndexType;
00397   typedef typename TInputImage::PixelType       PixelType;
00398   typedef typename TInputImage::OffsetType      OffsetType;
00399   typedef TOutputImage                          OutputImageType;
00400   typedef typename TOutputImage::PixelType      OutputPixelType;
00401   typedef typename TInputImage::PixelType       InputPixelType;
00402   typedef typename InputPixelType::ValueType    ValueType;
00403   // use the face generator for speed
00404   typedef typename NeighborhoodAlgorithm::ImageBoundaryFacesCalculator< InputImageType > FaceCalculatorType;
00405   typedef typename FaceCalculatorType::FaceListType                                      FaceListType;
00406   typedef typename FaceCalculatorType::FaceListType::iterator                            FaceListTypeIt;
00407   FaceCalculatorType faceCalculator;
00408 
00409   FaceListType                                    faceList;
00410   FaceListTypeIt                                  fit;
00411   ZeroFluxNeumannBoundaryCondition< TInputImage > nbc;
00412 
00413   // this process is actually slightly asymmetric because we need to
00414   // subtract rectangles that are next to our kernel, not overlapping it
00415   SizeType  kernelSize;
00416   SizeType  internalRadius;
00417   SizeType  RegionLimit;
00418   IndexType RegionStart = inputRegion.GetIndex();
00419   for ( unsigned int i = 0; i < TInputImage::ImageDimension; i++ )
00420     {
00421     kernelSize[i] = Radius[i] * 2 + 1;
00422     internalRadius[i] = Radius[i] + 1;
00423     RegionLimit[i] = inputRegion.GetSize()[i] + RegionStart[i] - 1;
00424     }
00425 
00426   typedef typename NumericTraits< OutputPixelType >::RealType AccPixType;
00427   // get a set of offsets to corners for a unit hypercube in this image
00428   std::vector< OffsetType > UnitCorners = CornerOffsets< TInputImage >(accImage);
00429   std::vector< OffsetType > RealCorners;
00430   std::vector< AccPixType > Weights;
00431   // now compute the weights
00432   for ( unsigned int k = 0; k < UnitCorners.size(); k++ )
00433     {
00434     int        prod = 1;
00435     OffsetType ThisCorner;
00436     for ( unsigned int i = 0; i < TInputImage::ImageDimension; i++ )
00437       {
00438       prod *= UnitCorners[k][i];
00439       if ( UnitCorners[k][i] > 0 )
00440         {
00441         ThisCorner[i] = Radius[i];
00442         }
00443       else
00444         {
00445         ThisCorner[i] = -( Radius[i] + 1 );
00446         }
00447       }
00448     Weights.push_back( (AccPixType)prod );
00449     RealCorners.push_back(ThisCorner);
00450     }
00451 
00452   faceList = faceCalculator(accImage, outputRegion, internalRadius);
00453   // start with the body region
00454   for ( fit = faceList.begin(); fit != faceList.end(); ++fit )
00455     {
00456     if ( fit == faceList.begin() )
00457       {
00458       // this is the body region. This is meant to be an optimized
00459       // version that doesn't use neigborhood regions
00460       // compute the various offsets
00461       AccPixType pixelscount = 1;
00462       for ( unsigned int i = 0; i < TInputImage::ImageDimension; i++ )
00463         {
00464         pixelscount *= (AccPixType)( 2 * Radius[i] + 1 );
00465         }
00466 
00467       typedef ImageRegionIterator< OutputImageType >     OutputIteratorType;
00468       typedef ImageRegionConstIterator< InputImageType > InputIteratorType;
00469 
00470       typedef std::vector< InputIteratorType > CornerItVecType;
00471       CornerItVecType CornerItVec;
00472       // set up the iterators for each corner
00473       for ( unsigned int k = 0; k < RealCorners.size(); k++ )
00474         {
00475         typename InputImageType::RegionType tReg = ( *fit );
00476         tReg.SetIndex(tReg.GetIndex() + RealCorners[k]);
00477         InputIteratorType tempIt(accImage, tReg);
00478         tempIt.GoToBegin();
00479         CornerItVec.push_back(tempIt);
00480         }
00481       // set up the output iterator
00482       OutputIteratorType oIt(outputImage, *fit);
00483       // now do the work
00484       for ( oIt.GoToBegin(); !oIt.IsAtEnd(); ++oIt )
00485         {
00486         AccPixType Sum = 0;
00487         AccPixType SquareSum = 0;
00488         // check each corner
00489         for ( unsigned int k = 0; k < CornerItVec.size(); k++ )
00490           {
00491           const InputPixelType & i = CornerItVec[k].Get();
00492           Sum += Weights[k] * i[0];
00493           SquareSum += Weights[k] * i[1];
00494           // increment each corner iterator
00495           ++( CornerItVec[k] );
00496           }
00497 
00498         oIt.Set( static_cast< OutputPixelType >( vcl_sqrt( ( SquareSum - Sum * Sum / pixelscount ) / ( pixelscount - 1 ) ) ) );
00499         progress.CompletedPixel();
00500         }
00501       }
00502     else
00503       {
00504       // now we need to deal with the border regions
00505       typedef ImageRegionIteratorWithIndex< OutputImageType > OutputIteratorType;
00506       OutputIteratorType oIt(outputImage, *fit);
00507       // now do the work
00508       for ( oIt.GoToBegin(); !oIt.IsAtEnd(); ++oIt )
00509         {
00510         // figure out the number of pixels in the box by creating an
00511         // equivalent region and cropping - this could probably be
00512         // included in the loop below.
00513         RegionType currentKernelRegion;
00514         currentKernelRegion.SetSize(kernelSize);
00515         // compute the region's index
00516         IndexType kernelRegionIdx = oIt.GetIndex();
00517         IndexType CentIndex = kernelRegionIdx;
00518         for ( unsigned int i = 0; i < TInputImage::ImageDimension; i++ )
00519           {
00520           kernelRegionIdx[i] -= Radius[i];
00521           }
00522         currentKernelRegion.SetIndex(kernelRegionIdx);
00523         currentKernelRegion.Crop(inputRegion);
00524         SizeValueType edgepixelscount = currentKernelRegion.GetNumberOfPixels();
00525         AccPixType Sum = 0;
00526         AccPixType SquareSum = 0;
00527         // rules are : for each corner,
00528         //               for each dimension
00529         //                  if dimension offset is positive -> this is
00530         //                  a leading edge. Crop if outside the input
00531         //                  region
00532         //                  if dimension offset is negative -> this is
00533         //                  a trailing edge. Ignore if it is outside
00534         //                  image region
00535         for ( unsigned int k = 0; k < RealCorners.size(); k++ )
00536           {
00537           IndexType ThisCorner = CentIndex + RealCorners[k];
00538           bool      IncludeCorner = true;
00539           for ( unsigned int j = 0; j < TInputImage::ImageDimension; j++ )
00540             {
00541             if ( UnitCorners[k][j] > 0 )
00542               {
00543               // leading edge - crop it
00544               if ( ThisCorner[j] > static_cast< OffsetValueType >( RegionLimit[j] ) )
00545                 {
00546                 ThisCorner[j] = static_cast< OffsetValueType >( RegionLimit[j] );
00547                 }
00548               }
00549             else
00550               {
00551               // trailing edge - check bounds
00552               if ( ThisCorner[j] < RegionStart[j] )
00553                 {
00554                 IncludeCorner = false;
00555                 break;
00556                 }
00557               }
00558             }
00559           if ( IncludeCorner )
00560             {
00561             const InputPixelType & i = accImage->GetPixel(ThisCorner);
00562             Sum += Weights[k] * i[0];
00563             SquareSum += Weights[k] * i[1];
00564             }
00565           }
00566 
00567         oIt.Set( static_cast< OutputPixelType >( vcl_sqrt( ( SquareSum - Sum * Sum
00568                                                              / edgepixelscount ) / ( edgepixelscount - 1 ) ) ) );
00569         progress.CompletedPixel();
00570         }
00571       }
00572     }
00573 }
00574 
00575 template< class TInputImage, class TOutputImage >
00576 void
00577 BoxSquareAccumulateFunction(const TInputImage *inputImage,
00578                             TOutputImage *outputImage,
00579                             typename TInputImage::RegionType inputRegion,
00580                             typename TOutputImage::RegionType outputRegion,
00581                             ProgressReporter & progress)
00582 {
00583   // typedefs
00584   typedef TInputImage                         InputImageType;
00585   typedef typename TInputImage::RegionType    RegionType;
00586   typedef typename TInputImage::SizeType      SizeType;
00587   typedef typename TInputImage::IndexType     IndexType;
00588   typedef typename TInputImage::PixelType     PixelType;
00589   typedef typename TInputImage::OffsetType    OffsetType;
00590   typedef TOutputImage                        OutputImageType;
00591   typedef typename TOutputImage::PixelType    OutputPixelType;
00592   typedef typename OutputPixelType::ValueType ValueType;
00593   typedef typename TInputImage::PixelType     InputPixelType;
00594 
00595   typedef ImageRegionConstIterator< TInputImage > InputIterator;
00596   typedef ImageRegionIterator< TOutputImage >     OutputIterator;
00597 
00598   typedef ShapedNeighborhoodIterator< TOutputImage > NOutputIterator;
00599   InputIterator inIt(inputImage, inputRegion);
00600   typename TInputImage::SizeType kernelRadius;
00601   kernelRadius.Fill(1);
00602 
00603   NOutputIterator noutIt(kernelRadius, outputImage, outputRegion);
00604   // this iterator is fully connected
00605   setConnectivityEarlyBox(&noutIt, true);
00606 
00607   ConstantBoundaryCondition< OutputImageType > oBC;
00608   oBC.SetConstant(NumericTraits< OutputPixelType >::Zero);
00609   noutIt.OverrideBoundaryCondition(&oBC);
00610   // This uses several iterators. An alternative and probably better
00611   // approach would be to copy the input to the output and convolve
00612   // with the following weights (in 2D)
00613   //   -(dim - 1)  1
00614   //       1       1
00615   // The result of each convolution needs to get written back to the
00616   // image being convolved so that the accumulation propogates
00617   // This should be implementable with neighborhood operators.
00618 
00619   std::vector< int > Weights;
00620   typename NOutputIterator::ConstIterator sIt;
00621   for ( typename NOutputIterator::IndexListType::const_iterator idxIt = noutIt.GetActiveIndexList().begin();
00622         idxIt != noutIt.GetActiveIndexList().end();
00623         idxIt++ )
00624     {
00625     OffsetType offset = noutIt.GetOffset(*idxIt);
00626     int        w = -1;
00627     for ( unsigned int k = 0; k < InputImageType::ImageDimension; k++ )
00628       {
00629       if ( offset[k] != 0 )
00630         {
00631         w *= offset[k];
00632         }
00633       }
00634     Weights.push_back(w);
00635     }
00636 
00637   for ( inIt.GoToBegin(), noutIt.GoToBegin(); !noutIt.IsAtEnd(); ++inIt, ++noutIt )
00638     {
00639     ValueType Sum = 0;
00640     ValueType SquareSum = 0;
00641     int       k;
00642     for ( k = 0, sIt = noutIt.Begin(); !sIt.IsAtEnd(); ++sIt, ++k )
00643       {
00644       const OutputPixelType & v = sIt.Get();
00645       Sum += v[0] * Weights[k];
00646       SquareSum += v[1] * Weights[k];
00647       }
00648     OutputPixelType        o;
00649     const InputPixelType & i = inIt.Get();
00650     o[0] = Sum + i;
00651     o[1] = SquareSum + i * i;
00652     noutIt.SetCenterPixel(o);
00653     progress.CompletedPixel();
00654     }
00655 }
00656 } //namespace itk
00657 
00658 #endif
00659