28#include <cxmessages.h>
47_giraffe_halfrange_mode(cxdouble *mode, cxdouble* array, cxsize* size,
48 cxdouble portion, cxdouble epsilon)
53 register cxsize i = 0;
58 cxdouble tiny = CX_MAXDOUBLE;
61 for (i = 0; i < _size - 1; i++) {
63 cxdouble t = array[i + 1] - array[i];
76 if (tiny <= epsilon) {
90 _mode = (array[0] + array[1]) / 2.;
110 cxdouble iwidth = array[_size - 1] - array[0];
113 cx_list* intervals = NULL;
115 GiRange* interval = NULL;
118 if (iwidth <= epsilon) {
119 *mode = giraffe_array_mean(array, _size);
124 iweps = iwidth + tiny;
126 intervals = cx_list_new();
131 register cxsize j = 0;
132 register cxssize k = -1;
140 for (j = 0; j < _size; j++) {
142 register cxdouble value = array[j];
163 if (nvalues > count) {
165 cx_list_iterator position = cx_list_begin(intervals);
166 cx_list_const_iterator last = cx_list_end(intervals);
170 while (position != last) {
172 cx_list_erase(intervals, position,
175 cx_list_clear(intervals);
177 cx_list_push_back(intervals, _interval);
181 else if (nvalues == count) {
183 cx_list_push_back(intervals, _interval);
198 if (cx_list_size(intervals) == 1) {
200 GiRange* _interval = cx_list_front(intervals);
210 cxdouble minimum = 0.;
211 cxdouble maximum = 0.;
213 cx_list_iterator position = cx_list_begin(intervals);
215 cx_list_const_iterator last = cx_list_end(intervals);
218 iwidth = CX_MAXDOUBLE;
225 while (position != last) {
227 GiRange* _interval = cx_list_get(intervals, position);
241 position = cx_list_next(intervals, position);
252 position = cx_list_begin(intervals);
253 last = cx_list_end(intervals);
255 while (position != last) {
257 GiRange* _interval = cx_list_get(intervals, position);
265 cx_list_erase(intervals, position,
269 position = cx_list_next(intervals, position);
291 for (i = 0; i < _size; i++) {
301 array[ndata++] = array[i];
309 if (ndata == _size) {
311 cxdouble start = array[1] - array[0];
312 cxdouble end = array[ndata - 1] - array[ndata - 2];
315 if (fabs(start - end) < epsilon) {
319 memmove(array, &array[1], ndata *
sizeof(cxdouble));
334 memmove(array, &array[1], ndata *
sizeof(cxdouble));
344 status = _giraffe_halfrange_mode(mode, array, size, portion, epsilon);
353inline static cxdouble
354_giraffe_dark_compute_mode(
const cpl_image* image,
const cpl_image* bpixel)
357 register cxsize i = 0;
361 cxsize ndata = cpl_image_get_size_x(image) * cpl_image_get_size_y(image);
365 const cxdouble* _image = cpl_image_get_data_double_const(image);
369 cxdouble* buffer = NULL;
370 cxdouble* sorted_image = NULL;
373 cx_assert(cpl_image_get_type(image) == CPL_TYPE_DOUBLE);
375 sorted_image = cx_calloc(ndata,
sizeof(cxdouble));
376 memcpy(sorted_image, _image, ndata *
sizeof(cxdouble));
378 if (bpixel != NULL) {
380 const cxint* _bpixel = cpl_image_get_data_int_const(bpixel);
383 for (i = 0; i < ndata; i++) {
385 if (_bpixel[i] == GI_BPIX_OK) {
386 sorted_image[count++] = _image[i];
403 buffer = cx_calloc(count,
sizeof(cxdouble));
405 for (i = 0; i < count; i += 1000) {
406 buffer[nbuffer++] = sorted_image[i];
413 status = _giraffe_halfrange_mode(&mode, buffer, &nbuffer, 0.1, 1.e-9);
415 delta = CX_MIN(mode / 10.,
416 (sorted_image[count - 1] - sorted_image[0]) / 2.);
419 while ((nbuffer > 50000) && (delta > 1.e-6)) {
421 register cxsize j = 0;
423 for (i = 0; i < count; i++) {
425 if (sorted_image[i] < (mode - delta)) {
429 if (sorted_image[i] > (mode + delta)) {
433 buffer[j++] = sorted_image[i];
446 status = _giraffe_halfrange_mode(&mode, buffer, &nbuffer, 0.5, 1.e-9);
449 mode = giraffe_array_mean(buffer, nbuffer);
455 cx_free(sorted_image);
481 const GiImage* bpixel, GiDarkResults* data,
482 const GiDarkConfig* config)
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.;
497 cpl_propertylist* properties = NULL;
499 const cpl_image* _dark = NULL;
500 const cpl_image* _bpixel = NULL;
502 cpl_image* _image = NULL;
505 if ((image == NULL) || (dark == NULL)) {
509 if (config == NULL) {
516 nx = cpl_image_get_size_y(_image);
517 ny = cpl_image_get_size_x(_image);
519 if ((nx != cpl_image_get_size_y(_dark)) ||
520 (ny != cpl_image_get_size_x(_dark))) {
524 if (bpixel != NULL) {
526 GiWindow area = {1, 1, ny, nx};
531 if (cpl_propertylist_has(properties, GIALIAS_PRSCX) == TRUE) {
532 area.x0 += cpl_propertylist_get_int(properties, GIALIAS_PRSCX);
536 if (cpl_propertylist_has(properties, GIALIAS_PRSCY) == TRUE) {
537 area.y0 += cpl_propertylist_get_int(properties, GIALIAS_PRSCY);
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);
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);
554 _bpixel = cpl_image_extract(_bpixel, area.x0, area.y0,
566 cx_assert(properties != NULL);
568 if (cpl_propertylist_has(properties, GIALIAS_EXPTIME) == FALSE) {
572 exptime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
576 cx_assert(properties != NULL);
578 if (cpl_propertylist_has(properties, GIALIAS_EXPTIME) == FALSE) {
582 darktime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
590 timescale = exptime / darktime;
597 dark_max = cpl_image_get_max(_dark) * timescale;
598 dark_mode = _giraffe_dark_compute_mode(_dark, _bpixel) * timescale;
605 switch (config->method) {
606 case GIDARK_METHOD_UNIFORM:
608 if (dark_max < config->threshold) {
617 dark_value = dark_mode;
618 cpl_image_subtract_scalar(_image, dark_value);
623 case GIDARK_METHOD_ZMASTER:
626 register cxint i = 0;
628 cxdouble* pximage = NULL;
629 cxdouble* pxdark = NULL;
631 cpl_image* scaled_dark = cpl_image_duplicate(_dark);
633 pximage = cpl_image_get_data_double(_image);
634 pxdark = cpl_image_get_data_double(scaled_dark);
636 if (_bpixel == NULL) {
638 register cxint j = 0;
639 register cxint n = nx * ny;
641 for (j = 0; j < n; j++) {
643 pxdark[j] *= timescale;
645 if (pxdark[j] < config->threshold) {
646 pxdark[j] = dark_mode;
654 register cxint j = 0;
655 register cxint n = nx * ny;
657 const cxint* pxmask = cpl_image_get_data_int_const(_bpixel);
660 for (j = 0; j < n; j++) {
662 if ((pxmask[j] & GI_M_PIX_SET) == 0x0) {
663 pxdark[j] *= timescale;
666 pxdark[j] = dark_mode;
674 for (i = 0; i < nx; i++) {
676 register cxint j = 0;
677 register cxint base = i * ny;
679 for (j = 0; j < ny; j++) {
681 register cxint offset = base + j;
683 pximage[offset] -= pxdark[offset];
689 dark_mode = _giraffe_dark_compute_mode(scaled_dark, _bpixel);
690 dark_value = dark_mode;
692 cpl_image_delete(scaled_dark);
698 case GIDARK_METHOD_MASTER:
702 register cxint i = 0;
704 const cxdouble* pxdark = NULL;
706 cxdouble* pximage = NULL;
708 pximage = cpl_image_get_data_double(_image);
709 pxdark = cpl_image_get_data_double_const(_dark);
711 for (i = 0; i < nx; i++) {
713 register cxint j = 0;
714 register cxint base = i * ny;
716 for (j = 0; j < ny; j++) {
718 register cxint offset = base + j;
720 pximage[offset] -= pxdark[offset] * timescale;
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]");
752 data->value = dark_value;
753 data->expected = dark_mode;
754 data->mode = dark_mode / timescale;
755 data->maximum = dark_max / timescale;
764 cpl_image_delete((cpl_image*)_bpixel);
cxint giraffe_array_sort(cxdouble *array, cxsize size)
Sorts an array in ascending order.
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.
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
cpl_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
void giraffe_range_set_min(GiRange *self, cxdouble min)
Set the minimum of a range.
void giraffe_range_delete(GiRange *self)
Destroys a range object.
cxdouble giraffe_range_get_min(const GiRange *const self)
Get the minimum of a range.
cxdouble giraffe_range_get_max(const GiRange *const self)
Get the maximum of a range.
GiRange * giraffe_range_create(cxdouble min, cxdouble max)
Creates a new range from the given minimum and maximum values.
void giraffe_range_set_max(GiRange *self, cxdouble max)
Set the maximum of a range.