ITK
4.1.0
Insight Segmentation and Registration Toolkit
|
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