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