53 _giraffe_halfrange_mode(cxdouble *mode, cxdouble* array, cxsize* size,
54 cxdouble portion, cxdouble epsilon)
59 register cxsize i = 0;
64 cxdouble tiny = CX_MAXDOUBLE;
67 for (i = 0; i < _size - 1; i++) {
69 cxdouble t = array[i + 1] - array[i];
82 if (tiny <= epsilon) {
96 _mode = (array[0] + array[1]) / 2.;
116 cxdouble iwidth = array[_size - 1] - array[0];
119 cx_list* intervals = NULL;
121 GiRange* interval = NULL;
124 if (iwidth <= epsilon) {
125 *mode = giraffe_array_mean(array, _size);
130 iweps = iwidth + tiny;
132 intervals = cx_list_new();
137 register cxsize j = 0;
138 register cxssize k = -1;
146 for (j = 0; j < _size; j++) {
148 register cxdouble value = array[j];
169 if (nvalues > count) {
171 cx_list_iterator position = cx_list_begin(intervals);
172 cx_list_const_iterator last = cx_list_end(intervals);
176 while (position != last) {
178 cx_list_erase(intervals, position,
181 cx_list_clear(intervals);
183 cx_list_push_back(intervals, _interval);
187 else if (nvalues == count) {
189 cx_list_push_back(intervals, _interval);
204 if (cx_list_size(intervals) == 1) {
206 GiRange* _interval = cx_list_front(intervals);
216 cxdouble minimum = 0.;
217 cxdouble maximum = 0.;
219 cx_list_iterator position = cx_list_begin(intervals);
221 cx_list_const_iterator last = cx_list_end(intervals);
224 iwidth = CX_MAXDOUBLE;
231 while (position != last) {
233 GiRange* _interval = cx_list_get(intervals, position);
247 position = cx_list_next(intervals, position);
258 position = cx_list_begin(intervals);
259 last = cx_list_end(intervals);
261 while (position != last) {
263 GiRange* _interval = cx_list_get(intervals, position);
271 cx_list_erase(intervals, position,
275 position = cx_list_next(intervals, position);
297 for (i = 0; i < _size; i++) {
307 array[ndata++] = array[i];
315 if (ndata == _size) {
317 cxdouble start = array[1] - array[0];
318 cxdouble end = array[ndata - 1] - array[ndata - 2];
321 if (fabs(start - end) < epsilon) {
325 memmove(array, &array[1], ndata *
sizeof(cxdouble));
340 memmove(array, &array[1], ndata *
sizeof(cxdouble));
350 status = _giraffe_halfrange_mode(mode, array, size, portion, epsilon);
359 inline static cxdouble
360 _giraffe_dark_compute_mode(
const cpl_image* image,
const cpl_image* bpixel)
363 register cxsize i = 0;
367 cxsize ndata = cpl_image_get_size_x(image) * cpl_image_get_size_y(image);
371 const cxdouble* _image = cpl_image_get_data_double_const(image);
375 cxdouble* buffer = NULL;
376 cxdouble* sorted_image = NULL;
379 cx_assert(cpl_image_get_type(image) == CPL_TYPE_DOUBLE);
381 sorted_image = cx_calloc(ndata,
sizeof(cxdouble));
382 memcpy(sorted_image, _image, ndata *
sizeof(cxdouble));
384 if (bpixel != NULL) {
386 const cxint* _bpixel = cpl_image_get_data_int_const(bpixel);
389 for (i = 0; i < ndata; i++) {
391 if (_bpixel[i] == GI_BPIX_OK) {
392 sorted_image[count++] = _image[i];
409 buffer = cx_calloc(count,
sizeof(cxdouble));
411 for (i = 0; i < count; i += 1000) {
412 buffer[nbuffer++] = sorted_image[i];
419 status = _giraffe_halfrange_mode(&mode, buffer, &nbuffer, 0.1, 1.e-9);
421 delta = CX_MIN(mode / 10.,
422 (sorted_image[count - 1] - sorted_image[0]) / 2.);
425 while ((nbuffer > 50000) && (delta > 1.e-6)) {
427 register cxsize j = 0;
429 for (i = 0; i < count; i++) {
431 if (sorted_image[i] < (mode - delta)) {
435 if (sorted_image[i] > (mode + delta)) {
439 buffer[j++] = sorted_image[i];
452 status = _giraffe_halfrange_mode(&mode, buffer, &nbuffer, 0.5, 1.e-9);
455 mode = giraffe_array_mean(buffer, nbuffer);
461 cx_free(sorted_image);
487 const GiImage* bpixel, GiDarkResults* data,
488 const GiDarkConfig* config)
496 cxdouble exptime = 0.;
497 cxdouble darktime = 0.;
498 cxdouble dark_max = 0.;
499 cxdouble dark_mode = 0.;
500 cxdouble dark_value = 0.;
501 cxdouble timescale = 1.;
503 cpl_propertylist* properties = NULL;
505 const cpl_image* _dark = NULL;
506 const cpl_image* _bpixel = NULL;
508 cpl_image* _image = NULL;
511 if ((image == NULL) || (dark == NULL)) {
515 if (config == NULL) {
522 nx = cpl_image_get_size_y(_image);
523 ny = cpl_image_get_size_x(_image);
525 if ((nx != cpl_image_get_size_y(_dark)) ||
526 (ny != cpl_image_get_size_x(_dark))) {
530 if (bpixel != NULL) {
532 GiWindow area = {1, 1, ny, nx};
537 if (cpl_propertylist_has(properties, GIALIAS_PRSCX) == TRUE) {
538 area.x0 += cpl_propertylist_get_int(properties, GIALIAS_PRSCX);
542 if (cpl_propertylist_has(properties, GIALIAS_PRSCY) == TRUE) {
543 area.y0 += cpl_propertylist_get_int(properties, GIALIAS_PRSCY);
547 if (cpl_propertylist_has(properties, GIALIAS_OVSCX) == TRUE) {
548 area.x1 = cpl_image_get_size_x(_bpixel) -
549 cpl_propertylist_get_int(properties, GIALIAS_OVSCX);
553 if (cpl_propertylist_has(properties, GIALIAS_OVSCY) == TRUE) {
554 area.y1 = cpl_image_get_size_y(_bpixel) -
555 cpl_propertylist_get_int(properties, GIALIAS_OVSCY);
560 _bpixel = cpl_image_extract(_bpixel, area.x0, area.y0,
572 cx_assert(properties != NULL);
574 if (cpl_propertylist_has(properties, GIALIAS_EXPTIME) == FALSE) {
578 exptime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
582 cx_assert(properties != NULL);
584 if (cpl_propertylist_has(properties, GIALIAS_EXPTIME) == FALSE) {
588 darktime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
596 timescale = exptime / darktime;
603 dark_max = cpl_image_get_max(_dark) * timescale;
604 dark_mode = _giraffe_dark_compute_mode(_dark, _bpixel) * timescale;
611 switch (config->method) {
612 case GIDARK_METHOD_UNIFORM:
614 if (dark_max < config->threshold) {
623 dark_value = dark_mode;
624 cpl_image_subtract_scalar(_image, dark_value);
629 case GIDARK_METHOD_ZMASTER:
632 register cxint i = 0;
634 cxdouble* pximage = NULL;
635 cxdouble* pxdark = NULL;
637 cpl_image* scaled_dark = cpl_image_duplicate(_dark);
639 pximage = cpl_image_get_data_double(_image);
640 pxdark = cpl_image_get_data_double(scaled_dark);
642 if (_bpixel == NULL) {
644 register cxint j = 0;
645 register cxint n = nx * ny;
647 for (j = 0; j < n; j++) {
649 pxdark[j] *= timescale;
651 if (pxdark[j] < config->threshold) {
652 pxdark[j] = dark_mode;
660 register cxint j = 0;
661 register cxint n = nx * ny;
663 const cxint* pxmask = cpl_image_get_data_int_const(_bpixel);
666 for (j = 0; j < n; j++) {
668 if ((pxmask[j] & GI_M_PIX_SET) == 0x0) {
669 pxdark[j] *= timescale;
672 pxdark[j] = dark_mode;
680 for (i = 0; i < nx; i++) {
682 register cxint j = 0;
683 register cxint base = i * ny;
685 for (j = 0; j < ny; j++) {
687 register cxint offset = base + j;
689 pximage[offset] -= pxdark[offset];
695 dark_mode = _giraffe_dark_compute_mode(scaled_dark, _bpixel);
696 dark_value = dark_mode;
698 cpl_image_delete(scaled_dark);
704 case GIDARK_METHOD_MASTER:
708 register cxint i = 0;
710 const cxdouble* pxdark = NULL;
712 cxdouble* pximage = NULL;
714 pximage = cpl_image_get_data_double(_image);
715 pxdark = cpl_image_get_data_double_const(_dark);
717 for (i = 0; i < nx; i++) {
719 register cxint j = 0;
720 register cxint base = i * ny;
722 for (j = 0; j < ny; j++) {
724 register cxint offset = base + j;
726 pximage[offset] -= pxdark[offset] * timescale;
743 cpl_propertylist_update_double(properties, GIALIAS_DARKVALUE,
744 dark_value / timescale);
745 cpl_propertylist_set_comment(properties, GIALIAS_DARKVALUE,
746 "Used dark current [ADU/s]");
747 cpl_propertylist_update_double(properties, GIALIAS_DARKEXPECT,
748 dark_mode / timescale);
749 cpl_propertylist_set_comment(properties, GIALIAS_DARKEXPECT,
750 "Expected dark current [ADU/s]");
758 data->value = dark_value;
759 data->expected = dark_mode;
760 data->mode = dark_mode / timescale;
761 data->maximum = dark_max / timescale;
770 cpl_image_delete((cpl_image*)_bpixel);
cxdouble giraffe_range_get_min(const GiRange *const self)
Get the minimum of a range.
void giraffe_range_set_min(GiRange *self, cxdouble min)
Set the minimum 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.
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
cxint giraffe_array_sort(cxdouble *array, cxsize size)
Sorts an array in ascending order.
void giraffe_range_delete(GiRange *self)
Destroys a range object.
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.
cxdouble giraffe_range_get_max(const GiRange *const self)
Get the maximum of a range.