Begin implementation of textured images.
[Ale.git] / d2 / image.h
blob8ff8db7a1d5e65fa271318c7cefe31fe4fbd44e1
1 // Copyright 2002, 2003, 2004 David Hilvert <dhilvert@auricle.dyndns.org>,
2 // <dhilvert@ugcs.caltech.edu>
4 /* This file is part of the Anti-Lamenessing Engine.
6 The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with the Anti-Lamenessing Engine; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * image.h: Abstract base class for the internal representations of images used
23 * by ALE.
26 #ifndef __image_h__
27 #define __image_h__
29 #include "point.h"
30 #include "pixel.h"
31 #include "exposure/exposure.h"
33 #define IMAGE_BAYER_NONE 0
36 * This constant indicates that some other default value should be filled in.
39 #define IMAGE_BAYER_DEFAULT 0x8
42 * Do not change these values without inspecting
43 * image_bayer_ale_real::r_*_offset().
45 #define IMAGE_BAYER_RGBG 0x4 /* binary 100 */
46 #define IMAGE_BAYER_GBGR 0x5 /* binary 101 */
47 #define IMAGE_BAYER_GRGB 0x6 /* binary 110 */
48 #define IMAGE_BAYER_BGRG 0x7 /* binary 111 */
50 class image : protected exposure::listener {
51 protected:
52 static double resident;
53 unsigned int _dimx, _dimy, _depth;
54 point _offset;
55 const char *name;
56 mutable exposure *_exp;
57 unsigned int bayer;
58 public:
59 static void set_resident(double r) {
60 resident = r;
63 static double get_resident() {
64 return resident;
67 image (unsigned int dimy, unsigned int dimx, unsigned int depth,
68 const char *name = "anonymous", exposure *_exp = NULL,
69 unsigned int bayer = IMAGE_BAYER_NONE) {
71 assert (depth == 3);
72 _depth = 3;
74 _dimx = dimx;
75 _dimy = dimy;
76 _offset = point(0, 0);
77 this->name = name;
78 this->_exp = _exp;
79 this->bayer = bayer;
81 if (_exp != NULL)
82 _exp->add_listener(this, name);
85 unsigned int get_bayer() const {
86 return bayer;
89 virtual char get_channels(int i, int j) const {
90 return 0x7;
93 virtual unsigned int bayer_color(unsigned int i, unsigned int j) const {
94 assert(0);
97 double storage_size() const {
98 if (bayer != IMAGE_BAYER_NONE)
99 return _dimx * _dimy * sizeof(ale_real);
101 return 3 * _dimx * _dimy * sizeof(ale_real);
104 exposure &exp() const {
105 return *_exp;
108 point offset() const {
109 return _offset;
112 void set_offset(int i, int j) {
113 _offset[0] = i;
114 _offset[1] = j;
117 void set_offset(point p) {
118 _offset = p;
121 unsigned int width() const {
122 return _dimx;
125 unsigned int height() const {
126 return _dimy;
129 unsigned int depth() const {
130 return _depth;
133 virtual void set_pixel(unsigned int y, unsigned int x, spixel p) = 0;
135 virtual spixel get_pixel(unsigned int y, unsigned int x) const = 0;
137 virtual spixel get_raw_pixel(unsigned int y, unsigned int x) const {
138 return ((const image *)this)->get_pixel(y, x);
141 virtual void add_pixel(unsigned int y, unsigned int x, pixel p) {
142 assert(0);
145 virtual void mul_pixel(unsigned int y, unsigned int x, pixel p) {
146 assert(0);
149 virtual void div_pixel(unsigned int y, unsigned int x, pixel p) {
150 assert(0);
153 virtual void add_chan(unsigned int y, unsigned int x, unsigned int k, ale_real c) {
154 assert(0);
157 virtual void div_chan(unsigned int y, unsigned int x, unsigned int k, ale_real c) {
158 assert(0);
161 virtual void set_chan(unsigned int y, unsigned int x, unsigned int k, ale_sreal c) = 0;
163 virtual ale_sreal get_chan(unsigned int y, unsigned int x, unsigned int k) const = 0;
165 ale_real maxval() const {
166 ale_real result = get_pixel(0, 0)[0];
168 for (unsigned int i = 0; i < _dimy; i++)
169 for (unsigned int j = 0; j < _dimx; j++) {
170 pixel p = get_pixel(i, j);
172 for (unsigned int k = 0; k < _depth; k++)
173 if (p[k] > result || !finite(result))
174 result = p[k];
177 return result;
180 ale_real minval() const {
181 ale_real result = get_pixel(0, 0)[0];
183 for (unsigned int i = 0; i < _dimy; i++)
184 for (unsigned int j = 0; j < _dimx; j++) {
185 pixel p = get_pixel(i, j);
187 for (unsigned int k = 0; k < _depth; k++)
188 if (p[k] < result || !finite(result))
189 result = p[k];
192 return result;
196 * Get the maximum difference among adjacent pixels.
199 pixel get_max_diff(unsigned int i, unsigned int j) const {
200 assert(i <= _dimy - 1);
201 assert(j <= _dimx - 1);
203 pixel max = get_pixel(i, j), min = get_pixel(i, j);
205 for (int ii = -1; ii <= 1; ii++)
206 for (int jj = -1; jj <= 1; jj++) {
207 int iii = i + ii;
208 int jjj = j + jj;
210 if (iii < 0)
211 continue;
212 if (jjj < 0)
213 continue;
214 if ((unsigned int) iii > _dimy - 1)
215 continue;
216 if ((unsigned int) jjj > _dimx - 1)
217 continue;
219 pixel p = get_pixel(iii, jjj);
221 for (int d = 0; d < 3; d++) {
222 if (p[d] > max[d])
223 max[d] = p[d];
224 if (p[d] < min[d])
225 min[d] = p[d];
229 return max - min;
232 pixel get_max_diff(point x) const {
233 assert (x[0] >= 0);
234 assert (x[1] >= 0);
235 assert (x[0] <= _dimy - 1);
236 assert (x[1] <= _dimx - 1);
238 unsigned int i = (unsigned int) round(x[0]);
239 unsigned int j = (unsigned int) round(x[1]);
241 return get_max_diff(i, j);
244 int in_bounds(point x) const {
245 if (x[0] < 0
246 || x[1] < 0
247 || x[0] > height() - 1
248 || x[1] > width() - 1)
249 return 0;
250 if (!x.defined())
251 return 0;
252 return 1;
256 * Get a color value at a given position using bilinear interpolation between the
257 * four nearest pixels.
259 pixel get_bl(point x, int defined = 0) const {
260 // fprintf(stderr, "get_bl x=%f %f\n", (double) x[0], (double) x[1]);
262 pixel result;
264 assert (x[0] >= 0);
265 assert (x[1] >= 0);
266 assert (x[0] <= _dimy - 1);
267 assert (x[1] <= _dimx - 1);
269 int lx = (int) floor(x[1]);
270 int hx = (int) floor(x[1]) + 1;
271 int ly = (int) floor(x[0]);
272 int hy = (int) floor(x[0]) + 1;
274 // fprintf(stderr, "get_bl l=%d %d h=%d %d\n", ly, lx, hy, hx);
276 pixel neighbor[4];
277 ale_real factor[4];
279 neighbor[0] = get_pixel(ly, lx);
280 neighbor[1] = get_pixel(hy % _dimy, lx);
281 neighbor[2] = get_pixel(hy % _dimy, hx % _dimx);
282 neighbor[3] = get_pixel(ly, hx % _dimx);
284 // for (int d = 0; d < 4; d++)
285 // fprintf(stderr, "neighbor_%d=%f %f %f\n", d,
286 // (double) neighbor[d][0],
287 // (double) neighbor[d][1],
288 // (double) neighbor[d][2]);
290 factor[0] = (ale_real) (hx - x[1]) * (ale_real) (hy - x[0]);
291 factor[1] = (ale_real) (hx - x[1]) * (ale_real) (x[0] - ly);
292 factor[2] = (ale_real) (x[1] - lx) * (ale_real) (x[0] - ly);
293 factor[3] = (ale_real) (x[1] - lx) * (ale_real) (hy - x[0]);
295 // for (int d = 0; d < 4; d++)
296 // fprintf(stderr, "factor_%d=%f\n", d,
297 // (double) factor[d]);
300 * Use bilinear and/or geometric interpolation
303 if (defined == 0) {
304 result = pixel(0, 0, 0);
306 for (int n = 0; n < 4; n++)
307 result += factor[n] * neighbor[n];
308 } else {
309 #if 0
311 * Calculating the geometric mean may be expensive on
312 * some platforms (e.g., those without floating-point
313 * support.
316 result = pixel(1, 1, 1);
318 for (int n = 0; n < 4; n++)
319 result *= ppow(neighbor[n], factor[n]);
320 #else
322 * Taking the minimum value may be cheaper than
323 * calculating a geometric mean.
326 result = neighbor[0];
328 for (int n = 1; n < 4; n++)
329 for (int k = 0; k < 3; k++)
330 if (neighbor[n][k] < result[k])
331 result[k] = neighbor[n][k];
332 #endif
335 // fprintf(stderr, "result=%f %f %f\n",
336 // (double) result[0],
337 // (double) result[1],
338 // (double) result[2]);
340 return result;
343 pixel get_scaled_bl(point x, ale_pos f, int defined = 0) const {
344 point scaled(
345 x[0]/f <= height() - 1
346 ? (x[0]/f)
347 : (ale_pos) (height() - 1),
348 x[1]/f <= width() - 1
349 ? (x[1]/f)
350 : (ale_pos) (width() - 1));
352 return get_bl(scaled, defined);
357 * Make a new image suitable for receiving scaled values.
359 virtual image *scale_generator(int height, int width, int depth, const char *name) const = 0;
362 * Generate an image of medians within a given radius
365 image *medians(int radius) const {
367 assert (radius >= 0);
369 image *is = scale_generator(height(), width(), depth(), "median");
370 assert(is);
372 for (unsigned int i = 0; i < height(); i++)
373 for (unsigned int j = 0; j < width(); j++) {
375 std::vector<ale_real> p[3];
377 for (int ii = -radius; ii <= radius; ii++)
378 for (int jj = -radius; jj <= radius; jj++) {
379 int iii = i + ii;
380 int jjj = j + jj;
382 if (in_bounds(point(iii, jjj)))
383 for (int k = 0; k < 3; k++)
384 if (finite(get_pixel(iii, jjj)[k]))
385 p[k].push_back(get_pixel(iii, jjj)[k]);
388 is->set_pixel(i, j, d2::pixel::undefined());
390 for (int k = 0; k < 3; k++) {
391 std::sort(p[k].begin(), p[k].end());
393 unsigned int pkc = p[k].size();
395 if (pkc == 0)
396 continue;
398 if (pkc % 2 == 0)
399 is->set_chan(i, j, k,
400 (p[k][pkc / 2] + p[k][pkc / 2 - 1]) / 2);
401 else
402 is->set_chan(i, j, k,
403 p[k][pkc / 2]);
407 return is;
411 * Generate an image of differences of the first channel. The first
412 * coordinate differences are stored in the first channel, second in the
413 * second channel.
416 image *fcdiffs() const {
417 image *is = scale_generator(height(), width(), depth(), "diff");
419 assert(is);
421 for (unsigned int i = 0; i < height(); i++)
422 for (unsigned int j = 0; j < width(); j++) {
424 if (i + 1 < height()
425 && i > 0
426 && !finite(get_chan(i, j, 0))) {
428 is->set_chan(i, j, 0, (get_chan(i + 1, j, 0)
429 - get_chan(i - 1, j, 0)) / 2);
431 } else if (i + 1 < height()
432 && i > 0
433 && finite(get_chan(i + 1, j, 0))
434 && finite(get_chan(i - 1, j, 0))) {
436 is->set_chan(i, j, 0, ((get_chan(i, j, 0) - get_chan(i - 1, j, 0))
437 + (get_chan(i + 1, j, 0) - get_chan(i, j, 0))) / 2);
439 } else if (i + 1 < height()
440 && finite(get_chan(i + 1, j, 0))) {
442 is->set_chan(i, j, 0, get_chan(i + 1, j, 0) - get_chan(i, j, 0));
444 } else if (i > 0
445 && finite(get_chan(i - 1, j, 0))) {
447 is->set_chan(i, j, 0, get_chan(i, j, 0) - get_chan(i - 1, j, 0));
449 } else {
450 is->set_chan(i, j, 0, 0);
453 if (j + 1 < width()
454 && j > 0
455 && !finite(get_chan(i, j, 0))) {
457 is->set_chan(i, j, 1, (get_chan(i, j + 1, 0) - get_chan(i, j - 1, 0)) / 2);
459 } else if (j + 1 < width()
460 && j > 0
461 && finite(get_chan(i, j + 1, 0))
462 && finite(get_chan(i, j - 1, 0))) {
464 is->set_chan(i, j, 1, ((get_chan(i, j, 0) - get_chan(i, j - 1, 0))
465 + (get_chan(i, j + 1, 0) - get_chan(i, j, 0))) / 2);
467 } else if (j + 1 < width() && finite(get_chan(i, j + 1, 0))) {
469 is->set_chan(i, j, 1, get_chan(i, j + 1, 0) - get_chan(i, j, 0));
471 } else if (j > 0 && finite(get_chan(i, j - 1, 0))) {
473 is->set_chan(i, j, 1, get_chan(i, j, 0) - get_chan(i, j - 1, 0));
475 } else {
476 is->set_chan(i, j, 1, 0);
480 return is;
484 * Generate an image of median (within a given radius) difference of the
485 * first channel.
488 image *fcdiff_median(int radius) const {
489 image *diff = fcdiffs();
491 assert(diff);
493 image *median = diff->medians(radius);
495 assert(median);
497 delete diff;
499 return median;
503 * Scale by half. We use the following filter:
505 * 1/16 1/8 1/16
506 * 1/8 1/4 1/8
507 * 1/16 1/8 1/16
509 * At the edges, these values are normalized so that the sum of the
510 * weights of contributing pixels is 1.
512 class scale_by_half_threaded : public thread::decompose_domain {
513 image *is;
514 const image *iu;
515 protected:
516 void subdomain_algorithm(unsigned int thread,
517 int i_min, int i_max, int j_min, int j_max) {
519 ale_real _0625 = (ale_real) 0.0625;
520 ale_real _125 = (ale_real) 0.125;
521 ale_real _25 = (ale_real) 0.25;
522 ale_real _0 = (ale_real) 0;
524 unsigned int ui_min = (unsigned int) i_min;
525 unsigned int ui_max = (unsigned int) i_max;
526 unsigned int uj_min = (unsigned int) j_min;
527 unsigned int uj_max = (unsigned int) j_max;
529 for (unsigned int i = ui_min; i < ui_max; i++)
530 for (unsigned int j = uj_min; j < uj_max; j++) {
531 is->set_pixel(i, j,
533 ( ( ((i > 0 && j > 0)
534 ? iu->get_pixel(2 * i - 1, 2 * j - 1) * _0625
535 : pixel(0, 0, 0))
536 + ((i > 0)
537 ? iu->get_pixel(2 * i - 1, 2 * j) * _125
538 : pixel(0, 0, 0))
539 + ((i > 0 && j < is->width() - 1)
540 ? iu->get_pixel(2 * i - 1, 2 * j + 1) * _0625
541 : pixel(0, 0, 0))
542 + ((j > 0)
543 ? iu->get_pixel(2 * i, 2 * j - 1) * _125
544 : pixel(0, 0, 0))
545 + iu->get_pixel(2 * i, 2 * j) * _25
546 + ((j < is->width() - 1)
547 ? iu->get_pixel(2 * i, 2 * j + 1) * _125
548 : pixel(0, 0, 0))
549 + ((i < is->height() - 1 && j > 0)
550 ? iu->get_pixel(2 * i + 1, 2 * j - 1) * _0625
551 : pixel(0, 0, 0))
552 + ((i < is->height() - 1)
553 ? iu->get_pixel(2 * i + 1, 2 * j) * _125
554 : pixel(0, 0, 0))
555 + ((i < is->height() && j < is->width() - 1)
556 ? iu->get_pixel(2 * i + 1, 2 * j + 1) * _0625
557 : pixel(0, 0, 0)))
561 ( ((i > 0 && j > 0)
562 ? _0625
563 : _0)
564 + ((i > 0)
565 ? _125
566 : _0)
567 + ((i > 0 && j < is->width() - 1)
568 ? _0625
569 : _0)
570 + ((j > 0)
571 ? _125
572 : _0)
573 + _25
574 + ((j < is->width() - 1)
575 ? _125
576 : _0)
577 + ((i < is->height() - 1 && j > 0)
578 ? _0625
579 : _0)
580 + ((i < is->height() - 1)
581 ? _125
582 : _0)
583 + ((i < is->height() && j < is->width() - 1)
584 ? _0625
585 : _0) ) ) );
589 public:
590 scale_by_half_threaded(image *_is, const image *_iu)
591 : decompose_domain(0, _is->height(),
592 0, _is->width()) {
593 is = _is;
594 iu = _iu;
598 image *scale_by_half(const char *name) const {
599 ale_pos f = 0.5;
601 image *is = scale_generator(
602 (int) floor(height() * (double) f),
603 (int) floor(width() * (double) f), depth(), name);
605 assert(is);
607 scale_by_half_threaded sbht(is, this);
608 sbht.run();
610 is->_offset = point(_offset[0] * f, _offset[1] * f);
612 return is;
616 * Scale by half. This function uses externally-provided weights,
617 * multiplied by the following filter:
619 * 1/16 1/8 1/16
620 * 1/8 1/4 1/8
621 * 1/16 1/8 1/16
623 * Values are normalized so that the sum of the weights of contributing
624 * pixels is 1.
626 image *scale_by_half(const image *weights, const char *name) const {
628 if (weights == NULL)
629 return scale_by_half(name);
631 ale_pos f = 0.5;
633 image *is = scale_generator(
634 (int) floor(height() * (double) f),
635 (int) floor(width() * (double) f), depth(), name);
637 assert(is);
639 for (unsigned int i = 0; i < is->height(); i++)
640 for (unsigned int j = 0; j < is->width(); j++) {
642 pixel value = pixel
644 ( ( ((i > 0 && j > 0)
645 ? (pixel) get_pixel(2 * i - 1, 2 * j - 1)
646 * (pixel) weights->get_pixel(2 * i - 1, 2 * j - 1)
647 * (ale_real) 0.0625
648 : pixel(0, 0, 0))
649 + ((i > 0)
650 ? (pixel) get_pixel(2 * i - 1, 2 * j)
651 * (pixel) weights->get_pixel(2 * i - 1, 2 * j)
652 * 0.125
653 : pixel(0, 0, 0))
654 + ((i > 0 && j < is->width() - 1)
655 ? (pixel) get_pixel(2 * i - 1, 2 * j + 1)
656 * (pixel) weights->get_pixel(2 * i - 1, 2 * j + 1)
657 * 0.0625
658 : pixel(0, 0, 0))
659 + ((j > 0)
660 ? (pixel) get_pixel(2 * i, 2 * j - 1)
661 * (pixel) weights->get_pixel(2 * i, 2 * j - 1)
662 * 0.125
663 : pixel(0, 0, 0))
664 + get_pixel(2 * i, 2 * j)
665 * (pixel) weights->get_pixel(2 * i, 2 * j)
666 * 0.25
667 + ((j < is->width() - 1)
668 ? (pixel) get_pixel(2 * i, 2 * j + 1)
669 * (pixel) weights->get_pixel(2 * i, 2 * j + 1)
670 * 0.125
671 : pixel(0, 0, 0))
672 + ((i < is->height() - 1 && j > 0)
673 ? (pixel) get_pixel(2 * i + 1, 2 * j - 1)
674 * (pixel) weights->get_pixel(2 * i + 1, 2 * j - 1)
675 * 0.0625
676 : pixel(0, 0, 0))
677 + ((i < is->height() - 1)
678 ? (pixel) get_pixel(2 * i + 1, 2 * j)
679 * (pixel) weights->get_pixel(2 * i + 1, 2 * j)
680 * 0.125
681 : pixel(0, 0, 0))
682 + ((i < is->height() && j < is->width() - 1)
683 ? (pixel) get_pixel(2 * i + 1, 2 * j + 1)
684 * (pixel) weights->get_pixel(2 * i + 1, 2 * j + 1)
685 * 0.0625
686 : pixel(0, 0, 0)))
690 ( ((i > 0 && j > 0)
691 ? weights->get_pixel(2 * i - 1, 2 * j - 1)
692 * 0.0625
693 : pixel(0, 0, 0))
694 + ((i > 0)
695 ? weights->get_pixel(2 * i - 1, 2 * j)
696 * 0.125
697 : pixel(0, 0, 0))
698 + ((i > 0 && j < is->width() - 1)
699 ? weights->get_pixel(2 * i - 1, 2 * j + 1)
700 * 0.0625
701 : pixel(0, 0, 0))
702 + ((j > 0)
703 ? weights->get_pixel(2 * i, 2 * j - 1)
704 * 0.125
705 : pixel(0, 0, 0))
706 + weights->get_pixel(2 * i, 2 * j)
707 * 0.25
708 + ((j < is->width() - 1)
709 ? weights->get_pixel(2 * i, 2 * j + 1)
710 * 0.125
711 : pixel(0, 0, 0))
712 + ((i < is->height() - 1 && j > 0)
713 ? weights->get_pixel(2 * i + 1, 2 * j - 1)
714 * 0.0625
715 : pixel(0, 0, 0))
716 + ((i < is->height() - 1)
717 ? weights->get_pixel(2 * i + 1, 2 * j)
718 * 0.125
719 : pixel(0, 0, 0))
720 + ((i < is->height() && j < is->width() - 1)
721 ? weights->get_pixel(2 * i + 1, 2 * j + 1)
722 * 0.0625
723 : pixel(0, 0, 0)) ) );
725 for (int k = 0; k < 3; k++)
726 if (!finite(value[k]))
727 value[k] = 0;
729 is->set_pixel(i, j, value);
732 is->_offset = point(_offset[0] * f, _offset[1] * f);
734 return is;
738 * Scale an image definition array by 1/2.
740 * ALE considers an image definition array as a special kind of image
741 * weight array (typedefs of which should appear below the definition
742 * of this class). ALE uses nonzero pixel values to mean 'defined' and
743 * zero values to mean 'undefined'. Through this interpretation, the
744 * image weight array implementation that ALE uses allows image weight
745 * arrays to also serve as image definition arrays.
747 * Whereas scaling of image weight arrays is not generally obvious in
748 * either purpose or method, ALE requires that image definition arrays
749 * be scalable. (Note that in the special case where weight is treated
750 * as certainty, using a geometric mean is probably correct.)
752 * We currently use a geometric mean to implement scaling of
753 * definition arrays.
756 class defined_scale_by_half_threaded : public thread::decompose_domain {
757 image *is;
758 const image *iu;
759 protected:
760 void subdomain_algorithm(unsigned int thread,
761 int i_min, int i_max, int j_min, int j_max) {
763 #if 0
764 ale_real _0625 = (ale_real) 0.0625;
765 ale_real _125 = (ale_real) 0.125;
766 ale_real _25 = (ale_real) 0.25;
767 #endif
769 int ui_min = (int) i_min;
770 int ui_max = (int) i_max;
771 int uj_min = (int) j_min;
772 int uj_max = (int) j_max;
774 for (int i = ui_min; i < ui_max; i++)
775 for (int j = uj_min; j < uj_max; j++) {
777 #if 0
780 * Calculate a geometric mean; this approach
781 * may be expensive on some platforms (e.g.,
782 * those without floating-point support in
783 * hardware).
786 pixel value = pixel
788 ( ( ((i > 0 && j > 0)
789 ? ppow(iu->get_pixel(2 * i - 1, 2 * j - 1), _0625)
790 : pixel(0, 0, 0))
791 * ((i > 0)
792 ? ppow(iu->get_pixel(2 * i - 1, 2 * j), _125)
793 : pixel(0, 0, 0))
794 * ((i > 0 && j < is->width() - 1)
795 ? ppow(iu->get_pixel(2 * i - 1, 2 * j + 1), _0625)
796 : pixel(0, 0, 0))
797 * ((j > 0)
798 ? ppow(iu->get_pixel(2 * i, 2 * j - 1), _125)
799 : pixel(0, 0, 0))
800 * ppow(iu->get_pixel(2 * i, 2 * j), _25)
801 * ((j < is->width() - 1)
802 ? ppow(iu->get_pixel(2 * i, 2 * j + 1), _125)
803 : pixel(0, 0, 0))
804 * ((i < is->height() - 1 && j > 0)
805 ? ppow(iu->get_pixel(2 * i + 1, 2 * j - 1), _0625)
806 : pixel(0, 0, 0))
807 * ((i < is->height() - 1)
808 ? ppow(iu->get_pixel(2 * i + 1, 2 * j), _125)
809 : pixel(0, 0, 0))
810 * ((i < is->height() && j < is->width() - 1)
811 ? ppow(iu->get_pixel(2 * i + 1, 2 * j + 1), _0625)
812 : pixel(0, 0, 0))));
813 #else
815 pixel value = iu->get_pixel(2 * i, 2 * j);
817 for (int ii = 2 * i - 1; ii <= 2 * i + 1; ii++)
818 for (int jj = 2 * j - 1; jj <= 2 * j + 1; jj++) {
819 if (ii < 0
820 || jj < 0
821 || ii > (int) iu->height() - 1
822 || jj > (int) iu->height() - 1)
823 continue;
825 pixel value2 = iu->get_pixel(ii, jj);
827 for (int k = 0; k < 3; k++)
828 if (value2[k] < value[k]
829 || !finite(value2[k])) /* propagate non-finites */
830 value[k] = value2[k];
833 #endif
836 for (int k = 0; k < 3; k++)
837 if (!finite(value[k]))
838 value[k] = 0;
840 is->set_pixel(i, j, value);
844 public:
845 defined_scale_by_half_threaded(image *_is, const image *_iu)
846 : decompose_domain(0, _is->height(),
847 0, _is->width()) {
848 is = _is;
849 iu = _iu;
853 image *defined_scale_by_half(const char *name) const {
854 ale_pos f = 0.5;
856 image *is = scale_generator(
857 (int) floor(height() * (double) f),
858 (int) floor(width() * (double) f), depth(), name);
860 assert(is);
862 defined_scale_by_half_threaded dsbht(is, this);
863 dsbht.run();
865 is->_offset = point(_offset[0] * f, _offset[1] * f);
867 return is;
871 * Return an image scaled by some factor != 1.0, using bilinear
872 * interpolation.
874 image *scale(ale_pos f, const char *name, int defined = 0) const {
877 * We probably don't want to scale images by a factor of 1.0,
878 * or by non-positive values.
880 assert (f != 1.0 && f > 0);
882 if (f > 1.0) {
883 image *is = scale_generator(
884 (int) floor(height() * (double) f),
885 (int) floor(width() * (double) f), depth(), name);
887 assert(is);
889 unsigned int i, j, k;
891 for (i = 0; i < is->height(); i++)
892 for (j = 0; j < is->width(); j++)
893 for (k = 0; k < is->depth(); k++)
894 is->set_pixel(i, j,
895 get_scaled_bl(point(i, j), f, defined));
897 is->_offset = point(_offset[0] * f, _offset[1] * f);
899 return is;
900 } else if (f == 0.5) {
901 if (defined == 0)
902 return scale_by_half(name);
903 else
904 return defined_scale_by_half(name);
905 } else {
906 image *is = scale(2*f, name, defined);
907 image *result = is->scale(0.5, name, defined);
908 delete is;
909 return result;
915 * Extend the image area to the top, bottom, left, and right,
916 * initializing the new image areas with black pixels. Negative values
917 * shrink the image.
919 virtual image *_extend(int top, int bottom, int left, int right) = 0;
921 static void extend(image **i, int top, int bottom, int left, int right) {
922 image *is = (*i)->_extend(top, bottom, left, right);
924 if (is != NULL) {
925 delete (*i);
926 *i = is;
931 * Clone
933 image *clone(const char *name) const {
934 image *ic = scale_generator(
935 height(), width(), depth(), name);
937 assert(ic);
939 for (unsigned int i = 0; i < height(); i++)
940 for (unsigned int j = 0; j < width(); j++)
941 ic->set_pixel(i, j,
942 get_pixel(i, j));
945 ic->_offset = _offset;
947 return ic;
950 virtual ~image() {
954 #endif