doc/user: Add captions to uncaptioned tables.
[Ale.git] / d2 / image.h
blob5ac60b6be130cb8bf7a2443680fa1e3c25f8b86f
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 2 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 unsigned int _dimx, _dimy, _depth;
53 point _offset;
54 char *name;
55 mutable exposure *_exp;
56 unsigned int bayer;
57 private:
59 * Memoized function variables. We may want to change these even when
60 * *this is constant.
62 mutable int _apm_memo;
63 mutable ale_real _apm;
64 mutable int _accm_memo;
65 mutable pixel _accm;
66 mutable int _acm_memo;
67 mutable pixel _acm;
69 void avg_channel_clamped_magnitude_memo() const {
70 unsigned int i, j, k;
71 pixel_accum accumulator;
72 pixel_accum divisor;
74 if (_accm_memo)
75 return;
77 _accm_memo = 1;
79 accumulator = pixel_accum(0, 0, 0);
81 for (i = 0; i < _dimy; i++)
82 for (j = 0; j < _dimx; j++) {
83 pixel value = get_pixel(i, j);
85 for (k = 0; k < _depth; k++)
86 if (finite(value[k])) {
87 if (value[k] > 1)
88 value[k] = 1;
89 if (value[k] < 0)
90 value[k] = 0;
91 accumulator[k] += value[k];
92 divisor[k] += 1;
96 accumulator /= divisor;
98 _accm = accumulator;
101 void avg_channel_magnitude_memo() const {
102 unsigned int i, j, k;
103 pixel_accum accumulator;
104 pixel_accum divisor;
106 if (_acm_memo)
107 return;
109 _acm_memo = 1;
111 accumulator = pixel_accum(0, 0, 0);
113 for (i = 0; i < _dimy; i++)
114 for (j = 0; j < _dimx; j++) {
115 pixel value = get_pixel(i, j);
117 for (k = 0; k < _depth; k++)
118 if (finite(value[k])) {
119 accumulator[k] += value[k];
120 divisor[k] += 1;
124 accumulator /= divisor;
126 _acm = accumulator;
129 protected:
130 void image_updated() {
131 _apm_memo = 0;
132 _acm_memo = 0;
133 _accm_memo = 0;
136 public:
137 image (unsigned int dimy, unsigned int dimx, unsigned int depth,
138 char *name = "anonymous", exposure *_exp = NULL,
139 unsigned int bayer = IMAGE_BAYER_NONE) {
141 assert (depth == 3);
142 _depth = 3;
144 _dimx = dimx;
145 _dimy = dimy;
146 _offset = point(0, 0);
147 _apm_memo = 0;
148 _acm_memo = 0;
149 _accm_memo = 0;
150 this->name = name;
151 this->_exp = _exp;
152 this->bayer = bayer;
154 if (_exp != NULL)
155 _exp->add_listener(this, name);
158 unsigned int get_bayer() const {
159 return bayer;
162 exposure &exp() const {
163 return *_exp;
166 point offset() const {
167 return _offset;
170 void set_offset(int i, int j) {
171 _offset[0] = i;
172 _offset[1] = j;
175 void set_offset(point p) {
176 _offset = p;
179 unsigned int width() const {
180 return _dimx;
183 unsigned int height() const {
184 return _dimy;
187 unsigned int depth() const {
188 return _depth;
191 virtual spixel &pix(unsigned int y, unsigned int x) = 0;
193 virtual const spixel &pix(unsigned int y, unsigned int x) const = 0;
195 virtual ale_real &chan(unsigned int y, unsigned int x, unsigned int k) = 0;
197 virtual const ale_real &chan(unsigned int y, unsigned int x, unsigned int k) const = 0;
199 virtual void set_pixel(unsigned int y, unsigned int x, spixel p) {
200 pix(y, x) = p;
203 virtual pixel get_pixel(unsigned int y, unsigned int x) const {
204 return ((const image *)this)->pix(y, x);
207 ale_real maxval() const {
208 ale_real result = get_pixel(0, 0)[0];
210 for (unsigned int i = 0; i < _dimy; i++)
211 for (unsigned int j = 0; j < _dimx; j++) {
212 pixel p = get_pixel(i, j);
214 for (unsigned int k = 0; k < _depth; k++)
215 if (p[k] > result || !finite(result))
216 result = p[k];
219 return result;
222 ale_real minval() const {
223 ale_real result = get_pixel(0, 0)[0];
225 for (unsigned int i = 0; i < _dimy; i++)
226 for (unsigned int j = 0; j < _dimx; j++) {
227 pixel p = get_pixel(i, j);
229 for (unsigned int k = 0; k < _depth; k++)
230 if (p[k] < result || !finite(result))
231 result = p[k];
234 return result;
238 * Get the maximum difference among adjacent pixels.
241 pixel get_max_diff(unsigned int i, unsigned int j) const {
242 assert(i >= 0);
243 assert(j >= 0);
244 assert(i <= _dimy - 1);
245 assert(j <= _dimx - 1);
247 pixel max = get_pixel(i, j), min = get_pixel(i, j);
249 for (int ii = -1; ii <= 1; ii++)
250 for (int jj = -1; jj <= 1; jj++) {
251 int iii = i + ii;
252 int jjj = j + jj;
254 if (iii < 0)
255 continue;
256 if (jjj < 0)
257 continue;
258 if ((unsigned int) iii > _dimy - 1)
259 continue;
260 if ((unsigned int) jjj > _dimx - 1)
261 continue;
263 pixel p = get_pixel(iii, jjj);
265 for (int d = 0; d < 3; d++) {
266 if (p[d] > max[d])
267 max[d] = p[d];
268 if (p[d] < min[d])
269 min[d] = p[d];
273 return max - min;
276 pixel get_max_diff(point x) const {
277 assert (x[0] >= 0);
278 assert (x[1] >= 0);
279 assert (x[0] <= _dimy - 1);
280 assert (x[1] <= _dimx - 1);
282 unsigned int i = (unsigned int) round(x[0]);
283 unsigned int j = (unsigned int) round(x[1]);
285 return get_max_diff(i, j);
289 * Get a color value at a given position using bilinear interpolation between the
290 * four nearest pixels. Result values:
292 * result[0] == pixel value
293 * result[1] == pixel confidence
295 void get_bl(point x, pixel result[2]) const {
297 assert (x[0] >= 0);
298 assert (x[1] >= 0);
299 assert (x[0] <= _dimy - 1);
300 assert (x[1] <= _dimx - 1);
302 int lx = (int) floor(x[1]);
303 int hx = (int) floor(x[1]) + 1;
304 int ly = (int) floor(x[0]);
305 int hy = (int) floor(x[0]) + 1;
307 pixel neighbor[4];
308 ale_pos factor[4];
310 neighbor[0] = get_pixel(ly, lx);
311 neighbor[1] = get_pixel(hy % _dimy, lx);
312 neighbor[2] = get_pixel(hy % _dimy, hx % _dimx);
313 neighbor[3] = get_pixel(ly, hx % _dimx);
315 factor[0] = (hx - x[1]) * (hy - x[0]);
316 factor[1] = (hx - x[1]) * (x[0] - ly);
317 factor[2] = (x[1] - lx) * (x[0] - ly);
318 factor[3] = (x[1] - lx) * (hy - x[0]);
321 * Use bilinear interpolation for pixel value
324 result[0] = pixel(0, 0, 0);
326 for (int n = 0; n < 4; n++)
327 result[0] += factor[n] * neighbor[n];
329 #if 0
331 * Take the minimum confidence
334 if (_exp) {
335 result[1] = _exp->confidence(neighbor[0]);
337 for (int n = 1; n < 4; n++)
338 if (factor[n] > 0) {
339 pixel confidence
340 = _exp->confidence(neighbor[n]);
342 for (int k = 0; k < 3; k++)
343 if (confidence[k] < result[1][k])
344 result[1][k] = confidence[k];
346 } else {
347 result[1] = pixel(1, 1, 1);
349 #else
351 * Use bilinear interpolation for confidence
354 if (_exp) {
355 result[1] = pixel(0, 0, 0);
356 for (int n = 0; n < 4; n++)
357 result[1] += factor[n] * _exp->confidence(neighbor[n]);
358 } else {
359 result[1] = pixel(1, 1, 1);
361 #endif
364 int in_bounds(point x) const {
365 if (x[0] < 0
366 || x[1] < 0
367 || x[0] > height() - 1
368 || x[1] > width() - 1)
369 return 0;
370 if (!x.defined())
371 return 0;
372 return 1;
375 pixel get_bl(point x) const {
376 pixel result[2];
378 get_bl(x, result);
380 return result[0];
383 void get_scaled_bl(point x, ale_pos f, pixel result[2]) const {
384 point scaled(
385 x[0]/f <= height() - 1
386 ? (x[0]/f)
387 : (height() - 1),
388 x[1]/f <= width() - 1
389 ? (x[1]/f)
390 : (width() - 1));
392 get_bl(scaled, result);
395 pixel get_scaled_bl(point x, ale_pos f) const {
396 pixel result[2];
398 get_scaled_bl(x, f, result);
400 return result[0];
405 * Make a new image suitable for receiving scaled values.
407 virtual image *scale_generator(int height, int width, int depth, char *name) const = 0;
410 * Generate an image of medians within a given radius
413 image *medians(int radius) const {
415 assert (radius >= 0);
417 image *is = scale_generator(height(), width(), depth(), "median");
418 assert(is);
420 for (unsigned int i = 0; i < height(); i++)
421 for (unsigned int j = 0; j < width(); j++) {
423 std::vector<ale_real> p[3];
425 for (int ii = -radius; ii <= radius; ii++)
426 for (int jj = -radius; jj <= radius; jj++) {
427 int iii = i + ii;
428 int jjj = j + jj;
430 if (in_bounds(point(iii, jjj)))
431 for (int k = 0; k < 3; k++)
432 if (finite(get_pixel(iii, jjj)[k]))
433 p[k].push_back(get_pixel(iii, jjj)[k]);
436 is->pix(i, j) = d2::pixel::undefined();
438 for (int k = 0; k < 3; k++) {
439 std::sort(p[k].begin(), p[k].end());
441 unsigned int pkc = p[k].size();
443 if (pkc == 0)
444 continue;
446 if (pkc % 2 == 0)
447 is->chan(i, j, k) = (p[k][pkc / 2] + p[k][pkc / 2 - 1]) / 2;
448 else
449 is->chan(i, j, k) = p[k][pkc / 2];
453 return is;
457 * Generate an image of differences of the first channel. The first
458 * coordinate differences are stored in the first channel, second in the
459 * second channel.
462 image *fcdiffs() const {
463 image *is = scale_generator(height(), width(), depth(), "diff");
465 assert(is);
467 for (unsigned int i = 0; i < height(); i++)
468 for (unsigned int j = 0; j < width(); j++) {
470 if (i + 1 < height()
471 && i > 0
472 && !finite(chan(i, j, 0))) {
474 is->chan(i, j, 0) = (chan(i + 1, j, 0) - chan(i - 1, j, 0)) / 2;
476 } else if (i + 1 < height()
477 && i > 0
478 && finite(chan(i + 1, j, 0))
479 && finite(chan(i - 1, j, 0))) {
481 is->chan(i, j, 0) = ((chan(i, j, 0) - chan(i - 1, j, 0))
482 + (chan(i + 1, j, 0) - chan(i, j, 0))) / 2;
484 } else if (i + 1 < height()
485 && finite(chan(i + 1, j, 0))) {
487 is->chan(i, j, 0) = chan(i + 1, j, 0) - chan(i, j, 0);
489 } else if (i > 0
490 && finite(chan(i - 1, j, 0))) {
492 is->chan(i, j, 0) = chan(i, j, 0) - chan(i - 1, j, 0);
494 } else {
495 is->chan(i, j, 0) = 0;
498 if (j + 1 < width()
499 && j > 0
500 && !finite(chan(i, j, 0))) {
502 is->chan(i, j, 1) = (chan(i, j + 1, 0) - chan(i, j - 1, 0)) / 2;
504 } else if (j + 1 < width()
505 && j > 0
506 && finite(chan(i, j + 1, 0))
507 && finite(chan(i, j - 1, 0))) {
509 is->chan(i, j, 1) = ((chan(i, j, 0) - chan(i, j - 1, 0))
510 + (chan(i, j + 1, 0) - chan(i, j, 0))) / 2;
512 } else if (j + 1 < width() && finite(chan(i, j + 1, 0))) {
514 is->chan(i, j, 1) = chan(i, j + 1, 0) - chan(i, j, 0);
516 } else if (j > 0 && finite(chan(i, j - 1, 0))) {
518 is->chan(i, j, 1) = chan(i, j, 0) - chan(i, j - 1, 0);
520 } else {
521 is->chan(i, j, 1) = 0;
525 return is;
529 * Generate an image of median (within a given radius) difference of the
530 * first channel.
533 image *fcdiff_median(int radius) const {
534 image *diff = fcdiffs();
536 assert(diff);
538 image *median = diff->medians(radius);
540 assert(median);
542 delete diff;
544 return median;
548 * Scale by half. We use the following filter:
550 * 1/16 1/8 1/16
551 * 1/8 1/4 1/8
552 * 1/16 1/8 1/16
554 * At the edges, these values are normalized so that the sum of the
555 * weights of contributing pixels is 1.
557 image *scale_by_half(char *name) const {
558 ale_pos f = 0.5;
560 image *is = scale_generator(
561 (int) floor(height() * f),
562 (int) floor(width() * f), depth(), name);
564 assert(is);
566 for (unsigned int i = 0; i < is->height(); i++)
567 for (unsigned int j = 0; j < is->width(); j++)
569 is->set_pixel(i, j,
571 ( ( ((i > 0 && j > 0)
572 ? get_pixel(2 * i - 1, 2 * j - 1) * (ale_real) 0.0625
573 : pixel(0, 0, 0))
574 + ((i > 0)
575 ? get_pixel(2 * i - 1, 2 * j) * 0.125
576 : pixel(0, 0, 0))
577 + ((i > 0 && j < is->width() - 1)
578 ? get_pixel(2 * i - 1, 2 * j + 1) * 0.0625
579 : pixel(0, 0, 0))
580 + ((j > 0)
581 ? get_pixel(2 * i, 2 * j - 1) * 0.125
582 : pixel(0, 0, 0))
583 + get_pixel(2 * i, 2 * j) * 0.25
584 + ((j < is->width() - 1)
585 ? get_pixel(2 * i, 2 * j + 1) * 0.125
586 : pixel(0, 0, 0))
587 + ((i < is->height() - 1 && j > 0)
588 ? get_pixel(2 * i + 1, 2 * j - 1) * 0.0625
589 : pixel(0, 0, 0))
590 + ((i < is->height() - 1)
591 ? get_pixel(2 * i + 1, 2 * j) * 0.125
592 : pixel(0, 0, 0))
593 + ((i < is->height() && j < is->width() - 1)
594 ? get_pixel(2 * i + 1, 2 * j + 1) * 0.0625
595 : pixel(0, 0, 0)))
599 ( ((i > 0 && j > 0)
600 ? 0.0625
601 : 0)
602 + ((i > 0)
603 ? 0.125
604 : 0)
605 + ((i > 0 && j < is->width() - 1)
606 ? 0.0625
607 : 0)
608 + ((j > 0)
609 ? 0.125
610 : 0)
611 + 0.25
612 + ((j < is->width() - 1)
613 ? 0.125
614 : 0)
615 + ((i < is->height() - 1 && j > 0)
616 ? 0.0625
617 : 0)
618 + ((i < is->height() - 1)
619 ? 0.125
620 : 0)
621 + ((i < is->height() && j < is->width() - 1)
622 ? 0.0625
623 : 0) ) ) );
625 is->_offset = point(_offset[0] * f, _offset[1] * f);
627 return is;
631 * Scale by half. This function uses externally-provided weights,
632 * multiplied by the following filter:
634 * 1/16 1/8 1/16
635 * 1/8 1/4 1/8
636 * 1/16 1/8 1/16
638 * Values are normalized so that the sum of the weights of contributing
639 * pixels is 1.
641 image *scale_by_half(const image *weights, char *name) const {
643 if (weights == NULL)
644 return scale_by_half(name);
646 ale_pos f = 0.5;
648 image *is = scale_generator(
649 (int) floor(height() * f),
650 (int) floor(width() * f), depth(), name);
652 assert(is);
654 for (unsigned int i = 0; i < is->height(); i++)
655 for (unsigned int j = 0; j < is->width(); j++) {
657 pixel value = pixel
659 ( ( ((i > 0 && j > 0)
660 ? get_pixel(2 * i - 1, 2 * j - 1)
661 * weights->get_pixel(2 * i - 1, 2 * j - 1)
662 * (ale_real) 0.0625
663 : pixel(0, 0, 0))
664 + ((i > 0)
665 ? get_pixel(2 * i - 1, 2 * j)
666 * weights->get_pixel(2 * i - 1, 2 * j)
667 * 0.125
668 : pixel(0, 0, 0))
669 + ((i > 0 && j < is->width() - 1)
670 ? get_pixel(2 * i - 1, 2 * j + 1)
671 * weights->get_pixel(2 * i - 1, 2 * j + 1)
672 * 0.0625
673 : pixel(0, 0, 0))
674 + ((j > 0)
675 ? get_pixel(2 * i, 2 * j - 1)
676 * weights->get_pixel(2 * i, 2 * j - 1)
677 * 0.125
678 : pixel(0, 0, 0))
679 + get_pixel(2 * i, 2 * j)
680 * weights->get_pixel(2 * i, 2 * j)
681 * 0.25
682 + ((j < is->width() - 1)
683 ? get_pixel(2 * i, 2 * j + 1)
684 * weights->get_pixel(2 * i, 2 * j + 1)
685 * 0.125
686 : pixel(0, 0, 0))
687 + ((i < is->height() - 1 && j > 0)
688 ? get_pixel(2 * i + 1, 2 * j - 1)
689 * weights->get_pixel(2 * i + 1, 2 * j - 1)
690 * 0.0625
691 : pixel(0, 0, 0))
692 + ((i < is->height() - 1)
693 ? get_pixel(2 * i + 1, 2 * j)
694 * weights->get_pixel(2 * i + 1, 2 * j)
695 * 0.125
696 : pixel(0, 0, 0))
697 + ((i < is->height() && j < is->width() - 1)
698 ? get_pixel(2 * i + 1, 2 * j + 1)
699 * weights->get_pixel(2 * i + 1, 2 * j + 1)
700 * 0.0625
701 : pixel(0, 0, 0)))
705 ( ((i > 0 && j > 0)
706 ? weights->get_pixel(2 * i - 1, 2 * j - 1)
707 * 0.0625
708 : pixel(0, 0, 0))
709 + ((i > 0)
710 ? weights->get_pixel(2 * i - 1, 2 * j)
711 * 0.125
712 : pixel(0, 0, 0))
713 + ((i > 0 && j < is->width() - 1)
714 ? weights->get_pixel(2 * i - 1, 2 * j + 1)
715 * 0.0625
716 : pixel(0, 0, 0))
717 + ((j > 0)
718 ? weights->get_pixel(2 * i, 2 * j - 1)
719 * 0.125
720 : pixel(0, 0, 0))
721 + weights->get_pixel(2 * i, 2 * j)
722 * 0.25
723 + ((j < is->width() - 1)
724 ? weights->get_pixel(2 * i, 2 * j + 1)
725 * 0.125
726 : pixel(0, 0, 0))
727 + ((i < is->height() - 1 && j > 0)
728 ? weights->get_pixel(2 * i + 1, 2 * j - 1)
729 * 0.0625
730 : pixel(0, 0, 0))
731 + ((i < is->height() - 1)
732 ? weights->get_pixel(2 * i + 1, 2 * j)
733 * 0.125
734 : pixel(0, 0, 0))
735 + ((i < is->height() && j < is->width() - 1)
736 ? weights->get_pixel(2 * i + 1, 2 * j + 1)
737 * 0.0625
738 : pixel(0, 0, 0)) ) );
740 for (int k = 0; k < 3; k++)
741 if (!finite(value[k]))
742 value[k] = 0;
744 is->set_pixel(i, j, value);
747 is->_offset = point(_offset[0] * f, _offset[1] * f);
749 return is;
753 * Return an image scaled by some factor != 1.0, using bilinear
754 * interpolation.
756 image *scale(ale_pos f, char *name) const {
759 * We probably don't want to scale images by a factor of 1.0,
760 * or by non-positive values.
762 assert (f != 1.0 && f > 0);
764 if (f > 1.0) {
765 image *is = scale_generator(
766 (int) floor(height() * f),
767 (int) floor(width() * f), depth(), name);
769 assert(is);
771 unsigned int i, j, k;
773 for (i = 0; i < is->height(); i++)
774 for (j = 0; j < is->width(); j++)
775 for (k = 0; k < is->depth(); k++)
776 is->set_pixel(i, j,
777 get_scaled_bl(point(i, j), f));
779 is->_offset = point(_offset[0] * f, _offset[1] * f);
781 return is;
782 } else if (f == 0.5) {
783 return scale_by_half(name);
784 } else {
785 image *is = scale(2*f, name);
786 image *result = is->scale(0.5, name);
787 delete is;
788 return result;
794 * Scale an image definition array by 1/2.
796 * ALE considers an image definition array as a special kind of image
797 * weight array (typedefs of which should appear below the definition
798 * of this class). ALE uses nonzero pixel values to mean 'defined' and
799 * zero values to mean 'undefined'. Through this interpretation, the
800 * image weight array implementation that ALE uses allows image weight
801 * arrays to also serve as image definition arrays.
803 * Whereas scaling of image weight arrays is not generally obvious in
804 * either purpose or method, ALE requires that image definition arrays
805 * be scalable, and the method we implement here is a fairly obvious
806 * one. In particular, if any source pixel contributing to the value of
807 * a scaled target pixel has an undefined value, then the scaled target
808 * pixel is undefined (zero). Otherwise, it is defined (non-zero).
810 * Since there are many possible ways of implementing this function, we
811 * choose an easy way and simply multiply the numerical values of the
812 * source pixels to obtain the value of the scaled target pixel.
814 * XXX: we consider all pixels within a 9-pixel square to contribute.
815 * There are other approaches. For example, edge pixels could be
816 * considered to have six contributing pixels and corner pixels four
817 * contributing pixels. To use this convention, change the ': 0' text
818 * in the code below to ': 1'.
821 image *defined_scale_by_half(char *name) const {
822 ale_pos f = 0.5;
824 image *is = scale_generator(
825 (int) floor(height() * f),
826 (int) floor(width() * f), depth(), name);
828 assert(is);
830 for (unsigned int i = 0; i < is->height(); i++)
831 for (unsigned int j = 0; j < is->width(); j++)
833 is->set_pixel(i, j,
835 ( ((i > 0 && j > 0)
836 ? get_pixel(2 * i - 1, 2 * j - 1)
837 : pixel())
838 * ((i > 0)
839 ? get_pixel(2 * i - 1, 2 * j)
840 : pixel())
841 * ((i > 0 && j < is->width() - 1)
842 ? get_pixel(2 * i - 1, 2 * j + 1)
843 : pixel())
844 * ((j > 0)
845 ? get_pixel(2 * i, 2 * j - 1)
846 : pixel())
847 * get_pixel(2 * i, 2 * j)
848 * ((j < is->width() - 1)
849 ? get_pixel(2 * i, 2 * j + 1)
850 : pixel())
851 * ((i < is->height() - 1 && j > 0)
852 ? get_pixel(2 * i + 1, 2 * j - 1)
853 : pixel())
854 * ((i < is->height() - 1)
855 ? get_pixel(2 * i + 1, 2 * j)
856 : pixel())
857 * ((i < is->height() && j < is->width() - 1)
858 ? get_pixel(2 * i + 1, 2 * j + 1)
859 : pixel())));
861 is->_offset = point(_offset[0] * f, _offset[1] * f);
863 return is;
867 * Extend the image area to the top, bottom, left, and right,
868 * initializing the new image areas with black pixels. Negative values
869 * shrink the image.
871 virtual void extend(int top, int bottom, int left, int right) = 0;
874 * Clone
876 image *clone(char *name) const {
877 image *ic = scale_generator(
878 height(), width(), depth(), name);
880 assert(ic);
882 for (unsigned int i = 0; i < height(); i++)
883 for (unsigned int j = 0; j < width(); j++)
884 ic->set_pixel(i, j,
885 get_pixel(i, j));
888 ic->_offset = _offset;
890 ic->_apm_memo = _apm_memo;
891 ic->_acm_memo = _acm_memo;
892 ic->_accm_memo = _accm_memo;
893 ic->_apm = _apm;
894 ic->_acm = _acm;
895 ic->_accm = _accm;
897 return ic;
901 * Calculate the average (mean) clamped magnitude of a channel across
902 * all pixels in an image. The magnitude is clamped to the range of
903 * real inputs.
905 ale_real avg_channel_clamped_magnitude(unsigned int k) const {
908 * This is a memoized function
911 assert (k < _depth);
913 avg_channel_clamped_magnitude_memo();
914 return _accm[k];
917 pixel avg_channel_clamped_magnitude() const {
918 avg_channel_clamped_magnitude_memo();
919 return _accm;
923 * Calculate the average (mean) magnitude of a channel across all
924 * pixels in an image.
926 ale_real avg_channel_magnitude(unsigned int k) const {
929 * This is a memoized function
932 assert (k < _depth);
934 avg_channel_magnitude_memo();
935 return _acm[k];
938 pixel avg_channel_magnitude() const {
939 avg_channel_magnitude_memo();
940 return _acm;
944 * Calculate the average (mean) magnitude of a pixel (where magnitude
945 * is defined as the mean of the channel values).
947 ale_real avg_pixel_magnitude() const {
948 unsigned int i, j, k;
950 ale_accum accumulator;
951 ale_accum divisor = 0;
953 if (_apm_memo)
954 return _apm;
956 _apm_memo = 1;
957 accumulator = 0;
959 for (i = 0; i < _dimy; i++)
960 for (j = 0; j < _dimx; j++) {
961 pixel value = get_pixel(i, j);
963 for (k = 0; k < _depth; k++)
964 if (finite(value[k])) {
965 accumulator += value[k];
966 divisor++;
970 accumulator /= divisor;
972 _apm = accumulator;
974 return _apm;
977 virtual ~image() {
981 #endif