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
1.5.6