00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include <pandabase.h>
00040 #include <math.h>
00041 #include <cmath.h>
00042
00043 #include "pnmImage.h"
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 typedef double WorkType;
00079 typedef float StoreType;
00080 static const WorkType source_max = 1.0;
00081 static const WorkType filter_max = 1.0;
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111 static void
00112 filter_row(StoreType dest[], int dest_len,
00113 const StoreType source[], int source_len,
00114 double scale,
00115 const WorkType filter[],
00116 double filter_width) {
00117
00118
00119
00120
00121 double iscale = max(scale, 1.0);
00122
00123
00124
00125
00126 int offset = (int)cfloor(iscale*0.5);
00127
00128 for (int dest_x=0; dest_x<dest_len; dest_x++) {
00129 double center = (dest_x-offset)/scale;
00130
00131
00132
00133
00134 int left = max((int)cfloor(center - filter_width), 0);
00135 int right = min((int)cceil(center + filter_width), source_len-1);
00136
00137
00138
00139 int right_center = (int)cceil(center);
00140
00141 WorkType net_weight = 0;
00142 WorkType net_value = 0;
00143
00144 int index, source_x;
00145
00146
00147
00148
00149 for (source_x=left; source_x<right_center; source_x++) {
00150 index = (int)(iscale*(center-source_x));
00151 net_value += filter[index] * source[source_x];
00152 net_weight += filter[index];
00153 }
00154
00155 for (; source_x<=right; source_x++) {
00156 index = (int)(iscale*(source_x-center));
00157 net_value += filter[index] * source[source_x];
00158 net_weight += filter[index];
00159 }
00160
00161 if (net_weight>0) {
00162 dest[dest_x] = (StoreType)(net_value / net_weight);
00163 } else {
00164 dest[dest_x] = 0;
00165 }
00166 }
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 typedef void FilterFunction(double scale, double width,
00181 WorkType *&filter, double &filter_width);
00182
00183 static void
00184 box_filter_impl(double scale, double width,
00185 WorkType *&filter, double &filter_width) {
00186 double fscale;
00187 if (scale < 1.0) {
00188
00189
00190
00191 fscale = 1.0 / scale;
00192 } else {
00193
00194
00195
00196
00197 fscale = scale;
00198 }
00199 filter_width = width;
00200 int actual_width = (int)cceil((filter_width+1) * fscale);
00201
00202 filter = new WorkType[actual_width];
00203
00204 for (int i=0; i<actual_width; i++) {
00205 filter[i] = (i<=filter_width*fscale) ? filter_max : 0;
00206 }
00207 }
00208
00209 static void
00210 gaussian_filter_impl(double scale, double width,
00211 WorkType *&filter, double &filter_width) {
00212 double fscale;
00213 if (scale < 1.0) {
00214
00215
00216
00217 fscale = 1.0 / scale;
00218 } else {
00219
00220
00221
00222
00223 fscale = scale;
00224 }
00225 double sigma = width/2;
00226 filter_width = 3.0 * sigma;
00227 int actual_width = (int)cceil((filter_width+1) * fscale);
00228
00229
00230
00231
00232
00233
00234
00235 filter = new WorkType[actual_width];
00236 double div = 2*sigma*sigma;
00237
00238 for (int i=0; i<actual_width; i++) {
00239 double x = i/fscale;
00240 filter[i] = (WorkType)(filter_max * exp(-x*x / div));
00241
00242
00243
00244 }
00245 }
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 #define FUNCTION_NAME filter_red_xy
00273 #define ASIZE get_x_size
00274 #define BSIZE get_y_size
00275 #define GETVAL(a, b) get_red(a, b)
00276 #define SETVAL(a, b, v) set_red(a, b, v)
00277 #include "pnm-image-filter-core.cxx"
00278 #undef SETVAL
00279 #undef GETVAL
00280 #undef BSIZE
00281 #undef ASIZE
00282 #undef FUNCTION_NAME
00283
00284 #define FUNCTION_NAME filter_green_xy
00285 #define ASIZE get_x_size
00286 #define BSIZE get_y_size
00287 #define GETVAL(a, b) get_green(a, b)
00288 #define SETVAL(a, b, v) set_green(a, b, v)
00289 #include "pnm-image-filter-core.cxx"
00290 #undef SETVAL
00291 #undef GETVAL
00292 #undef BSIZE
00293 #undef ASIZE
00294 #undef FUNCTION_NAME
00295
00296 #define FUNCTION_NAME filter_blue_xy
00297 #define ASIZE get_x_size
00298 #define BSIZE get_y_size
00299 #define GETVAL(a, b) get_blue(a, b)
00300 #define SETVAL(a, b, v) set_blue(a, b, v)
00301 #include "pnm-image-filter-core.cxx"
00302 #undef SETVAL
00303 #undef GETVAL
00304 #undef BSIZE
00305 #undef ASIZE
00306 #undef FUNCTION_NAME
00307
00308 #define FUNCTION_NAME filter_gray_xy
00309 #define ASIZE get_x_size
00310 #define BSIZE get_y_size
00311 #define GETVAL(a, b) get_bright(a, b)
00312 #define SETVAL(a, b, v) set_xel(a, b, v)
00313 #include "pnm-image-filter-core.cxx"
00314 #undef SETVAL
00315 #undef GETVAL
00316 #undef BSIZE
00317 #undef ASIZE
00318 #undef FUNCTION_NAME
00319
00320 #define FUNCTION_NAME filter_alpha_xy
00321 #define ASIZE get_x_size
00322 #define BSIZE get_y_size
00323 #define GETVAL(a, b) get_alpha(a, b)
00324 #define SETVAL(a, b, v) set_alpha(a, b, v)
00325 #include "pnm-image-filter-core.cxx"
00326 #undef SETVAL
00327 #undef GETVAL
00328 #undef BSIZE
00329 #undef ASIZE
00330 #undef FUNCTION_NAME
00331
00332
00333
00334
00335 #define FUNCTION_NAME filter_red_yx
00336 #define ASIZE get_y_size
00337 #define BSIZE get_x_size
00338 #define GETVAL(a, b) get_red(b, a)
00339 #define SETVAL(a, b, v) set_red(b, a, v)
00340 #include "pnm-image-filter-core.cxx"
00341 #undef SETVAL
00342 #undef GETVAL
00343 #undef BSIZE
00344 #undef ASIZE
00345 #undef FUNCTION_NAME
00346
00347 #define FUNCTION_NAME filter_green_yx
00348 #define ASIZE get_y_size
00349 #define BSIZE get_x_size
00350 #define GETVAL(a, b) get_green(b, a)
00351 #define SETVAL(a, b, v) set_green(b, a, v)
00352 #include "pnm-image-filter-core.cxx"
00353 #undef SETVAL
00354 #undef GETVAL
00355 #undef BSIZE
00356 #undef ASIZE
00357 #undef FUNCTION_NAME
00358
00359 #define FUNCTION_NAME filter_blue_yx
00360 #define ASIZE get_y_size
00361 #define BSIZE get_x_size
00362 #define GETVAL(a, b) get_blue(b, a)
00363 #define SETVAL(a, b, v) set_blue(b, a, v)
00364 #include "pnm-image-filter-core.cxx"
00365 #undef SETVAL
00366 #undef GETVAL
00367 #undef BSIZE
00368 #undef ASIZE
00369 #undef FUNCTION_NAME
00370
00371 #define FUNCTION_NAME filter_gray_yx
00372 #define ASIZE get_y_size
00373 #define BSIZE get_x_size
00374 #define GETVAL(a, b) get_bright(b, a)
00375 #define SETVAL(a, b, v) set_xel(b, a, v)
00376 #include "pnm-image-filter-core.cxx"
00377 #undef SETVAL
00378 #undef GETVAL
00379 #undef BSIZE
00380 #undef ASIZE
00381 #undef FUNCTION_NAME
00382
00383 #define FUNCTION_NAME filter_alpha_yx
00384 #define ASIZE get_y_size
00385 #define BSIZE get_x_size
00386 #define GETVAL(a, b) get_alpha(b, a)
00387 #define SETVAL(a, b, v) set_alpha(b, a, v)
00388 #include "pnm-image-filter-core.cxx"
00389 #undef SETVAL
00390 #undef GETVAL
00391 #undef BSIZE
00392 #undef ASIZE
00393 #undef FUNCTION_NAME
00394
00395
00396
00397
00398 static void
00399 filter_image(PNMImage &dest, const PNMImage &source,
00400 double width, FilterFunction *make_filter) {
00401
00402
00403
00404
00405 if (dest.get_x_size() <= dest.get_y_size()) {
00406 if (dest.is_grayscale() || source.is_grayscale()) {
00407 filter_gray_xy(dest, source, width, make_filter);
00408 } else {
00409 filter_red_xy(dest, source, width, make_filter);
00410 filter_green_xy(dest, source, width, make_filter);
00411 filter_blue_xy(dest, source, width, make_filter);
00412 }
00413
00414 if (dest.has_alpha() && source.has_alpha()) {
00415 filter_alpha_xy(dest, source, width, make_filter);
00416 }
00417
00418 } else {
00419 if (dest.is_grayscale() || source.is_grayscale()) {
00420 filter_gray_yx(dest, source, width, make_filter);
00421 } else {
00422 filter_red_yx(dest, source, width, make_filter);
00423 filter_green_yx(dest, source, width, make_filter);
00424 filter_blue_yx(dest, source, width, make_filter);
00425 }
00426
00427 if (dest.has_alpha() && source.has_alpha()) {
00428 filter_alpha_yx(dest, source, width, make_filter);
00429 }
00430 }
00431 }
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444 void PNMImage::
00445 box_filter_from(double width, const PNMImage ©) {
00446 filter_image(*this, copy, width, &box_filter_impl);
00447 }
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458 void PNMImage::
00459 gaussian_filter_from(double width, const PNMImage ©) {
00460 filter_image(*this, copy, width, &gaussian_filter_impl);
00461 }
00462
00463
00464
00465
00466
00467
00468 INLINE void
00469 box_filter_xel(const PNMImage &image,
00470 int x, int y, double x_contrib, double y_contrib,
00471 double &red, double &grn, double &blu, double &alpha,
00472 double &pixel_count) {
00473 double contrib = x_contrib * y_contrib;
00474 red += image.get_red_val(x, y) * contrib;
00475 grn += image.get_green_val(x, y) * contrib;
00476 blu += image.get_blue_val(x, y) * contrib;
00477 if (image.has_alpha()) {
00478 alpha += image.get_alpha_val(x, y) * contrib;
00479 }
00480
00481 pixel_count += contrib;
00482 }
00483
00484
00485 INLINE void
00486 box_filter_line(const PNMImage &image,
00487 double x0, int y, double x1, double y_contrib,
00488 double &red, double &grn, double &blu, double &alpha,
00489 double &pixel_count) {
00490 int x = (int)x0;
00491
00492 box_filter_xel(image, x, y, (double)(x+1)-x0, y_contrib,
00493 red, grn, blu, alpha, pixel_count);
00494
00495 int x_last = (int)x1;
00496 if (x < x_last) {
00497 x++;
00498 while (x < x_last) {
00499
00500 box_filter_xel(image, x, y, 1.0, y_contrib,
00501 red, grn, blu, alpha, pixel_count);
00502 x++;
00503 }
00504
00505
00506 double x_contrib = x1 - (double)x_last;
00507 if (x_contrib > 0.0001) {
00508 box_filter_xel(image, x, y, x_contrib, y_contrib,
00509 red, grn, blu, alpha, pixel_count);
00510 }
00511 }
00512 }
00513
00514 static void
00515 box_filter_region(const PNMImage &image,
00516 double x0, double y0, double x1, double y1,
00517 xel &result, xelval &alpha_result) {
00518 double red = 0.0, grn = 0.0, blu = 0.0, alpha = 0.0;
00519 double pixel_count = 0.0;
00520
00521 assert(y0 >=0 && y1 >=0);
00522
00523 int y = (int)y0;
00524
00525 box_filter_line(image, x0, y, x1, (double)(y+1)-y0,
00526 red, grn, blu, alpha, pixel_count);
00527
00528 int y_last = (int)y1;
00529 if (y < y_last) {
00530 y++;
00531 while (y < y_last) {
00532
00533 box_filter_line(image, x0, y, x1, 1.0,
00534 red, grn, blu, alpha, pixel_count);
00535 y++;
00536 }
00537
00538
00539 double y_contrib = y1 - (double)y_last;
00540 if (y_contrib > 0.0001) {
00541 box_filter_line(image, x0, y, x1, y_contrib,
00542 red, grn, blu, alpha, pixel_count);
00543 }
00544 }
00545
00546 PPM_ASSIGN(result,
00547 (xelval)(red / pixel_count + 0.5),
00548 (xelval)(grn / pixel_count + 0.5),
00549 (xelval)(blu / pixel_count + 0.5));
00550
00551 alpha_result = (xelval)(alpha / pixel_count + 0.5);
00552 }
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566 void PNMImage::
00567 quick_filter_from(const PNMImage &from, int xborder, int yborder) {
00568 int from_xs = from.get_x_size();
00569 int from_ys = from.get_y_size();
00570
00571 int to_xs = get_x_size() - xborder;
00572 int to_ys = get_y_size() - yborder;
00573
00574 int to_xoff = xborder / 2;
00575 int to_yoff = yborder / 2;
00576
00577 double from_x0, from_x1, from_y0, from_y1;
00578 int to_x, to_y;
00579
00580 double x_scale = (double)from_xs / (double)to_xs;
00581 double y_scale = (double)from_ys / (double)to_ys;
00582
00583 from_y0 = max(0, -to_yoff) * y_scale;
00584 for (to_y = max(0, -to_yoff);
00585 to_y < min(to_ys, get_y_size()-to_yoff);
00586 to_y++) {
00587 from_y1 = (to_y+1) * y_scale;
00588
00589 from_x0 = max(0, -to_xoff) * x_scale;
00590 for (to_x = max(0, -to_xoff);
00591 to_x < min(to_xs, get_x_size()-to_xoff);
00592 to_x++) {
00593 from_x1 = (to_x+1) * x_scale;
00594
00595
00596
00597 xelval alpha_result;
00598 box_filter_region(from,
00599 from_x0, from_y0, from_x1, from_y1,
00600 (*this)[to_yoff + to_y][to_xoff + to_x],
00601 alpha_result);
00602 if (has_alpha()) {
00603 set_alpha_val(to_xoff+to_x, to_yoff+to_y, alpha_result);
00604 }
00605
00606 from_x0 = from_x1;
00607 }
00608 from_y0 = from_y1;
00609 }
00610 }