convolve2D.h

Go to the documentation of this file.
00001 
00015 #ifndef _DLR_NUMERIC_CONVOLVE2D_H_
00016 #define _DLR_NUMERIC_CONVOLVE2D_H_
00017 
00018 #include <dlrNumeric/array2D.h>
00019 #include <dlrNumeric/convolutionStrategy.h>
00020 #include <dlrNumeric/index2D.h>
00021 
00022 namespace dlr {
00023 
00024   namespace numeric {
00025 
00027     template <class OutputType, class AccumulatorType,
00028               class KernelType, class SignalType>
00029     inline Array2D<OutputType>
00030     convolve2D(const Array2D<KernelType>& kernel,
00031                const Array2D<SignalType>& signal,
00032                ConvolutionStrategy strategy = DLR_CONVOLVE_PAD_RESULT,
00033                ConvolutionROI roi = DLR_CONVOLVE_ROI_SAME);
00034 
00035 
00037     template <class OutputType, class AccumulatorType,
00038               class KernelType, class SignalType, class FillType>
00039     inline Array2D<OutputType>
00040     convolve2D(const Array2D<KernelType>& kernel,
00041                const Array2D<SignalType>& signal,
00042                ConvolutionStrategy strategy,
00043                ConvolutionROI roi,
00044                const FillType& fillValue);
00045   
00046 
00048     template <class OutputType, class AccumulatorType,
00049               class KernelType, class SignalType>
00050     Array2D<OutputType>
00051     convolve2D(const Array2D<KernelType>& kernel,
00052                const Array2D<SignalType>& signal,
00053                ConvolutionStrategy strategy,
00054                const Index2D& corner0,
00055                const Index2D& corner1);
00056 
00057     
00059     template <class OutputType, class AccumulatorType,
00060               class KernelType, class SignalType, class FillType>
00061     Array2D<OutputType>
00062     convolve2D(const Array2D<KernelType>& kernel,
00063                const Array2D<SignalType>& signal,
00064                ConvolutionStrategy strategy,
00065                const Index2D& corner0,
00066                const Index2D& corner1,
00067                const FillType& fillValue);
00068 
00069     
00071     template <class OutputType, class AccumulatorType,
00072               class KernelType, class SignalType>
00073     inline Array2D<OutputType>
00074     correlate2D(const Array2D<KernelType>& kernel,
00075                 const Array2D<SignalType>& signal,
00076                 ConvolutionStrategy strategy = DLR_CONVOLVE_PAD_RESULT,
00077                 ConvolutionROI roi = DLR_CONVOLVE_ROI_SAME);
00078 
00079 
00081     template <class OutputType, class AccumulatorType,
00082               class KernelType, class SignalType, class FillType>
00083     Array2D<OutputType>
00084     correlate2D(const Array2D<KernelType>& kernel,
00085                 const Array2D<SignalType>& signal,
00086                 ConvolutionStrategy strategy,
00087                 ConvolutionROI roi,
00088                 const FillType& fillValue);
00089 
00090     
00092     template <class OutputType, class AccumulatorType,
00093               class KernelType, class SignalType>
00094     Array2D<OutputType>
00095     correlate2D(const Array2D<KernelType>& kernel,
00096                 const Array2D<SignalType>& signal,
00097                 ConvolutionStrategy strategy,
00098                 const Index2D& corner0,
00099                 const Index2D& corner1);
00100 
00101     
00103     template <class OutputType, class AccumulatorType,
00104               class KernelType, class SignalType, class FillType>
00105     Array2D<OutputType>
00106     correlate2D(const Array2D<KernelType>& kernel,
00107                 const Array2D<SignalType>& signal,
00108                 ConvolutionStrategy strategy,
00109                 const Index2D& corner0,
00110                 const Index2D& corner1,
00111                 const FillType& fillValue);
00112 
00113     
00114   } // namespace numeric
00115 
00116 } // namespace dlr
00117 
00118 
00119 /* ================ Definitions follow ================ */
00120 
00121 #include <algorithm> // For std::reverse_copy()
00122 #include <numeric> // For std::partial_sum()
00123 #include <dlrCommon/functional.h>
00124 #include <dlrNumeric/numericTraits.h>
00125 #include <dlrNumeric/stencil2D.h>
00126 
00127 namespace dlr {
00128 
00129   namespace numeric {
00130 
00132     namespace privateCode {
00133 
00134       template <class AccumulatorType, class KernelType, class SignalType>
00135       Array2D<AccumulatorType>
00136       doubleAccumulateKernel(const Array2D<KernelType>& kernel,
00137                              SignalType fillValue)
00138       {
00139         typedef typename NumericTraits<KernelType>::SumType KernelSumType;
00140         Array2D<KernelSumType> tempKernel(
00141           kernel.rows() + 1, kernel.columns() + 1);
00142         std::fill(tempKernel.rowBegin(0), tempKernel.rowEnd(0),
00143                   static_cast<KernelSumType>(0));
00144         for(size_t row = 0; row < kernel.rows(); ++row) {
00145           tempKernel(row + 1, 0) = static_cast<KernelSumType>(0);
00146           std::copy(kernel.rowBegin(row), kernel.rowEnd(row),
00147                     tempKernel.rowBegin(row + 1) + 1);              
00148         }
00149 
00150         // Accumulate horizontally.
00151         Array2D<KernelSumType> accumulatedKernel(
00152           kernel.rows() + 1, kernel.columns() + 1);
00153         std::partial_sum(tempKernel.begin(), tempKernel.end(),
00154                          accumulatedKernel.begin());
00155 
00156         // Accumulate vertically.
00157         tempKernel = accumulatedKernel.transpose();
00158         accumulatedKernel.reshape(
00159           static_cast<int>(kernel.columns()) + 1,
00160           static_cast<int>(kernel.rows()) + 1);
00161         std::partial_sum(tempKernel.begin(), tempKernel.end(),
00162                          accumulatedKernel.begin());
00163 
00164         Array2D<AccumulatorType> result(
00165           kernel.rows() + 1, kernel.columns() + 1);
00166         for(size_t row = 0; row < result.rows(); ++row) {
00167           for(size_t column = 0; column < result.columns(); ++column) {
00168             result(row, column) =
00169               static_cast<AccumulatorType>(
00170                 accumulatedKernel(column, row)
00171                 * static_cast<AccumulatorType>(fillValue));
00172           }
00173         }
00174         return result;
00175       }
00176 
00177 
00178       template<class OutputType, class InputType>
00179       inline OutputType
00180       integrateArea(const Array2D<InputType>& accumulatedKernel,
00181                     size_t row0, size_t row1,
00182                     size_t column0, size_t column1)
00183       {
00184         return static_cast<OutputType>(
00185           accumulatedKernel(row1, column1)
00186           - accumulatedKernel(row0, column1)
00187           - accumulatedKernel(row1, column0)
00188           + accumulatedKernel(row0, column0));
00189       }
00190       
00191       
00192       template <class OutputType, class AccumulatorType,
00193                 class KernelType, class SignalType,
00194                 size_t StencilSize>
00195       void
00196       sizedCorrelate2DCommon(const Array2D<KernelType>& kernel,
00197                              const Array2D<SignalType>& signal,
00198                              Array2D<OutputType>& result,
00199                              const Index2D& corner0, const Index2D& corner1,
00200                              const Index2D& resultCorner0)
00201       {
00202         typedef StencilIterator<const SignalType, StencilSize> SignalIterator;
00203         typedef typename Array2D<KernelType>::const_iterator KernelIterator;
00204 
00205         if(kernel.size() == 0) {
00206           DLR_THROW(ValueException, "sizedCorrelate2DCommon()",
00207                     "Argument kernel has zero size.");
00208         }
00209         if(signal.size() == 0) {
00210           DLR_THROW(ValueException, "sizedCorrelate2DCommon()",
00211                     "Argument signal has zero size.");
00212         }
00213 
00214         Stencil2D<const SignalType, StencilSize> signalStencil(
00215           kernel.rows(), kernel.columns());
00216         signalStencil.setTarget(signal);
00217 
00218         const size_t startRow = corner0.getRow() - kernel.rows() / 2;
00219         const size_t stopRow = corner1.getRow() - kernel.rows() / 2;
00220         const size_t startColumn = corner0.getColumn() - kernel.columns() / 2;
00221         const size_t stopColumn = corner1.getColumn() - kernel.columns() / 2;
00222         const size_t resultRow0 = resultCorner0.getRow();
00223         const size_t resultColumn0 = resultCorner0.getColumn();
00224         for(size_t row = startRow; row < stopRow; ++row) {
00225           size_t resultIndex =
00226             ((resultRow0 + row - startRow) * result.columns() + resultColumn0);
00227           signalStencil.goTo(row, startColumn);
00228           for(size_t column = startColumn; column < stopColumn; ++column) {
00229             AccumulatorType dotProduct = static_cast<AccumulatorType>(0);
00230             KernelIterator kernelIter = kernel.begin();
00231             KernelIterator endIter = kernel.end();
00232             SignalIterator signalIter = signalStencil.begin();
00233             while(kernelIter != endIter) {
00234               dotProduct +=
00235                 static_cast<AccumulatorType>(
00236                   *kernelIter * static_cast<AccumulatorType>(*signalIter));
00237               ++kernelIter;
00238               ++signalIter;
00239             }
00240             result(resultIndex) = static_cast<OutputType>(dotProduct);
00241             ++resultIndex;
00242             signalStencil.advance();
00243           }
00244         }
00245       }
00246 
00247 
00248       template <class OutputType, class AccumulatorType,
00249                 class KernelType, class SignalType>
00250       void
00251       correlate2DCommon(const Array2D<KernelType>& kernel,
00252                         const Array2D<SignalType>& signal,
00253                         Array2D<OutputType>& result,
00254                         const Index2D& corner0, const Index2D& corner1,
00255                         const Index2D& resultCorner0)
00256       {
00257         if(kernel.size() <= 9) {
00258           sizedCorrelate2DCommon<
00259             OutputType, AccumulatorType, KernelType, SignalType, 9>(
00260               kernel, signal, result, corner0, corner1, resultCorner0);
00261         } else if(kernel.size() <= 25) {
00262           sizedCorrelate2DCommon<
00263             OutputType, AccumulatorType, KernelType, SignalType, 25>(
00264               kernel, signal, result, corner0, corner1, resultCorner0);
00265         } else if(kernel.size() <= 49) {
00266           sizedCorrelate2DCommon<
00267             OutputType, AccumulatorType, KernelType, SignalType, 49>(
00268               kernel, signal, result, corner0, corner1, resultCorner0);
00269         } else if(kernel.size() <= 81) {
00270           sizedCorrelate2DCommon<
00271             OutputType, AccumulatorType, KernelType, SignalType, 81>(
00272               kernel, signal, result, corner0, corner1, resultCorner0);
00273         } else if(kernel.size() <= 121) {
00274           sizedCorrelate2DCommon<
00275             OutputType, AccumulatorType, KernelType, SignalType, 121>(
00276               kernel, signal, result, corner0, corner1, resultCorner0);
00277         } else if(kernel.size() <= 255) {
00278           sizedCorrelate2DCommon<
00279             OutputType, AccumulatorType, KernelType, SignalType, 255>(
00280               kernel, signal, result, corner0, corner1, resultCorner0);
00281         } else if(kernel.size() <= 1023) {
00282           sizedCorrelate2DCommon<
00283             OutputType, AccumulatorType, KernelType, SignalType, 1023>(
00284               kernel, signal, result, corner0, corner1, resultCorner0);
00285         } else if(kernel.size() <= 4095) {
00286           sizedCorrelate2DCommon<
00287             OutputType, AccumulatorType, KernelType, SignalType, 4095>(
00288               kernel, signal, result, corner0, corner1, resultCorner0);
00289         } else if(kernel.size() <= 16383) {
00290           sizedCorrelate2DCommon<
00291             OutputType, AccumulatorType, KernelType, SignalType, 16383>(
00292               kernel, signal, result, corner0, corner1, resultCorner0);
00293         } else if(kernel.size() <= 65535) {
00294           sizedCorrelate2DCommon<
00295             OutputType, AccumulatorType, KernelType, SignalType, 65535>(
00296               kernel, signal, result, corner0, corner1, resultCorner0);
00297         } else if(kernel.size() <= 262143) {
00298           sizedCorrelate2DCommon<
00299             OutputType, AccumulatorType, KernelType, SignalType, 262143>(
00300               kernel, signal, result, corner0, corner1, resultCorner0);
00301         } else if(kernel.size() <= 1048575) {
00302           sizedCorrelate2DCommon<
00303             OutputType, AccumulatorType, KernelType, SignalType, 1048575>(
00304               kernel, signal, result, corner0, corner1, resultCorner0);
00305         } else {
00306           DLR_THROW(NotImplementedException, "correlate2DCommon()",
00307                     "Kernels with more than 2^24 elements are not supported.");
00308         }
00309       }
00310 
00311       
00312       template <class OutputType, class AccumulatorType,
00313                 class KernelType, class SignalType>
00314       inline OutputType
00315       innerProduct2D(const Array2D<KernelType>& kernel,
00316                      const Array2D<SignalType>& signal,
00317                      size_t kernelRow0, size_t kernelRow1,
00318                      size_t kernelColumn0, size_t kernelColumn1,
00319                      size_t signalRow0, size_t signalColumn0)
00320       {
00321         typedef typename Array2D<KernelType>::const_iterator KernelIterator;
00322         typedef typename Array2D<SignalType>::const_iterator SignalIterator;
00323 
00324         size_t overlapWidth = kernelColumn1 - kernelColumn0;
00325         AccumulatorType dotProduct = static_cast<AccumulatorType>(0);
00326         size_t signalRow = signalRow0;
00327         for(size_t kernelRow = kernelRow0; kernelRow < kernelRow1;
00328             ++kernelRow) {
00329           KernelIterator kernelIter =
00330             kernel.rowBegin(kernelRow) + kernelColumn0;
00331           KernelIterator kernelEnd = kernelIter + overlapWidth;
00332           SignalIterator signalIter =
00333             signal.rowBegin(signalRow) + signalColumn0;
00334           while(kernelIter != kernelEnd) {
00335             dotProduct += static_cast<AccumulatorType>(
00336               *kernelIter * static_cast<AccumulatorType>(*signalIter));
00337             ++kernelIter;
00338             ++signalIter;
00339           }
00340           ++signalRow;
00341         }
00342         return static_cast<OutputType>(dotProduct);
00343       }
00344       
00345 
00346       template <class OutputType, class AccumulatorType,
00347                 class KernelType, class SignalType>
00348       inline OutputType
00349       correlate2DLeftRightWrap(const Array2D<KernelType>& kernel,
00350                                const Array2D<SignalType>& signal,
00351                                size_t kernelRow0, size_t kernelRow1,
00352                                size_t signalRow0,
00353                                size_t leftOverlap)
00354       {
00355         AccumulatorType result;
00356         size_t kernelStartColumn = kernel.columns() - leftOverlap;
00357         size_t signalRightStartColumn = signal.columns() - kernelStartColumn;
00358         result = innerProduct2D<
00359           AccumulatorType, AccumulatorType, KernelType, SignalType>(
00360             kernel, signal, kernelRow0, kernelRow1,
00361             kernelStartColumn, kernel.columns(), signalRow0, 0);
00362         result += innerProduct2D<
00363           AccumulatorType, AccumulatorType, KernelType, SignalType>(
00364             kernel, signal, kernelRow0, kernelRow1,
00365             0, kernelStartColumn, signalRow0, signalRightStartColumn);
00366         return static_cast<OutputType>(result);
00367       }
00368       
00369 
00370       template <class OutputType, class AccumulatorType,
00371                 class KernelType, class SignalType>
00372       inline OutputType
00373       correlate2DLeftReflection(const Array2D<KernelType>& kernel,
00374                                 const Array2D<SignalType>& signal,
00375                                 size_t kernelRow0, size_t kernelRow1,
00376                                 size_t signalRow0,
00377                                 size_t leftOverlap)
00378       {
00379         typedef typename Array2D<KernelType>::const_iterator KernelIterator;
00380         typedef typename Array2D<SignalType>::const_iterator SignalIterator;
00381 
00382         AccumulatorType dotProduct = static_cast<AccumulatorType>(0);
00383         size_t signalRow = signalRow0;
00384         size_t reflectionSize = kernel.columns() - leftOverlap;
00385         for(size_t kernelRow = kernelRow0; kernelRow < kernelRow1;
00386             ++kernelRow) {
00387           // Compute reflected component.
00388           KernelIterator kernelIter = kernel.rowBegin(kernelRow);
00389           KernelIterator kernelMiddle = kernelIter + reflectionSize;
00390           KernelIterator kernelEnd = kernel.rowEnd(kernelRow);
00391           SignalIterator signalIter =
00392             signal.rowBegin(signalRow) + (reflectionSize - 1);
00393           while(kernelIter != kernelMiddle) {
00394             dotProduct += static_cast<AccumulatorType>(
00395               *kernelIter * static_cast<AccumulatorType>(*signalIter));
00396             ++kernelIter;
00397             --signalIter;
00398           }
00399 
00400           // Compute in-bounds component.
00401           ++signalIter;
00402           while(kernelIter != kernelEnd) {
00403             dotProduct += static_cast<AccumulatorType>(
00404               *kernelIter * static_cast<AccumulatorType>(*signalIter));
00405             ++kernelIter;
00406             ++signalIter;
00407           }
00408 
00409           ++signalRow;
00410         }
00411         return static_cast<OutputType>(dotProduct);
00412       }
00413       
00414 
00415       template <class OutputType, class AccumulatorType,
00416                 class KernelType, class SignalType>
00417       inline OutputType
00418       correlate2DRightReflection(const Array2D<KernelType>& kernel,
00419                                  const Array2D<SignalType>& signal,
00420                                  size_t kernelRow0, size_t kernelRow1,
00421                                  size_t signalRow0,
00422                                  size_t rightOverlap)
00423       {
00424         typedef typename Array2D<KernelType>::const_iterator KernelIterator;
00425         typedef typename Array2D<SignalType>::const_iterator SignalIterator;
00426 
00427         AccumulatorType dotProduct = static_cast<AccumulatorType>(0);
00428         size_t signalRow = signalRow0;
00429         for(size_t kernelRow = kernelRow0; kernelRow < kernelRow1;
00430             ++kernelRow) {
00431           KernelIterator kernelIter = kernel.rowBegin(kernelRow);
00432           KernelIterator kernelMiddle = kernelIter + rightOverlap;
00433           KernelIterator kernelEnd = kernel.rowEnd(kernelRow);
00434           SignalIterator signalIter = signal.rowEnd(signalRow) - rightOverlap;
00435           
00436           // Compute in-bounds component.
00437           while(kernelIter != kernelMiddle) {
00438             dotProduct += static_cast<AccumulatorType>(
00439               *kernelIter * static_cast<AccumulatorType>(*signalIter));
00440             ++kernelIter;
00441             ++signalIter;
00442           }
00443 
00444           // Compute reflected component.
00445           --signalIter;
00446           while(kernelIter != kernelEnd) {
00447             dotProduct += static_cast<AccumulatorType>(
00448               *kernelIter * static_cast<AccumulatorType>(*signalIter));
00449             ++kernelIter;
00450             --signalIter;
00451           }
00452           ++signalRow;
00453         }
00454         return static_cast<OutputType>(dotProduct);
00455       }
00456       
00457 
00458       template <class OutputType, class AccumulatorType,
00459                 class KernelType, class SignalType>
00460       Array2D<OutputType>
00461       correlate2DTruncateResult(const Array2D<KernelType>& kernel,
00462                                 const Array2D<SignalType>& signal)
00463       {
00464         Array2D<OutputType> result(signal.rows() - kernel.rows() + 1,
00465                                    signal.columns() - kernel.columns() + 1);
00466         Index2D corner0(static_cast<int>(kernel.rows()) / 2,
00467                         static_cast<int>(kernel.columns()) / 2);
00468         Index2D corner1(
00469           static_cast<int>(signal.rows())
00470           - static_cast<int>(kernel.rows()) / 2,
00471           static_cast<int>(signal.columns())
00472           - static_cast<int>(kernel.columns()) / 2);
00473         Index2D resultCorner0(0, 0);
00474         correlate2DCommon<OutputType, AccumulatorType, KernelType, SignalType>(
00475           kernel, signal, result, corner0, corner1, resultCorner0);
00476         return result;
00477       }
00478 
00479 
00480       template <class OutputType, class AccumulatorType,
00481                 class KernelType, class SignalType>
00482       Array2D<OutputType>
00483       correlate2DPadResult(const Array2D<KernelType>& kernel,
00484                            const Array2D<SignalType>& signal,
00485                            const Index2D& corner0,
00486                            const Index2D& corner1,
00487                            OutputType fillValue)
00488       {
00489         typedef typename Array2D<OutputType>::iterator ResultIterator;
00490 
00491         size_t outputRows =
00492           corner1.getRow() - corner0.getRow();
00493         size_t outputColumns =
00494           corner1.getColumn() - corner0.getColumn();
00495         Array2D<OutputType> result(outputRows, outputColumns);
00496 
00497         // Check for degenerate case.
00498         if(kernel.rows() > signal.rows()
00499            || kernel.columns() > signal.columns()) {
00500           result = fillValue;
00501           return result;
00502         }
00503 
00504         // Establish significant row and column coordinates in the
00505         // output image.
00506 
00507         // Constants specified without reference to signal or result.
00508         const int kRowOverTwo = static_cast<int>(kernel.rows()) / 2;
00509         const int kColOverTwo = static_cast<int>(kernel.columns()) / 2;
00510         
00511         // Constants specified with respect to rows & columns in
00512         // argument signal.
00513         const int startRow = corner0.getRow();
00514         const int stopRow = corner1.getRow();
00515         const int transitionRow0 = kRowOverTwo;
00516         const int transitionRow1 =
00517           static_cast<int>(signal.rows()) - transitionRow0;
00518         const int startColumn = corner0.getColumn();
00519         const int stopColumn = corner1.getColumn();
00520         const int transitionColumn0 = kColOverTwo;
00521         const int transitionColumn1 =
00522           static_cast<int>(signal.columns()) - transitionColumn0;
00523         const int clippedTransitionRow0 =
00524           dlr::common::clip(transitionRow0, startRow, stopRow);
00525         const int clippedTransitionRow1 =
00526           dlr::common::clip(transitionRow1, startRow, stopRow);
00527         const int clippedTransitionColumn0 =
00528           dlr::common::clip(transitionColumn0, startColumn, stopColumn);
00529         const int clippedTransitionColumn1 =
00530           dlr::common::clip(transitionColumn1, startColumn, stopColumn);
00531 
00532         // Constants specified with respect to rows & columns in
00533         // result.
00534         const int resultTransitionRow0 =
00535           clippedTransitionRow0 - startRow;
00536         const int resultTransitionColumn0 =
00537           clippedTransitionColumn0 - startColumn;
00538 
00539         // Fill in areas along top of image.
00540         int row = startRow;
00541         int outputRow = 0;
00542         while(row < clippedTransitionRow0) {
00543           ResultIterator rowBegin = result.rowBegin(outputRow);
00544           ResultIterator rowEnd = result.rowEnd(outputRow);
00545           std::fill(rowBegin, rowEnd, fillValue);
00546           ++row;
00547           ++outputRow;
00548         }
00549 
00550         // Fill in areas along sides.
00551         int leftBorderIndex = clippedTransitionColumn0 - startColumn;
00552         int rightBorderIndex = clippedTransitionColumn1 - startColumn;
00553         while(row < clippedTransitionRow1) {
00554           ResultIterator rowBegin = result.rowBegin(outputRow);
00555           ResultIterator rowEnd = result.rowEnd(outputRow);
00556           std::fill(rowBegin, rowBegin + leftBorderIndex, fillValue);
00557           std::fill(rowBegin + rightBorderIndex, rowEnd, fillValue);
00558           ++row;
00559           ++outputRow;
00560         }
00561 
00562         // Fill in areas along bottom of image.
00563         while(row < stopRow) {
00564           ResultIterator rowBegin = result.rowBegin(outputRow);
00565           ResultIterator rowEnd = result.rowEnd(outputRow);
00566           std::fill(rowBegin, rowEnd, fillValue);
00567           ++row;
00568           ++outputRow;
00569         }
00570         
00571         Index2D signalCorner0(clippedTransitionRow0, clippedTransitionColumn0);
00572         Index2D signalCorner1(clippedTransitionRow1, clippedTransitionColumn1);
00573         Index2D resultCorner0(resultTransitionRow0, resultTransitionColumn0);
00574         correlate2DCommon<OutputType, AccumulatorType, KernelType, SignalType>(
00575           kernel, signal, result, signalCorner0, signalCorner1, resultCorner0);
00576         return result;
00577       }
00578     
00579                    
00580       template <class OutputType, class AccumulatorType,
00581                 class KernelType, class SignalType>
00582       Array2D<OutputType>
00583       correlate2DZeroPadSignal(const Array2D<KernelType>& kernel,
00584                                const Array2D<SignalType>& signal,
00585                                const Index2D& corner0,
00586                                const Index2D& corner1)
00587       {
00588         size_t outputRows =
00589           corner1.getRow() - corner0.getRow();
00590         size_t outputColumns =
00591           corner1.getColumn() - corner0.getColumn();
00592         Array2D<OutputType> result(outputRows, outputColumns);
00593 
00594         // Constants specified without reference to signal or result.
00595         const int kRowOverTwo = static_cast<int>(kernel.rows()) / 2;
00596         const int kColOverTwo = static_cast<int>(kernel.columns()) / 2;
00597 
00598         // Constants specified with respect to rows & columns in
00599         // argument signal.
00600         const int startRow = corner0.getRow();
00601         const int stopRow = corner1.getRow();
00602         const int transitionRow0 = kRowOverTwo;
00603         const int transitionRow1
00604           = static_cast<int>(signal.rows()) - transitionRow0;
00605         const int startColumn = corner0.getColumn();
00606         const int stopColumn = corner1.getColumn();
00607         const int transitionColumn0 = kColOverTwo;
00608         const int transitionColumn1 =
00609           static_cast<int>(signal.columns()) - transitionColumn0;
00610         const int clippedTransitionRow0 =
00611           dlr::common::clip(transitionRow0, startRow, stopRow);
00612         const int clippedTransitionRow1 =
00613           dlr::common::clip(transitionRow1, startRow, stopRow);
00614         const int clippedTransitionColumn0 =
00615           dlr::common::clip(transitionColumn0, startColumn, stopColumn);
00616         const int clippedTransitionColumn1 =
00617           dlr::common::clip(transitionColumn1, startColumn, stopColumn);
00618 
00619         // Fill in areas along top of image.
00620         int row = startRow;
00621         int outputRow = 0;
00622         while(row < clippedTransitionRow0) {
00623           // Fill in top left corner.
00624           int column = startColumn;
00625           int outputColumn = 0;
00626           while(column < clippedTransitionColumn0) {
00627             result(outputRow, outputColumn) = innerProduct2D<
00628               OutputType, AccumulatorType, KernelType, SignalType>(
00629                 kernel, signal, transitionRow0 - row, kernel.rows(),
00630                 transitionColumn0 - column, kernel.columns(), 0, 0);
00631             ++column;
00632             ++outputColumn;
00633           }
00634 
00635           // Fill in top edge.
00636           while(column < clippedTransitionColumn1) {
00637             result(outputRow, outputColumn) = innerProduct2D<
00638               OutputType, AccumulatorType, KernelType, SignalType>(
00639                 kernel, signal, transitionRow0 - row, kernel.rows(),
00640                 0, kernel.columns(), 0, column - transitionColumn0);
00641             ++column;
00642             ++outputColumn;
00643           }
00644 
00645           // Fill in top right corner.
00646           while(column < stopColumn) {
00647             result(outputRow, outputColumn) = innerProduct2D<
00648               OutputType, AccumulatorType, KernelType, SignalType>(
00649                 kernel, signal, transitionRow0 - row, kernel.rows(),
00650                 0, signal.columns() - column + kColOverTwo,
00651                 0, column - transitionColumn0);
00652             ++column;
00653             ++outputColumn;
00654           }
00655 
00656           ++row;
00657           ++outputRow;
00658         }
00659 
00660         // Fill in areas along left and right edges of image.
00661         while(row < clippedTransitionRow1) {
00662           // Fill in left edge.
00663           int column = startColumn;
00664           int outputColumn = 0;
00665           while(column < clippedTransitionColumn0) {
00666             result(outputRow, outputColumn) = innerProduct2D<
00667               OutputType, AccumulatorType, KernelType, SignalType>(
00668                 kernel, signal, 0, kernel.rows(),
00669                 transitionColumn0 - column, kernel.columns(),
00670                 row - transitionRow0, 0);
00671             ++column;
00672             ++outputColumn;
00673           }
00674             
00675           // Fill in right edge.
00676           column = clippedTransitionColumn1;
00677           outputColumn +=
00678             clippedTransitionColumn1 - clippedTransitionColumn0;
00679           while(column < stopColumn) {
00680             result(outputRow, outputColumn) = innerProduct2D<
00681               OutputType, AccumulatorType, KernelType, SignalType>(
00682                 kernel, signal, 0, kernel.rows(),
00683                 0, signal.columns() - column + kColOverTwo,
00684                 row - transitionRow0, column - transitionColumn0);
00685             ++column;
00686             ++outputColumn;
00687           }
00688           ++row;
00689           ++outputRow;
00690         }
00691         
00692         // Fill in areas along bottom of image.
00693         while(row < stopRow) {
00694           // Fill in bottom left corner.
00695           int column = startColumn;
00696           int outputColumn = 0;
00697           while(column < clippedTransitionColumn0) {
00698             result(outputRow, outputColumn) = innerProduct2D<
00699               OutputType, AccumulatorType, KernelType, SignalType>(
00700                 kernel, signal, 0, signal.rows() - row + kRowOverTwo,
00701                 transitionColumn0 - column, kernel.columns(),
00702                 row - transitionRow0, 0);
00703             ++column;
00704             ++outputColumn;
00705           }
00706 
00707           // Fill in bottom edge.
00708           while(column < clippedTransitionColumn1) {
00709             result(outputRow, outputColumn) = innerProduct2D<
00710               OutputType, AccumulatorType, KernelType, SignalType>(
00711                 kernel, signal, 0, signal.rows() - row + kRowOverTwo,
00712                 0, kernel.columns(),
00713                 row - transitionRow0, column - transitionColumn0);
00714             ++column;
00715             ++outputColumn;
00716           }
00717 
00718           // Fill in bottom right corner.
00719           while(column < stopColumn) {
00720             result(outputRow, outputColumn) = innerProduct2D<
00721               OutputType, AccumulatorType, KernelType, SignalType>(
00722                 kernel, signal, 0, signal.rows() - row + kRowOverTwo,
00723                 0, signal.columns() - column + kColOverTwo,
00724                 row - transitionRow0, column - transitionColumn0);
00725             ++column;
00726             ++outputColumn;
00727           }
00728           ++row;
00729           ++outputRow;
00730         }
00731 
00732         // Fill in the middle of the image.
00733         Index2D newCorner0(kRowOverTwo, kColOverTwo);
00734         Index2D newCorner1(static_cast<int>(signal.rows()) - kRowOverTwo,
00735                            static_cast<int>(signal.columns()) - kColOverTwo);
00736         Index2D resultCorner0(static_cast<int>(kernel.rows()) - 1,
00737                               static_cast<int>(kernel.columns()) - 1);
00738         correlate2DCommon<OutputType, AccumulatorType, KernelType, SignalType>(
00739           kernel, signal, result, newCorner0, newCorner1, resultCorner0);
00740         return result;
00741       }
00742 
00743 
00744       template <class OutputType, class AccumulatorType,
00745                 class KernelType, class SignalType>
00746       Array2D<OutputType>
00747       correlate2DPadSignal(const Array2D<KernelType>& kernel,
00748                            const Array2D<SignalType>& signal,
00749                            const Index2D& corner0,
00750                            const Index2D& corner1,
00751                            SignalType fillValue)
00752       {
00753         size_t outputRows =
00754           corner1.getRow() - corner0.getRow();
00755         size_t outputColumns =
00756           corner1.getColumn() - corner0.getColumn();
00757         Array2D<OutputType> result(outputRows, outputColumns);
00758 
00759         // Precompute numbers which will make it easy to total up the
00760         // portions of the kernel which overlap padded areas of the
00761         // signal.
00762         Array2D<AccumulatorType> accumulatedKernel =
00763           doubleAccumulateKernel<AccumulatorType, KernelType, SignalType>(
00764             kernel, fillValue);
00765         
00766         // Constants specified without reference to signal or result.
00767         const int kRowOverTwo = static_cast<int>(kernel.rows()) / 2;
00768         const int kColOverTwo = static_cast<int>(kernel.columns()) / 2;
00769         
00770         // Constants specified with respect to rows & columns in
00771         // argument signal.
00772         const int startRow = corner0.getRow();
00773         const int stopRow = corner1.getRow();
00774         const int transitionRow0 = kRowOverTwo;
00775         const int transitionRow1 =
00776           static_cast<int>(signal.rows()) - transitionRow0;
00777         const int startColumn = corner0.getColumn();
00778         const int stopColumn = corner1.getColumn();
00779         const int transitionColumn0 = kColOverTwo;
00780         const int transitionColumn1 =
00781           static_cast<int>(signal.columns()) - transitionColumn0;
00782         const int clippedTransitionRow0 =
00783           dlr::common::clip(transitionRow0, startRow, stopRow);
00784         const int clippedTransitionRow1 =
00785           dlr::common::clip(transitionRow1, startRow, stopRow);
00786         const int clippedTransitionColumn0 =
00787           dlr::common::clip(transitionColumn0, startColumn, stopColumn);
00788         const int clippedTransitionColumn1 =
00789           dlr::common::clip(transitionColumn1, startColumn, stopColumn);
00790 
00791         // Fill in areas along top of image.
00792         int row = startRow;
00793         int outputRow = 0;
00794         while(row < clippedTransitionRow0) {
00795           // Fill in top left corner.
00796           int column = startColumn;
00797           int outputColumn = 0;
00798           while(column < clippedTransitionColumn0) {
00799             result(outputRow, outputColumn) = static_cast<OutputType>(
00800               innerProduct2D<
00801               AccumulatorType, AccumulatorType, KernelType, SignalType>(
00802                 kernel, signal, transitionRow0 - row, kernel.rows(),
00803                 transitionColumn0 - column, kernel.columns(), 0, 0)
00804               + integrateArea<AccumulatorType>(
00805                 accumulatedKernel, 0, transitionRow0 - row,
00806                 0, kernel.columns())
00807               + integrateArea<AccumulatorType>(
00808                 accumulatedKernel, transitionRow0 - row, kernel.rows(),
00809                 0, transitionColumn0 - column));
00810             ++column;
00811             ++outputColumn;
00812           }
00813 
00814           // Fill in top edge.
00815           while(column < clippedTransitionColumn1) {
00816             result(outputRow, outputColumn) = static_cast<OutputType>(
00817               innerProduct2D<
00818               AccumulatorType, AccumulatorType, KernelType, SignalType>(
00819                 kernel, signal, transitionRow0 - row, kernel.rows(),
00820                 0, kernel.columns(), 0, column - transitionColumn0)
00821               + integrateArea<AccumulatorType>(
00822                 accumulatedKernel, 0, transitionRow0 - row,
00823                 0, kernel.columns()));
00824             ++column;
00825             ++outputColumn;
00826           }
00827 
00828           // Fill in top right corner.
00829           while(column < stopColumn) {
00830             result(outputRow, outputColumn) = static_cast<OutputType>(
00831               innerProduct2D<
00832               AccumulatorType, AccumulatorType, KernelType, SignalType>(
00833                 kernel, signal, transitionRow0 - row, kernel.rows(),
00834                 0, signal.columns() - column + kColOverTwo,
00835                 0, column - transitionColumn0)
00836               + integrateArea<AccumulatorType>(
00837                 accumulatedKernel, 0, transitionRow0 - row,
00838                 0, kernel.columns())
00839               + integrateArea<AccumulatorType>(
00840                 accumulatedKernel, transitionRow0 - row, kernel.rows(),
00841                 signal.columns() - column + kColOverTwo, kernel.columns()));
00842             ++column;
00843             ++outputColumn;
00844           }
00845 
00846           ++row;
00847           ++outputRow;
00848         }
00849 
00850         // Fill in areas along left and right edges of image.
00851         while(row < clippedTransitionRow1) {
00852           // Fill in left edge.
00853           int column = startColumn;
00854           int outputColumn = 0;
00855           while(column < clippedTransitionColumn0) {
00856             result(outputRow, outputColumn) = static_cast<OutputType>(
00857               innerProduct2D<
00858               AccumulatorType, AccumulatorType, KernelType, SignalType>(
00859                 kernel, signal, 0, kernel.rows(),
00860                 transitionColumn0 - column, kernel.columns(),
00861                 row - transitionRow0, 0)
00862               + integrateArea<AccumulatorType>(
00863                 accumulatedKernel, 0, kernel.rows(),
00864                 0, transitionColumn0 - column));
00865             ++column;
00866             ++outputColumn;
00867           }
00868             
00869           // Fill in right edge.
00870           column = clippedTransitionColumn1;
00871           outputColumn +=
00872             clippedTransitionColumn1 - clippedTransitionColumn0;
00873           while(column < stopColumn) {
00874             result(outputRow, outputColumn) = static_cast<OutputType>(
00875               innerProduct2D<
00876               AccumulatorType, AccumulatorType, KernelType, SignalType>(
00877                 kernel, signal, 0, kernel.rows(),
00878                 0, signal.columns() - column + kColOverTwo,
00879                 row - transitionRow0, column - transitionColumn0)
00880               + integrateArea<AccumulatorType>(
00881                 accumulatedKernel, 0, kernel.rows(),
00882                 signal.columns() - column + kColOverTwo, kernel.columns()));
00883             ++column;
00884             ++outputColumn;
00885           }
00886           ++row;
00887           ++outputRow;
00888         }
00889         
00890         // Fill in areas along bottom of image.
00891         while(row < stopRow) {
00892           // Fill in bottom left corner.
00893           int column = startColumn;
00894           int outputColumn = 0;
00895           while(column < clippedTransitionColumn0) {
00896             result(outputRow, outputColumn) = static_cast<OutputType>(
00897               innerProduct2D<
00898               AccumulatorType, AccumulatorType, KernelType, SignalType>(
00899                 kernel, signal, 0, signal.rows() - row + kRowOverTwo,
00900                 transitionColumn0 - column, kernel.columns(),
00901                 row - transitionRow0, 0)
00902               + integrateArea<AccumulatorType>(
00903                 accumulatedKernel,
00904                 signal.rows() - row + kRowOverTwo, kernel.rows(),
00905                 0, kernel.columns())
00906               + integrateArea<AccumulatorType>(
00907                 accumulatedKernel, 0, signal.rows() - row + kRowOverTwo,
00908                 0, transitionColumn0 - column));
00909             ++column;
00910             ++outputColumn;
00911           }
00912 
00913           // Fill in bottom edge.
00914           while(column < clippedTransitionColumn1) {
00915             result(outputRow, outputColumn) = static_cast<OutputType>(
00916               innerProduct2D<
00917               AccumulatorType, AccumulatorType, KernelType, SignalType>(
00918                 kernel, signal, 0, signal.rows() - row + kRowOverTwo,
00919                 0, kernel.columns(),
00920                 row - transitionRow0, column - transitionColumn0)
00921               + integrateArea<AccumulatorType>(
00922                 accumulatedKernel,
00923                 signal.rows() - row + kRowOverTwo, kernel.rows(),
00924                 0, kernel.columns()));
00925             ++column;
00926             ++outputColumn;
00927           }
00928 
00929           // Fill in bottom right corner.
00930           while(column < stopColumn) {
00931             result(outputRow, outputColumn) = static_cast<OutputType>(
00932               innerProduct2D<
00933               AccumulatorType, AccumulatorType, KernelType, SignalType>(
00934                 kernel, signal, 0, signal.rows() - row + kRowOverTwo,
00935                 0, signal.columns() - column + kColOverTwo,
00936                 row - transitionRow0, column - transitionColumn0)
00937               + integrateArea<AccumulatorType>(
00938                 accumulatedKernel,
00939                 signal.rows() - row + kRowOverTwo, kernel.rows(),
00940                 0, kernel.columns())
00941               + integrateArea<AccumulatorType>(
00942                 accumulatedKernel, 0, signal.rows() - row + kRowOverTwo,
00943                 signal.columns() - column + kColOverTwo, kernel.columns()));
00944             ++column;
00945             ++outputColumn;
00946           }
00947           ++row;
00948           ++outputRow;
00949         }
00950 
00951         // Fill in the middle of the image.
00952         Index2D newCorner0(kRowOverTwo, kColOverTwo);
00953         Index2D newCorner1(static_cast<int>(signal.rows()) - kRowOverTwo,
00954                            static_cast<int>(signal.columns()) - kColOverTwo);
00955         Index2D resultCorner0(static_cast<int>(kernel.rows()) - 1,
00956                               static_cast<int>(kernel.columns()) - 1);
00957         correlate2DCommon<OutputType, AccumulatorType, KernelType, SignalType>(
00958           kernel, signal, result, newCorner0, newCorner1, resultCorner0);
00959         return result;
00960       }
00961 
00962 
00963       template <class OutputType, class AccumulatorType,
00964                 class KernelType, class SignalType>
00965       Array2D<OutputType>
00966       correlate2DReflectSignal(const Array2D<KernelType>& kernel,
00967                                const Array2D<SignalType>& signal,
00968                                const Index2D& corner0,
00969                                const Index2D& corner1)
00970       {
00971         // Brace yourself...
00972 
00973         size_t outputRows =
00974           corner1.getRow() - corner0.getRow();
00975         size_t outputColumns =
00976           corner1.getColumn() - corner0.getColumn();
00977         Array2D<OutputType> result(outputRows, outputColumns);
00978 
00979         // Make a flipped (upside down) kernel for coding convenience.
00980         Array2D<KernelType> kernelUD(kernel.rows(), kernel.columns());
00981         for(size_t rowIndex = 0; rowIndex < kernel.rows(); ++rowIndex) {
00982           std::copy(
00983             kernel.rowBegin(rowIndex), kernel.rowEnd(rowIndex),
00984             kernelUD.rowBegin(kernel.rows() - rowIndex - 1));
00985         }
00986 
00987         // Constants specified without reference to signal or result.
00988         const int kRowOverTwo = static_cast<int>(kernel.rows()) / 2;
00989         const int kColOverTwo = static_cast<int>(kernel.columns()) / 2;
00990         
00991         // Constants specified with respect to rows & columns in
00992         // argument signal.
00993         const int startRow = corner0.getRow();
00994         const int stopRow = corner1.getRow();
00995         const int transitionRow0 = kRowOverTwo;
00996         const int transitionRow1 =
00997           static_cast<int>(signal.rows()) - transitionRow0;
00998         const int startColumn = corner0.getColumn();
00999         const int stopColumn = corner1.getColumn();
01000         const int transitionColumn0 = kColOverTwo;
01001         const int transitionColumn1 =
01002           static_cast<int>(signal.columns()) - transitionColumn0;
01003         const int clippedTransitionRow0 =
01004           dlr::common::clip(transitionRow0, startRow, stopRow);
01005         const int clippedTransitionRow1 =
01006           dlr::common::clip(transitionRow1, startRow, stopRow);
01007         const int clippedTransitionColumn0 =
01008           dlr::common::clip(transitionColumn0, startColumn, stopColumn);
01009         const int clippedTransitionColumn1 =
01010           dlr::common::clip(transitionColumn1, startColumn, stopColumn);
01011 
01012         // Fill in areas along top of image.
01013         int row = startRow;
01014         int outputRow = 0;
01015         while(row < clippedTransitionRow0) {
01016           // Intermediate variable keeping track of the first kernel
01017           // row that overlaps valid image data.
01018           size_t kernelStartRow = transitionRow0 - row;
01019 
01020           // Fill in top left corner.
01021           int column = startColumn;
01022           int outputColumn = 0;
01023           while(column < clippedTransitionColumn0) {
01024             AccumulatorType elementValue = correlate2DLeftReflection<
01025               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01026                 kernel, signal, kernelStartRow, kernel.rows(), 0,
01027                 column + kColOverTwo + 1);
01028             elementValue += correlate2DLeftReflection<
01029               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01030                 kernelUD, signal,
01031                 kernel.rows() - kernelStartRow, kernel.rows(), 0,
01032                 column + kColOverTwo + 1);
01033             result(outputRow, outputColumn) =
01034               static_cast<OutputType>(elementValue);
01035             ++column;
01036             ++outputColumn;
01037           }
01038 
01039           // Fill in top edge.
01040           while(column < clippedTransitionColumn1) {
01041             AccumulatorType elementValue = innerProduct2D<
01042               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01043                 kernel, signal, kernelStartRow, kernel.rows(),
01044                 0, kernel.columns(), 0, column - transitionColumn0);
01045             elementValue += innerProduct2D<
01046               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01047                 kernelUD, signal, kernel.rows() - kernelStartRow,
01048                 kernel.rows(), 0, kernel.columns(), 0,
01049                 column - transitionColumn0);
01050             result(outputRow, outputColumn) =
01051               static_cast<OutputType>(elementValue);
01052             ++column;
01053             ++outputColumn;
01054           }
01055 
01056           // Fill in top right corner.
01057           while(column < stopColumn) {
01058             AccumulatorType elementValue = correlate2DRightReflection<
01059               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01060                 kernel, signal, kernelStartRow, kernel.rows(), 0,
01061                 signal.columns() - column + kColOverTwo);
01062             elementValue += correlate2DRightReflection<
01063               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01064               kernelUD, signal,
01065               kernel.rows() - kernelStartRow, kernel.rows(), 0,
01066               signal.columns() - column + kColOverTwo);
01067             result(outputRow, outputColumn) =
01068               static_cast<OutputType>(elementValue);
01069             ++column;
01070             ++outputColumn;
01071           }
01072           ++row;
01073           ++outputRow;
01074         }
01075 
01076         // Fill in areas along left and right edges of image.
01077         while(row < clippedTransitionRow1) {
01078 
01079           // Fill in left edge.
01080           int column = startColumn;
01081           int outputColumn = 0;
01082           while(column < clippedTransitionColumn0) {
01083             result(outputRow, outputColumn) = correlate2DLeftReflection<
01084               OutputType, AccumulatorType, KernelType, SignalType>(
01085                 kernel, signal, 0, kernel.rows(), row - transitionRow0,
01086                 column + kColOverTwo + 1);
01087             ++column;
01088             ++outputColumn;
01089           }
01090 
01091           // Fill in right edge.
01092           column = clippedTransitionColumn1;
01093           outputColumn +=
01094             clippedTransitionColumn1 - clippedTransitionColumn0;
01095           while(column < stopColumn) {
01096             result(outputRow, outputColumn) = correlate2DRightReflection<
01097               OutputType, AccumulatorType, KernelType, SignalType>(
01098                 kernel, signal, 0, kernel.rows(), row - transitionRow0,
01099                 signal.columns() - column + kColOverTwo);
01100             ++column;
01101             ++outputColumn;
01102           }
01103           ++row;
01104           ++outputRow;
01105         }
01106 
01107         // Fill in areas along bottom of image.
01108         while(row < stopRow) {
01109           // Intermediate variable keeping track of the last kernel
01110           // row that overlaps valid image data.
01111           size_t kernelStopRow = signal.rows() - row + kRowOverTwo;
01112           size_t kernelStopRowUD = kernel.rows() - kernelStopRow;
01113 
01114           // Fill in bottom left corner.
01115           int column = startColumn;
01116           int outputColumn = 0;
01117           while(column < clippedTransitionColumn0) {
01118             AccumulatorType elementValue = correlate2DLeftReflection<
01119               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01120                 kernel, signal, 0, kernelStopRow,
01121                 signal.rows() - kernelStopRow,
01122                 column + kColOverTwo + 1);
01123             elementValue += correlate2DLeftReflection<
01124               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01125                 kernelUD, signal,
01126                 0, kernelStopRowUD, signal.rows() - kernelStopRowUD,
01127                 column + kColOverTwo + 1);
01128             result(outputRow, outputColumn) =
01129               static_cast<OutputType>(elementValue);
01130             ++column;
01131             ++outputColumn;
01132           }
01133 
01134           // Fill in bottom edge.
01135           while(column < clippedTransitionColumn1) {
01136             AccumulatorType elementValue = innerProduct2D<
01137               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01138                 kernel, signal, 0, kernelStopRow,
01139                 0, kernel.columns(), signal.rows() - kernelStopRow,
01140                 column - transitionColumn0);
01141             elementValue += innerProduct2D<
01142               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01143                 kernelUD, signal, 0, kernelStopRowUD,
01144                 0, kernel.columns(), signal.rows() - kernelStopRowUD,
01145                 column - transitionColumn0);
01146             result(outputRow, outputColumn) =
01147               static_cast<OutputType>(elementValue);
01148             ++column;
01149             ++outputColumn;
01150           }
01151 
01152           // Fill in bottom right corner.
01153           while(column < stopColumn) {
01154             AccumulatorType elementValue = correlate2DRightReflection<
01155               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01156                 kernel, signal, 0, kernelStopRow,
01157                 signal.rows() - kernelStopRow,
01158                 signal.columns() + kColOverTwo - column);
01159             elementValue += correlate2DRightReflection<
01160               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01161                 kernelUD, signal, 0, kernelStopRowUD,
01162                 signal.rows() - kernelStopRowUD,
01163                 signal.columns() + kColOverTwo - column);
01164             result(outputRow, outputColumn) =
01165               static_cast<OutputType>(elementValue);
01166             ++column;
01167             ++outputColumn;
01168           }
01169           ++row;
01170           ++outputRow;
01171         }
01172 
01173         // Fill in the middle of the image.
01174         Index2D newCorner0(kRowOverTwo, kColOverTwo);
01175         Index2D newCorner1(static_cast<int>(signal.rows()) - kRowOverTwo,
01176                            static_cast<int>(signal.columns()) - kColOverTwo);
01177         Index2D resultCorner0(static_cast<int>(kernel.rows()) - 1,
01178                               static_cast<int>(kernel.columns()) - 1);
01179         correlate2DCommon<OutputType, AccumulatorType, KernelType, SignalType>(
01180           kernel, signal, result, newCorner0, newCorner1, resultCorner0);
01181         return result;
01182       }
01183 
01184 
01185       template <class OutputType, class AccumulatorType,
01186                 class KernelType, class SignalType>
01187       Array2D<OutputType>
01188       correlate2DWrapSignal(const Array2D<KernelType>& kernel,
01189                             const Array2D<SignalType>& signal,
01190                             const Index2D& corner0,
01191                             const Index2D& corner1)
01192       {
01193         // Brace yourself...
01194         
01195         size_t outputRows =
01196           corner1.getRow() - corner0.getRow();
01197         size_t outputColumns =
01198           corner1.getColumn() - corner0.getColumn();
01199         Array2D<OutputType> result(outputRows, outputColumns);
01200 
01201         // Constants specified without reference to signal or result.
01202         const int kRowOverTwo = static_cast<int>(kernel.rows()) / 2;
01203         const int kColOverTwo = static_cast<int>(kernel.columns()) / 2;
01204         
01205         // Constants specified with respect to rows & columns in
01206         // argument signal.
01207         const int startRow = corner0.getRow();
01208         const int stopRow = corner1.getRow();
01209         const int transitionRow0 = kRowOverTwo;
01210         const int transitionRow1 =
01211           static_cast<int>(signal.rows()) - transitionRow0;
01212         const int startColumn = corner0.getColumn();
01213         const int stopColumn = corner1.getColumn();
01214         const int transitionColumn0 = kColOverTwo;
01215         const int transitionColumn1 =
01216           static_cast<int>(signal.columns()) - transitionColumn0;
01217         const int clippedTransitionRow0 =
01218           dlr::common::clip(transitionRow0, startRow, stopRow);
01219         const int clippedTransitionRow1 =
01220           dlr::common::clip(transitionRow1, startRow, stopRow);
01221         const int clippedTransitionColumn0 =
01222           dlr::common::clip(transitionColumn0, startColumn, stopColumn);
01223         const int clippedTransitionColumn1 =
01224           dlr::common::clip(transitionColumn1, startColumn, stopColumn);
01225 
01226         // Fill in areas along top of image.
01227         int row = startRow;
01228         int outputRow = 0;
01229         Array1D<AccumulatorType> accumulator(result.columns());
01230         while(row < clippedTransitionRow0) {
01231 
01232           // Intermediate variable to simplify things later.
01233           size_t kernelStartRow = transitionRow0 - row;
01234 
01235           // Fill in top left corner.  Do this in two passes to reduce
01236           // cache misses.
01237           int outputColumn = 0;
01238           for(int column = startColumn; column < clippedTransitionColumn0;
01239               ++column) {
01240             // Add upper left and upper right contributions.
01241             accumulator[outputColumn] = correlate2DLeftRightWrap<
01242               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01243                 kernel, signal, kernelStartRow, kernel.rows(), 0,
01244                 column + kColOverTwo + 1);
01245             ++outputColumn;
01246           }
01247           outputColumn = 0;
01248           for(int column = startColumn; column < clippedTransitionColumn0;
01249               ++column) {
01250             // Add lower left and lower right contributions.
01251             accumulator[outputColumn] += correlate2DLeftRightWrap<
01252               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01253                 kernel, signal, 0, kernelStartRow,
01254                 signal.rows() - kernelStartRow, column + kColOverTwo + 1);
01255             result(outputRow, outputColumn) =
01256               static_cast<OutputType>(accumulator[outputColumn]);
01257             ++outputColumn;
01258           }
01259 
01260           // Fill in top edge.  Do this in two passes to reduce
01261           // cache misses.
01262           outputColumn = clippedTransitionColumn0 - startColumn;
01263           for(int column = clippedTransitionColumn0;
01264               column < clippedTransitionColumn1;
01265               ++column) {
01266             // Add the upper contribution.
01267             accumulator[outputColumn] = innerProduct2D<
01268               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01269                 kernel, signal, kernelStartRow, kernel.rows(),
01270                 0, kernel.columns(), 0, column - transitionColumn0);
01271             ++outputColumn;
01272           }
01273           outputColumn = clippedTransitionColumn0 - startColumn;
01274           for(int column = clippedTransitionColumn0;
01275               column < clippedTransitionColumn1;
01276               ++column) {
01277             // Add the lower contribution.
01278             accumulator[outputColumn] += innerProduct2D<
01279               AccumulatorType, AccumulatorType, KernelType, SignalType>(
01280                 kernel, signal, 0, kernelStartRow,
01281                 0, kernel.columns(),
01282                 signal.rows() - kernelStartRow, column - transitionColumn0);
01283             result(outputRow, outputColumn) =
01284               static_cast<OutputType>(accumulator[outputColumn]);
01285             ++outputColumn;
01286           }
01287 
01288           // Fill in top right corner.  Because we're wrapping, this
01289           // corner has the same element values as a shifted version
01290           // of the top left corner.  If we calculated the top left
01291           // corner, we simply copy it.
01292           outputColumn = clippedTransitionColumn1 - startColumn;
01293           for(int column = clippedTransitionColumn1; column < stopColumn;
01294               ++column) {
01295             int donorColumn =
01296               outputColumn - static_cast<int>(signal.columns());
01297             if(donorColumn >= 0) {
01298               result(outputRow, outputColumn) = result(outputRow, donorColumn);
01299             } else {
01300               // Add upper left and upper right contributions.
01301               accumulator[outputColumn] = correlate2DLeftRightWrap<
01302                 AccumulatorType, AccumulatorType, KernelType, SignalType>(
01303                   kernel, signal, kernelStartRow, kernel.rows(), 0,
01304                   column - signal.columns() + kColOverTwo + 1);
01305             }
01306             ++outputColumn;
01307           }
01308           outputColumn = clippedTransitionColumn1 - startColumn;
01309           for(int column = clippedTransitionColumn1; column < stopColumn;
01310               ++column) {
01311             int donorColumn = outputColumn - static_cast<int>(signal.columns());
01312             if(donorColumn < 0) {
01313               // Add lower left and lower right contributions.
01314               accumulator[outputColumn] += correlate2DLeftRightWrap<
01315                 AccumulatorType, AccumulatorType, KernelType, SignalType>(
01316                   kernel, signal, 0, kernelStartRow,
01317                   signal.rows() - kernelStartRow,
01318                   column - signal.columns() + kColOverTwo + 1);
01319               result(outputRow, outputColumn) =
01320                 static_cast<OutputType>(accumulator[outputColumn]);
01321             }
01322             ++outputColumn;
01323           }
01324           ++row;
01325           ++outputRow;
01326         }
01327 
01328         // Fill in areas along left and right edges of image.
01329         while(row < clippedTransitionRow1) {
01330 
01331           // Fill in left edge.
01332           size_t outputColumn = 0;
01333           for(int column = startColumn; column < clippedTransitionColumn0;
01334               ++column) {
01335             result(outputRow, outputColumn) = correlate2DLeftRightWrap<
01336               OutputType, AccumulatorType, KernelType, SignalType>(
01337                 kernel, signal, 0, kernel.rows(), row - transitionRow0,
01338                 column + kColOverTwo + 1);
01339             ++outputColumn;
01340           }
01341 
01342           // Fill in right edge.
01343           outputColumn = clippedTransitionColumn1 - startColumn;
01344           for(int column = clippedTransitionColumn1; column < stopColumn;
01345               ++column) {
01346             int donorColumn = (static_cast<int>(outputColumn)
01347                                - static_cast<int>(signal.columns()));
01348             if(donorColumn >= 0) {
01349               result(outputRow, outputColumn) = result(outputRow, donorColumn);
01350             } else {
01351               result(outputRow, outputColumn) = correlate2DLeftRightWrap<
01352                 OutputType, AccumulatorType, KernelType, SignalType>(
01353                   kernel, signal, 0, kernel.rows(), row - transitionRow0,
01354                   column - signal.columns() + kColOverTwo + 1);
01355             }
01356             ++outputColumn;
01357           }
01358           ++row;
01359           ++outputRow;
01360         }
01361 
01362         // Fill in areas along bottom of image.
01363         while(row < stopRow) {
01364           int donorRow = row - outputRow - static_cast<int>(signal.rows());
01365 
01366           if(donorRow >= 0) {
01367             std::copy(result.rowBegin(donorRow), result.rowEnd(donorRow),
01368                       result.rowBegin(outputRow));
01369           } else {
01370 
01371             // Intermediate variable to simplify things later.
01372             size_t kernelStartRow = transitionRow0 - row + signal.rows();
01373 
01374             // Fill in bottom left corner.  Do this in two passes to reduce
01375             // cache misses.
01376             int outputColumn = 0;
01377             for(int column = startColumn; column < clippedTransitionColumn0;
01378                 ++column) {
01379               // Add upper left and upper right contributions.
01380               accumulator[outputColumn] = correlate2DLeftRightWrap<
01381                 AccumulatorType, AccumulatorType, KernelType, SignalType>(
01382                   kernel, signal, kernelStartRow, kernel.rows(), 0,
01383                   column + kColOverTwo + 1);
01384               ++outputColumn;
01385             }
01386             outputColumn = 0;
01387             for(int column = startColumn; column < clippedTransitionColumn0;
01388                 ++column) {
01389               // Add lower left and lower right contributions.
01390               accumulator[outputColumn] += correlate2DLeftRightWrap<
01391                 AccumulatorType, AccumulatorType, KernelType, SignalType>(
01392                   kernel, signal, 0, kernelStartRow,
01393                   signal.rows() - kernelStartRow, column + kColOverTwo + 1);
01394               result(outputRow, outputColumn) =
01395                 static_cast<OutputType>(accumulator[outputColumn]);
01396               ++outputColumn;
01397             }
01398 
01399             // Fill in bottom edge.  Do this in two passes to reduce
01400             // cache misses.
01401             outputColumn = clippedTransitionColumn0 - startColumn;
01402             for(int column = clippedTransitionColumn0;
01403                 column < clippedTransitionColumn1;
01404                 ++column) {
01405               // Add the upper contribution.
01406               accumulator[outputColumn] = innerProduct2D<
01407                 AccumulatorType, AccumulatorType, KernelType, SignalType>(
01408                   kernel, signal, kernelStartRow, kernel.rows(),
01409                   0, kernel.columns(), 0, column - transitionColumn0);
01410               ++outputColumn;
01411             }
01412             outputColumn = clippedTransitionColumn0 - startColumn;
01413             for(int column = clippedTransitionColumn0;
01414                 column < clippedTransitionColumn1;
01415                 ++column) {
01416               // Add the lower contribution.
01417               accumulator[outputColumn] += innerProduct2D<
01418                 AccumulatorType, AccumulatorType, KernelType, SignalType>(
01419                   kernel, signal, 0, kernelStartRow,
01420                   0, kernel.columns(),
01421                   signal.rows() - kernelStartRow, column - transitionColumn0);
01422               result(outputRow, outputColumn) =
01423                 static_cast<OutputType>(accumulator[outputColumn]);
01424               ++outputColumn;
01425             }
01426 
01427             // Fill in bottom right corner.  Because we're wrapping, this
01428             // corner has the same element values as a shifted version
01429             // of the bottom left corner.  If we calculated the bottom left
01430             // corner, we simply copy it.
01431             outputColumn = clippedTransitionColumn1 - startColumn;
01432             for(int column = clippedTransitionColumn1; column < stopColumn;
01433                 ++column) {
01434               int donorColumn = outputColumn - static_cast<int>(signal.columns());
01435               if(donorColumn >= 0) {
01436                 result(outputRow, outputColumn) =
01437                   result(outputRow, donorColumn);
01438               } else {
01439                 // Add upper left and upper right contributions.
01440                 accumulator[outputColumn] = correlate2DLeftRightWrap<
01441                   AccumulatorType, AccumulatorType, KernelType, SignalType>(
01442                     kernel, signal, kernelStartRow, kernel.rows(), 0,
01443                     column - signal.columns() + kColOverTwo + 1);
01444               }
01445               ++outputColumn;
01446             }
01447             outputColumn = clippedTransitionColumn1 - startColumn;
01448             for(int column = clippedTransitionColumn1; column < stopColumn;
01449                 ++column) {
01450               int donorColumn = outputColumn - static_cast<int>(signal.columns());
01451               if(donorColumn < 0) {
01452                 // Add lower left and lower right contributions.
01453                 accumulator[outputColumn] += correlate2DLeftRightWrap<
01454                   AccumulatorType, AccumulatorType, KernelType, SignalType>(
01455                     kernel, signal, 0, kernelStartRow,
01456                     signal.rows() - kernelStartRow,
01457                     column - signal.columns() + kColOverTwo + 1);
01458                 result(outputRow, outputColumn) =
01459                   static_cast<OutputType>(accumulator[outputColumn]);
01460               }
01461               ++outputColumn;
01462             }
01463           }
01464           ++row;
01465           ++outputRow;
01466         }
01467 
01468         // Fill in the middle of the image.
01469         Index2D newCorner0(kRowOverTwo, kColOverTwo);
01470         Index2D newCorner1(static_cast<int>(signal.rows()) - kRowOverTwo,
01471                            static_cast<int>(signal.columns()) - kColOverTwo);
01472         Index2D resultCorner0(static_cast<int>(kernel.rows()) - 1,
01473                               static_cast<int>(kernel.columns()) - 1);
01474         correlate2DCommon<OutputType, AccumulatorType, KernelType, SignalType>(
01475           kernel, signal, result, newCorner0, newCorner1, resultCorner0);
01476         return result;
01477       }
01478 
01479       
01480       template <class KernelType>
01481       Array2D<KernelType>
01482       reverseKernel(const Array2D<KernelType>& kernel) {
01483         Array2D<KernelType> reversedKernel(kernel.rows(), kernel.columns());
01484         for(size_t rowIndex = 0; rowIndex < kernel.rows(); ++rowIndex) {
01485           std::reverse_copy(
01486             kernel.rowBegin(rowIndex), kernel.rowEnd(rowIndex),
01487             reversedKernel.rowBegin(kernel.rows() - rowIndex - 1));
01488         }
01489         return reversedKernel;
01490       }
01491       
01492                    
01493     } // namespace privateCode
01495 
01496 
01497     template <class OutputType, class AccumulatorType,
01498               class KernelType, class SignalType>
01499     inline Array2D<OutputType>
01500     convolve2D(const Array2D<KernelType>& kernel,
01501                const Array2D<SignalType>& signal,
01502                ConvolutionStrategy strategy,
01503                ConvolutionROI roi)
01504     {
01505       Array2D<KernelType> reversedKernel = privateCode::reverseKernel(kernel);
01506       return correlate2D<OutputType, AccumulatorType, KernelType, SignalType>(
01507         reversedKernel, signal, strategy, roi);
01508     }
01509     
01510 
01511     template <class OutputType, class AccumulatorType,
01512               class KernelType, class SignalType, class FillType>
01513     inline Array2D<OutputType>
01514     convolve2D(const Array2D<KernelType>& kernel,
01515                const Array2D<SignalType>& signal,
01516                ConvolutionStrategy strategy,
01517                ConvolutionROI roi,
01518                const FillType& fillValue)
01519     {
01520       Array2D<KernelType> reversedKernel = privateCode::reverseKernel(kernel);
01521       return correlate2D<OutputType, AccumulatorType, KernelType, SignalType>(
01522         reversedKernel, signal, strategy, roi, fillValue);
01523     }
01524     
01525 
01526     template <class OutputType, class AccumulatorType,
01527               class KernelType, class SignalType>
01528     inline Array2D<OutputType>
01529     convolve2D(const Array2D<KernelType>& kernel,
01530                const Array2D<SignalType>& signal,
01531                ConvolutionStrategy strategy,
01532                const Index2D& corner0,
01533                const Index2D& corner1)
01534     {
01535       Array2D<KernelType> reversedKernel = privateCode::reverseKernel(kernel);
01536       return correlate2D<OutputType, AccumulatorType, KernelType, SignalType>(
01537         reversedKernel, signal, strategy, corner0, corner1);
01538     }
01539     
01540 
01541     template <class OutputType, class AccumulatorType,
01542               class KernelType, class SignalType, class FillType>
01543     inline Array2D<OutputType>
01544     convolve2D(const Array2D<KernelType>& kernel,
01545                const Array2D<SignalType>& signal,
01546                ConvolutionStrategy strategy,
01547                const Index2D& corner0,
01548                const Index2D& corner1,
01549                const FillType& fillValue)
01550     {
01551       Array2D<KernelType> reversedKernel = privateCode::reverseKernel(kernel);
01552       return correlate2D<OutputType, AccumulatorType, KernelType, SignalType>(
01553         reversedKernel, signal, strategy, corner0, corner1, fillValue);
01554     }
01555     
01556 
01557     template <class OutputType, class AccumulatorType,
01558               class KernelType, class SignalType>
01559     Array2D<OutputType>
01560     correlate2D(const Array2D<KernelType>& kernel,
01561                 const Array2D<SignalType>& signal,
01562                 ConvolutionStrategy strategy,
01563                 ConvolutionROI roi)
01564     {
01565       switch(roi) {
01566       case DLR_CONVOLVE_ROI_SAME:
01567       {
01568         Index2D corner0(0, 0);
01569         Index2D corner1(static_cast<int>(signal.rows()), static_cast<int>(signal.columns()));
01570         return correlate2D<OutputType, AccumulatorType, KernelType, SignalType>(
01571           kernel, signal, strategy, corner0, corner1);
01572         break;
01573       }
01574       case DLR_CONVOLVE_ROI_VALID:
01575       {
01576         Index2D corner0(static_cast<int>(kernel.rows()) / 2, static_cast<int>(kernel.columns()) / 2);
01577         Index2D corner1(static_cast<int>(signal.rows()) - static_cast<int>(corner0.getRow()),
01578                         static_cast<int>(signal.columns()) - static_cast<int>(corner0.getColumn()));
01579         return correlate2D<OutputType, AccumulatorType, KernelType, SignalType>(
01580           kernel, signal, strategy, corner0, corner1);
01581         break;
01582       }
01583       case DLR_CONVOLVE_ROI_FULL:
01584       {
01585         Index2D corner0(-(static_cast<int>(kernel.rows()) / 2),
01586                         -(static_cast<int>(kernel.columns()) / 2));
01587         Index2D corner1(static_cast<int>(signal.rows()) - static_cast<int>(corner0.getRow()),
01588                         static_cast<int>(signal.columns()) - static_cast<int>(corner0.getColumn()));
01589         return correlate2D<OutputType, AccumulatorType, KernelType, SignalType>(
01590           kernel, signal, strategy, corner0, corner1);
01591         break;
01592       }
01593       default:
01594         DLR_THROW(LogicException, "correlate2D()",
01595                   "Illegal value for roi argument.");
01596         break;
01597       }
01598       return Array2D<OutputType>();
01599     }
01600     
01601 
01602     template <class OutputType, class AccumulatorType,
01603               class KernelType, class SignalType, class FillType>
01604     Array2D<OutputType>
01605     correlate2D(const Array2D<KernelType>& kernel,
01606                 const Array2D<SignalType>& signal,
01607                 ConvolutionStrategy strategy,
01608                 ConvolutionROI roi,
01609                 const FillType& fillValue)
01610     {
01611       switch(roi) {
01612       case DLR_CONVOLVE_ROI_SAME:
01613       {
01614         Index2D corner0(0, 0);
01615         Index2D corner1(static_cast<int>(signal.rows()), static_cast<int>(signal.columns()));
01616         return correlate2D<OutputType, AccumulatorType, KernelType, SignalType, FillType>(
01617           kernel, signal, strategy, corner0, corner1, fillValue);
01618         break;
01619       }
01620       case DLR_CONVOLVE_ROI_VALID:
01621       {
01622         Index2D corner0(static_cast<int>(kernel.rows()) / 2, static_cast<int>(kernel.columns()) / 2);
01623         Index2D corner1(static_cast<int>(signal.rows()) - corner0.getRow(),
01624                         static_cast<int>(signal.columns()) - corner0.getColumn());
01625         return correlate2D<OutputType, AccumulatorType, KernelType, SignalType, FillType>(
01626           kernel, signal, strategy, corner0, corner1, fillValue);
01627         break;
01628       }
01629       case DLR_CONVOLVE_ROI_FULL:
01630       {
01631         Index2D corner0(-(static_cast<int>(kernel.rows()) / 2),
01632                         -(static_cast<int>(kernel.columns()) / 2));
01633         Index2D corner1(static_cast<int>(signal.rows()) - corner0.getRow(),
01634                         static_cast<int>(signal.columns()) - corner0.getColumn());
01635         return correlate2D<OutputType, AccumulatorType, KernelType, SignalType, FillType>(
01636           kernel, signal, strategy, corner0, corner1, fillValue);
01637         break;
01638       }
01639       default:
01640         DLR_THROW(LogicException, "correlate2D()",
01641                   "Illegal value for roi argument.");
01642         break;
01643       }
01644       return Array2D<OutputType>();
01645     }
01646 
01647     
01648     template <class OutputType, class AccumulatorType,
01649               class KernelType, class SignalType>
01650     Array2D<OutputType>
01651     correlate2D(const Array2D<KernelType>& kernel,
01652                 const Array2D<SignalType>& signal,
01653                 ConvolutionStrategy strategy,
01654                 const Index2D& corner0,
01655                 const Index2D& corner1)
01656     {
01657       if(kernel.rows() % 2 != 1) {
01658         DLR_THROW(ValueException, "correlate2D()",
01659                   "Argument kernel must have an odd number of rows.");
01660       }
01661       if(kernel.columns() % 2 != 1) {
01662         DLR_THROW(ValueException, "correlate2D()",
01663                   "Argument kernel must have an odd number of columns.");
01664       }
01665       // Note(xxx): is the following check necessary?
01666       if(kernel.rows() > signal.rows()) {
01667         DLR_THROW(ValueException, "correlate2D()",
01668                   "Argument kernel must not have more rows than "
01669                   "argument signal.");
01670       }
01671       if(kernel.columns() > signal.columns()) {
01672         DLR_THROW(ValueException, "correlate2D()",
01673                   "Argument kernel must not have more columns than "
01674                   "argument signal.");
01675       }
01676 
01677       switch(strategy) {
01678       case DLR_CONVOLVE_TRUNCATE_RESULT:
01679         return privateCode::correlate2DTruncateResult<
01680           OutputType, AccumulatorType, KernelType, SignalType>(kernel, signal);
01681         break;
01682       case DLR_CONVOLVE_PAD_RESULT:
01683       case DLR_CONVOLVE_ZERO_PAD_RESULT:
01684       case DLR_CONVOLVE_PAD_SIGNAL:
01685         DLR_THROW(ValueException, "correlate2D()",
01686                   "The specified convolution strategy requires that a "
01687                   "fill value be specified.");
01688       case DLR_CONVOLVE_ZERO_PAD_SIGNAL:
01689         return privateCode::correlate2DZeroPadSignal<
01690           OutputType, AccumulatorType, KernelType, SignalType>(
01691             kernel, signal, corner0, corner1);
01692         break;
01693       case DLR_CONVOLVE_REFLECT_SIGNAL:
01694         return privateCode::correlate2DReflectSignal<
01695           OutputType, AccumulatorType, KernelType, SignalType>(
01696             kernel, signal, corner0, corner1);
01697         break;
01698       case DLR_CONVOLVE_WRAP_SIGNAL:
01699         return privateCode::correlate2DWrapSignal<
01700           OutputType, AccumulatorType, KernelType, SignalType>(
01701             kernel, signal, corner0, corner1);
01702         break;
01703       default:
01704         DLR_THROW(LogicException, "correlate2D()",
01705                   "Illegal value for strategy argument.");
01706         break;
01707       }
01708       return Array2D<OutputType>();
01709     }
01710     
01711 
01712     template <class OutputType, class AccumulatorType,
01713               class KernelType, class SignalType, class FillType>
01714     Array2D<OutputType>
01715     correlate2D(const Array2D<KernelType>& kernel,
01716                 const Array2D<SignalType>& signal,
01717                 ConvolutionStrategy strategy,
01718                 const Index2D& corner0,
01719                 const Index2D& corner1,
01720                 const FillType& fillValue)
01721     {
01722       if(kernel.rows() % 2 != 1) {
01723         DLR_THROW(ValueException, "correlate2D()",
01724                   "Argument kernel must have an odd number of rows.");
01725       }
01726       if(kernel.columns() % 2 != 1) {
01727         DLR_THROW(ValueException, "correlate2D()",
01728                   "Argument kernel must have an odd number of columns.");
01729       }
01730       // Note(xxx): is the following check necessary?
01731       if(kernel.rows() > signal.rows()) {
01732         DLR_THROW(ValueException, "correlate2D()",
01733                   "Argument kernel must not have more rows than "
01734                   "argument signal.");
01735       }
01736       if(kernel.columns() > signal.columns()) {
01737         DLR_THROW(ValueException, "correlate2D()",
01738                   "Argument kernel must not have more columns than "
01739                   "argument signal.");
01740       }
01741     
01742       switch(strategy) {
01743       case DLR_CONVOLVE_TRUNCATE_RESULT:
01744         return privateCode::correlate2DTruncateResult<
01745           OutputType, AccumulatorType, KernelType, SignalType>(kernel, signal);
01746         break;
01747       case DLR_CONVOLVE_PAD_RESULT:
01748       case DLR_CONVOLVE_ZERO_PAD_RESULT:
01749         return privateCode::correlate2DPadResult<
01750           OutputType, AccumulatorType, KernelType, SignalType>(
01751             kernel, signal, corner0, corner1,
01752             static_cast<OutputType>(fillValue));
01753         break;
01754       case DLR_CONVOLVE_PAD_SIGNAL:
01755         return privateCode::correlate2DPadSignal<
01756           OutputType, AccumulatorType, KernelType, SignalType>(
01757             kernel, signal, corner0, corner1,
01758             static_cast<SignalType>(fillValue));
01759         break;
01760       case DLR_CONVOLVE_ZERO_PAD_SIGNAL:
01761         return privateCode::correlate2DZeroPadSignal<
01762           OutputType, AccumulatorType, KernelType, SignalType>(
01763             kernel, signal, corner0, corner1);
01764         break;
01765       case DLR_CONVOLVE_REFLECT_SIGNAL:
01766         return privateCode::correlate2DReflectSignal<
01767           OutputType, AccumulatorType, KernelType, SignalType>(
01768             kernel, signal, corner0, corner1);
01769         break;
01770       case DLR_CONVOLVE_WRAP_SIGNAL:
01771         return privateCode::correlate2DWrapSignal<
01772           OutputType, AccumulatorType, KernelType, SignalType>(
01773             kernel, signal, corner0, corner1);
01774         break;
01775       default:
01776         DLR_THROW(LogicException, "correlate2D()",
01777                   "Illegal value for strategy argument.");
01778         break;
01779       }
01780       return Array2D<OutputType>();
01781     }
01782     
01783   } // namespace numeric
01784 
01785 } // namespace dlr
01786 
01787 #endif // #ifndef _DLR_NUMERIC_CONVOLVE2D_H_

Generated on Wed Nov 25 00:42:42 2009 for dlrUtilities Utility Library by  doxygen 1.5.8