1 //---------------------------------------------------------------------------- 2 // Anti-Grain Geometry - Version 2.4 3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) 4 // 5 // Permission to copy, use, modify, sell and distribute this software 6 // is granted provided this copyright notice appears in all copies. 7 // This software is provided "as is" without express or implied 8 // warranty, and with no claim as to its suitability for any purpose. 9 // 10 //---------------------------------------------------------------------------- 11 // Contact: mcseem@antigrain.com 12 // mcseemagg@yahoo.com 13 // http://www.antigrain.com 14 //---------------------------------------------------------------------------- 15 // 16 // Image transformation filters, 17 // Filtering classes (image_filter_lut, image_filter), 18 // Basic filter shape classes 19 //---------------------------------------------------------------------------- 20 #ifndef AGG_IMAGE_FILTERS_INCLUDED 21 #define AGG_IMAGE_FILTERS_INCLUDED 22 23 #include "agg_array.h" 24 #include "agg_math.h" 25 26 namespace agg 27 { 28 29 // See Implementation agg_image_filters.cpp 30 31 enum image_filter_scale_e 32 { 33 image_filter_shift = 14, //----image_filter_shift 34 image_filter_scale = 1 << image_filter_shift, //----image_filter_scale 35 image_filter_mask = image_filter_scale - 1 //----image_filter_mask 36 }; 37 38 enum image_subpixel_scale_e 39 { 40 image_subpixel_shift = 8, //----image_subpixel_shift 41 image_subpixel_scale = 1 << image_subpixel_shift, //----image_subpixel_scale 42 image_subpixel_mask = image_subpixel_scale - 1 //----image_subpixel_mask 43 }; 44 45 46 //-----------------------------------------------------image_filter_lut 47 class image_filter_lut 48 { 49 public: 50 template<class FilterF> void calculate(const FilterF& filter, 51 bool normalization=true) 52 { 53 double r = filter.radius(); 54 realloc_lut(r); 55 unsigned i; 56 unsigned pivot = diameter() << (image_subpixel_shift - 1); 57 for(i = 0; i < pivot; i++) 58 { 59 double x = double(i) / double(image_subpixel_scale); 60 double y = filter.calc_weight(x); 61 m_weight_array[pivot + i] = 62 m_weight_array[pivot - i] = (int16)iround(y * image_filter_scale); 63 } 64 unsigned end = (diameter() << image_subpixel_shift) - 1; 65 m_weight_array[0] = m_weight_array[end]; 66 if(normalization) 67 { 68 normalize(); 69 } 70 } 71 image_filter_lut()72 image_filter_lut() : m_radius(0), m_diameter(0), m_start(0) {} 73 74 template<class FilterF> image_filter_lut(const FilterF& filter, 75 bool normalization=true) 76 { 77 calculate(filter, normalization); 78 } 79 radius()80 double radius() const { return m_radius; } diameter()81 unsigned diameter() const { return m_diameter; } start()82 int start() const { return m_start; } weight_array()83 const int16* weight_array() const { return &m_weight_array[0]; } 84 void normalize(); 85 86 private: 87 void realloc_lut(double radius); 88 image_filter_lut(const image_filter_lut&); 89 const image_filter_lut& operator = (const image_filter_lut&); 90 91 double m_radius; 92 unsigned m_diameter; 93 int m_start; 94 pod_array<int16> m_weight_array; 95 }; 96 97 98 99 //--------------------------------------------------------image_filter 100 template<class FilterF> class image_filter : public image_filter_lut 101 { 102 public: image_filter()103 image_filter() 104 { 105 calculate(m_filter_function); 106 } 107 private: 108 FilterF m_filter_function; 109 }; 110 111 112 //-----------------------------------------------image_filter_bilinear 113 struct image_filter_bilinear 114 { radiusimage_filter_bilinear115 static double radius() { return 1.0; } calc_weightimage_filter_bilinear116 static double calc_weight(double x) 117 { 118 return 1.0 - x; 119 } 120 }; 121 122 123 //-----------------------------------------------image_filter_hanning 124 struct image_filter_hanning 125 { radiusimage_filter_hanning126 static double radius() { return 1.0; } calc_weightimage_filter_hanning127 static double calc_weight(double x) 128 { 129 return 0.5 + 0.5 * cos(pi * x); 130 } 131 }; 132 133 134 //-----------------------------------------------image_filter_hamming 135 struct image_filter_hamming 136 { radiusimage_filter_hamming137 static double radius() { return 1.0; } calc_weightimage_filter_hamming138 static double calc_weight(double x) 139 { 140 return 0.54 + 0.46 * cos(pi * x); 141 } 142 }; 143 144 //-----------------------------------------------image_filter_hermite 145 struct image_filter_hermite 146 { radiusimage_filter_hermite147 static double radius() { return 1.0; } calc_weightimage_filter_hermite148 static double calc_weight(double x) 149 { 150 return (2.0 * x - 3.0) * x * x + 1.0; 151 } 152 }; 153 154 //------------------------------------------------image_filter_quadric 155 struct image_filter_quadric 156 { radiusimage_filter_quadric157 static double radius() { return 1.5; } calc_weightimage_filter_quadric158 static double calc_weight(double x) 159 { 160 double t; 161 if(x < 0.5) return 0.75 - x * x; 162 if(x < 1.5) {t = x - 1.5; return 0.5 * t * t;} 163 return 0.0; 164 } 165 }; 166 167 //------------------------------------------------image_filter_bicubic 168 class image_filter_bicubic 169 { pow3(double x)170 static double pow3(double x) 171 { 172 return (x <= 0.0) ? 0.0 : x * x * x; 173 } 174 175 public: radius()176 static double radius() { return 2.0; } calc_weight(double x)177 static double calc_weight(double x) 178 { 179 return 180 (1.0/6.0) * 181 (pow3(x + 2) - 4 * pow3(x + 1) + 6 * pow3(x) - 4 * pow3(x - 1)); 182 } 183 }; 184 185 //-------------------------------------------------image_filter_kaiser 186 class image_filter_kaiser 187 { 188 double a; 189 double i0a; 190 double epsilon; 191 192 public: 193 image_filter_kaiser(double b = 6.33) : a(b)194 a(b), epsilon(1e-12) 195 { 196 i0a = 1.0 / bessel_i0(b); 197 } 198 radius()199 static double radius() { return 1.0; } calc_weight(double x)200 double calc_weight(double x) const 201 { 202 return bessel_i0(a * sqrt(1. - x * x)) * i0a; 203 } 204 205 private: bessel_i0(double x)206 double bessel_i0(double x) const 207 { 208 int i; 209 double sum, y, t; 210 211 sum = 1.; 212 y = x * x / 4.; 213 t = y; 214 215 for(i = 2; t > epsilon; i++) 216 { 217 sum += t; 218 t *= (double)y / (i * i); 219 } 220 return sum; 221 } 222 }; 223 224 //----------------------------------------------image_filter_catrom 225 struct image_filter_catrom 226 { radiusimage_filter_catrom227 static double radius() { return 2.0; } calc_weightimage_filter_catrom228 static double calc_weight(double x) 229 { 230 if(x < 1.0) return 0.5 * (2.0 + x * x * (-5.0 + x * 3.0)); 231 if(x < 2.0) return 0.5 * (4.0 + x * (-8.0 + x * (5.0 - x))); 232 return 0.; 233 } 234 }; 235 236 //---------------------------------------------image_filter_mitchell 237 class image_filter_mitchell 238 { 239 double p0, p2, p3; 240 double q0, q1, q2, q3; 241 242 public: 243 image_filter_mitchell(double b = 1.0/3.0, double c = 1.0/3.0) : 244 p0((6.0 - 2.0 * b) / 6.0), 245 p2((-18.0 + 12.0 * b + 6.0 * c) / 6.0), 246 p3((12.0 - 9.0 * b - 6.0 * c) / 6.0), 247 q0((8.0 * b + 24.0 * c) / 6.0), 248 q1((-12.0 * b - 48.0 * c) / 6.0), 249 q2((6.0 * b + 30.0 * c) / 6.0), 250 q3((-b - 6.0 * c) / 6.0) 251 {} 252 radius()253 static double radius() { return 2.0; } calc_weight(double x)254 double calc_weight(double x) const 255 { 256 if(x < 1.0) return p0 + x * x * (p2 + x * p3); 257 if(x < 2.0) return q0 + x * (q1 + x * (q2 + x * q3)); 258 return 0.0; 259 } 260 }; 261 262 263 //----------------------------------------------image_filter_spline16 264 struct image_filter_spline16 265 { radiusimage_filter_spline16266 static double radius() { return 2.0; } calc_weightimage_filter_spline16267 static double calc_weight(double x) 268 { 269 if(x < 1.0) 270 { 271 return ((x - 9.0/5.0 ) * x - 1.0/5.0 ) * x + 1.0; 272 } 273 return ((-1.0/3.0 * (x-1) + 4.0/5.0) * (x-1) - 7.0/15.0 ) * (x-1); 274 } 275 }; 276 277 278 //---------------------------------------------image_filter_spline36 279 struct image_filter_spline36 280 { radiusimage_filter_spline36281 static double radius() { return 3.0; } calc_weightimage_filter_spline36282 static double calc_weight(double x) 283 { 284 if(x < 1.0) 285 { 286 return ((13.0/11.0 * x - 453.0/209.0) * x - 3.0/209.0) * x + 1.0; 287 } 288 if(x < 2.0) 289 { 290 return ((-6.0/11.0 * (x-1) + 270.0/209.0) * (x-1) - 156.0/ 209.0) * (x-1); 291 } 292 return ((1.0/11.0 * (x-2) - 45.0/209.0) * (x-2) + 26.0/209.0) * (x-2); 293 } 294 }; 295 296 297 //----------------------------------------------image_filter_gaussian 298 struct image_filter_gaussian 299 { radiusimage_filter_gaussian300 static double radius() { return 2.0; } calc_weightimage_filter_gaussian301 static double calc_weight(double x) 302 { 303 return exp(-2.0 * x * x) * sqrt(2.0 / pi); 304 } 305 }; 306 307 308 //------------------------------------------------image_filter_bessel 309 struct image_filter_bessel 310 { radiusimage_filter_bessel311 static double radius() { return 3.2383; } calc_weightimage_filter_bessel312 static double calc_weight(double x) 313 { 314 return (x == 0.0) ? pi / 4.0 : besj(pi * x, 1) / (2.0 * x); 315 } 316 }; 317 318 319 //-------------------------------------------------image_filter_sinc 320 class image_filter_sinc 321 { 322 public: image_filter_sinc(double r)323 image_filter_sinc(double r) : m_radius(r < 2.0 ? 2.0 : r) {} radius()324 double radius() const { return m_radius; } calc_weight(double x)325 double calc_weight(double x) const 326 { 327 if(x == 0.0) return 1.0; 328 x *= pi; 329 return sin(x) / x; 330 } 331 private: 332 double m_radius; 333 }; 334 335 336 //-----------------------------------------------image_filter_lanczos 337 class image_filter_lanczos 338 { 339 public: image_filter_lanczos(double r)340 image_filter_lanczos(double r) : m_radius(r < 2.0 ? 2.0 : r) {} radius()341 double radius() const { return m_radius; } calc_weight(double x)342 double calc_weight(double x) const 343 { 344 if(x == 0.0) return 1.0; 345 if(x > m_radius) return 0.0; 346 x *= pi; 347 double xr = x / m_radius; 348 return (sin(x) / x) * (sin(xr) / xr); 349 } 350 private: 351 double m_radius; 352 }; 353 354 355 //----------------------------------------------image_filter_blackman 356 class image_filter_blackman 357 { 358 public: image_filter_blackman(double r)359 image_filter_blackman(double r) : m_radius(r < 2.0 ? 2.0 : r) {} radius()360 double radius() const { return m_radius; } calc_weight(double x)361 double calc_weight(double x) const 362 { 363 if(x == 0.0) return 1.0; 364 if(x > m_radius) return 0.0; 365 x *= pi; 366 double xr = x / m_radius; 367 return (sin(x) / x) * (0.42 + 0.5*cos(xr) + 0.08*cos(2*xr)); 368 } 369 private: 370 double m_radius; 371 }; 372 373 //------------------------------------------------image_filter_sinc36 374 class image_filter_sinc36 : public image_filter_sinc image_filter_sinc36()375 { public: image_filter_sinc36() : image_filter_sinc(3.0){} }; 376 377 //------------------------------------------------image_filter_sinc64 378 class image_filter_sinc64 : public image_filter_sinc image_filter_sinc64()379 { public: image_filter_sinc64() : image_filter_sinc(4.0){} }; 380 381 //-----------------------------------------------image_filter_sinc100 382 class image_filter_sinc100 : public image_filter_sinc image_filter_sinc100()383 { public: image_filter_sinc100() : image_filter_sinc(5.0){} }; 384 385 //-----------------------------------------------image_filter_sinc144 386 class image_filter_sinc144 : public image_filter_sinc image_filter_sinc144()387 { public: image_filter_sinc144() : image_filter_sinc(6.0){} }; 388 389 //-----------------------------------------------image_filter_sinc196 390 class image_filter_sinc196 : public image_filter_sinc image_filter_sinc196()391 { public: image_filter_sinc196() : image_filter_sinc(7.0){} }; 392 393 //-----------------------------------------------image_filter_sinc256 394 class image_filter_sinc256 : public image_filter_sinc image_filter_sinc256()395 { public: image_filter_sinc256() : image_filter_sinc(8.0){} }; 396 397 //---------------------------------------------image_filter_lanczos36 398 class image_filter_lanczos36 : public image_filter_lanczos image_filter_lanczos36()399 { public: image_filter_lanczos36() : image_filter_lanczos(3.0){} }; 400 401 //---------------------------------------------image_filter_lanczos64 402 class image_filter_lanczos64 : public image_filter_lanczos image_filter_lanczos64()403 { public: image_filter_lanczos64() : image_filter_lanczos(4.0){} }; 404 405 //--------------------------------------------image_filter_lanczos100 406 class image_filter_lanczos100 : public image_filter_lanczos image_filter_lanczos100()407 { public: image_filter_lanczos100() : image_filter_lanczos(5.0){} }; 408 409 //--------------------------------------------image_filter_lanczos144 410 class image_filter_lanczos144 : public image_filter_lanczos image_filter_lanczos144()411 { public: image_filter_lanczos144() : image_filter_lanczos(6.0){} }; 412 413 //--------------------------------------------image_filter_lanczos196 414 class image_filter_lanczos196 : public image_filter_lanczos image_filter_lanczos196()415 { public: image_filter_lanczos196() : image_filter_lanczos(7.0){} }; 416 417 //--------------------------------------------image_filter_lanczos256 418 class image_filter_lanczos256 : public image_filter_lanczos image_filter_lanczos256()419 { public: image_filter_lanczos256() : image_filter_lanczos(8.0){} }; 420 421 //--------------------------------------------image_filter_blackman36 422 class image_filter_blackman36 : public image_filter_blackman image_filter_blackman36()423 { public: image_filter_blackman36() : image_filter_blackman(3.0){} }; 424 425 //--------------------------------------------image_filter_blackman64 426 class image_filter_blackman64 : public image_filter_blackman image_filter_blackman64()427 { public: image_filter_blackman64() : image_filter_blackman(4.0){} }; 428 429 //-------------------------------------------image_filter_blackman100 430 class image_filter_blackman100 : public image_filter_blackman image_filter_blackman100()431 { public: image_filter_blackman100() : image_filter_blackman(5.0){} }; 432 433 //-------------------------------------------image_filter_blackman144 434 class image_filter_blackman144 : public image_filter_blackman image_filter_blackman144()435 { public: image_filter_blackman144() : image_filter_blackman(6.0){} }; 436 437 //-------------------------------------------image_filter_blackman196 438 class image_filter_blackman196 : public image_filter_blackman image_filter_blackman196()439 { public: image_filter_blackman196() : image_filter_blackman(7.0){} }; 440 441 //-------------------------------------------image_filter_blackman256 442 class image_filter_blackman256 : public image_filter_blackman image_filter_blackman256()443 { public: image_filter_blackman256() : image_filter_blackman(8.0){} }; 444 445 446 } 447 448 #endif 449