KernelFilter.cpp

Go to the documentation of this file.
00001 /**<!-------------------------------------------------------------------->
00002    @file   KernelFilter.cpp
00003    @author Travis Fischer (fisch0920@gmail.com)
00004    @author Matthew Jacobs (jacobs.mh@gmail.com)
00005    @date   Fall 2008
00006    
00007    @brief
00008       2D discrete, symmetric filter which can be compactly / efficiently 
00009    stored / applied using a 2D kernel (array)
00010    <!-------------------------------------------------------------------->**/
00011 
00012 #include "KernelFilter.h"
00013 #include <filters.h>
00014 
00015 #include <Image.h>
00016 
00017 KernelFilter *KernelFilter::create(const std::string &type, PropertyMap &p) {
00018    // Parse filter from PropertyMap (or defaults)
00019    const unsigned support = p.getValue<unsigned>("support", 2);
00020    
00021    if (type == "box") {
00022       return new BoxFilter(support);
00023    } else if (type == "triangle") {
00024       return new TriangleFilter(support);
00025    } else if (type == "gaussian") {
00026       const real_t sigma = p.getValue<real_t>("sigma", 1.0);
00027       
00028       return new GaussianFilter(support, sigma);
00029    } else if (type == "mitchell") {
00030       const real_t b = p.getValue<real_t>("B", 1.0 / 3.0);
00031       const real_t c = p.getValue<real_t>("C", 1.0 / 3.0);
00032       
00033       return new MitchellFilter(support, b, c);
00034    } else if (type == "lanczosSinc") {
00035       const real_t tau = p.getValue<real_t>("tau", 3.0);
00036       
00037       return new LanczosSincFilter(support, tau);
00038    } else {
00039       cerr << "encountered unexpected filter: " << type << endl;
00040       ASSERT(0 && "encountered unexpected filter");
00041       
00042       return NULL;
00043    }
00044 }
00045 
00046 KernelFilter::~KernelFilter() {
00047    safeDeleteArray(m_kernel);
00048 }
00049 
00050 void KernelFilter::init() {
00051    Filter2D::init();
00052    
00053    if (NULL == m_kernel) {
00054       _computeKernel();
00055       ASSERT(m_kernel);
00056    }
00057 }
00058 
00059 /*
00060 // discretized filter evaluation
00061 real_t KernelFilter::evaluate(const Vector2 &pt) {
00062    if (NULL == m_kernel) {
00063       _computeKernel();
00064       ASSERT(m_kernel);
00065    }
00066    
00067    const int x = floor(pt[0] + m_width / 2.0);
00068    const int y = floor(pt[1] + m_width / 2.0);
00069    
00070    if (x < 0 || x >= m_width || y < 0 || y >= m_width)
00071       return 0;
00072    
00073    return m_kernel[y * m_width + x];
00074 }
00075 */
00076 
00077 void KernelFilter::apply(Image *image) {
00078    ASSERT(image);
00079    
00080    if (NULL == m_kernel) {
00081       _computeKernel();
00082       ASSERT(m_kernel);
00083    }
00084    
00085    const int width  = image->getWidth();
00086    const int height = image->getHeight();
00087    const int size   = image->getSize();
00088    const int half   = (m_width >> 1);
00089    real_t sum = 0, normalizationFactor = 1.0;
00090    Image *temp = image->clone();
00091    
00092    if (!m_isNormalized) {
00093       // Compute cumulative kernel sum
00094       for(unsigned i = m_width * m_width; i--;)
00095          sum += m_kernel[i];
00096       
00097       ASSERT(sum > 0);
00098       normalizationFactor /= sum;
00099    }
00100    
00101    // Apply the kernel to each pixel of the input image
00102    for(int i = height; i--;) {
00103       for(int j = width; j--;) {
00104          real_t *kernel = m_kernel;
00105          RgbaHDR rgb(0, 0, 0);
00106          
00107          // Convolve kernel with current pixel of input image
00108          for(int y = -half; y <= half; ++y) {
00109             int row = CAP(i + y, 0, height - 1);
00110             
00111             for(int x = -half; x <= half; ++x) {
00112                int col = CAP(j + x, 0, width - 1);
00113                
00114                const RgbaHDR &d = image->getPixel<RgbaHDR>(row, col);
00115                real_t weight = *kernel++;
00116                
00117                rgb.r += d.r * weight;
00118                rgb.g += d.g * weight;
00119                rgb.b += d.b * weight;
00120             }
00121          }
00122          
00123          temp->setPixel<RgbaHDR>(i, j, rgb * normalizationFactor);
00124       }
00125    }
00126    
00127    image->copyData(temp);
00128    safeDelete(temp);
00129 }
00130 
00131 RgbaHDR KernelFilter::apply(Image *image, real_t x_, real_t y_) {
00132    ASSERT(image);
00133    
00134    if (NULL == m_kernel) {
00135       _computeKernel();
00136       ASSERT(m_kernel);
00137    }
00138    
00139    int x = floor(x_), y = floor(y_);
00140    const int width  = image->getWidth();
00141    const int height = image->getHeight();
00142    const int half   = (m_width >> 1);
00143    real_t sum = 0, normalizationFactor = 1.0;
00144    
00145    if (!m_isNormalized) {
00146       // Compute cumulative kernel sum
00147       for(int i = m_width * m_width; i--;)
00148          sum += m_kernel[i];
00149       
00150       ASSERT(sum > 0);
00151       normalizationFactor /= sum;
00152    }
00153    
00154    real_t *kernel = m_kernel;
00155    RgbaHDR rgb(0, 0, 0);
00156    
00157    // Convolve kernel at a single location in input image
00158    for(int i = -half; i <= half; ++i) {
00159       int row = CAP(i + y, 0, height - 1);
00160       
00161       for(int j = -half; j <= half; ++j) {
00162          int col = CAP(j + x, 0, width - 1);
00163          
00164          const RgbaHDR &d = image->getPixel<RgbaHDR>(row, col);
00165          real_t weight = *kernel++;
00166          
00167          rgb.r += d.r * weight;
00168          rgb.g += d.g * weight;
00169          rgb.b += d.b * weight;
00170       }
00171    }
00172    
00173    rgb *= normalizationFactor;
00174    return rgb;
00175 }
00176 
00177 void KernelFilter::_computeKernel() {
00178    const real_t half = m_width / 2.0;
00179    ASSERT(m_width > 0);
00180    
00181    safeDeleteArray(m_kernel);
00182    m_kernel = new real_t[getSize()];
00183    
00184    for(unsigned i = m_width; i--;) {
00185       for(unsigned j = m_width; j--;) {
00186          const real_t val = evaluate(Vector2(i - half, j - half));
00187          
00188          m_kernel[i * m_width + j] = val;
00189       }
00190    }
00191 }
00192 

Generated on 28 Feb 2009 for Milton by doxygen 1.5.6