45 _giraffe_halfrange_mode(cxdouble *mode, cxdouble* array, cxsize* size,
46 cxdouble portion, cxdouble epsilon)
51 register cxsize i = 0;
56 cxdouble tiny = CX_MAXDOUBLE;
59 for (i = 0; i < _size - 1; i++) {
61 cxdouble t = array[i + 1] - array[i];
74 if (tiny <= epsilon) {
88 _mode = (array[0] + array[1]) / 2.;
108 cxdouble iwidth = array[_size - 1] - array[0];
111 cx_list* intervals = NULL;
113 GiRange* interval = NULL;
116 if (iwidth <= epsilon) {
117 *mode = giraffe_array_mean(array, _size);
122 iweps = iwidth + tiny;
124 intervals = cx_list_new();
129 register cxsize j = 0;
130 register cxssize k = -1;
138 for (j = 0; j < _size; j++) {
140 register cxdouble value = array[j];
161 if (nvalues > count) {
163 cx_list_iterator position = cx_list_begin(intervals);
164 cx_list_const_iterator last = cx_list_end(intervals);
168 while (position != last) {
170 cx_list_erase(intervals, position,
173 cx_list_clear(intervals);
175 cx_list_push_back(intervals, _interval);
179 else if (nvalues == count) {
181 cx_list_push_back(intervals, _interval);
196 if (cx_list_size(intervals) == 1) {
198 GiRange* _interval = cx_list_front(intervals);
208 cxdouble minimum = 0.;
209 cxdouble maximum = 0.;
211 cx_list_iterator position = cx_list_begin(intervals);
213 cx_list_const_iterator last = cx_list_end(intervals);
216 iwidth = CX_MAXDOUBLE;
223 while (position != last) {
225 GiRange* _interval = cx_list_get(intervals, position);
239 position = cx_list_next(intervals, position);
250 position = cx_list_begin(intervals);
251 last = cx_list_end(intervals);
253 while (position != last) {
255 GiRange* _interval = cx_list_get(intervals, position);
263 cx_list_erase(intervals, position,
267 position = cx_list_next(intervals, position);
289 for (i = 0; i < _size; i++) {
299 array[ndata++] = array[i];
307 if (ndata == _size) {
309 cxdouble start = array[1] - array[0];
310 cxdouble end = array[ndata - 1] - array[ndata - 2];
313 if (fabs(start - end) < epsilon) {
317 memmove(array, &array[1], ndata *
sizeof(cxdouble));
332 memmove(array, &array[1], ndata *
sizeof(cxdouble));
342 status = _giraffe_halfrange_mode(mode, array, size, portion, epsilon);
351 inline static cxdouble
352 _giraffe_dark_compute_mode(
const cpl_image* image,
const cpl_image* bpixel)
355 register cxsize i = 0;
359 cxsize ndata = cpl_image_get_size_x(image) * cpl_image_get_size_y(image);
363 const cxdouble* _image = cpl_image_get_data_double_const(image);
367 cxdouble* buffer = NULL;
368 cxdouble* sorted_image = NULL;
371 cx_assert(cpl_image_get_type(image) == CPL_TYPE_DOUBLE);
373 sorted_image = cx_calloc(ndata,
sizeof(cxdouble));
374 memcpy(sorted_image, _image, ndata *
sizeof(cxdouble));
376 if (bpixel != NULL) {
378 const cxint* _bpixel = cpl_image_get_data_int_const(bpixel);
381 for (i = 0; i < ndata; i++) {
383 if (_bpixel[i] == GI_BPIX_OK) {
384 sorted_image[count++] = _image[i];
401 buffer = cx_calloc(count,
sizeof(cxdouble));
403 for (i = 0; i < count; i += 1000) {
404 buffer[nbuffer++] = sorted_image[i];
411 status = _giraffe_halfrange_mode(&mode, buffer, &nbuffer, 0.1, 1.e-9);
413 delta = CX_MIN(mode / 10.,
414 (sorted_image[count - 1] - sorted_image[0]) / 2.);
417 while ((nbuffer > 50000) && (delta > 1.e-6)) {
419 register cxsize j = 0;
421 for (i = 0; i < count; i++) {
423 if (sorted_image[i] < (mode - delta)) {
427 if (sorted_image[i] > (mode + delta)) {
431 buffer[j++] = sorted_image[i];
444 status = _giraffe_halfrange_mode(&mode, buffer, &nbuffer, 0.5, 1.e-9);
447 mode = giraffe_array_mean(buffer, nbuffer);
453 cx_free(sorted_image);
479 const GiImage* bpixel, GiDarkResults* data,
480 const GiDarkConfig* config)
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.;
495 cpl_propertylist* properties = NULL;
497 const cpl_image* _dark = NULL;
498 const cpl_image* _bpixel = NULL;
500 cpl_image* _image = NULL;
503 if ((image == NULL) || (dark == NULL)) {
507 if (config == NULL) {
514 nx = cpl_image_get_size_y(_image);
515 ny = cpl_image_get_size_x(_image);
517 if ((nx != cpl_image_get_size_y(_dark)) ||
518 (ny != cpl_image_get_size_x(_dark))) {
522 if (bpixel != NULL) {
524 GiWindow area = {1, 1, ny, nx};
529 if (cpl_propertylist_has(properties, GIALIAS_PRSCX) == TRUE) {
530 area.x0 += cpl_propertylist_get_int(properties, GIALIAS_PRSCX);
534 if (cpl_propertylist_has(properties, GIALIAS_PRSCY) == TRUE) {
535 area.y0 += cpl_propertylist_get_int(properties, GIALIAS_PRSCY);
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);
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);
552 _bpixel = cpl_image_extract(_bpixel, area.x0, area.y0,
564 cx_assert(properties != NULL);
566 if (cpl_propertylist_has(properties, GIALIAS_EXPTIME) == FALSE) {
570 exptime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
574 cx_assert(properties != NULL);
576 if (cpl_propertylist_has(properties, GIALIAS_EXPTIME) == FALSE) {
580 darktime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
588 timescale = exptime / darktime;
595 dark_max = cpl_image_get_max(_dark) * timescale;
596 dark_mode = _giraffe_dark_compute_mode(_dark, _bpixel) * timescale;
603 switch (config->method) {
604 case GIDARK_METHOD_UNIFORM:
606 if (dark_max < config->threshold) {
615 dark_value = dark_mode;
616 cpl_image_subtract_scalar(_image, dark_value);
621 case GIDARK_METHOD_ZMASTER:
624 register cxint i = 0;
626 cxdouble* pximage = NULL;
627 cxdouble* pxdark = NULL;
629 cpl_image* scaled_dark = cpl_image_duplicate(_dark);
631 pximage = cpl_image_get_data_double(_image);
632 pxdark = cpl_image_get_data_double(scaled_dark);
634 if (_bpixel == NULL) {
636 register cxint j = 0;
637 register cxint n = nx * ny;
639 for (j = 0; j < n; j++) {
641 pxdark[j] *= timescale;
643 if (pxdark[j] < config->threshold) {
644 pxdark[j] = dark_mode;
652 register cxint j = 0;
653 register cxint n = nx * ny;
655 const cxint* pxmask = cpl_image_get_data_int_const(_bpixel);
658 for (j = 0; j < n; j++) {
660 if ((pxmask[j] & GI_M_PIX_SET) == 0x0) {
661 pxdark[j] *= timescale;
664 pxdark[j] = dark_mode;
672 for (i = 0; i < nx; i++) {
674 register cxint j = 0;
675 register cxint base = i * ny;
677 for (j = 0; j < ny; j++) {
679 register cxint offset = base + j;
681 pximage[offset] -= pxdark[offset];
687 dark_mode = _giraffe_dark_compute_mode(scaled_dark, _bpixel);
688 dark_value = dark_mode;
690 cpl_image_delete(scaled_dark);
696 case GIDARK_METHOD_MASTER:
700 register cxint i = 0;
702 const cxdouble* pxdark = NULL;
704 cxdouble* pximage = NULL;
706 pximage = cpl_image_get_data_double(_image);
707 pxdark = cpl_image_get_data_double_const(_dark);
709 for (i = 0; i < nx; i++) {
711 register cxint j = 0;
712 register cxint base = i * ny;
714 for (j = 0; j < ny; j++) {
716 register cxint offset = base + j;
718 pximage[offset] -= pxdark[offset] * timescale;
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]");
750 data->value = dark_value;
751 data->expected = dark_mode;
752 data->mode = dark_mode / timescale;
753 data->maximum = dark_max / timescale;
762 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_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
GiRange * giraffe_range_create(cxdouble min, cxdouble max)
Creates a new range from the given minimum and maximum values.
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.
void giraffe_range_set_max(GiRange *self, cxdouble max)
Set the maximum of a range.