00001
00015 #ifndef _DLRCOMPUTERVISION_FILTER_H_
00016 #define _DLRCOMPUTERVISION_FILTER_H_
00017
00018 #include <dlrComputerVision/image.h>
00019 #include <dlrComputerVision/kernel.h>
00020 #include <dlrNumeric/convolutionStrategy.h>
00021
00022 namespace dlr {
00023
00024 namespace computerVision {
00025
00026
00033 using dlr::numeric::ConvolutionStrategy;
00034 using dlr::numeric::DLR_CONVOLVE_PAD_RESULT;
00035
00057 template<ImageFormat OutputFormat,
00058 ImageFormat IntermediateFormat,
00059 ImageFormat ImageFormat,
00060 class KernelType>
00061 Image<OutputFormat> filter2D(
00062 const Kernel<KernelType>& kernel,
00063 const Image<ImageFormat>& image,
00064 const typename ImageFormatTraits<OutputFormat>::PixelType fillValue,
00065 ConvolutionStrategy convolutionStrategy = DLR_CONVOLVE_PAD_RESULT);
00066
00067
00092 template<ImageFormat OutputFormat,
00093 ImageFormat IntermediateFormat,
00094 ImageFormat ImageFormat,
00095 class KernelType>
00096 void
00097 filter2D(
00098 Image<OutputFormat>& outputImage,
00099 const Kernel<KernelType>& kernel,
00100 const Image<ImageFormat>& image,
00101 const typename ImageFormatTraits<OutputFormat>::PixelType fillValue,
00102 ConvolutionStrategy convolutionStrategy = DLR_CONVOLVE_PAD_RESULT);
00103
00104
00105 }
00106
00107 }
00108
00109
00110
00111
00112
00113
00114
00115 #include <cmath>
00116 #include <dlrNumeric/convolve2D.h>
00117 #include <dlrNumeric/functional.h>
00118
00119 namespace dlr {
00120
00121 namespace computerVision {
00122
00123 #if 0
00124
00126 namespace privateCode {
00127
00128 template<class OUTPUT_TYPE, class INPUT_TYPE, class KernelType>
00129 void
00130 filter2DZeroPad(Array2D<OUTPUT_TYPE>& outputImage,
00131 const Array2D<KernelType>& kernel,
00132 const Array2D<INPUT_TYPE>& image)
00133 {
00134 if(outputImage.rows() != image.rows()
00135 || outputImage.columns() != image.columns()) {
00136 std::ostringstream message;
00137 message << "Size of output image (" << outputImage.rows()
00138 << ", " << outputImage.columns()
00139 << ") does not match size if input image ("
00140 << image.rows() << ", " << image.columns() << ").";
00141 DLR_THROW(ValueException, "filter2DZeroPad()",
00142 message.str().c_str());
00143 }
00144
00145 if((kernel.rows() % 2 != 1) || (kernel.columns() % 2 != 1)) {
00146 std::ostringstream message;
00147 message << "Kernel must have an odd number of rows and columns, "
00148 << "but is (" << kernel.rows() << ", " << kernel.columns()
00149 << ").";
00150 DLR_THROW(ValueException, "filter2DZeroPad()",
00151 message.str().c_str());
00152 }
00153
00154 if((kernel.rows() >= image.rows())
00155 || (kernel.columns() >= image.columns())
00156 || (kernel.size() == 0)) {
00157 outputImage = static_cast<OUTPUT_TYPE>(0);
00158 return;
00159 }
00160
00161 size_t halfKernelColumns = kernel.columns() / 2;
00162 size_t halfKernelRows = kernel.rows() / 2;
00163 size_t imageColumns = image.columns();
00164 size_t imageRows = image.rows();
00165 size_t kernelColumns = kernel.columns();
00166 size_t kernelRows = kernel.rows();
00167 size_t lastAffectedColumn = image.columns() - halfKernelColumns;
00168 size_t lastAffectedRow = image.rows() - halfKernelRows;
00169
00170
00171 typename Array2D<OUTPUT_TYPE>::iterator resultIterator =
00172 outputImage.begin();
00173
00174
00175 size_t rowIndex = 0;
00176 while(rowIndex < halfKernelRows) {
00177 for(size_t columnIndex = 0; columnIndex < image.columns();
00178 ++columnIndex) {
00179 *(resultIterator++) = static_cast<OUTPUT_TYPE>(0);
00180 }
00181 ++rowIndex;
00182 }
00183
00184
00185
00186 NumericTypeConversionFunctor<KernelType, OUTPUT_TYPE>
00187 numericTypeConversionFunctor;
00188 while(rowIndex < lastAffectedRow) {
00189
00190 size_t columnIndex = 0;
00191 while(columnIndex < halfKernelColumns) {
00192 *(resultIterator++) = static_cast<OUTPUT_TYPE>(0);
00193 ++columnIndex;
00194 }
00195
00196
00197
00198 typename Array2D<INPUT_TYPE>::const_iterator imageIterator =
00199 image.begin() + (rowIndex - halfKernelRows) * imageColumns;
00200
00201
00202 while(columnIndex < lastAffectedColumn) {
00203
00204
00205
00206 KernelType dotProduct = static_cast<KernelType>(0);
00207 typename Array2D<INPUT_TYPE>::const_iterator imageIteratorCopy =
00208 imageIterator;
00209 typename Array2D<KernelType>::const_iterator kernelIterator =
00210 kernel.begin();
00211 for(size_t kernelRow = 0; kernelRow < kernelRows; ++kernelRow) {
00212 for(size_t kernelColumn = 0; kernelColumn < kernelColumns;
00213 ++kernelColumn) {
00214 dotProduct += *(kernelIterator++) * *(imageIteratorCopy++);
00215 }
00216 imageIteratorCopy += imageColumns - kernelColumns;
00217 }
00218 *resultIterator = numericTypeConversionFunctor(dotProduct);
00219
00220
00221 ++imageIterator;
00222 ++resultIterator;
00223 ++columnIndex;
00224 }
00225
00226
00227 while(columnIndex < imageColumns) {
00228 *(resultIterator++) = static_cast<OUTPUT_TYPE>(0);
00229 ++columnIndex;
00230 }
00231
00232
00233 ++rowIndex;
00234 }
00235
00236
00237 while(rowIndex < imageRows) {
00238 for(size_t columnIndex = 0; columnIndex < imageColumns;
00239 ++columnIndex) {
00240 *(resultIterator++) = static_cast<OUTPUT_TYPE>(0);
00241 }
00242 ++rowIndex;
00243 }
00244 }
00245
00246
00247
00248 template<class OUTPUT_TYPE, class INPUT_TYPE, class KernelType>
00249 void
00250 filterColumnsZeroPad(Array2D<OUTPUT_TYPE>& outputImage,
00251 const Array1D<KernelType>& kernel,
00252 const Array2D<INPUT_TYPE>& image,
00253 size_t skipColumns=0)
00254 {
00255 if(outputImage.rows() != image.rows()
00256 || outputImage.columns() != image.columns()) {
00257 std::ostringstream message;
00258 message << "Size of output image (" << outputImage.rows()
00259 << ", " << outputImage.columns()
00260 << ") does not match size if input image ("
00261 << image.rows() << ", " << image.columns() << ").";
00262 DLR_THROW(ValueException, "filterColumnsZeroPad()",
00263 message.str().c_str());
00264 }
00265
00266 if(kernel.size() % 2 != 1) {
00267 std::ostringstream message;
00268 message << "Kernel must have an odd number of elements, "
00269 << "but has size of " << kernel.size() << ".";
00270 DLR_THROW(ValueException, "filterColumnsZeroPad()",
00271 message.str().c_str());
00272 }
00273
00274 if((kernel.size() >= image.rows())
00275 || (kernel.size() == 0)) {
00276 outputImage = static_cast<OUTPUT_TYPE>(0);
00277 return;
00278 }
00279
00280 size_t halfKernelSize = kernel.size() / 2;
00281 size_t imageColumns = image.columns();
00282 size_t imageRows = image.rows();
00283 size_t kernelSize = kernel.size();
00284 size_t lastAffectedColumn = imageColumns - skipColumns;
00285 size_t lastAffectedRow = imageRows - halfKernelSize;
00286
00287
00288 Array1D<OUTPUT_TYPE> outputRow;
00289 size_t rowIndex = 0;
00290 while(rowIndex < halfKernelSize) {
00291 outputRow = outputImage.row(rowIndex);
00292 for(size_t columnIndex = skipColumns;
00293 columnIndex < lastAffectedColumn;
00294 ++columnIndex) {
00295 outputRow[columnIndex] = static_cast<OUTPUT_TYPE>(0);
00296 }
00297 ++rowIndex;
00298 }
00299
00300
00301
00302 Array1D<INPUT_TYPE> inputRow;
00303 Array1D<KernelType> accumulator(image.columns());
00304 while(rowIndex < lastAffectedRow) {
00305 outputRow = outputImage.row(rowIndex);
00306 inputRow = image.row(rowIndex - halfKernelSize);
00307
00308 size_t columnIndex0 = 0;
00309 while(columnIndex0 < skipColumns) {
00310 outputRow(columnIndex0) = static_cast<OUTPUT_TYPE>(0);
00311 ++columnIndex0;
00312 }
00313 columnIndex0 = lastAffectedColumn;
00314 while(columnIndex0 < outputImage.columns()) {
00315 outputRow(columnIndex0) = static_cast<OUTPUT_TYPE>(0);
00316 ++columnIndex0;
00317 }
00318
00319 for(size_t columnIndex1 = skipColumns;
00320 columnIndex1 < lastAffectedColumn;
00321 ++columnIndex1) {
00322 accumulator(columnIndex1) = inputRow(columnIndex1) * kernel[0];
00323 }
00324 for(size_t kernelRow = 1; kernelRow < kernelSize; ++kernelRow) {
00325 inputRow = image.row(rowIndex - halfKernelSize + kernelRow);
00326 for(size_t columnIndex2 = skipColumns;
00327 columnIndex2 < lastAffectedColumn;
00328 ++columnIndex2) {
00329 accumulator(columnIndex2) +=
00330 inputRow(columnIndex2) * kernel[kernelRow];
00331 }
00332 }
00333 for(size_t columnIndex3 = skipColumns;
00334 columnIndex3 < lastAffectedColumn;
00335 ++columnIndex3) {
00336 outputRow(columnIndex3) =
00337 static_cast<OUTPUT_TYPE>(accumulator(columnIndex3) + 0.5);
00338 }
00339
00340
00341 ++rowIndex;
00342 }
00343
00344
00345 while(rowIndex < imageRows) {
00346 outputRow = outputImage.row(rowIndex);
00347 for(size_t columnIndex = skipColumns;
00348 columnIndex < lastAffectedColumn;
00349 ++columnIndex) {
00350 outputRow[columnIndex] = static_cast<OUTPUT_TYPE>(0);
00351 }
00352 ++rowIndex;
00353 }
00354 }
00355
00356
00357 template<class OUTPUT_TYPE, class INPUT_TYPE, class KernelType>
00358 void
00359 filterRowsZeroPad(Array2D<OUTPUT_TYPE>& outputImage,
00360 const Array1D<KernelType>& kernel,
00361 const Array2D<INPUT_TYPE>& image,
00362 size_t skipRows=0)
00363 {
00364 if(outputImage.rows() != image.rows()
00365 || outputImage.columns() != image.columns()) {
00366 std::ostringstream message;
00367 message << "Size of output image (" << outputImage.rows()
00368 << ", " << outputImage.columns()
00369 << ") does not match size if input image ("
00370 << image.rows() << ", " << image.columns() << ").";
00371 DLR_THROW(ValueException, "filterRowsZeroPad()",
00372 message.str().c_str());
00373 }
00374
00375 if(kernel.size() % 2 != 1) {
00376 std::ostringstream message;
00377 message << "Kernel must have an odd number of elements, "
00378 << "but has size of " << kernel.size() << ".";
00379 DLR_THROW(ValueException, "filterRowsZeroPad()",
00380 message.str().c_str());
00381 }
00382
00383 if((kernel.size() >= image.columns())
00384 || (kernel.size() == 0)) {
00385 outputImage = static_cast<OUTPUT_TYPE>(0);
00386 return;
00387 }
00388
00389 size_t halfKernelSize = kernel.size() / 2;
00390 size_t imageColumns = image.columns();
00391 size_t imageRows = image.rows();
00392 size_t kernelSize = kernel.size();
00393 size_t lastAffectedColumn = imageColumns - halfKernelSize;
00394 size_t lastAffectedRow = imageRows - skipRows;
00395
00396
00397 for(size_t index0 = 0; index0 < skipRows; ++index0) {
00398 std::fill(outputImage.rowBegin(index0),
00399 outputImage.rowBegin(index0),
00400 static_cast<OUTPUT_TYPE>(0));
00401 }
00402
00403
00404 typename Array2D<OUTPUT_TYPE>::iterator resultIterator =
00405 outputImage.begin() + skipRows * imageColumns;
00406
00407
00408
00409 size_t rowIndex = skipRows;
00410 NumericTypeConversionFunctor<KernelType, OUTPUT_TYPE>
00411 numericTypeConversionFunctor;
00412 while(rowIndex < lastAffectedRow) {
00413
00414 size_t columnIndex = 0;
00415 while(columnIndex < halfKernelSize) {
00416 *(resultIterator++) = static_cast<OUTPUT_TYPE>(0);
00417 ++columnIndex;
00418 }
00419
00420
00421
00422 typename Array2D<INPUT_TYPE>::const_iterator imageIterator =
00423 image.begin() + rowIndex * imageColumns;
00424
00425
00426 while(columnIndex < lastAffectedColumn) {
00427
00428
00429 KernelType dotProduct = static_cast<KernelType>(0);
00430 typename Array2D<INPUT_TYPE>::const_iterator imageIteratorCopy =
00431 imageIterator;
00432 typename Array2D<KernelType>::const_iterator kernelIterator =
00433 kernel.begin();
00434 for(size_t kernelElement = 0; kernelElement < kernelSize;
00435 ++kernelElement) {
00436
00437 dotProduct += *(kernelIterator++) * *(imageIteratorCopy++);
00438 }
00439 *resultIterator = numericTypeConversionFunctor(dotProduct);
00440
00441
00442 ++imageIterator;
00443 ++resultIterator;
00444 ++columnIndex;
00445 }
00446
00447
00448 while(columnIndex < imageColumns) {
00449 *(resultIterator++) = static_cast<OUTPUT_TYPE>(0);
00450 ++columnIndex;
00451 }
00452
00453
00454 ++rowIndex;
00455 }
00456
00457
00458 for(size_t index1 = lastAffectedRow; index1 < outputImage.rows();
00459 ++index1) {
00460 std::fill(outputImage.rowBegin(index1),
00461 outputImage.rowBegin(index1),
00462 static_cast<OUTPUT_TYPE>(0));
00463 }
00464 }
00465
00466 }
00468
00469 #endif
00470
00471
00472 template<ImageFormat OutputFormat,
00473 ImageFormat IntermediateFormat,
00474 ImageFormat ImageFormat,
00475 class KernelType>
00476 Image<OutputFormat>
00477 filter2D(
00478 const Kernel<KernelType>& kernel,
00479 const Image<ImageFormat>& image,
00480 const typename ImageFormatTraits<OutputFormat>::PixelType fillValue,
00481 ConvolutionStrategy convolutionStrategy)
00482 {
00483 Image<OutputFormat> returnImage(image.rows(), image.columns());
00484
00485 filter2D<OutputFormat, IntermediateFormat, ImageFormat, KernelType>(
00486 returnImage, kernel, image, fillValue, convolutionStrategy);
00487 return returnImage;
00488 }
00489
00490
00491
00492
00493 template<ImageFormat OutputFormat,
00494 ImageFormat IntermediateFormat,
00495 ImageFormat ImageFormat,
00496 class KernelType>
00497 void
00498 filter2D(
00499 Image<OutputFormat>& outputImage,
00500 const Kernel<KernelType>& kernel,
00501 const Image<ImageFormat>& image,
00502 const typename ImageFormatTraits<OutputFormat>::PixelType fillValue,
00503 ConvolutionStrategy convolutionStrategy)
00504 {
00505 typedef typename ImageFormatTraits<OutputFormat>::PixelType
00506 OutputPixelType;
00507 typedef typename ImageFormatTraits<IntermediateFormat>::PixelType
00508 IntermediatePixelType;
00509
00510 if(kernel.isSeparable()) {
00511 Array1D<KernelType> kernelRowComponent =
00512 kernel.getRowComponent();
00513 Array1D<KernelType> kernelColumnComponent =
00514 kernel.getColumnComponent();
00515 Array2D<KernelType> rowKernel(
00516 1, kernelRowComponent.size(), kernelRowComponent.data());
00517 Array2D<KernelType> columnKernel(
00518 kernelColumnComponent.size(), 1, kernelColumnComponent.data());
00519
00520 Image<IntermediateFormat> intermediateImage =
00521 numeric::correlate2D<IntermediatePixelType, IntermediatePixelType>(
00522 rowKernel, image,
00523 numeric::DLR_CONVOLVE_PAD_RESULT,
00524 numeric::DLR_CONVOLVE_ROI_SAME,
00525 fillValue);
00526 outputImage =
00527 numeric::correlate2D<OutputPixelType, IntermediatePixelType>(
00528 columnKernel, intermediateImage,
00529 numeric::DLR_CONVOLVE_PAD_RESULT,
00530 numeric::DLR_CONVOLVE_ROI_SAME,
00531 fillValue);
00532 } else {
00533 outputImage =
00534 numeric::correlate2D<OutputPixelType, IntermediatePixelType>(
00535 kernel.getArray2D(), image,
00536 numeric::DLR_CONVOLVE_PAD_RESULT,
00537 numeric::DLR_CONVOLVE_ROI_SAME,
00538 fillValue);
00539 }
00540 }
00541
00542
00543 }
00544
00545 }
00546
00547
00548 #endif