filter.h

Go to the documentation of this file.
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   } // namespace computerVision
00106   
00107 } // namespace dlr
00108 
00109 
00110 /* =============================================================== */
00111 /* Implementation follows.                                         */
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         // Get a pointer to the output image data.
00171         typename Array2D<OUTPUT_TYPE>::iterator resultIterator =
00172           outputImage.begin();
00173 
00174         // Zero untouched rows at the top of the image.
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         // Now process all of the rows which are affected by the
00185         // convolution.
00186         NumericTypeConversionFunctor<KernelType, OUTPUT_TYPE>
00187           numericTypeConversionFunctor;
00188         while(rowIndex < lastAffectedRow) {
00189           // Zero untouched pixels at the beginning of the row.
00190           size_t columnIndex = 0;
00191           while(columnIndex < halfKernelColumns) {
00192             *(resultIterator++) = static_cast<OUTPUT_TYPE>(0);
00193             ++columnIndex;
00194           }
00195 
00196           // Construct an iterator to keep track of where the
00197           // upper-left corner of the kernel falls in the input image.
00198           typename Array2D<INPUT_TYPE>::const_iterator imageIterator =
00199             image.begin() + (rowIndex - halfKernelRows) * imageColumns;
00200 
00201           // Process most of the pixels in the current row.
00202           while(columnIndex < lastAffectedColumn) {
00203               
00204             // Calculate one dot-product between the kernel and the
00205             // current bit of image.
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             // Advance to the next pixel.
00221             ++imageIterator;
00222             ++resultIterator;
00223             ++columnIndex;
00224           }
00225 
00226           // Zero untouched pixels at the end of the row.
00227           while(columnIndex < imageColumns) {
00228             *(resultIterator++) = static_cast<OUTPUT_TYPE>(0);
00229             ++columnIndex;
00230           }
00231 
00232           // Advance to the next row.
00233           ++rowIndex;
00234         }
00235 
00236         // Zero untouched rows at the bottom of the image.
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         // Zero untouched rows at the top of the image.
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         // Now process all of the rows which are affected by the
00301         // convolution.
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           // Advance to the next row.
00341           ++rowIndex;
00342         }
00343 
00344         // Zero untouched rows at the bottom of the image.
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         // Zero out skipped rows.
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         // Get a pointer to the output image data.
00404         typename Array2D<OUTPUT_TYPE>::iterator resultIterator =
00405           outputImage.begin() + skipRows * imageColumns;
00406 
00407         // Now process all of the rows which are affected by the
00408         // convolution.
00409         size_t rowIndex = skipRows;
00410         NumericTypeConversionFunctor<KernelType, OUTPUT_TYPE>
00411           numericTypeConversionFunctor;
00412         while(rowIndex < lastAffectedRow) {
00413           // Zero untouched pixels at the beginning of the row.
00414           size_t columnIndex = 0;
00415           while(columnIndex < halfKernelSize) {
00416             *(resultIterator++) = static_cast<OUTPUT_TYPE>(0);
00417             ++columnIndex;
00418           }
00419 
00420           // Construct an iterator to keep track of where the
00421           // leftmost element of the kernel falls in the input image.
00422           typename Array2D<INPUT_TYPE>::const_iterator imageIterator =
00423             image.begin() + rowIndex * imageColumns;
00424 
00425           // Process most of the pixels in the current row.
00426           while(columnIndex < lastAffectedColumn) {
00427             // Calculate one dot-product between the kernel and the
00428             // current bit of image.
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               // xxx problem here.
00437               dotProduct += *(kernelIterator++) * *(imageIteratorCopy++);
00438             }
00439             *resultIterator = numericTypeConversionFunctor(dotProduct);
00440 
00441             // Advance to the next pixel.
00442             ++imageIterator;
00443             ++resultIterator;
00444             ++columnIndex;
00445           }
00446 
00447           // Zero untouched pixels at the end of the row.
00448           while(columnIndex < imageColumns) {
00449             *(resultIterator++) = static_cast<OUTPUT_TYPE>(0);
00450             ++columnIndex;
00451           }
00452 
00453           // Advance to the next row.
00454           ++rowIndex;
00455         }
00456 
00457         // Zero out skipped rows.
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     } // namespace privateCode
00468 
00469 #endif    
00470 
00471     // This function filters an image with the given kernel.
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       // filter2D<IntermediateFormat>(
00485       filter2D<OutputFormat, IntermediateFormat, ImageFormat, KernelType>(
00486         returnImage, kernel, image, fillValue, convolutionStrategy);
00487       return returnImage;
00488     }
00489     
00490 
00491     // This function filters an image with the given kernel, placing
00492     // the result into a pre-constructed Image instance.
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   } // namespace computerVision
00544   
00545 } // namespace dlr
00546 
00547 
00548 #endif /* #ifndef _DLRCOMPUTERVISION_FILTER_H_ */

Generated on Wed Nov 25 12:15:04 2009 for dlrComputerVision Utility Library by  doxygen 1.5.8