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