Ditz task for gallery documentation integration.
[Ale.git] / d2 / image_bayer_ale_real.h
blob2f9c21d901d2c614e51e03b69d4d2f577161b0f7
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"
29 #include "point.h"
30 #include "image.h"
31 #include "image_ale_real.h"
33 template <int disk_support>
34 class image_bayer_ale_real : public image {
35 private:
37 * Data structures without file support.
40 ale_sreal *_p;
43 * Data structures for file support.
46 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;
51 int resident_max;
52 int rows_per_segment;
53 mutable thread::rwlock_t rwlock;
55 private:
57 * X offset of 'R' element
59 unsigned int r_x_offset() const {
60 return bayer & 0x1;
64 * Y offset of 'R' element
66 unsigned int r_y_offset() const {
67 return (bayer & 0x2) >> 1;
70 public:
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));
82 public:
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,
89 unsigned int dimx,
90 unsigned int depth,
91 unsigned int bayer,
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];
116 assert (_p);
118 if (!_p) {
119 fprintf(stderr, "Could not allocate memory for image data.\n");
120 exit(1);
123 for (unsigned int i = 0; i < dimx * dimy; i++) {
124 _p[i] = 0;
126 } else {
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");
148 resident_next = 0;
150 support = tmpfile();
152 if (!support) {
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];
160 assert(zero);
162 for (unsigned int i = 0; i < dimx; i++)
163 zero[i] = 0;
165 for (unsigned int i = 0; i < dimy; i++) {
166 unsigned int c = fwrite(zero, sizeof(ale_sreal), dimx, support);
167 if (c < dimx)
168 ui::get()->error_hint("Image array support file error.",
169 "Submit a bug report.");
172 delete[] zero;
176 virtual ~image_bayer_ale_real() {
177 if (disk_support == 0) {
178 delete[] _p;
179 } else {
180 for (int i = 0; i < RESIDENT_DIVISIONS; i++) {
181 if (_p_segments[i])
182 delete[] _p_segments[i];
185 fclose(support);
189 void resident_begin(unsigned int segment) const {
190 rwlock.rdlock();
191 if (_p_segments[segment])
192 return;
193 rwlock.unlock();
195 rwlock.wrlock();
197 if (_p_segments[segment])
198 return;
200 if (resident_list[resident_next] >= 0) {
202 * Eject a segment
205 if (dirty_segments[resident_list[resident_next]]) {
206 fseek(support, rows_per_segment * _dimx * sizeof(ale_sreal)
207 * resident_list[resident_next],
208 SEEK_SET);
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)
229 * segment,
230 SEEK_SET);
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.
239 resident_next++;
240 if (resident_next >= resident_max)
241 resident_next = 0;
244 void resident_end(unsigned int segment) const {
245 rwlock.unlock();
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;
252 } else {
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;
269 } else {
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;
286 } else {
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 {
300 #if 0
302 * This may be expensive.
304 assert (k == bayer_color(y, x));
305 #endif
306 if (disk_support == 0) {
307 return _p[y * _dimx + x];
308 } else {
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);
319 return result;
324 * This method throws away data not stored at this pixel
325 * position.
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 {
335 pixel result;
336 unsigned int k = bayer_color(y, x);
337 ale_real sum;
338 unsigned int num;
340 result[k] = get_chan(y, x, k);
342 if (k == 1) {
343 unsigned int k1 = bayer_color(y + 1, x);
344 unsigned int k2 = 2 - k1;
346 sum = 0; num = 0;
347 if (y > 0) {
348 sum += get_chan(y - 1, x, k1);
349 num++;
351 if (y < _dimy - 1) {
352 sum += get_chan(y + 1, x, k1);
353 num++;
355 assert (num > 0);
356 result[k1] = sum / num;
358 sum = 0; num = 0;
359 if (x > 0) {
360 sum += get_chan(y, x - 1, k2);
361 num++;
363 if (x < _dimx - 1) {
364 sum += get_chan(y, x + 1, k2);
365 num++;
367 assert (num > 0);
368 result[k2] = sum / num;
370 return result;
373 sum = 0; num = 0;
374 if (y > 0) {
375 sum += get_chan(y - 1, x, 1);
376 num++;
378 if (x > 0) {
379 sum += get_chan(y, x - 1, 1);
380 num++;
382 if (y < _dimy - 1) {
383 sum += get_chan(y + 1, x, 1);
384 num++;
386 if (x < _dimx - 1) {
387 sum += get_chan(y, x + 1, 1);
388 num++;
390 assert (num > 0);
391 result[1] = sum / num;
393 sum = 0; num = 0;
394 if (y > 0 && x > 0) {
395 sum += get_chan(y - 1, x - 1, 2 - k);
396 num++;
398 if (y > 0 && x < _dimx - 1) {
399 sum += get_chan(y - 1, x + 1, 2 - k);
400 num++;
402 if (y < _dimy - 1 && x > 0) {
403 sum += get_chan(y + 1, x - 1, 2 - k);
404 num++;
406 if (y < _dimy - 1 && x < _dimx - 1) {
407 sum += get_chan(y + 1, x + 1, 2 - k);
408 num++;
410 result[2 - k] = sum/num;
412 return result;
415 spixel get_raw_pixel(unsigned int y, unsigned int x) const {
416 pixel result;
417 int k = bayer_color(y, x);
419 result[k] = get_chan(y, x, k);
421 return result;
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.
440 assert(0);
442 return NULL;
445 private:
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,
461 unsigned int dimx,
462 unsigned int depth,
463 unsigned int bayer,
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);
470 #endif