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_bayer_ale_real.h: Bayer-patterned image represented by an array of ale_reals
25 #ifndef __image_bayer_ale_real_h__
26 #define __image_bayer_ale_real_h__
28 #include "exposure/exposure.h"
31 #include "image_ale_real.h"
33 template <int disk_support
>
34 class image_bayer_ale_real
: public image
{
37 * Data structures without file support.
43 * Data structures for file support.
47 mutable ale_sreal
*_p_segments
[RESIDENT_DIVISIONS
];
48 mutable int dirty_segments
[RESIDENT_DIVISIONS
];
49 mutable int resident_list
[RESIDENT_DIVISIONS
];
50 mutable int resident_next
;
53 mutable thread::rwlock_t rwlock
;
57 * X offset of 'R' element
59 unsigned int r_x_offset() const {
64 * Y offset of 'R' element
66 unsigned int r_y_offset() const {
67 return (bayer
& 0x2) >> 1;
72 * Return the color of a given pixel.
74 unsigned int bayer_color(unsigned int i
, unsigned int j
) const {
75 return (i
+ r_y_offset()) % 2 + (j
+ r_x_offset()) % 2;
78 char get_channels(int i
, int j
) const {
79 return (1 << bayer_color(i
, j
));
85 * Wrapper encapsulating details of the separation between the
86 * resident-checking implementation and non-checking.
88 static inline image
*new_image_bayer_ale_real(unsigned int dimy
,
92 const char *name
= "anonymous",
93 exposure
*exp
= NULL
) {
95 unsigned int resident
= image::get_resident();
97 if (resident
== 0 || resident
* 1000000 > dimy
* dimx
)
98 return new image_bayer_ale_real
<0>(dimy
, dimx
, depth
, bayer
, name
, exp
);
100 return new image_bayer_ale_real
<1>(dimy
, dimx
, depth
, bayer
, name
, exp
);
104 image_bayer_ale_real (unsigned int dimy
, unsigned int dimx
, unsigned int depth
,
105 unsigned int bayer
, const char *name
= "anonymous", exposure
*exp
= NULL
)
106 : image(dimy
, dimx
, depth
, name
, exp
, bayer
) {
108 assert (bayer
== IMAGE_BAYER_BGRG
109 || bayer
== IMAGE_BAYER_GBGR
110 || bayer
== IMAGE_BAYER_GRGB
111 || bayer
== IMAGE_BAYER_RGBG
);
113 if (disk_support
== 0) {
114 _p
= new ale_sreal
[dimx
* dimy
];
119 fprintf(stderr
, "Could not allocate memory for image data.\n");
123 for (unsigned int i
= 0; i
< dimx
* dimy
; i
++) {
127 rows_per_segment
= (int) ceil((double) dimy
/ (double) RESIDENT_DIVISIONS
);
129 assert (rows_per_segment
> 0);
131 for (int i
= 0; i
< RESIDENT_DIVISIONS
; i
++) {
132 _p_segments
[i
] = NULL
;
133 dirty_segments
[i
] = 0;
134 resident_list
[i
] = -1;
137 resident_max
= (unsigned int) floor((image::get_resident() * 1000000)
138 / (rows_per_segment
* dimx
));
140 assert (resident_max
<= RESIDENT_DIVISIONS
);
142 if (resident_max
== 0) {
143 ui::get()->error_hint(
144 "No segments resident in image array.",
145 "Try recompiling with more RESIDENT_DIVISIONS");
153 ui::get()->error_hint(
154 "Unable to create temporary file to support image array.",
155 "Set --resident 0, or Win32/64 users might run as admin.");
158 ale_sreal
*zero
= new ale_sreal
[dimx
];
162 for (unsigned int i
= 0; i
< dimx
; i
++)
165 for (unsigned int i
= 0; i
< dimy
; i
++) {
166 unsigned int c
= fwrite(zero
, sizeof(ale_sreal
), dimx
, support
);
168 ui::get()->error_hint("Image array support file error.",
169 "Submit a bug report.");
176 virtual ~image_bayer_ale_real() {
177 if (disk_support
== 0) {
180 for (int i
= 0; i
< RESIDENT_DIVISIONS
; i
++) {
182 delete[] _p_segments
[i
];
189 void resident_begin(unsigned int segment
) const {
191 if (_p_segments
[segment
])
197 if (_p_segments
[segment
])
200 if (resident_list
[resident_next
] >= 0) {
205 if (dirty_segments
[resident_list
[resident_next
]]) {
206 fseek(support
, rows_per_segment
* _dimx
* sizeof(ale_sreal
)
207 * resident_list
[resident_next
],
209 assert(_p_segments
[resident_list
[resident_next
]]);
210 size_t fwrite_result
= fwrite(_p_segments
[resident_list
[resident_next
]],
211 sizeof(ale_sreal
), rows_per_segment
* _dimx
, support
);
213 assert(fwrite_result
== rows_per_segment
* _dimx
);
215 dirty_segments
[resident_list
[resident_next
]] = 0;
218 delete[] _p_segments
[resident_list
[resident_next
]];
219 _p_segments
[resident_list
[resident_next
]] = NULL
;
222 resident_list
[resident_next
] = segment
;
224 _p_segments
[segment
] = new ale_sreal
[_dimx
* rows_per_segment
];
226 assert (_p_segments
[segment
]);
228 fseek(support
, rows_per_segment
* _dimx
* sizeof(ale_sreal
)
232 size_t fread_result
= fread(_p_segments
[segment
], sizeof(ale_sreal
), rows_per_segment
* _dimx
, support
);
234 assert(fread_result
== rows_per_segment
* _dimx
);
237 * Update the next ejection candidate.
240 if (resident_next
>= resident_max
)
244 void resident_end(unsigned int segment
) const {
248 void set_chan(unsigned int y
, unsigned int x
, unsigned int k
, ale_sreal c
) {
249 assert (k
== bayer_color(y
, x
));
250 if (disk_support
== 0) {
251 _p
[y
* _dimx
+ x
] = c
;
253 int segment
= y
/ rows_per_segment
;
254 assert (segment
< RESIDENT_DIVISIONS
);
256 resident_begin(segment
);
258 _p_segments
[segment
][(y
% rows_per_segment
) * _dimx
+ x
] = c
;
259 dirty_segments
[segment
] = 1;
261 resident_end(segment
);
265 void add_chan(unsigned int y
, unsigned int x
, unsigned int k
, ale_sreal c
) {
266 assert (k
== bayer_color(y
, x
));
267 if (disk_support
== 0) {
268 _p
[y
* _dimx
+ x
] += c
;
270 int segment
= y
/ rows_per_segment
;
271 assert (segment
< RESIDENT_DIVISIONS
);
273 resident_begin(segment
);
275 _p_segments
[segment
][(y
% rows_per_segment
) * _dimx
+ x
] += c
;
276 dirty_segments
[segment
] = 1;
278 resident_end(segment
);
282 void div_chan(unsigned int y
, unsigned int x
, unsigned int k
, ale_sreal c
) {
283 assert (k
== bayer_color(y
, x
));
284 if (disk_support
== 0) {
285 _p
[y
* _dimx
+ x
] /= c
;
287 int segment
= y
/ rows_per_segment
;
288 assert (segment
< RESIDENT_DIVISIONS
);
290 resident_begin(segment
);
292 _p_segments
[segment
][(y
% rows_per_segment
) * _dimx
+ x
] /= c
;
293 dirty_segments
[segment
] = 1;
295 resident_end(segment
);
299 ale_sreal
get_chan(unsigned int y
, unsigned int x
, unsigned int k
) const {
302 * This may be expensive.
304 assert (k
== bayer_color(y
, x
));
306 if (disk_support
== 0) {
307 return _p
[y
* _dimx
+ x
];
309 int segment
= y
/ rows_per_segment
;
310 assert (segment
< RESIDENT_DIVISIONS
);
312 resident_begin(segment
);
314 ale_sreal result
= _p_segments
[segment
]
315 [(y
% rows_per_segment
) * _dimx
+ x
];
317 resident_end(segment
);
324 * This method throws away data not stored at this pixel
327 void set_pixel(unsigned int y
, unsigned int x
, spixel p
) {
328 set_chan(y
, x
, bayer_color(y
, x
), p
[bayer_color(y
, x
)]);
332 * This method uses bilinear interpolation.
334 spixel
get_pixel(unsigned int y
, unsigned int x
) const {
336 unsigned int k
= bayer_color(y
, x
);
340 result
[k
] = get_chan(y
, x
, k
);
343 unsigned int k1
= bayer_color(y
+ 1, x
);
344 unsigned int k2
= 2 - k1
;
348 sum
+= get_chan(y
- 1, x
, k1
);
352 sum
+= get_chan(y
+ 1, x
, k1
);
356 result
[k1
] = sum
/ num
;
360 sum
+= get_chan(y
, x
- 1, k2
);
364 sum
+= get_chan(y
, x
+ 1, k2
);
368 result
[k2
] = sum
/ num
;
375 sum
+= get_chan(y
- 1, x
, 1);
379 sum
+= get_chan(y
, x
- 1, 1);
383 sum
+= get_chan(y
+ 1, x
, 1);
387 sum
+= get_chan(y
, x
+ 1, 1);
391 result
[1] = sum
/ num
;
394 if (y
> 0 && x
> 0) {
395 sum
+= get_chan(y
- 1, x
- 1, 2 - k
);
398 if (y
> 0 && x
< _dimx
- 1) {
399 sum
+= get_chan(y
- 1, x
+ 1, 2 - k
);
402 if (y
< _dimy
- 1 && x
> 0) {
403 sum
+= get_chan(y
+ 1, x
- 1, 2 - k
);
406 if (y
< _dimy
- 1 && x
< _dimx
- 1) {
407 sum
+= get_chan(y
+ 1, x
+ 1, 2 - k
);
410 result
[2 - k
] = sum
/num
;
415 spixel
get_raw_pixel(unsigned int y
, unsigned int x
) const {
417 int k
= bayer_color(y
, x
);
419 result
[k
] = get_chan(y
, x
, k
);
425 * Make a new image suitable for receiving scaled values.
427 virtual image
*scale_generator(int height
, int width
, int depth
, const char *name
) const {
428 return new_image_ale_real(height
, width
, depth
, name
, _exp
);
432 * Extend the image area to the top, bottom, left, and right,
433 * initializing the new image areas with black pixels.
435 image
*_extend(int top
, int bottom
, int left
, int right
) {
437 * Bayer-patterned images should always represent inputs,
438 * which should not ever be extended.
446 void trigger(pixel multiplier
) {
447 for (unsigned int i
= 0; i
< _dimy
; i
++)
448 for (unsigned int j
= 0; j
< _dimx
; j
++) {
449 unsigned int k
= bayer_color(i
, j
);
450 set_chan(i
, j
, k
, get_chan(i
, j
, k
) * multiplier
[k
]);
457 * Wrapper encapsulating details of the separation between the
458 * resident-checking implementation and non-checking.
460 static inline image
*new_image_bayer_ale_real(unsigned int dimy
,
464 const char *name
= "anonymous",
465 exposure
*exp
= NULL
) {
467 return image_bayer_ale_real
<0>::new_image_bayer_ale_real(dimy
, dimx
, depth
, bayer
, name
, exp
);