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
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
{
52 unsigned int _dimx
, _dimy
, _depth
;
55 mutable exposure
*_exp
;
59 * Memoized function variables. We may want to change these even when
62 mutable int _apm_memo
;
63 mutable ale_real _apm
;
64 mutable int _accm_memo
;
66 mutable int _acm_memo
;
69 void avg_channel_clamped_magnitude_memo() const {
71 pixel_accum accumulator
;
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
])) {
91 accumulator
[k
] += value
[k
];
96 accumulator
/= divisor
;
101 void avg_channel_magnitude_memo() const {
102 unsigned int i
, j
, k
;
103 pixel_accum accumulator
;
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
];
124 accumulator
/= divisor
;
130 void image_updated() {
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
) {
146 _offset
= point(0, 0);
155 _exp
->add_listener(this, name
);
158 unsigned int get_bayer() const {
162 virtual char get_channels(int i
, int j
) const {
166 double storage_size() const {
167 if (bayer
!= IMAGE_BAYER_NONE
)
168 return _dimx
* _dimy
* sizeof(ale_real
);
170 return 3 * _dimx
* _dimy
* sizeof(ale_real
);
173 exposure
&exp() const {
177 point
offset() const {
181 void set_offset(int i
, int j
) {
186 void set_offset(point p
) {
190 unsigned int width() const {
194 unsigned int height() const {
198 unsigned int depth() const {
202 virtual spixel
&pix(unsigned int y
, unsigned int x
) = 0;
204 virtual const spixel
&pix(unsigned int y
, unsigned int x
) const = 0;
206 virtual ale_real
&chan(unsigned int y
, unsigned int x
, unsigned int k
) = 0;
208 virtual const ale_real
&chan(unsigned int y
, unsigned int x
, unsigned int k
) const = 0;
210 virtual void set_pixel(unsigned int y
, unsigned int x
, spixel p
) {
214 virtual pixel
get_pixel(unsigned int y
, unsigned int x
) const {
215 return ((const image
*)this)->pix(y
, x
);
218 virtual pixel
get_raw_pixel(unsigned int y
, unsigned int x
) const {
219 return ((const image
*)this)->get_pixel(y
, x
);
222 ale_real
maxval() 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
))
237 ale_real
minval() const {
238 ale_real result
= get_pixel(0, 0)[0];
240 for (unsigned int i
= 0; i
< _dimy
; i
++)
241 for (unsigned int j
= 0; j
< _dimx
; j
++) {
242 pixel p
= get_pixel(i
, j
);
244 for (unsigned int k
= 0; k
< _depth
; k
++)
245 if (p
[k
] < result
|| !finite(result
))
253 * Get the maximum difference among adjacent pixels.
256 pixel
get_max_diff(unsigned int i
, unsigned int j
) const {
257 assert(i
<= _dimy
- 1);
258 assert(j
<= _dimx
- 1);
260 pixel max
= get_pixel(i
, j
), min
= get_pixel(i
, j
);
262 for (int ii
= -1; ii
<= 1; ii
++)
263 for (int jj
= -1; jj
<= 1; jj
++) {
271 if ((unsigned int) iii
> _dimy
- 1)
273 if ((unsigned int) jjj
> _dimx
- 1)
276 pixel p
= get_pixel(iii
, jjj
);
278 for (int d
= 0; d
< 3; d
++) {
289 pixel
get_max_diff(point x
) const {
292 assert (x
[0] <= _dimy
- 1);
293 assert (x
[1] <= _dimx
- 1);
295 unsigned int i
= (unsigned int) round(x
[0]);
296 unsigned int j
= (unsigned int) round(x
[1]);
298 return get_max_diff(i
, j
);
301 int in_bounds(point x
) const {
304 || x
[0] > height() - 1
305 || x
[1] > width() - 1)
313 * Get a color value at a given position using bilinear interpolation between the
314 * four nearest pixels.
316 pixel
get_bl(point x
, int defined
= 0) const {
322 assert (x
[0] <= _dimy
- 1);
323 assert (x
[1] <= _dimx
- 1);
325 int lx
= (int) floor(x
[1]);
326 int hx
= (int) floor(x
[1]) + 1;
327 int ly
= (int) floor(x
[0]);
328 int hy
= (int) floor(x
[0]) + 1;
333 neighbor
[0] = get_pixel(ly
, lx
);
334 neighbor
[1] = get_pixel(hy
% _dimy
, lx
);
335 neighbor
[2] = get_pixel(hy
% _dimy
, hx
% _dimx
);
336 neighbor
[3] = get_pixel(ly
, hx
% _dimx
);
338 factor
[0] = (hx
- x
[1]) * (hy
- x
[0]);
339 factor
[1] = (hx
- x
[1]) * (x
[0] - ly
);
340 factor
[2] = (x
[1] - lx
) * (x
[0] - ly
);
341 factor
[3] = (x
[1] - lx
) * (hy
- x
[0]);
344 * Use bilinear and/or geometric interpolation
348 result
= pixel(0, 0, 0);
350 for (int n
= 0; n
< 4; n
++)
351 result
+= factor
[n
] * neighbor
[n
];
353 result
= pixel(1, 1, 1);
355 for (int n
= 0; n
< 4; n
++)
356 result
*= ppow(neighbor
[n
], factor
[n
]);
362 pixel
get_scaled_bl(point x
, ale_pos f
, int defined
= 0) const {
364 x
[0]/f
<= height() - 1
367 x
[1]/f
<= width() - 1
371 return get_bl(scaled
, defined
);
376 * Make a new image suitable for receiving scaled values.
378 virtual image
*scale_generator(int height
, int width
, int depth
, char *name
) const = 0;
381 * Generate an image of medians within a given radius
384 image
*medians(int radius
) const {
386 assert (radius
>= 0);
388 image
*is
= scale_generator(height(), width(), depth(), "median");
391 for (unsigned int i
= 0; i
< height(); i
++)
392 for (unsigned int j
= 0; j
< width(); j
++) {
394 std::vector
<ale_real
> p
[3];
396 for (int ii
= -radius
; ii
<= radius
; ii
++)
397 for (int jj
= -radius
; jj
<= radius
; jj
++) {
401 if (in_bounds(point(iii
, jjj
)))
402 for (int k
= 0; k
< 3; k
++)
403 if (finite(get_pixel(iii
, jjj
)[k
]))
404 p
[k
].push_back(get_pixel(iii
, jjj
)[k
]);
407 is
->pix(i
, j
) = d2::pixel::undefined();
409 for (int k
= 0; k
< 3; k
++) {
410 std::sort(p
[k
].begin(), p
[k
].end());
412 unsigned int pkc
= p
[k
].size();
418 is
->chan(i
, j
, k
) = (p
[k
][pkc
/ 2] + p
[k
][pkc
/ 2 - 1]) / 2;
420 is
->chan(i
, j
, k
) = p
[k
][pkc
/ 2];
428 * Generate an image of differences of the first channel. The first
429 * coordinate differences are stored in the first channel, second in the
433 image
*fcdiffs() const {
434 image
*is
= scale_generator(height(), width(), depth(), "diff");
438 for (unsigned int i
= 0; i
< height(); i
++)
439 for (unsigned int j
= 0; j
< width(); j
++) {
443 && !finite(chan(i
, j
, 0))) {
445 is
->chan(i
, j
, 0) = (chan(i
+ 1, j
, 0) - chan(i
- 1, j
, 0)) / 2;
447 } else if (i
+ 1 < height()
449 && finite(chan(i
+ 1, j
, 0))
450 && finite(chan(i
- 1, j
, 0))) {
452 is
->chan(i
, j
, 0) = ((chan(i
, j
, 0) - chan(i
- 1, j
, 0))
453 + (chan(i
+ 1, j
, 0) - chan(i
, j
, 0))) / 2;
455 } else if (i
+ 1 < height()
456 && finite(chan(i
+ 1, j
, 0))) {
458 is
->chan(i
, j
, 0) = chan(i
+ 1, j
, 0) - chan(i
, j
, 0);
461 && finite(chan(i
- 1, j
, 0))) {
463 is
->chan(i
, j
, 0) = chan(i
, j
, 0) - chan(i
- 1, j
, 0);
466 is
->chan(i
, j
, 0) = 0;
471 && !finite(chan(i
, j
, 0))) {
473 is
->chan(i
, j
, 1) = (chan(i
, j
+ 1, 0) - chan(i
, j
- 1, 0)) / 2;
475 } else if (j
+ 1 < width()
477 && finite(chan(i
, j
+ 1, 0))
478 && finite(chan(i
, j
- 1, 0))) {
480 is
->chan(i
, j
, 1) = ((chan(i
, j
, 0) - chan(i
, j
- 1, 0))
481 + (chan(i
, j
+ 1, 0) - chan(i
, j
, 0))) / 2;
483 } else if (j
+ 1 < width() && finite(chan(i
, j
+ 1, 0))) {
485 is
->chan(i
, j
, 1) = chan(i
, j
+ 1, 0) - chan(i
, j
, 0);
487 } else if (j
> 0 && finite(chan(i
, j
- 1, 0))) {
489 is
->chan(i
, j
, 1) = chan(i
, j
, 0) - chan(i
, j
- 1, 0);
492 is
->chan(i
, j
, 1) = 0;
500 * Generate an image of median (within a given radius) difference of the
504 image
*fcdiff_median(int radius
) const {
505 image
*diff
= fcdiffs();
509 image
*median
= diff
->medians(radius
);
519 * Scale by half. We use the following filter:
525 * At the edges, these values are normalized so that the sum of the
526 * weights of contributing pixels is 1.
528 image
*scale_by_half(char *name
) const {
531 image
*is
= scale_generator(
532 (int) floor(height() * f
),
533 (int) floor(width() * f
), depth(), name
);
537 for (unsigned int i
= 0; i
< is
->height(); i
++)
538 for (unsigned int j
= 0; j
< is
->width(); j
++)
542 ( ( ((i
> 0 && j
> 0)
543 ? get_pixel(2 * i
- 1, 2 * j
- 1) * (ale_real
) 0.0625
546 ? get_pixel(2 * i
- 1, 2 * j
) * 0.125
548 + ((i
> 0 && j
< is
->width() - 1)
549 ? get_pixel(2 * i
- 1, 2 * j
+ 1) * 0.0625
552 ? get_pixel(2 * i
, 2 * j
- 1) * 0.125
554 + get_pixel(2 * i
, 2 * j
) * 0.25
555 + ((j
< is
->width() - 1)
556 ? get_pixel(2 * i
, 2 * j
+ 1) * 0.125
558 + ((i
< is
->height() - 1 && j
> 0)
559 ? get_pixel(2 * i
+ 1, 2 * j
- 1) * 0.0625
561 + ((i
< is
->height() - 1)
562 ? get_pixel(2 * i
+ 1, 2 * j
) * 0.125
564 + ((i
< is
->height() && j
< is
->width() - 1)
565 ? get_pixel(2 * i
+ 1, 2 * j
+ 1) * 0.0625
576 + ((i
> 0 && j
< is
->width() - 1)
583 + ((j
< is
->width() - 1)
586 + ((i
< is
->height() - 1 && j
> 0)
589 + ((i
< is
->height() - 1)
592 + ((i
< is
->height() && j
< is
->width() - 1)
596 is
->_offset
= point(_offset
[0] * f
, _offset
[1] * f
);
602 * Scale by half. This function uses externally-provided weights,
603 * multiplied by the following filter:
609 * Values are normalized so that the sum of the weights of contributing
612 image
*scale_by_half(const image
*weights
, char *name
) const {
615 return scale_by_half(name
);
619 image
*is
= scale_generator(
620 (int) floor(height() * f
),
621 (int) floor(width() * f
), depth(), name
);
625 for (unsigned int i
= 0; i
< is
->height(); i
++)
626 for (unsigned int j
= 0; j
< is
->width(); j
++) {
630 ( ( ((i
> 0 && j
> 0)
631 ? get_pixel(2 * i
- 1, 2 * j
- 1)
632 * weights
->get_pixel(2 * i
- 1, 2 * j
- 1)
636 ? get_pixel(2 * i
- 1, 2 * j
)
637 * weights
->get_pixel(2 * i
- 1, 2 * j
)
640 + ((i
> 0 && j
< is
->width() - 1)
641 ? get_pixel(2 * i
- 1, 2 * j
+ 1)
642 * weights
->get_pixel(2 * i
- 1, 2 * j
+ 1)
646 ? get_pixel(2 * i
, 2 * j
- 1)
647 * weights
->get_pixel(2 * i
, 2 * j
- 1)
650 + get_pixel(2 * i
, 2 * j
)
651 * weights
->get_pixel(2 * i
, 2 * j
)
653 + ((j
< is
->width() - 1)
654 ? get_pixel(2 * i
, 2 * j
+ 1)
655 * weights
->get_pixel(2 * i
, 2 * j
+ 1)
658 + ((i
< is
->height() - 1 && j
> 0)
659 ? get_pixel(2 * i
+ 1, 2 * j
- 1)
660 * weights
->get_pixel(2 * i
+ 1, 2 * j
- 1)
663 + ((i
< is
->height() - 1)
664 ? get_pixel(2 * i
+ 1, 2 * j
)
665 * weights
->get_pixel(2 * i
+ 1, 2 * j
)
668 + ((i
< is
->height() && j
< is
->width() - 1)
669 ? get_pixel(2 * i
+ 1, 2 * j
+ 1)
670 * weights
->get_pixel(2 * i
+ 1, 2 * j
+ 1)
677 ? weights
->get_pixel(2 * i
- 1, 2 * j
- 1)
681 ? weights
->get_pixel(2 * i
- 1, 2 * j
)
684 + ((i
> 0 && j
< is
->width() - 1)
685 ? weights
->get_pixel(2 * i
- 1, 2 * j
+ 1)
689 ? weights
->get_pixel(2 * i
, 2 * j
- 1)
692 + weights
->get_pixel(2 * i
, 2 * j
)
694 + ((j
< is
->width() - 1)
695 ? weights
->get_pixel(2 * i
, 2 * j
+ 1)
698 + ((i
< is
->height() - 1 && j
> 0)
699 ? weights
->get_pixel(2 * i
+ 1, 2 * j
- 1)
702 + ((i
< is
->height() - 1)
703 ? weights
->get_pixel(2 * i
+ 1, 2 * j
)
706 + ((i
< is
->height() && j
< is
->width() - 1)
707 ? weights
->get_pixel(2 * i
+ 1, 2 * j
+ 1)
709 : pixel(0, 0, 0)) ) );
711 for (int k
= 0; k
< 3; k
++)
712 if (!finite(value
[k
]))
715 is
->set_pixel(i
, j
, value
);
718 is
->_offset
= point(_offset
[0] * f
, _offset
[1] * f
);
724 * Return an image scaled by some factor != 1.0, using bilinear
727 image
*scale(ale_pos f
, char *name
, int defined
= 0) const {
730 * We probably don't want to scale images by a factor of 1.0,
731 * or by non-positive values.
733 assert (f
!= 1.0 && f
> 0);
736 image
*is
= scale_generator(
737 (int) floor(height() * f
),
738 (int) floor(width() * f
), depth(), name
);
742 unsigned int i
, j
, k
;
744 for (i
= 0; i
< is
->height(); i
++)
745 for (j
= 0; j
< is
->width(); j
++)
746 for (k
= 0; k
< is
->depth(); k
++)
748 get_scaled_bl(point(i
, j
), f
, defined
));
750 is
->_offset
= point(_offset
[0] * f
, _offset
[1] * f
);
753 } else if (f
== 0.5) {
754 return scale_by_half(name
);
756 image
*is
= scale(2*f
, name
);
757 image
*result
= is
->scale(0.5, name
);
765 * Scale an image definition array by 1/2.
767 * ALE considers an image definition array as a special kind of image
768 * weight array (typedefs of which should appear below the definition
769 * of this class). ALE uses nonzero pixel values to mean 'defined' and
770 * zero values to mean 'undefined'. Through this interpretation, the
771 * image weight array implementation that ALE uses allows image weight
772 * arrays to also serve as image definition arrays.
774 * Whereas scaling of image weight arrays is not generally obvious in
775 * either purpose or method, ALE requires that image definition arrays
776 * be scalable. (Note that in the special case where weight is treated
777 * as certainty, using a geometric mean is probably correct.)
779 * We currently use a geometric mean to implement scaling of
783 image
*defined_scale_by_half(char *name
) const {
786 image
*is
= scale_generator(
787 (int) floor(height() * f
),
788 (int) floor(width() * f
), depth(), name
);
792 for (unsigned int i
= 0; i
< is
->height(); i
++)
793 for (unsigned int j
= 0; j
< is
->width(); j
++) {
797 ( ( ((i
> 0 && j
> 0)
798 ? ppow(get_pixel(2 * i
- 1, 2 * j
- 1), 0.0625)
801 ? ppow(get_pixel(2 * i
- 1, 2 * j
), 0.125)
803 * ((i
> 0 && j
< is
->width() - 1)
804 ? ppow(get_pixel(2 * i
- 1, 2 * j
+ 1), 0.0625)
807 ? ppow(get_pixel(2 * i
, 2 * j
- 1), 0.125)
809 * ppow(get_pixel(2 * i
, 2 * j
), 0.25)
810 * ((j
< is
->width() - 1)
811 ? ppow(get_pixel(2 * i
, 2 * j
+ 1), 0.125)
813 * ((i
< is
->height() - 1 && j
> 0)
814 ? ppow(get_pixel(2 * i
+ 1, 2 * j
- 1), 0.0625)
816 * ((i
< is
->height() - 1)
817 ? ppow(get_pixel(2 * i
+ 1, 2 * j
), 0.125)
819 * ((i
< is
->height() && j
< is
->width() - 1)
820 ? ppow(get_pixel(2 * i
+ 1, 2 * j
+ 1), 0.0625)
824 for (int k
= 0; k
< 3; k
++)
825 if (!finite(value
[k
]))
828 is
->set_pixel(i
, j
, value
);
831 is
->_offset
= point(_offset
[0] * f
, _offset
[1] * f
);
837 * Extend the image area to the top, bottom, left, and right,
838 * initializing the new image areas with black pixels. Negative values
841 virtual void extend(int top
, int bottom
, int left
, int right
) = 0;
846 image
*clone(char *name
) const {
847 image
*ic
= scale_generator(
848 height(), width(), depth(), name
);
852 for (unsigned int i
= 0; i
< height(); i
++)
853 for (unsigned int j
= 0; j
< width(); j
++)
858 ic
->_offset
= _offset
;
860 ic
->_apm_memo
= _apm_memo
;
861 ic
->_acm_memo
= _acm_memo
;
862 ic
->_accm_memo
= _accm_memo
;
871 * Calculate the average (mean) clamped magnitude of a channel across
872 * all pixels in an image. The magnitude is clamped to the range of
875 ale_real
avg_channel_clamped_magnitude(unsigned int k
) const {
878 * This is a memoized function
883 avg_channel_clamped_magnitude_memo();
887 pixel
avg_channel_clamped_magnitude() const {
888 avg_channel_clamped_magnitude_memo();
893 * Calculate the average (mean) magnitude of a channel across all
894 * pixels in an image.
896 ale_real
avg_channel_magnitude(unsigned int k
) const {
899 * This is a memoized function
904 avg_channel_magnitude_memo();
908 pixel
avg_channel_magnitude() const {
909 avg_channel_magnitude_memo();
914 * Calculate the average (mean) magnitude of a pixel (where magnitude
915 * is defined as the mean of the channel values).
917 ale_real
avg_pixel_magnitude() const {
918 unsigned int i
, j
, k
;
920 ale_accum accumulator
;
921 ale_accum divisor
= 0;
929 for (i
= 0; i
< _dimy
; i
++)
930 for (j
= 0; j
< _dimx
; j
++) {
931 pixel value
= get_pixel(i
, j
);
933 for (k
= 0; k
< _depth
; k
++)
934 if (finite(value
[k
])) {
935 accumulator
+= value
[k
];
940 accumulator
/= divisor
;