Ditz entry for migrating technical documentation.
[Ale.git] / d2 / image.h
blob355613b046c0fb63e3760f55e79c77b1f835750e
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 #define ALE_GLSL_IMAGE_INCLUDE \
51 "struct image {\n"\
52 " int type;\n"\
53 "};\n"\
54 "vec3 image_get_pixel(image _this, vec4 pos);\n"
56 class image : protected exposure::listener {
57 protected:
58 static double resident;
59 unsigned int _dimx, _dimy, _depth;
60 point _offset;
61 const char *name;
62 mutable exposure *_exp;
63 unsigned int bayer;
66 * XXX: dummy_value prevents automatic conversions. Is there a better
67 * way? This constructor is used by, e.g., d2/image_accel.
70 image (const image *source, int dummy_value) {
72 assert (source->_depth == 3);
73 _depth = 3;
75 _dimx = source->_dimx;
76 _dimy = source->_dimy;
77 _offset = source->_offset;
78 name = source->name;
79 _exp = source->_exp;
80 bayer = source->bayer;
82 if (_exp != NULL)
83 _exp->add_listener(this, name);
86 public:
87 static void set_resident(double r) {
88 resident = r;
91 static double get_resident() {
92 return resident;
95 image (unsigned int dimy, unsigned int dimx, unsigned int depth,
96 const char *name = "anonymous", exposure *_exp = NULL,
97 unsigned int bayer = IMAGE_BAYER_NONE) {
99 assert (depth == 3);
100 _depth = 3;
102 _dimx = dimx;
103 _dimy = dimy;
104 _offset = point(0, 0);
105 this->name = name;
106 this->_exp = _exp;
107 this->bayer = bayer;
109 if (_exp != NULL)
110 _exp->add_listener(this, name);
113 unsigned int get_bayer() const {
114 return bayer;
117 virtual char get_channels(int i, int j) const {
118 return 0x7;
121 virtual unsigned int bayer_color(unsigned int i, unsigned int j) const {
122 assert(0);
125 double storage_size() const {
126 if (bayer != IMAGE_BAYER_NONE)
127 return _dimx * _dimy * sizeof(ale_real);
129 return 3 * _dimx * _dimy * sizeof(ale_real);
132 exposure &exp() const {
133 return *_exp;
136 point offset() const {
137 return _offset;
140 void set_offset(int i, int j) {
141 _offset[0] = i;
142 _offset[1] = j;
145 void set_offset(point p) {
146 _offset = p;
149 unsigned int width() const {
150 return _dimx;
153 unsigned int height() const {
154 return _dimy;
157 unsigned int depth() const {
158 return _depth;
161 virtual void set_pixel(unsigned int y, unsigned int x, spixel p) = 0;
163 virtual spixel get_pixel(unsigned int y, unsigned int x) const = 0;
165 virtual spixel get_raw_pixel(unsigned int y, unsigned int x) const {
166 return ((const image *)this)->get_pixel(y, x);
169 virtual void add_pixel(unsigned int y, unsigned int x, pixel p) {
170 assert(0);
173 virtual void mul_pixel(unsigned int y, unsigned int x, pixel p) {
174 assert(0);
177 virtual void div_pixel(unsigned int y, unsigned int x, pixel p) {
178 assert(0);
181 virtual void add_chan(unsigned int y, unsigned int x, unsigned int k, ale_real c) {
182 assert(0);
185 virtual void div_chan(unsigned int y, unsigned int x, unsigned int k, ale_real c) {
186 assert(0);
189 virtual void set_chan(unsigned int y, unsigned int x, unsigned int k, ale_sreal c) = 0;
191 virtual ale_sreal get_chan(unsigned int y, unsigned int x, unsigned int k) const = 0;
193 ale_real maxval() const {
194 ale_real result = get_pixel(0, 0)[0];
196 for (unsigned int i = 0; i < _dimy; i++)
197 for (unsigned int j = 0; j < _dimx; j++) {
198 pixel p = get_pixel(i, j);
200 for (unsigned int k = 0; k < _depth; k++)
201 if (p[k] > result || !finite(result))
202 result = p[k];
205 return result;
208 ale_real minval() const {
209 ale_real result = get_pixel(0, 0)[0];
211 for (unsigned int i = 0; i < _dimy; i++)
212 for (unsigned int j = 0; j < _dimx; j++) {
213 pixel p = get_pixel(i, j);
215 for (unsigned int k = 0; k < _depth; k++)
216 if (p[k] < result || !finite(result))
217 result = p[k];
220 return result;
224 * Get the maximum difference among adjacent pixels.
227 pixel get_max_diff(unsigned int i, unsigned int j) const {
228 assert(i <= _dimy - 1);
229 assert(j <= _dimx - 1);
231 pixel max = get_pixel(i, j), min = get_pixel(i, j);
233 for (int ii = -1; ii <= 1; ii++)
234 for (int jj = -1; jj <= 1; jj++) {
235 int iii = i + ii;
236 int jjj = j + jj;
238 if (iii < 0)
239 continue;
240 if (jjj < 0)
241 continue;
242 if ((unsigned int) iii > _dimy - 1)
243 continue;
244 if ((unsigned int) jjj > _dimx - 1)
245 continue;
247 pixel p = get_pixel(iii, jjj);
249 for (int d = 0; d < 3; d++) {
250 if (p[d] > max[d])
251 max[d] = p[d];
252 if (p[d] < min[d])
253 min[d] = p[d];
257 return max - min;
260 pixel get_max_diff(point x) const {
261 assert (x[0] >= 0);
262 assert (x[1] >= 0);
263 assert (x[0] <= _dimy - 1);
264 assert (x[1] <= _dimx - 1);
266 unsigned int i = (unsigned int) round(x[0]);
267 unsigned int j = (unsigned int) round(x[1]);
269 return get_max_diff(i, j);
272 int in_bounds(point x) const {
273 if (x[0] < 0
274 || x[1] < 0
275 || x[0] > height() - 1
276 || x[1] > width() - 1)
277 return 0;
278 if (!x.defined())
279 return 0;
280 return 1;
284 * Get a color value at a given position using bilinear interpolation between the
285 * four nearest pixels.
287 pixel get_bl(point x, int defined = 0) const {
288 // fprintf(stderr, "get_bl x=%f %f\n", (double) x[0], (double) x[1]);
290 pixel result;
292 assert (x[0] >= 0);
293 assert (x[1] >= 0);
294 assert (x[0] <= _dimy - 1);
295 assert (x[1] <= _dimx - 1);
297 int lx = (int) floor(x[1]);
298 int hx = (int) floor(x[1]) + 1;
299 int ly = (int) floor(x[0]);
300 int hy = (int) floor(x[0]) + 1;
302 // fprintf(stderr, "get_bl l=%d %d h=%d %d\n", ly, lx, hy, hx);
304 pixel neighbor[4];
305 ale_real factor[4];
307 neighbor[0] = get_pixel(ly, lx);
308 neighbor[1] = get_pixel(hy % _dimy, lx);
309 neighbor[2] = get_pixel(hy % _dimy, hx % _dimx);
310 neighbor[3] = get_pixel(ly, hx % _dimx);
312 // for (int d = 0; d < 4; d++)
313 // fprintf(stderr, "neighbor_%d=%f %f %f\n", d,
314 // (double) neighbor[d][0],
315 // (double) neighbor[d][1],
316 // (double) neighbor[d][2]);
318 factor[0] = (ale_real) (hx - x[1]) * (ale_real) (hy - x[0]);
319 factor[1] = (ale_real) (hx - x[1]) * (ale_real) (x[0] - ly);
320 factor[2] = (ale_real) (x[1] - lx) * (ale_real) (x[0] - ly);
321 factor[3] = (ale_real) (x[1] - lx) * (ale_real) (hy - x[0]);
323 // for (int d = 0; d < 4; d++)
324 // fprintf(stderr, "factor_%d=%f\n", d,
325 // (double) factor[d]);
328 * Use bilinear and/or geometric interpolation
331 if (defined == 0) {
332 result = pixel(0, 0, 0);
334 for (int n = 0; n < 4; n++)
335 result += factor[n] * neighbor[n];
336 } else {
337 #if 0
339 * Calculating the geometric mean may be expensive on
340 * some platforms (e.g., those without floating-point
341 * support.
344 result = pixel(1, 1, 1);
346 for (int n = 0; n < 4; n++)
347 result *= ppow(neighbor[n], factor[n]);
348 #else
350 * Taking the minimum value may be cheaper than
351 * calculating a geometric mean.
354 result = neighbor[0];
356 for (int n = 1; n < 4; n++)
357 for (int k = 0; k < 3; k++)
358 if (neighbor[n][k] < result[k])
359 result[k] = neighbor[n][k];
360 #endif
363 // fprintf(stderr, "result=%f %f %f\n",
364 // (double) result[0],
365 // (double) result[1],
366 // (double) result[2]);
368 return result;
371 pixel get_scaled_bl(point x, ale_pos f, int defined = 0) const {
372 point scaled(
373 x[0]/f <= height() - 1
374 ? (x[0]/f)
375 : (ale_pos) (height() - 1),
376 x[1]/f <= width() - 1
377 ? (x[1]/f)
378 : (ale_pos) (width() - 1));
380 return get_bl(scaled, defined);
385 * Make a new image suitable for receiving scaled values.
387 virtual image *scale_generator(int height, int width, int depth, const char *name) const = 0;
390 * Generate an image of medians within a given radius
393 image *medians(int radius) const {
395 assert (radius >= 0);
397 image *is = scale_generator(height(), width(), depth(), "median");
398 assert(is);
400 for (unsigned int i = 0; i < height(); i++)
401 for (unsigned int j = 0; j < width(); j++) {
403 std::vector<ale_real> p[3];
405 for (int ii = -radius; ii <= radius; ii++)
406 for (int jj = -radius; jj <= radius; jj++) {
407 int iii = i + ii;
408 int jjj = j + jj;
410 if (in_bounds(point(iii, jjj)))
411 for (int k = 0; k < 3; k++)
412 if (finite(get_pixel(iii, jjj)[k]))
413 p[k].push_back(get_pixel(iii, jjj)[k]);
416 is->set_pixel(i, j, d2::pixel::undefined());
418 for (int k = 0; k < 3; k++) {
419 std::sort(p[k].begin(), p[k].end());
421 unsigned int pkc = p[k].size();
423 if (pkc == 0)
424 continue;
426 if (pkc % 2 == 0)
427 is->set_chan(i, j, k,
428 (p[k][pkc / 2] + p[k][pkc / 2 - 1]) / 2);
429 else
430 is->set_chan(i, j, k,
431 p[k][pkc / 2]);
435 return is;
439 * Generate an image of differences of the first channel. The first
440 * coordinate differences are stored in the first channel, second in the
441 * second channel.
444 image *fcdiffs() const {
445 image *is = scale_generator(height(), width(), depth(), "diff");
447 assert(is);
449 for (unsigned int i = 0; i < height(); i++)
450 for (unsigned int j = 0; j < width(); j++) {
452 if (i + 1 < height()
453 && i > 0
454 && !finite(get_chan(i, j, 0))) {
456 is->set_chan(i, j, 0, (get_chan(i + 1, j, 0)
457 - get_chan(i - 1, j, 0)) / 2);
459 } else if (i + 1 < height()
460 && i > 0
461 && finite(get_chan(i + 1, j, 0))
462 && finite(get_chan(i - 1, j, 0))) {
464 is->set_chan(i, j, 0, ((get_chan(i, j, 0) - get_chan(i - 1, j, 0))
465 + (get_chan(i + 1, j, 0) - get_chan(i, j, 0))) / 2);
467 } else if (i + 1 < height()
468 && finite(get_chan(i + 1, j, 0))) {
470 is->set_chan(i, j, 0, get_chan(i + 1, j, 0) - get_chan(i, j, 0));
472 } else if (i > 0
473 && finite(get_chan(i - 1, j, 0))) {
475 is->set_chan(i, j, 0, get_chan(i, j, 0) - get_chan(i - 1, j, 0));
477 } else {
478 is->set_chan(i, j, 0, 0);
481 if (j + 1 < width()
482 && j > 0
483 && !finite(get_chan(i, j, 0))) {
485 is->set_chan(i, j, 1, (get_chan(i, j + 1, 0) - get_chan(i, j - 1, 0)) / 2);
487 } else if (j + 1 < width()
488 && j > 0
489 && finite(get_chan(i, j + 1, 0))
490 && finite(get_chan(i, j - 1, 0))) {
492 is->set_chan(i, j, 1, ((get_chan(i, j, 0) - get_chan(i, j - 1, 0))
493 + (get_chan(i, j + 1, 0) - get_chan(i, j, 0))) / 2);
495 } else if (j + 1 < width() && finite(get_chan(i, j + 1, 0))) {
497 is->set_chan(i, j, 1, get_chan(i, j + 1, 0) - get_chan(i, j, 0));
499 } else if (j > 0 && finite(get_chan(i, j - 1, 0))) {
501 is->set_chan(i, j, 1, get_chan(i, j, 0) - get_chan(i, j - 1, 0));
503 } else {
504 is->set_chan(i, j, 1, 0);
508 return is;
512 * Generate an image of median (within a given radius) difference of the
513 * first channel.
516 image *fcdiff_median(int radius) const {
517 image *diff = fcdiffs();
519 assert(diff);
521 image *median = diff->medians(radius);
523 assert(median);
525 delete diff;
527 return median;
531 * Scale by half. We use the following filter:
533 * 1/16 1/8 1/16
534 * 1/8 1/4 1/8
535 * 1/16 1/8 1/16
537 * At the edges, these values are normalized so that the sum of the
538 * weights of contributing pixels is 1.
540 class scale_by_half_threaded : public thread::decompose_domain {
541 image *is;
542 const image *iu;
543 protected:
544 void subdomain_algorithm(unsigned int thread,
545 int i_min, int i_max, int j_min, int j_max) {
547 ale_real _0625 = (ale_real) 0.0625;
548 ale_real _125 = (ale_real) 0.125;
549 ale_real _25 = (ale_real) 0.25;
550 ale_real _0 = (ale_real) 0;
552 unsigned int ui_min = (unsigned int) i_min;
553 unsigned int ui_max = (unsigned int) i_max;
554 unsigned int uj_min = (unsigned int) j_min;
555 unsigned int uj_max = (unsigned int) j_max;
557 for (unsigned int i = ui_min; i < ui_max; i++)
558 for (unsigned int j = uj_min; j < uj_max; j++) {
559 is->set_pixel(i, j,
561 ( ( ((i > 0 && j > 0)
562 ? iu->get_pixel(2 * i - 1, 2 * j - 1) * _0625
563 : pixel(0, 0, 0))
564 + ((i > 0)
565 ? iu->get_pixel(2 * i - 1, 2 * j) * _125
566 : pixel(0, 0, 0))
567 + ((i > 0 && j < is->width() - 1)
568 ? iu->get_pixel(2 * i - 1, 2 * j + 1) * _0625
569 : pixel(0, 0, 0))
570 + ((j > 0)
571 ? iu->get_pixel(2 * i, 2 * j - 1) * _125
572 : pixel(0, 0, 0))
573 + iu->get_pixel(2 * i, 2 * j) * _25
574 + ((j < is->width() - 1)
575 ? iu->get_pixel(2 * i, 2 * j + 1) * _125
576 : pixel(0, 0, 0))
577 + ((i < is->height() - 1 && j > 0)
578 ? iu->get_pixel(2 * i + 1, 2 * j - 1) * _0625
579 : pixel(0, 0, 0))
580 + ((i < is->height() - 1)
581 ? iu->get_pixel(2 * i + 1, 2 * j) * _125
582 : pixel(0, 0, 0))
583 + ((i < is->height() && j < is->width() - 1)
584 ? iu->get_pixel(2 * i + 1, 2 * j + 1) * _0625
585 : pixel(0, 0, 0)))
589 ( ((i > 0 && j > 0)
590 ? _0625
591 : _0)
592 + ((i > 0)
593 ? _125
594 : _0)
595 + ((i > 0 && j < is->width() - 1)
596 ? _0625
597 : _0)
598 + ((j > 0)
599 ? _125
600 : _0)
601 + _25
602 + ((j < is->width() - 1)
603 ? _125
604 : _0)
605 + ((i < is->height() - 1 && j > 0)
606 ? _0625
607 : _0)
608 + ((i < is->height() - 1)
609 ? _125
610 : _0)
611 + ((i < is->height() && j < is->width() - 1)
612 ? _0625
613 : _0) ) ) );
617 public:
618 scale_by_half_threaded(image *_is, const image *_iu)
619 : decompose_domain(0, _is->height(),
620 0, _is->width()) {
621 is = _is;
622 iu = _iu;
626 image *scale_by_half(const char *name) const {
627 ale_pos f = 0.5;
629 image *is = scale_generator(
630 (int) floor(height() * (double) f),
631 (int) floor(width() * (double) f), depth(), name);
633 assert(is);
635 scale_by_half_threaded sbht(is, this);
636 sbht.run();
638 is->_offset = point(_offset[0] * f, _offset[1] * f);
640 return is;
644 * Scale by half. This function uses externally-provided weights,
645 * multiplied by the following filter:
647 * 1/16 1/8 1/16
648 * 1/8 1/4 1/8
649 * 1/16 1/8 1/16
651 * Values are normalized so that the sum of the weights of contributing
652 * pixels is 1.
654 image *scale_by_half(const image *weights, const char *name) const {
656 if (weights == NULL)
657 return scale_by_half(name);
659 ale_pos f = 0.5;
661 image *is = scale_generator(
662 (int) floor(height() * (double) f),
663 (int) floor(width() * (double) f), depth(), name);
665 assert(is);
667 for (unsigned int i = 0; i < is->height(); i++)
668 for (unsigned int j = 0; j < is->width(); j++) {
670 pixel value = pixel
672 ( ( ((i > 0 && j > 0)
673 ? (pixel) get_pixel(2 * i - 1, 2 * j - 1)
674 * (pixel) weights->get_pixel(2 * i - 1, 2 * j - 1)
675 * (ale_real) 0.0625
676 : pixel(0, 0, 0))
677 + ((i > 0)
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 > 0 && 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))
687 + ((j > 0)
688 ? (pixel) get_pixel(2 * i, 2 * j - 1)
689 * (pixel) weights->get_pixel(2 * i, 2 * j - 1)
690 * 0.125
691 : pixel(0, 0, 0))
692 + get_pixel(2 * i, 2 * j)
693 * (pixel) weights->get_pixel(2 * i, 2 * j)
694 * 0.25
695 + ((j < is->width() - 1)
696 ? (pixel) get_pixel(2 * i, 2 * j + 1)
697 * (pixel) weights->get_pixel(2 * i, 2 * j + 1)
698 * 0.125
699 : pixel(0, 0, 0))
700 + ((i < is->height() - 1 && j > 0)
701 ? (pixel) get_pixel(2 * i + 1, 2 * j - 1)
702 * (pixel) weights->get_pixel(2 * i + 1, 2 * j - 1)
703 * 0.0625
704 : pixel(0, 0, 0))
705 + ((i < is->height() - 1)
706 ? (pixel) get_pixel(2 * i + 1, 2 * j)
707 * (pixel) weights->get_pixel(2 * i + 1, 2 * j)
708 * 0.125
709 : pixel(0, 0, 0))
710 + ((i < is->height() && j < is->width() - 1)
711 ? (pixel) get_pixel(2 * i + 1, 2 * j + 1)
712 * (pixel) weights->get_pixel(2 * i + 1, 2 * j + 1)
713 * 0.0625
714 : pixel(0, 0, 0)))
718 ( ((i > 0 && j > 0)
719 ? weights->get_pixel(2 * i - 1, 2 * j - 1)
720 * 0.0625
721 : pixel(0, 0, 0))
722 + ((i > 0)
723 ? weights->get_pixel(2 * i - 1, 2 * j)
724 * 0.125
725 : pixel(0, 0, 0))
726 + ((i > 0 && j < is->width() - 1)
727 ? weights->get_pixel(2 * i - 1, 2 * j + 1)
728 * 0.0625
729 : pixel(0, 0, 0))
730 + ((j > 0)
731 ? weights->get_pixel(2 * i, 2 * j - 1)
732 * 0.125
733 : pixel(0, 0, 0))
734 + weights->get_pixel(2 * i, 2 * j)
735 * 0.25
736 + ((j < is->width() - 1)
737 ? weights->get_pixel(2 * i, 2 * j + 1)
738 * 0.125
739 : pixel(0, 0, 0))
740 + ((i < is->height() - 1 && j > 0)
741 ? weights->get_pixel(2 * i + 1, 2 * j - 1)
742 * 0.0625
743 : pixel(0, 0, 0))
744 + ((i < is->height() - 1)
745 ? weights->get_pixel(2 * i + 1, 2 * j)
746 * 0.125
747 : pixel(0, 0, 0))
748 + ((i < is->height() && j < is->width() - 1)
749 ? weights->get_pixel(2 * i + 1, 2 * j + 1)
750 * 0.0625
751 : pixel(0, 0, 0)) ) );
753 for (int k = 0; k < 3; k++)
754 if (!finite(value[k]))
755 value[k] = 0;
757 is->set_pixel(i, j, value);
760 is->_offset = point(_offset[0] * f, _offset[1] * f);
762 return is;
766 * Scale an image definition array by 1/2.
768 * ALE considers an image definition array as a special kind of image
769 * weight array (typedefs of which should appear below the definition
770 * of this class). ALE uses nonzero pixel values to mean 'defined' and
771 * zero values to mean 'undefined'. Through this interpretation, the
772 * image weight array implementation that ALE uses allows image weight
773 * arrays to also serve as image definition arrays.
775 * Whereas scaling of image weight arrays is not generally obvious in
776 * either purpose or method, ALE requires that image definition arrays
777 * be scalable. (Note that in the special case where weight is treated
778 * as certainty, using a geometric mean is probably correct.)
780 * We currently use a geometric mean to implement scaling of
781 * definition arrays.
784 class defined_scale_by_half_threaded : public thread::decompose_domain {
785 image *is;
786 const image *iu;
787 protected:
788 void subdomain_algorithm(unsigned int thread,
789 int i_min, int i_max, int j_min, int j_max) {
791 #if 0
792 ale_real _0625 = (ale_real) 0.0625;
793 ale_real _125 = (ale_real) 0.125;
794 ale_real _25 = (ale_real) 0.25;
795 #endif
797 int ui_min = (int) i_min;
798 int ui_max = (int) i_max;
799 int uj_min = (int) j_min;
800 int uj_max = (int) j_max;
802 for (int i = ui_min; i < ui_max; i++)
803 for (int j = uj_min; j < uj_max; j++) {
805 #if 0
808 * Calculate a geometric mean; this approach
809 * may be expensive on some platforms (e.g.,
810 * those without floating-point support in
811 * hardware).
814 pixel value = pixel
816 ( ( ((i > 0 && j > 0)
817 ? ppow(iu->get_pixel(2 * i - 1, 2 * j - 1), _0625)
818 : pixel(0, 0, 0))
819 * ((i > 0)
820 ? ppow(iu->get_pixel(2 * i - 1, 2 * j), _125)
821 : pixel(0, 0, 0))
822 * ((i > 0 && j < is->width() - 1)
823 ? ppow(iu->get_pixel(2 * i - 1, 2 * j + 1), _0625)
824 : pixel(0, 0, 0))
825 * ((j > 0)
826 ? ppow(iu->get_pixel(2 * i, 2 * j - 1), _125)
827 : pixel(0, 0, 0))
828 * ppow(iu->get_pixel(2 * i, 2 * j), _25)
829 * ((j < is->width() - 1)
830 ? ppow(iu->get_pixel(2 * i, 2 * j + 1), _125)
831 : pixel(0, 0, 0))
832 * ((i < is->height() - 1 && j > 0)
833 ? ppow(iu->get_pixel(2 * i + 1, 2 * j - 1), _0625)
834 : pixel(0, 0, 0))
835 * ((i < is->height() - 1)
836 ? ppow(iu->get_pixel(2 * i + 1, 2 * j), _125)
837 : pixel(0, 0, 0))
838 * ((i < is->height() && j < is->width() - 1)
839 ? ppow(iu->get_pixel(2 * i + 1, 2 * j + 1), _0625)
840 : pixel(0, 0, 0))));
841 #else
843 pixel value = iu->get_pixel(2 * i, 2 * j);
845 for (int ii = 2 * i - 1; ii <= 2 * i + 1; ii++)
846 for (int jj = 2 * j - 1; jj <= 2 * j + 1; jj++) {
847 if (ii < 0
848 || jj < 0
849 || ii > (int) iu->height() - 1
850 || jj > (int) iu->height() - 1)
851 continue;
853 pixel value2 = iu->get_pixel(ii, jj);
855 for (int k = 0; k < 3; k++)
856 if (value2[k] < value[k]
857 || !finite(value2[k])) /* propagate non-finites */
858 value[k] = value2[k];
861 #endif
864 for (int k = 0; k < 3; k++)
865 if (!finite(value[k]))
866 value[k] = 0;
868 is->set_pixel(i, j, value);
872 public:
873 defined_scale_by_half_threaded(image *_is, const image *_iu)
874 : decompose_domain(0, _is->height(),
875 0, _is->width()) {
876 is = _is;
877 iu = _iu;
881 image *defined_scale_by_half(const char *name) const {
882 ale_pos f = 0.5;
884 image *is = scale_generator(
885 (int) floor(height() * (double) f),
886 (int) floor(width() * (double) f), depth(), name);
888 assert(is);
890 defined_scale_by_half_threaded dsbht(is, this);
891 dsbht.run();
893 is->_offset = point(_offset[0] * f, _offset[1] * f);
895 return is;
899 * Return an image scaled by some factor != 1.0, using bilinear
900 * interpolation.
902 image *scale(ale_pos f, const char *name, int defined = 0) const {
905 * We probably don't want to scale images by a factor of 1.0,
906 * or by non-positive values.
908 assert (f != 1.0 && f > 0);
910 if (f > 1.0) {
911 image *is = scale_generator(
912 (int) floor(height() * (double) f),
913 (int) floor(width() * (double) f), depth(), name);
915 assert(is);
917 unsigned int i, j, k;
919 for (i = 0; i < is->height(); i++)
920 for (j = 0; j < is->width(); j++)
921 for (k = 0; k < is->depth(); k++)
922 is->set_pixel(i, j,
923 get_scaled_bl(point(i, j), f, defined));
925 is->_offset = point(_offset[0] * f, _offset[1] * f);
927 return is;
928 } else if (f == 0.5) {
929 if (defined == 0)
930 return scale_by_half(name);
931 else
932 return defined_scale_by_half(name);
933 } else {
934 image *is = scale(2*f, name, defined);
935 image *result = is->scale(0.5, name, defined);
936 delete is;
937 return result;
943 * Extend the image area to the top, bottom, left, and right,
944 * initializing the new image areas with black pixels. Negative values
945 * shrink the image.
947 virtual image *_extend(int top, int bottom, int left, int right) = 0;
949 static void extend(image **i, int top, int bottom, int left, int right) {
950 image *is = (*i)->_extend(top, bottom, left, right);
952 if (is != NULL) {
953 delete (*i);
954 *i = is;
959 * Clone
961 image *clone(const char *name) const {
962 image *ic = scale_generator(
963 height(), width(), depth(), name);
965 assert(ic);
967 for (unsigned int i = 0; i < height(); i++)
968 for (unsigned int j = 0; j < width(); j++)
969 ic->set_pixel(i, j,
970 get_pixel(i, j));
973 ic->_offset = _offset;
975 return ic;
979 * Acceleration domain sequence point.
982 virtual void accel_domain_sequence() {
986 * Acceleration type. 0 indicates that the type's pixels are directly
987 * accessible; 1 indicates pixels are of image_accel type.
990 virtual int accel_type() {
991 return 0;
995 * Unaccelerated equivalent of an image. Unaccelerated images return
996 * NULL.
999 virtual image *unaccel_equiv() const {
1000 return NULL;
1003 virtual ~image() {
1007 #endif