GIRAFFE Pipeline Reference Manual

gidark.c
1/*
2 * This file is part of the GIRAFFE Pipeline
3 * Copyright (C) 2002-2019 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
24#include <string.h>
25#include <math.h>
26
27#include <cxmemory.h>
28#include <cxmessages.h>
29#include <cxlist.h>
30
31#include "gialias.h"
32#include "giarray.h"
33#include "girange.h"
34#include "giwindow.h"
35#include "gidark.h"
36
37
46inline static cxint
47_giraffe_halfrange_mode(cxdouble *mode, cxdouble* array, cxsize* size,
48 cxdouble portion, cxdouble epsilon)
49{
50
51 cxint status = 0;
52
53 register cxsize i = 0;
54
55 cxsize ndata = 0;
56 cxsize _size = *size;
57
58 cxdouble tiny = CX_MAXDOUBLE;
59
60
61 for (i = 0; i < _size - 1; i++) {
62
63 cxdouble t = array[i + 1] - array[i];
64
65 if (t <= 0.) {
66 continue;
67 }
68
69 if (t < tiny) {
70 tiny = t;
71 }
72 }
73
74 tiny /= 2.;
75
76 if (tiny <= epsilon) {
77 tiny = epsilon;
78 // return -1;
79 }
80
81 if (_size < 3) {
82
83 cxdouble _mode = 0.;
84
85
86 status = 0;
87
88 switch (_size) {
89 case 2:
90 _mode = (array[0] + array[1]) / 2.;
91 break;
92
93 case 1:
94 _mode = array[0];
95 break;
96
97 default:
98 status = -2;
99 break;
100 }
101
102 *mode = _mode;
103 return status;
104
105 }
106 else {
107
108 cxsize count = 0;
109
110 cxdouble iwidth = array[_size - 1] - array[0];
111 cxdouble iweps = 0.;
112
113 cx_list* intervals = NULL;
114
115 GiRange* interval = NULL;
116
117
118 if (iwidth <= epsilon) {
119 *mode = giraffe_array_mean(array, _size);
120 return 0;
121 }
122
123 iwidth *= portion;
124 iweps = iwidth + tiny;
125
126 intervals = cx_list_new();
127
128 i = 0;
129 while (i < _size) {
130
131 register cxsize j = 0;
132 register cxssize k = -1;
133
134 cxsize nvalues = 0;
135
136 GiRange* _interval = giraffe_range_create(array[i] - tiny,
137 array[i] + iweps);
138
139
140 for (j = 0; j < _size; j++) {
141
142 register cxdouble value = array[j];
143
144
145 if (value >= giraffe_range_get_max(_interval)) {
146 break;
147 }
148
149 if (value <= giraffe_range_get_min(_interval)) {
150 continue;
151 }
152
153 if (k < 0) {
154 giraffe_range_set_min(_interval, value - tiny);
155 k = j;
156 }
157
158 }
159
160 giraffe_range_set_max(_interval, array[j - 1] + tiny);
161 nvalues = j - k;
162
163 if (nvalues > count) {
164
165 cx_list_iterator position = cx_list_begin(intervals);
166 cx_list_const_iterator last = cx_list_end(intervals);
167
168 count = nvalues;
169
170 while (position != last) {
171 position =
172 cx_list_erase(intervals, position,
173 (cx_free_func)giraffe_range_delete);
174 }
175 cx_list_clear(intervals);
176
177 cx_list_push_back(intervals, _interval);
178 _interval = NULL;
179
180 }
181 else if (nvalues == count) {
182
183 cx_list_push_back(intervals, _interval);
184 _interval = NULL;
185
186 }
187 else {
188
189 giraffe_range_delete(_interval);
190 _interval = NULL;
191
192 }
193
194 ++i;
195
196 }
197
198 if (cx_list_size(intervals) == 1) {
199
200 GiRange* _interval = cx_list_front(intervals);
201
202 cxdouble minimum = giraffe_range_get_min(_interval);
203 cxdouble maximum = giraffe_range_get_max(_interval);
204
205 interval = giraffe_range_create(minimum, maximum);
206
207 }
208 else {
209
210 cxdouble minimum = 0.;
211 cxdouble maximum = 0.;
212
213 cx_list_iterator position = cx_list_begin(intervals);
214
215 cx_list_const_iterator last = cx_list_end(intervals);
216
217
218 iwidth = CX_MAXDOUBLE;
219
220
221 /*
222 * Find smallest intervals
223 */
224
225 while (position != last) {
226
227 GiRange* _interval = cx_list_get(intervals, position);
228
229 cxdouble t = giraffe_range_get_max(_interval) -
230 giraffe_range_get_min(_interval);
231
232
233 if (t <= 0.) {
234 continue;
235 }
236
237 if (t < iwidth) {
238 iwidth = t;
239 }
240
241 position = cx_list_next(intervals, position);
242
243 }
244
245 iwidth += tiny;
246
247
248 /*
249 * Remove intervals with a larger width than iwidth.
250 */
251
252 position = cx_list_begin(intervals);
253 last = cx_list_end(intervals);
254
255 while (position != last) {
256
257 GiRange* _interval = cx_list_get(intervals, position);
258
259 cxdouble t = giraffe_range_get_max(_interval) -
260 giraffe_range_get_min(_interval);
261
262
263 if (t >= iwidth) {
264 position =
265 cx_list_erase(intervals, position,
266 (cx_free_func)giraffe_range_delete);
267 }
268 else {
269 position = cx_list_next(intervals, position);
270 }
271
272 }
273
274 minimum = giraffe_range_get_min(cx_list_front(intervals));
275 maximum = giraffe_range_get_max(cx_list_back(intervals));
276
277 interval = giraffe_range_create(minimum, maximum);
278
279 }
280
281 cx_list_destroy(intervals, (cx_free_func)giraffe_range_delete);
282 intervals = NULL;
283
284
285 /*
286 * Discard data outside the intervals
287 */
288
289 ndata = 0;
290
291 for (i = 0; i < _size; i++) {
292
293 if (array[i] < giraffe_range_get_min(interval)) {
294 continue;
295 }
296
297 if (array[i] > giraffe_range_get_max(interval)) {
298 break;
299 }
300
301 array[ndata++] = array[i];
302
303 }
304
305 giraffe_range_delete(interval);
306 interval = NULL;
307
308
309 if (ndata == _size) {
310
311 cxdouble start = array[1] - array[0];
312 cxdouble end = array[ndata - 1] - array[ndata - 2];
313
314
315 if (fabs(start - end) < epsilon) {
316
317 /* Remove the first and the last value */
318 ndata -=2;
319 memmove(array, &array[1], ndata * sizeof(cxdouble));
320
321 }
322 else {
323
324 if (start < end) {
325
326 /* Remove last value */
327 --ndata;
328
329 }
330 else {
331
332 /* Remove first value */
333 --ndata;
334 memmove(array, &array[1], ndata * sizeof(cxdouble));
335
336 }
337
338 }
339
340 }
341
342 *size = ndata;
343
344 status = _giraffe_halfrange_mode(mode, array, size, portion, epsilon);
345
346 }
347
348 return status;
349
350}
351
352
353inline static cxdouble
354_giraffe_dark_compute_mode(const cpl_image* image, const cpl_image* bpixel)
355{
356
357 register cxsize i = 0;
358
359 cxint status = 0;
360
361 cxsize ndata = cpl_image_get_size_x(image) * cpl_image_get_size_y(image);
362 cxsize count = 0;
363 cxsize nbuffer = 0;
364
365 const cxdouble* _image = cpl_image_get_data_double_const(image);
366
367 cxdouble mode = 0.;
368 cxdouble delta = 0.;
369 cxdouble* buffer = NULL;
370 cxdouble* sorted_image = NULL;
371
372
373 cx_assert(cpl_image_get_type(image) == CPL_TYPE_DOUBLE);
374
375 sorted_image = cx_calloc(ndata, sizeof(cxdouble));
376 memcpy(sorted_image, _image, ndata * sizeof(cxdouble));
377
378 if (bpixel != NULL) {
379
380 const cxint* _bpixel = cpl_image_get_data_int_const(bpixel);
381
382
383 for (i = 0; i < ndata; i++) {
384
385 if (_bpixel[i] == GI_BPIX_OK) {
386 sorted_image[count++] = _image[i];
387 }
388
389 }
390
391 }
392 else {
393 count = ndata;
394 }
395
396 status = giraffe_array_sort(sorted_image, count);
397
398 if (status != 0) {
399 return 0.;
400 }
401
402
403 buffer = cx_calloc(count, sizeof(cxdouble));
404
405 for (i = 0; i < count; i += 1000) {
406 buffer[nbuffer++] = sorted_image[i];
407 }
408
409
410 // FIXME: Check whether _giraffe_halfrange_mode() needs to update the
411 // size of buffer on return!
412
413 status = _giraffe_halfrange_mode(&mode, buffer, &nbuffer, 0.1, 1.e-9);
414
415 delta = CX_MIN(mode / 10.,
416 (sorted_image[count - 1] - sorted_image[0]) / 2.);
417 nbuffer = count;
418
419 while ((nbuffer > 50000) && (delta > 1.e-6)) {
420
421 register cxsize j = 0;
422
423 for (i = 0; i < count; i++) {
424
425 if (sorted_image[i] < (mode - delta)) {
426 continue;
427 }
428
429 if (sorted_image[i] > (mode + delta)) {
430 break;
431 }
432
433 buffer[j++] = sorted_image[i];
434
435 }
436
437 delta /= 2.;
438
439 if (j > 0) {
440 nbuffer = j;
441 }
442
443 }
444
445 if (delta > 1.e-6) {
446 status = _giraffe_halfrange_mode(&mode, buffer, &nbuffer, 0.5, 1.e-9);
447 }
448 else {
449 mode = giraffe_array_mean(buffer, nbuffer);
450 }
451
452 cx_free(buffer);
453 buffer = NULL;
454
455 cx_free(sorted_image);
456 sorted_image = NULL;
457
458 return mode;
459
460}
461
462
479cxint
480giraffe_subtract_dark(GiImage* image, const GiImage* dark,
481 const GiImage* bpixel, GiDarkResults* data,
482 const GiDarkConfig* config)
483{
484
485 cxbool crop = FALSE;
486
487 cxint nx = 0;
488 cxint ny = 0;
489
490 cxdouble exptime = 0.;
491 cxdouble darktime = 0.;
492 cxdouble dark_max = 0.;
493 cxdouble dark_mode = 0.;
494 cxdouble dark_value = 0.;
495 cxdouble timescale = 1.;
496
497 cpl_propertylist* properties = NULL;
498
499 const cpl_image* _dark = NULL;
500 const cpl_image* _bpixel = NULL;
501
502 cpl_image* _image = NULL;
503
504
505 if ((image == NULL) || (dark == NULL)) {
506 return -1;
507 }
508
509 if (config == NULL) {
510 return -2;
511 }
512
513 _image = giraffe_image_get(image);
514 _dark = giraffe_image_get(dark);
515
516 nx = cpl_image_get_size_y(_image);
517 ny = cpl_image_get_size_x(_image);
518
519 if ((nx != cpl_image_get_size_y(_dark)) ||
520 (ny != cpl_image_get_size_x(_dark))) {
521 return -3;
522 }
523
524 if (bpixel != NULL) {
525
526 GiWindow area = {1, 1, ny, nx};
527
528 properties = giraffe_image_get_properties(bpixel);
529 _bpixel = giraffe_image_get(bpixel);
530
531 if (cpl_propertylist_has(properties, GIALIAS_PRSCX) == TRUE) {
532 area.x0 += cpl_propertylist_get_int(properties, GIALIAS_PRSCX);
533 crop = TRUE;
534 }
535
536 if (cpl_propertylist_has(properties, GIALIAS_PRSCY) == TRUE) {
537 area.y0 += cpl_propertylist_get_int(properties, GIALIAS_PRSCY);
538 crop = TRUE;
539 }
540
541 if (cpl_propertylist_has(properties, GIALIAS_OVSCX) == TRUE) {
542 area.x1 = cpl_image_get_size_x(_bpixel) -
543 cpl_propertylist_get_int(properties, GIALIAS_OVSCX);
544 crop = TRUE;
545 }
546
547 if (cpl_propertylist_has(properties, GIALIAS_OVSCY) == TRUE) {
548 area.y1 = cpl_image_get_size_y(_bpixel) -
549 cpl_propertylist_get_int(properties, GIALIAS_OVSCY);
550 crop = TRUE;
551 }
552
553 if (crop == TRUE) {
554 _bpixel = cpl_image_extract(_bpixel, area.x0, area.y0,
555 area.x1, area.y1);
556 }
557
558 }
559
560
561 /*
562 * Get the dark current time from the input image and the dark.
563 */
564
565 properties = giraffe_image_get_properties(image);
566 cx_assert(properties != NULL);
567
568 if (cpl_propertylist_has(properties, GIALIAS_EXPTIME) == FALSE) {
569 return 1;
570 }
571 else {
572 exptime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
573 }
574
575 properties = giraffe_image_get_properties(dark);
576 cx_assert(properties != NULL);
577
578 if (cpl_propertylist_has(properties, GIALIAS_EXPTIME) == FALSE) {
579 return 1;
580 }
581 else {
582 darktime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
583 }
584
585
586 /*
587 * Dark current scale factor
588 */
589
590 timescale = exptime / darktime;
591
592
593 /*
594 * Compute mode and maximum of the dark.
595 */
596
597 dark_max = cpl_image_get_max(_dark) * timescale;
598 dark_mode = _giraffe_dark_compute_mode(_dark, _bpixel) * timescale;
599
600
601 /*
602 * Correct the input image for the dark current
603 */
604
605 switch (config->method) {
606 case GIDARK_METHOD_UNIFORM:
607
608 if (dark_max < config->threshold) {
609
610 /* No dark subtraction */
611
612 dark_value = 0.;
613
614 }
615 else {
616
617 dark_value = dark_mode;
618 cpl_image_subtract_scalar(_image, dark_value);
619
620 }
621 break;
622
623 case GIDARK_METHOD_ZMASTER:
624 {
625
626 register cxint i = 0;
627
628 cxdouble* pximage = NULL;
629 cxdouble* pxdark = NULL;
630
631 cpl_image* scaled_dark = cpl_image_duplicate(_dark);
632
633 pximage = cpl_image_get_data_double(_image);
634 pxdark = cpl_image_get_data_double(scaled_dark);
635
636 if (_bpixel == NULL) {
637
638 register cxint j = 0;
639 register cxint n = nx * ny;
640
641 for (j = 0; j < n; j++) {
642
643 pxdark[j] *= timescale;
644
645 if (pxdark[j] < config->threshold) {
646 pxdark[j] = dark_mode;
647 }
648
649 }
650
651 }
652 else {
653
654 register cxint j = 0;
655 register cxint n = nx * ny;
656
657 const cxint* pxmask = cpl_image_get_data_int_const(_bpixel);
658
659
660 for (j = 0; j < n; j++) {
661
662 if ((pxmask[j] & GI_M_PIX_SET) == 0x0) {
663 pxdark[j] *= timescale;
664 }
665 else {
666 pxdark[j] = dark_mode;
667 }
668
669 }
670
671 }
672
673
674 for (i = 0; i < nx; i++) {
675
676 register cxint j = 0;
677 register cxint base = i * ny;
678
679 for (j = 0; j < ny; j++) {
680
681 register cxint offset = base + j;
682
683 pximage[offset] -= pxdark[offset];
684
685 }
686
687 }
688
689 dark_mode = _giraffe_dark_compute_mode(scaled_dark, _bpixel);
690 dark_value = dark_mode;
691
692 cpl_image_delete(scaled_dark);
693 scaled_dark = NULL;
694
695 }
696 break;
697
698 case GIDARK_METHOD_MASTER:
699 default:
700 {
701
702 register cxint i = 0;
703
704 const cxdouble* pxdark = NULL;
705
706 cxdouble* pximage = NULL;
707
708 pximage = cpl_image_get_data_double(_image);
709 pxdark = cpl_image_get_data_double_const(_dark);
710
711 for (i = 0; i < nx; i++) {
712
713 register cxint j = 0;
714 register cxint base = i * ny;
715
716 for (j = 0; j < ny; j++) {
717
718 register cxint offset = base + j;
719
720 pximage[offset] -= pxdark[offset] * timescale;
721
722 }
723
724 }
725 }
726 break;
727
728 }
729
730
731 /*
732 * Update the properties of the corrected image.
733 */
734
735 properties = giraffe_image_get_properties(image);
736
737 cpl_propertylist_update_double(properties, GIALIAS_DARKVALUE,
738 dark_value / timescale);
739 cpl_propertylist_set_comment(properties, GIALIAS_DARKVALUE,
740 "Used dark current [ADU/s]");
741 cpl_propertylist_update_double(properties, GIALIAS_DARKEXPECT,
742 dark_mode / timescale);
743 cpl_propertylist_set_comment(properties, GIALIAS_DARKEXPECT,
744 "Expected dark current [ADU/s]");
745
746
747 /*
748 * Update dark results data
749 */
750
751 if (data != NULL) {
752 data->value = dark_value;
753 data->expected = dark_mode;
754 data->mode = dark_mode / timescale;
755 data->maximum = dark_max / timescale;
756 }
757
758
759 /*
760 * Cleanup
761 */
762
763 if (crop == TRUE) {
764 cpl_image_delete((cpl_image*)_bpixel);
765 _bpixel = NULL;
766 }
767
768
769 return 0;
770
771}
cxint giraffe_array_sort(cxdouble *array, cxsize size)
Sorts an array in ascending order.
Definition: giarray.c:169
cxint giraffe_subtract_dark(GiImage *image, const GiImage *dark, const GiImage *bpixel, GiDarkResults *data, const GiDarkConfig *config)
Subtract the dark current from a bias corrected image.
Definition: gidark.c:480
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
Definition: giimage.c:218
cpl_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
Definition: giimage.c:282
void giraffe_range_set_min(GiRange *self, cxdouble min)
Set the minimum of a range.
Definition: girange.c:144
void giraffe_range_delete(GiRange *self)
Destroys a range object.
Definition: girange.c:118
cxdouble giraffe_range_get_min(const GiRange *const self)
Get the minimum of a range.
Definition: girange.c:167
cxdouble giraffe_range_get_max(const GiRange *const self)
Get the maximum of a range.
Definition: girange.c:213
GiRange * giraffe_range_create(cxdouble min, cxdouble max)
Creates a new range from the given minimum and maximum values.
Definition: girange.c:83
void giraffe_range_set_max(GiRange *self, cxdouble max)
Set the maximum of a range.
Definition: girange.c:190

This file is part of the GIRAFFE Pipeline Reference Manual 2.19.4.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Fri Feb 6 2026 11:30:08 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2004