00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef HAVE_CONFIG_H
00029 # include <config.h>
00030 #endif
00031
00032 #include <string.h>
00033 #include <math.h>
00034
00035 #include <cxlist.h>
00036
00037 #include "gialias.h"
00038 #include "giarray.h"
00039 #include "girange.h"
00040 #include "giwindow.h"
00041 #include "gidark.h"
00042
00043
00052 inline static cxint
00053 _giraffe_halfrange_mode(cxdouble *mode, cxdouble* array, cxsize* size,
00054 cxdouble portion, cxdouble epsilon)
00055 {
00056
00057 cxint status = 0;
00058
00059 register cxsize i = 0;
00060
00061 cxsize ndata = 0;
00062 cxsize _size = *size;
00063
00064 cxdouble tiny = CX_MAXDOUBLE;
00065
00066
00067 for (i = 0; i < _size - 1; i++) {
00068
00069 cxdouble t = array[i + 1] - array[i];
00070
00071 if (t <= 0.) {
00072 continue;
00073 }
00074
00075 if (t < tiny) {
00076 tiny = t;
00077 }
00078 }
00079
00080 tiny /= 2.;
00081
00082 if (tiny <= epsilon) {
00083 tiny = epsilon;
00084
00085 }
00086
00087 if (_size < 3) {
00088
00089 cxdouble _mode = 0.;
00090
00091
00092 status = 0;
00093
00094 switch (_size) {
00095 case 2:
00096 _mode = (array[0] + array[1]) / 2.;
00097 break;
00098
00099 case 1:
00100 _mode = array[0];
00101 break;
00102
00103 default:
00104 status = -2;
00105 break;
00106 }
00107
00108 *mode = _mode;
00109 return status;
00110
00111 }
00112 else {
00113
00114 cxsize count = 0;
00115
00116 cxdouble iwidth = array[_size - 1] - array[0];
00117 cxdouble iweps = 0.;
00118
00119 cx_list* intervals = NULL;
00120
00121 GiRange* interval = NULL;
00122
00123
00124 if (iwidth <= epsilon) {
00125 *mode = giraffe_array_mean(array, _size);
00126 return 0;
00127 }
00128
00129 iwidth *= portion;
00130 iweps = iwidth + tiny;
00131
00132 intervals = cx_list_new();
00133
00134 i = 0;
00135 while (i < _size) {
00136
00137 register cxsize j = 0;
00138 register cxssize k = -1;
00139
00140 cxsize nvalues = 0;
00141
00142 GiRange* _interval = giraffe_range_create(array[i] - tiny,
00143 array[i] + iweps);
00144
00145
00146 for (j = 0; j < _size; j++) {
00147
00148 register cxdouble value = array[j];
00149
00150
00151 if (value >= giraffe_range_get_max(_interval)) {
00152 break;
00153 }
00154
00155 if (value <= giraffe_range_get_min(_interval)) {
00156 continue;
00157 }
00158
00159 if (k < 0) {
00160 giraffe_range_set_min(_interval, value - tiny);
00161 k = j;
00162 }
00163
00164 }
00165
00166 giraffe_range_set_max(_interval, array[j - 1] + tiny);
00167 nvalues = j - k;
00168
00169 if (nvalues > count) {
00170
00171 cx_list_iterator position = cx_list_begin(intervals);
00172 cx_list_const_iterator last = cx_list_end(intervals);
00173
00174 count = nvalues;
00175
00176 while (position != last) {
00177 position =
00178 cx_list_erase(intervals, position,
00179 (cx_free_func)giraffe_range_delete);
00180 }
00181 cx_list_clear(intervals);
00182
00183 cx_list_push_back(intervals, _interval);
00184 _interval = NULL;
00185
00186 }
00187 else if (nvalues == count) {
00188
00189 cx_list_push_back(intervals, _interval);
00190 _interval = NULL;
00191
00192 }
00193 else {
00194
00195 giraffe_range_delete(_interval);
00196 _interval = NULL;
00197
00198 }
00199
00200 ++i;
00201
00202 }
00203
00204 if (cx_list_size(intervals) == 1) {
00205
00206 GiRange* _interval = cx_list_front(intervals);
00207
00208 cxdouble minimum = giraffe_range_get_min(_interval);
00209 cxdouble maximum = giraffe_range_get_max(_interval);
00210
00211 interval = giraffe_range_create(minimum, maximum);
00212
00213 }
00214 else {
00215
00216 cxdouble minimum = 0.;
00217 cxdouble maximum = 0.;
00218
00219 cx_list_iterator position = cx_list_begin(intervals);
00220
00221 cx_list_const_iterator last = cx_list_end(intervals);
00222
00223
00224 iwidth = CX_MAXDOUBLE;
00225
00226
00227
00228
00229
00230
00231 while (position != last) {
00232
00233 GiRange* _interval = cx_list_get(intervals, position);
00234
00235 cxdouble t = giraffe_range_get_max(_interval) -
00236 giraffe_range_get_min(_interval);
00237
00238
00239 if (t <= 0.) {
00240 continue;
00241 }
00242
00243 if (t < iwidth) {
00244 iwidth = t;
00245 }
00246
00247 position = cx_list_next(intervals, position);
00248
00249 }
00250
00251 iwidth += tiny;
00252
00253
00254
00255
00256
00257
00258 position = cx_list_begin(intervals);
00259 last = cx_list_end(intervals);
00260
00261 while (position != last) {
00262
00263 GiRange* _interval = cx_list_get(intervals, position);
00264
00265 cxdouble t = giraffe_range_get_max(_interval) -
00266 giraffe_range_get_min(_interval);
00267
00268
00269 if (t >= iwidth) {
00270 position =
00271 cx_list_erase(intervals, position,
00272 (cx_free_func)giraffe_range_delete);
00273 }
00274 else {
00275 position = cx_list_next(intervals, position);
00276 }
00277
00278 }
00279
00280 minimum = giraffe_range_get_min(cx_list_front(intervals));
00281 maximum = giraffe_range_get_max(cx_list_back(intervals));
00282
00283 interval = giraffe_range_create(minimum, maximum);
00284
00285 }
00286
00287 cx_list_destroy(intervals, (cx_free_func)giraffe_range_delete);
00288 intervals = NULL;
00289
00290
00291
00292
00293
00294
00295 ndata = 0;
00296
00297 for (i = 0; i < _size; i++) {
00298
00299 if (array[i] < giraffe_range_get_min(interval)) {
00300 continue;
00301 }
00302
00303 if (array[i] > giraffe_range_get_max(interval)) {
00304 break;
00305 }
00306
00307 array[ndata++] = array[i];
00308
00309 }
00310
00311 giraffe_range_delete(interval);
00312 interval = NULL;
00313
00314
00315 if (ndata == _size) {
00316
00317 cxdouble start = array[1] - array[0];
00318 cxdouble end = array[ndata - 1] - array[ndata - 2];
00319
00320
00321 if (fabs(start - end) < epsilon) {
00322
00323
00324 ndata -=2;
00325 memmove(array, &array[1], ndata * sizeof(cxdouble));
00326
00327 }
00328 else {
00329
00330 if (start < end) {
00331
00332
00333 --ndata;
00334
00335 }
00336 else {
00337
00338
00339 --ndata;
00340 memmove(array, &array[1], ndata * sizeof(cxdouble));
00341
00342 }
00343
00344 }
00345
00346 }
00347
00348 *size = ndata;
00349
00350 status = _giraffe_halfrange_mode(mode, array, size, portion, epsilon);
00351
00352 }
00353
00354 return status;
00355
00356 }
00357
00358
00359 inline static cxdouble
00360 _giraffe_dark_compute_mode(const cpl_image* image, const cpl_image* bpixel)
00361 {
00362
00363 register cxsize i = 0;
00364
00365 cxint status = 0;
00366
00367 cxsize ndata = cpl_image_get_size_x(image) * cpl_image_get_size_y(image);
00368 cxsize count = 0;
00369 cxsize nbuffer = 0;
00370
00371 const cxdouble* _image = cpl_image_get_data_double_const(image);
00372
00373 cxdouble mode = 0.;
00374 cxdouble delta = 0.;
00375 cxdouble* buffer = NULL;
00376 cxdouble* sorted_image = NULL;
00377
00378
00379 cx_assert(cpl_image_get_type(image) == CPL_TYPE_DOUBLE);
00380
00381 sorted_image = cx_calloc(ndata, sizeof(cxdouble));
00382 memcpy(sorted_image, _image, ndata * sizeof(cxdouble));
00383
00384 if (bpixel != NULL) {
00385
00386 const cxint* _bpixel = cpl_image_get_data_int_const(bpixel);
00387
00388
00389 for (i = 0; i < ndata; i++) {
00390
00391 if (_bpixel[i] == GI_BPIX_OK) {
00392 sorted_image[count++] = _image[i];
00393 }
00394
00395 }
00396
00397 }
00398 else {
00399 count = ndata;
00400 }
00401
00402 status = giraffe_array_sort(sorted_image, count);
00403
00404 if (status != 0) {
00405 return 0.;
00406 }
00407
00408
00409 buffer = cx_calloc(count, sizeof(cxdouble));
00410
00411 for (i = 0; i < count; i += 1000) {
00412 buffer[nbuffer++] = sorted_image[i];
00413 }
00414
00415
00416
00417
00418
00419 status = _giraffe_halfrange_mode(&mode, buffer, &nbuffer, 0.1, 1.e-9);
00420
00421 delta = CX_MIN(mode / 10.,
00422 (sorted_image[count - 1] - sorted_image[0]) / 2.);
00423 nbuffer = count;
00424
00425 while ((nbuffer > 50000) && (delta > 1.e-6)) {
00426
00427 register cxsize j = 0;
00428
00429 for (i = 0; i < count; i++) {
00430
00431 if (sorted_image[i] < (mode - delta)) {
00432 continue;
00433 }
00434
00435 if (sorted_image[i] > (mode + delta)) {
00436 break;
00437 }
00438
00439 buffer[j++] = sorted_image[i];
00440
00441 }
00442
00443 delta /= 2.;
00444
00445 if (j > 0) {
00446 nbuffer = j;
00447 }
00448
00449 }
00450
00451 if (delta > 1.e-6) {
00452 status = _giraffe_halfrange_mode(&mode, buffer, &nbuffer, 0.5, 1.e-9);
00453 }
00454 else {
00455 mode = giraffe_array_mean(buffer, nbuffer);
00456 }
00457
00458 cx_free(buffer);
00459 buffer = NULL;
00460
00461 cx_free(sorted_image);
00462 sorted_image = NULL;
00463
00464 return mode;
00465
00466 }
00467
00468
00485 cxint
00486 giraffe_subtract_dark(GiImage* image, const GiImage* dark,
00487 const GiImage* bpixel, GiDarkResults* data,
00488 const GiDarkConfig* config)
00489 {
00490
00491 cxbool crop = FALSE;
00492
00493 cxint nx = 0;
00494 cxint ny = 0;
00495
00496 cxdouble exptime = 0.;
00497 cxdouble darktime = 0.;
00498 cxdouble dark_max = 0.;
00499 cxdouble dark_mode = 0.;
00500 cxdouble dark_value = 0.;
00501 cxdouble timescale = 1.;
00502
00503 cpl_propertylist* properties = NULL;
00504
00505 const cpl_image* _dark = NULL;
00506 const cpl_image* _bpixel = NULL;
00507
00508 cpl_image* _image = NULL;
00509
00510
00511 if ((image == NULL) || (dark == NULL)) {
00512 return -1;
00513 }
00514
00515 if (config == NULL) {
00516 return -2;
00517 }
00518
00519 _image = giraffe_image_get(image);
00520 _dark = giraffe_image_get(dark);
00521
00522 nx = cpl_image_get_size_y(_image);
00523 ny = cpl_image_get_size_x(_image);
00524
00525 if ((nx != cpl_image_get_size_y(_dark)) ||
00526 (ny != cpl_image_get_size_x(_dark))) {
00527 return -3;
00528 }
00529
00530 if (bpixel != NULL) {
00531
00532 GiWindow area = {1, 1, ny, nx};
00533
00534 properties = giraffe_image_get_properties(bpixel);
00535 _bpixel = giraffe_image_get(bpixel);
00536
00537 if (cpl_propertylist_has(properties, GIALIAS_PRSCX) == TRUE) {
00538 area.x0 += cpl_propertylist_get_int(properties, GIALIAS_PRSCX);
00539 crop = TRUE;
00540 }
00541
00542 if (cpl_propertylist_has(properties, GIALIAS_PRSCY) == TRUE) {
00543 area.y0 += cpl_propertylist_get_int(properties, GIALIAS_PRSCY);
00544 crop = TRUE;
00545 }
00546
00547 if (cpl_propertylist_has(properties, GIALIAS_OVSCX) == TRUE) {
00548 area.x1 = cpl_image_get_size_x(_bpixel) -
00549 cpl_propertylist_get_int(properties, GIALIAS_OVSCX);
00550 crop = TRUE;
00551 }
00552
00553 if (cpl_propertylist_has(properties, GIALIAS_OVSCY) == TRUE) {
00554 area.y1 = cpl_image_get_size_y(_bpixel) -
00555 cpl_propertylist_get_int(properties, GIALIAS_OVSCY);
00556 crop = TRUE;
00557 }
00558
00559 if (crop == TRUE) {
00560 _bpixel = cpl_image_extract(_bpixel, area.x0, area.y0,
00561 area.x1, area.y1);
00562 }
00563
00564 }
00565
00566
00567
00568
00569
00570
00571 properties = giraffe_image_get_properties(image);
00572 cx_assert(properties != NULL);
00573
00574 if (cpl_propertylist_has(properties, GIALIAS_EXPTIME) == FALSE) {
00575 return 1;
00576 }
00577 else {
00578 exptime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
00579 }
00580
00581 properties = giraffe_image_get_properties(dark);
00582 cx_assert(properties != NULL);
00583
00584 if (cpl_propertylist_has(properties, GIALIAS_EXPTIME) == FALSE) {
00585 return 1;
00586 }
00587 else {
00588 darktime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
00589 }
00590
00591
00592
00593
00594
00595
00596 timescale = exptime / darktime;
00597
00598
00599
00600
00601
00602
00603 dark_max = cpl_image_get_max(_dark) * timescale;
00604 dark_mode = _giraffe_dark_compute_mode(_dark, _bpixel) * timescale;
00605
00606
00607
00608
00609
00610
00611 switch (config->method) {
00612 case GIDARK_METHOD_UNIFORM:
00613
00614 if (dark_max < config->threshold) {
00615
00616
00617
00618 dark_value = 0.;
00619
00620 }
00621 else {
00622
00623 dark_value = dark_mode;
00624 cpl_image_subtract_scalar(_image, dark_value);
00625
00626 }
00627 break;
00628
00629 case GIDARK_METHOD_ZMASTER:
00630 {
00631
00632 register cxint i = 0;
00633
00634 cxdouble* pximage = NULL;
00635 cxdouble* pxdark = NULL;
00636
00637 cpl_image* scaled_dark = cpl_image_duplicate(_dark);
00638
00639 pximage = cpl_image_get_data_double(_image);
00640 pxdark = cpl_image_get_data_double(scaled_dark);
00641
00642 if (_bpixel == NULL) {
00643
00644 register cxint j = 0;
00645 register cxint n = nx * ny;
00646
00647 for (j = 0; j < n; j++) {
00648
00649 pxdark[j] *= timescale;
00650
00651 if (pxdark[j] < config->threshold) {
00652 pxdark[j] = dark_mode;
00653 }
00654
00655 }
00656
00657 }
00658 else {
00659
00660 register cxint j = 0;
00661 register cxint n = nx * ny;
00662
00663 const cxint* pxmask = cpl_image_get_data_int_const(_bpixel);
00664
00665
00666 for (j = 0; j < n; j++) {
00667
00668 if ((pxmask[j] & GI_M_PIX_SET) == 0x0) {
00669 pxdark[j] *= timescale;
00670 }
00671 else {
00672 pxdark[j] = dark_mode;
00673 }
00674
00675 }
00676
00677 }
00678
00679
00680 for (i = 0; i < nx; i++) {
00681
00682 register cxint j = 0;
00683 register cxint base = i * ny;
00684
00685 for (j = 0; j < ny; j++) {
00686
00687 register cxint offset = base + j;
00688
00689 pximage[offset] -= pxdark[offset];
00690
00691 }
00692
00693 }
00694
00695 dark_mode = _giraffe_dark_compute_mode(scaled_dark, _bpixel);
00696 dark_value = dark_mode;
00697
00698 cpl_image_delete(scaled_dark);
00699 scaled_dark = NULL;
00700
00701 }
00702 break;
00703
00704 case GIDARK_METHOD_MASTER:
00705 default:
00706 {
00707
00708 register cxint i = 0;
00709
00710 const cxdouble* pxdark = NULL;
00711
00712 cxdouble* pximage = NULL;
00713
00714 pximage = cpl_image_get_data_double(_image);
00715 pxdark = cpl_image_get_data_double_const(_dark);
00716
00717 for (i = 0; i < nx; i++) {
00718
00719 register cxint j = 0;
00720 register cxint base = i * ny;
00721
00722 for (j = 0; j < ny; j++) {
00723
00724 register cxint offset = base + j;
00725
00726 pximage[offset] -= pxdark[offset] * timescale;
00727
00728 }
00729
00730 }
00731 }
00732 break;
00733
00734 }
00735
00736
00737
00738
00739
00740
00741 properties = giraffe_image_get_properties(image);
00742
00743 cpl_propertylist_update_double(properties, GIALIAS_DARKVALUE,
00744 dark_value / timescale);
00745 cpl_propertylist_set_comment(properties, GIALIAS_DARKVALUE,
00746 "Used dark current [ADU/s]");
00747 cpl_propertylist_update_double(properties, GIALIAS_DARKEXPECT,
00748 dark_mode / timescale);
00749 cpl_propertylist_set_comment(properties, GIALIAS_DARKEXPECT,
00750 "Expected dark current [ADU/s]");
00751
00752
00753
00754
00755
00756
00757 if (data != NULL) {
00758 data->value = dark_value;
00759 data->expected = dark_mode;
00760 data->mode = dark_mode / timescale;
00761 data->maximum = dark_max / timescale;
00762 }
00763
00764
00765
00766
00767
00768
00769 if (crop == TRUE) {
00770 cpl_image_delete((cpl_image*)_bpixel);
00771 _bpixel = NULL;
00772 }
00773
00774
00775 return 0;
00776
00777 }