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 }
00115
00116 }
00117
00118
00119
00120
00121 #include <algorithm>
00122 #include <numeric>
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
00151 Array2D<KernelSumType> accumulatedKernel(
00152 kernel.rows() + 1, kernel.columns() + 1);
00153 std::partial_sum(tempKernel.begin(), tempKernel.end(),
00154 accumulatedKernel.begin());
00155
00156
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
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
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
00437 while(kernelIter != kernelMiddle) {
00438 dotProduct += static_cast<AccumulatorType>(
00439 *kernelIter * static_cast<AccumulatorType>(*signalIter));
00440 ++kernelIter;
00441 ++signalIter;
00442 }
00443
00444
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
00498 if(kernel.rows() > signal.rows()
00499 || kernel.columns() > signal.columns()) {
00500 result = fillValue;
00501 return result;
00502 }
00503
00504
00505
00506
00507
00508 const int kRowOverTwo = static_cast<int>(kernel.rows()) / 2;
00509 const int kColOverTwo = static_cast<int>(kernel.columns()) / 2;
00510
00511
00512
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
00533
00534 const int resultTransitionRow0 =
00535 clippedTransitionRow0 - startRow;
00536 const int resultTransitionColumn0 =
00537 clippedTransitionColumn0 - startColumn;
00538
00539
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
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
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
00595 const int kRowOverTwo = static_cast<int>(kernel.rows()) / 2;
00596 const int kColOverTwo = static_cast<int>(kernel.columns()) / 2;
00597
00598
00599
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
00620 int row = startRow;
00621 int outputRow = 0;
00622 while(row < clippedTransitionRow0) {
00623
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
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
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
00661 while(row < clippedTransitionRow1) {
00662
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
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
00693 while(row < stopRow) {
00694
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
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
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
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
00760
00761
00762 Array2D<AccumulatorType> accumulatedKernel =
00763 doubleAccumulateKernel<AccumulatorType, KernelType, SignalType>(
00764 kernel, fillValue);
00765
00766
00767 const int kRowOverTwo = static_cast<int>(kernel.rows()) / 2;
00768 const int kColOverTwo = static_cast<int>(kernel.columns()) / 2;
00769
00770
00771
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
00792 int row = startRow;
00793 int outputRow = 0;
00794 while(row < clippedTransitionRow0) {
00795
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
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
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
00851 while(row < clippedTransitionRow1) {
00852
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
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
00891 while(row < stopRow) {
00892
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
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
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
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
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
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
00988 const int kRowOverTwo = static_cast<int>(kernel.rows()) / 2;
00989 const int kColOverTwo = static_cast<int>(kernel.columns()) / 2;
00990
00991
00992
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
01013 int row = startRow;
01014 int outputRow = 0;
01015 while(row < clippedTransitionRow0) {
01016
01017
01018 size_t kernelStartRow = transitionRow0 - row;
01019
01020
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
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
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
01077 while(row < clippedTransitionRow1) {
01078
01079
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
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
01108 while(row < stopRow) {
01109
01110
01111 size_t kernelStopRow = signal.rows() - row + kRowOverTwo;
01112 size_t kernelStopRowUD = kernel.rows() - kernelStopRow;
01113
01114
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
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
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
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
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
01202 const int kRowOverTwo = static_cast<int>(kernel.rows()) / 2;
01203 const int kColOverTwo = static_cast<int>(kernel.columns()) / 2;
01204
01205
01206
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
01227 int row = startRow;
01228 int outputRow = 0;
01229 Array1D<AccumulatorType> accumulator(result.columns());
01230 while(row < clippedTransitionRow0) {
01231
01232
01233 size_t kernelStartRow = transitionRow0 - row;
01234
01235
01236
01237 int outputColumn = 0;
01238 for(int column = startColumn; column < clippedTransitionColumn0;
01239 ++column) {
01240
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
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
01261
01262 outputColumn = clippedTransitionColumn0 - startColumn;
01263 for(int column = clippedTransitionColumn0;
01264 column < clippedTransitionColumn1;
01265 ++column) {
01266
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
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
01289
01290
01291
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
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
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
01329 while(row < clippedTransitionRow1) {
01330
01331
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
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
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
01372 size_t kernelStartRow = transitionRow0 - row + signal.rows();
01373
01374
01375
01376 int outputColumn = 0;
01377 for(int column = startColumn; column < clippedTransitionColumn0;
01378 ++column) {
01379
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
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
01400
01401 outputColumn = clippedTransitionColumn0 - startColumn;
01402 for(int column = clippedTransitionColumn0;
01403 column < clippedTransitionColumn1;
01404 ++column) {
01405
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
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
01428
01429
01430
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
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
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
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 }
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
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
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 }
01784
01785 }
01786
01787 #endif // #ifndef _DLR_NUMERIC_CONVOLVE2D_H_