00001
00055 #ifndef __BILATERAL_FILTER__
00056 #define __BILATERAL_FILTER__
00057
00058 #include <cmath>
00059
00060 #include "array.h"
00061 #include "math_tools.h"
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00081 template <typename Space_weight_function,
00082 typename Data_weight_function>
00083 class Bilateral_filter{
00084
00085 public:
00086
00087 typedef unsigned int size_type;
00088
00089 Bilateral_filter(Space_weight_function& space_w,
00090 Data_weight_function& data_w);
00091
00092
00093 template<typename Data_array>
00094 void pixel_filter(const size_type x,
00095 const size_type y,
00096 const Data_array& data,
00097 typename Data_array::value_type* const result);
00098
00100 template<typename Data_array>
00101 void array_filter(const Data_array& data,
00102 Data_array* const result);
00103
00104
00105 private:
00106
00107 Space_weight_function& space_weight;
00108 Data_weight_function& data_weight;
00109 };
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00124 class Gaussian_space_weight{
00125
00126 public:
00127
00128 typedef unsigned int size_type;
00129 typedef float real_type;
00130
00131 inline Gaussian_space_weight(const real_type sig);
00132
00133 inline size_type far() const;
00134
00135 inline bool is_far(const int dx,const int dy) const;
00136
00137 inline void set_reference_data(const size_type x,
00138 const size_type y);
00139
00140 inline real_type operator()(const size_type x,
00141 const size_type y) const;
00142
00143 private:
00144 const real_type sigma;
00145 const int far_threshold;
00146
00147 size_type x_ref,y_ref;
00148
00150 Array_2D<real_type> weight;
00151 };
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 template <typename Space_weight_function,
00192 typename Data_weight_function>
00193 Bilateral_filter<Space_weight_function,Data_weight_function>::
00194 Bilateral_filter(Space_weight_function& space_w,
00195 Data_weight_function& data_w):
00196 space_weight(space_w),
00197 data_weight(data_w){
00198 }
00199
00200
00201 template <typename Space_weight_function,
00202 typename Data_weight_function>
00203 template <typename Data_array>
00204 void
00205 Bilateral_filter<Space_weight_function,Data_weight_function>::
00206 pixel_filter(const size_type x,
00207 const size_type y,
00208 const Data_array& data,
00209 typename Data_array::value_type* const result){
00210
00211 using namespace Math_tools;
00212
00213 const size_type width = data.x_size();
00214 const size_type height = data.y_size();
00215
00216 const int far = static_cast<int>(space_weight.far());
00217
00218 const size_type x_begin = clamp<int>(0,width-1,static_cast<int>(x)-far);
00219 const size_type x_end = clamp<int>(0,width-1,static_cast<int>(x)+far);
00220
00221 const size_type y_begin = clamp<int>(0,height-1,static_cast<int>(y)-far);
00222 const size_type y_end = clamp<int>(0,height-1,static_cast<int>(y)+far);
00223
00224 real_type weight_sum = 0;
00225 *result *= 0;
00226
00227 space_weight.set_reference_data(x,y);
00228 data_weight.set_reference_data(x,y);
00229
00230 for(size_type i=x_begin;i<=x_end;i++){
00231 for(size_type j=y_begin;j<=y_end;j++){
00232
00233 real_type weight = space_weight(i,j) * data_weight(i,j);
00234 *result += weight * data(i,j);
00235 weight_sum += weight;
00236 }
00237 }
00238
00239 if (weight_sum == 0){
00240 *result = data(x,y);
00241 }
00242 else{
00243 *result /= weight_sum;
00244 }
00245 }
00246
00247
00248
00249 template <typename Space_weight_function,
00250 typename Data_weight_function>
00251 template <typename Data_array>
00252 void
00253 Bilateral_filter<Space_weight_function,Data_weight_function>::
00254 array_filter(const Data_array& data,
00255 Data_array* const result){
00256
00257 const size_type width = data.x_size();
00258 const size_type height = data.y_size();
00259
00260 Data_array target(width,height);
00261
00262 for(size_type x=0;x<width;x++){
00263 for(size_type y=0;y<height;y++){
00264 pixel_filter(x,y,data,&target);
00265 }
00266 }
00267
00268 result->swap(target);
00269 }
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283 Gaussian_space_weight::Gaussian_space_weight(const real_type sig):
00284 sigma(sig),
00285 far_threshold(2*static_cast<int>(sig+1)){
00286
00287
00288 weight.resize(2*far_threshold+1,2*far_threshold+1);
00289
00290 for(int dx=0;dx<=far_threshold;dx++){
00291 for(int dy=0;dy<=far_threshold;dy++){
00292 const real_type x = static_cast<real_type>(dx) / sigma;
00293 const real_type y = static_cast<real_type>(dy) / sigma;
00294 const real_type g = std::exp(-0.5*(x*x+y*y));
00295
00296 weight(far_threshold-dx,far_threshold-dy) = g;
00297 weight(far_threshold+dx,far_threshold-dy) = g;
00298 weight(far_threshold+dx,far_threshold+dy) = g;
00299 weight(far_threshold-dx,far_threshold+dy) = g;
00300 }
00301 }
00302 }
00303
00304
00305
00306 inline Gaussian_space_weight::size_type
00307 Gaussian_space_weight::far() const{
00308
00309 return far_threshold;
00310 }
00311
00312
00313
00314 bool Gaussian_space_weight::is_far(const int dx,const int dy) const{
00315
00316 return
00317 (dx>far_threshold) || (dx<-far_threshold) ||
00318 (dy>far_threshold) || (dy<-far_threshold);
00319 }
00320
00321
00322 void Gaussian_space_weight::set_reference_data(const size_type x,
00323 const size_type y){
00324 x_ref = x;
00325 y_ref = y;
00326 }
00327
00328
00329 Gaussian_space_weight::real_type
00330 Gaussian_space_weight::operator()(const size_type x,
00331 const size_type y) const{
00332
00333 const int dx = static_cast<int>(x_ref) - static_cast<int>(x);
00334 const int dy = static_cast<int>(y_ref) - static_cast<int>(y);
00335
00336 return (is_far(dx,dy) ? 0 : weight(far_threshold+dx,far_threshold+dy));
00337 }
00338
00339 #endif