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 #define ALE_GLSL_IMAGE_INCLUDE \
54 "vec3 image_get_pixel(image _this, vec4 pos);\n"
56 class image
: protected exposure::listener
{
58 static double resident
;
59 unsigned int _dimx
, _dimy
, _depth
;
62 mutable exposure
*_exp
;
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);
75 _dimx
= source
->_dimx
;
76 _dimy
= source
->_dimy
;
77 _offset
= source
->_offset
;
80 bayer
= source
->bayer
;
83 _exp
->add_listener(this, name
);
87 static void set_resident(double r
) {
91 static double get_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
) {
104 _offset
= point(0, 0);
110 _exp
->add_listener(this, name
);
113 unsigned int get_bayer() const {
117 virtual char get_channels(int i
, int j
) const {
121 virtual unsigned int bayer_color(unsigned int i
, unsigned int j
) const {
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 {
136 point
offset() const {
140 void set_offset(int i
, int j
) {
145 void set_offset(point p
) {
149 unsigned int width() const {
153 unsigned int height() const {
157 unsigned int depth() const {
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
) {
173 virtual void mul_pixel(unsigned int y
, unsigned int x
, pixel p
) {
177 virtual void div_pixel(unsigned int y
, unsigned int x
, pixel p
) {
181 virtual void add_chan(unsigned int y
, unsigned int x
, unsigned int k
, ale_real c
) {
185 virtual void div_chan(unsigned int y
, unsigned int x
, unsigned int k
, ale_real c
) {
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
))
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
))
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
++) {
242 if ((unsigned int) iii
> _dimy
- 1)
244 if ((unsigned int) jjj
> _dimx
- 1)
247 pixel p
= get_pixel(iii
, jjj
);
249 for (int d
= 0; d
< 3; d
++) {
260 pixel
get_max_diff(point x
) const {
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 {
275 || x
[0] > height() - 1
276 || x
[1] > width() - 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]);
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);
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
332 result
= pixel(0, 0, 0);
334 for (int n
= 0; n
< 4; n
++)
335 result
+= factor
[n
] * neighbor
[n
];
339 * Calculating the geometric mean may be expensive on
340 * some platforms (e.g., those without floating-point
344 result
= pixel(1, 1, 1);
346 for (int n
= 0; n
< 4; n
++)
347 result
*= ppow(neighbor
[n
], factor
[n
]);
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
];
363 // fprintf(stderr, "result=%f %f %f\n",
364 // (double) result[0],
365 // (double) result[1],
366 // (double) result[2]);
371 pixel
get_scaled_bl(point x
, ale_pos f
, int defined
= 0) const {
373 x
[0]/f
<= height() - 1
375 : (ale_pos
) (height() - 1),
376 x
[1]/f
<= width() - 1
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");
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
++) {
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();
427 is
->set_chan(i
, j
, k
,
428 (p
[k
][pkc
/ 2] + p
[k
][pkc
/ 2 - 1]) / 2);
430 is
->set_chan(i
, j
, k
,
439 * Generate an image of differences of the first channel. The first
440 * coordinate differences are stored in the first channel, second in the
444 image
*fcdiffs() const {
445 image
*is
= scale_generator(height(), width(), depth(), "diff");
449 for (unsigned int i
= 0; i
< height(); i
++)
450 for (unsigned int j
= 0; j
< width(); j
++) {
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()
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));
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));
478 is
->set_chan(i
, j
, 0, 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()
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));
504 is
->set_chan(i
, j
, 1, 0);
512 * Generate an image of median (within a given radius) difference of the
516 image
*fcdiff_median(int radius
) const {
517 image
*diff
= fcdiffs();
521 image
*median
= diff
->medians(radius
);
531 * Scale by half. We use the following filter:
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
{
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
++) {
561 ( ( ((i
> 0 && j
> 0)
562 ? iu
->get_pixel(2 * i
- 1, 2 * j
- 1) * _0625
565 ? iu
->get_pixel(2 * i
- 1, 2 * j
) * _125
567 + ((i
> 0 && j
< is
->width() - 1)
568 ? iu
->get_pixel(2 * i
- 1, 2 * j
+ 1) * _0625
571 ? iu
->get_pixel(2 * i
, 2 * j
- 1) * _125
573 + iu
->get_pixel(2 * i
, 2 * j
) * _25
574 + ((j
< is
->width() - 1)
575 ? iu
->get_pixel(2 * i
, 2 * j
+ 1) * _125
577 + ((i
< is
->height() - 1 && j
> 0)
578 ? iu
->get_pixel(2 * i
+ 1, 2 * j
- 1) * _0625
580 + ((i
< is
->height() - 1)
581 ? iu
->get_pixel(2 * i
+ 1, 2 * j
) * _125
583 + ((i
< is
->height() && j
< is
->width() - 1)
584 ? iu
->get_pixel(2 * i
+ 1, 2 * j
+ 1) * _0625
595 + ((i
> 0 && j
< is
->width() - 1)
602 + ((j
< is
->width() - 1)
605 + ((i
< is
->height() - 1 && j
> 0)
608 + ((i
< is
->height() - 1)
611 + ((i
< is
->height() && j
< is
->width() - 1)
618 scale_by_half_threaded(image
*_is
, const image
*_iu
)
619 : decompose_domain(0, _is
->height(),
626 image
*scale_by_half(const char *name
) const {
629 image
*is
= scale_generator(
630 (int) floor(height() * (double) f
),
631 (int) floor(width() * (double) f
), depth(), name
);
635 scale_by_half_threaded
sbht(is
, this);
638 is
->_offset
= point(_offset
[0] * f
, _offset
[1] * f
);
644 * Scale by half. This function uses externally-provided weights,
645 * multiplied by the following filter:
651 * Values are normalized so that the sum of the weights of contributing
654 image
*scale_by_half(const image
*weights
, const char *name
) const {
657 return scale_by_half(name
);
661 image
*is
= scale_generator(
662 (int) floor(height() * (double) f
),
663 (int) floor(width() * (double) f
), depth(), name
);
667 for (unsigned int i
= 0; i
< is
->height(); i
++)
668 for (unsigned int j
= 0; j
< is
->width(); j
++) {
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)
678 ? (pixel
) get_pixel(2 * i
- 1, 2 * j
)
679 * (pixel
) weights
->get_pixel(2 * i
- 1, 2 * j
)
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)
688 ? (pixel
) get_pixel(2 * i
, 2 * j
- 1)
689 * (pixel
) weights
->get_pixel(2 * i
, 2 * j
- 1)
692 + get_pixel(2 * i
, 2 * j
)
693 * (pixel
) weights
->get_pixel(2 * i
, 2 * j
)
695 + ((j
< is
->width() - 1)
696 ? (pixel
) get_pixel(2 * i
, 2 * j
+ 1)
697 * (pixel
) weights
->get_pixel(2 * i
, 2 * j
+ 1)
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)
705 + ((i
< is
->height() - 1)
706 ? (pixel
) get_pixel(2 * i
+ 1, 2 * j
)
707 * (pixel
) weights
->get_pixel(2 * i
+ 1, 2 * j
)
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)
719 ? weights
->get_pixel(2 * i
- 1, 2 * j
- 1)
723 ? weights
->get_pixel(2 * i
- 1, 2 * j
)
726 + ((i
> 0 && j
< is
->width() - 1)
727 ? weights
->get_pixel(2 * i
- 1, 2 * j
+ 1)
731 ? weights
->get_pixel(2 * i
, 2 * j
- 1)
734 + weights
->get_pixel(2 * i
, 2 * j
)
736 + ((j
< is
->width() - 1)
737 ? weights
->get_pixel(2 * i
, 2 * j
+ 1)
740 + ((i
< is
->height() - 1 && j
> 0)
741 ? weights
->get_pixel(2 * i
+ 1, 2 * j
- 1)
744 + ((i
< is
->height() - 1)
745 ? weights
->get_pixel(2 * i
+ 1, 2 * j
)
748 + ((i
< is
->height() && j
< is
->width() - 1)
749 ? weights
->get_pixel(2 * i
+ 1, 2 * j
+ 1)
751 : pixel(0, 0, 0)) ) );
753 for (int k
= 0; k
< 3; k
++)
754 if (!finite(value
[k
]))
757 is
->set_pixel(i
, j
, value
);
760 is
->_offset
= point(_offset
[0] * f
, _offset
[1] * f
);
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
784 class defined_scale_by_half_threaded
: public thread::decompose_domain
{
788 void subdomain_algorithm(unsigned int thread
,
789 int i_min
, int i_max
, int j_min
, int j_max
) {
792 ale_real _0625
= (ale_real
) 0.0625;
793 ale_real _125
= (ale_real
) 0.125;
794 ale_real _25
= (ale_real
) 0.25;
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
++) {
808 * Calculate a geometric mean; this approach
809 * may be expensive on some platforms (e.g.,
810 * those without floating-point support in
816 ( ( ((i
> 0 && j
> 0)
817 ? ppow(iu
->get_pixel(2 * i
- 1, 2 * j
- 1), _0625
)
820 ? ppow(iu
->get_pixel(2 * i
- 1, 2 * j
), _125
)
822 * ((i
> 0 && j
< is
->width() - 1)
823 ? ppow(iu
->get_pixel(2 * i
- 1, 2 * j
+ 1), _0625
)
826 ? ppow(iu
->get_pixel(2 * i
, 2 * j
- 1), _125
)
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
)
832 * ((i
< is
->height() - 1 && j
> 0)
833 ? ppow(iu
->get_pixel(2 * i
+ 1, 2 * j
- 1), _0625
)
835 * ((i
< is
->height() - 1)
836 ? ppow(iu
->get_pixel(2 * i
+ 1, 2 * j
), _125
)
838 * ((i
< is
->height() && j
< is
->width() - 1)
839 ? ppow(iu
->get_pixel(2 * i
+ 1, 2 * j
+ 1), _0625
)
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
++) {
849 || ii
> (int) iu
->height() - 1
850 || jj
> (int) iu
->height() - 1)
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
];
864 for (int k
= 0; k
< 3; k
++)
865 if (!finite(value
[k
]))
868 is
->set_pixel(i
, j
, value
);
873 defined_scale_by_half_threaded(image
*_is
, const image
*_iu
)
874 : decompose_domain(0, _is
->height(),
881 image
*defined_scale_by_half(const char *name
) const {
884 image
*is
= scale_generator(
885 (int) floor(height() * (double) f
),
886 (int) floor(width() * (double) f
), depth(), name
);
890 defined_scale_by_half_threaded
dsbht(is
, this);
893 is
->_offset
= point(_offset
[0] * f
, _offset
[1] * f
);
899 * Return an image scaled by some factor != 1.0, using bilinear
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);
911 image
*is
= scale_generator(
912 (int) floor(height() * (double) f
),
913 (int) floor(width() * (double) f
), depth(), name
);
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
++)
923 get_scaled_bl(point(i
, j
), f
, defined
));
925 is
->_offset
= point(_offset
[0] * f
, _offset
[1] * f
);
928 } else if (f
== 0.5) {
930 return scale_by_half(name
);
932 return defined_scale_by_half(name
);
934 image
*is
= scale(2*f
, name
, defined
);
935 image
*result
= is
->scale(0.5, name
, defined
);
943 * Extend the image area to the top, bottom, left, and right,
944 * initializing the new image areas with black pixels. Negative values
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
);
961 image
*clone(const char *name
) const {
962 image
*ic
= scale_generator(
963 height(), width(), depth(), name
);
967 for (unsigned int i
= 0; i
< height(); i
++)
968 for (unsigned int j
= 0; j
< width(); j
++)
973 ic
->_offset
= _offset
;
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() {
995 * Unaccelerated equivalent of an image. Unaccelerated images return
999 virtual image
*unaccel_equiv() const {