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 <fors_image.h>
00033
00034 #include <fors_dfs.h>
00035 #include <fors_utils.h>
00036 #include <fors_pfits.h>
00037 #include <fors_double.h>
00038
00039 #include <moses.h>
00040
00041 #include <cpl.h>
00042
00043 #include <math.h>
00044 #include <stdbool.h>
00045 #include <stdio.h>
00046
00062 struct _fors_image
00063 {
00064 cpl_image *data;
00065 cpl_image *variance;
00066
00067
00068
00069
00070
00071
00072
00073 };
00074
00078 const cpl_type FORS_IMAGE_TYPE = CPL_TYPE_FLOAT;
00079 #define FORS_IMAGE_TYPE_MAX FLT_MAX
00080
00081
00082 #undef cleanup
00083
00084
00085
00086
00087
00088
00089
00090
00091 static int
00092 max_filter(const float *ibuffer, float *obuffer, int length, int size)
00093 {
00094 float max;
00095 int start = size / 2;
00096 int end = length - size / 2;
00097 int i, j;
00098
00099
00100 for (i = start; i < end; i++) {
00101 max = ibuffer[i-start];
00102 for (j = i - start + 1; j <= i + start; j++)
00103 if (max < ibuffer[j])
00104 max = ibuffer[j];
00105 obuffer[i] = max;
00106 }
00107
00108 for (i = 0; i < start; i++)
00109 obuffer[i] = obuffer[start];
00110
00111 for (i = end; i < length; i++)
00112 obuffer[i] = obuffer[end-1];
00113
00114 return 0;
00115 }
00116
00117 #define cleanup
00118
00127 fors_image *
00128 fors_image_new(cpl_image *data, cpl_image *variance)
00129 {
00130 fors_image *image = NULL;
00131
00132 assure( data != NULL, return NULL, NULL );
00133 assure( variance != NULL, return NULL, NULL );
00134
00135 assure( cpl_image_get_type(data) == FORS_IMAGE_TYPE, return NULL,
00136 "Provided data image type is %s, must be %s",
00137 fors_type_get_string(cpl_image_get_type(data)),
00138 fors_type_get_string(FORS_IMAGE_TYPE) );
00139
00140 assure( cpl_image_get_type(variance) == FORS_IMAGE_TYPE, return NULL,
00141 "Provided weight image type is %s, must be %s",
00142 fors_type_get_string(cpl_image_get_type(variance)),
00143 fors_type_get_string(FORS_IMAGE_TYPE) );
00144
00145 assure( cpl_image_get_size_x(data) == cpl_image_get_size_x(variance) &&
00146 cpl_image_get_size_y(data) == cpl_image_get_size_y(variance),
00147 return NULL,
00148 "Incompatible data and weight image sizes: %dx%d and %dx%d",
00149 cpl_image_get_size_x(data), cpl_image_get_size_y(data),
00150 cpl_image_get_size_x(variance), cpl_image_get_size_y(variance));
00151
00152 assure( cpl_image_get_min(variance) >= 0, return NULL,
00153 "Variances must be non-negative, minimum is %f",
00154 cpl_image_get_min(variance));
00155
00156 image = cpl_malloc(sizeof(*image));
00157
00158 image->data = data;
00159 image->variance = variance;
00160
00161 return image;
00162 }
00163
00164 #undef cleanup
00165 #define cleanup
00166
00171 fors_image *
00172 fors_image_duplicate(const fors_image *image)
00173 {
00174 assure( image != NULL, return NULL, NULL );
00175
00176 return fors_image_new(cpl_image_duplicate(image->data),
00177 cpl_image_duplicate(image->variance));
00178 }
00179
00184 void
00185 fors_image_delete(fors_image **image)
00186 {
00187 if (image && *image) {
00188 cpl_image_delete((*image)->data);
00189 cpl_image_delete((*image)->variance);
00190 cpl_free(*image); *image = NULL;
00191 }
00192 return;
00193 }
00194
00199 void
00200 fors_image_delete_const(const fors_image **image)
00201 {
00202 fors_image_delete((fors_image **)image);
00203
00204 return;
00205 }
00206
00207
00208 #if 0
00209
00213 static void
00214 fors_image_dump(const fors_image *image, FILE *file)
00215 {
00216 if (image == NULL) {
00217 fprintf(file, "Null image\n");
00218 }
00219 else {
00220 cpl_stats *stats;
00221
00222 fprintf(file, "Data:\n");
00223 stats = cpl_stats_new_from_image(image->data, CPL_STATS_ALL);
00224 cpl_stats_dump(stats, CPL_STATS_ALL, file);
00225 cpl_stats_delete(stats);
00226
00227 fprintf(file, "Variance:\n");
00228 stats = cpl_stats_new_from_image(image->variance, CPL_STATS_ALL);
00229 cpl_stats_dump(stats, CPL_STATS_ALL, file);
00230 cpl_stats_delete(stats);
00231 }
00232
00233 return;
00234 }
00235 #endif
00236
00237 #undef cleanup
00238 #define cleanup \
00239 do { \
00240 double_list_delete(&sat_percent, double_delete); \
00241 } while (0)
00242
00256 fors_image_list *
00257 fors_image_load_list(const cpl_frameset *frames, const fors_image *bias,
00258 const fors_setting *setting,
00259 double *saturated)
00260 {
00261 fors_image_list *ilist = fors_image_list_new();
00262 double_list *sat_percent = double_list_new();
00263
00264 assure( frames != NULL, return ilist, NULL );
00265 assure( !cpl_frameset_is_empty(frames), return ilist, "Empty frameset");
00266
00267 {
00268 const cpl_frame *f;
00269
00270 for (f = cpl_frameset_get_first_const(frames);
00271 f != NULL;
00272 f = cpl_frameset_get_next_const(frames)) {
00273
00274 double saturated_one;
00275
00276 fors_image *i = fors_image_load(f, bias, setting,
00277 saturated != NULL ?
00278 &saturated_one : NULL);
00279 assure( !cpl_error_get_code(), return ilist, NULL );
00280
00281 fors_image_list_insert(ilist, i);
00282 if (saturated != NULL) {
00283 double_list_insert(sat_percent,
00284 double_duplicate(&saturated_one));
00285 }
00286 }
00287 }
00288
00289
00290
00291
00292
00293 if (saturated != NULL) {
00294 *saturated = double_list_mean(sat_percent, double_eval, NULL);
00295 }
00296
00297 cleanup;
00298 return ilist;
00299 }
00300
00312 const fors_image_list *
00313 fors_image_load_list_const(const cpl_frameset *frames, const fors_image *bias,
00314 const fors_setting *setting,
00315 double *saturated)
00316 {
00317 return (const fors_image_list *)
00318 fors_image_load_list(frames, bias, setting, saturated);
00319 }
00320
00321 #undef cleanup
00322 #define cleanup \
00323 do { \
00324 cpl_propertylist_delete(header); \
00325 cpl_table_delete(overscans); \
00326 cpl_image_delete(temp); \
00327 cpl_mask_delete(non_saturated); \
00328 fors_setting_delete(&frame_setting); \
00329 } while (0)
00330
00348 fors_image *
00349 fors_image_load(const cpl_frame *frame, const fors_image *bias,
00350 const fors_setting *setting,
00351 double *saturated)
00352 {
00353 fors_image *image = NULL;
00354 fors_setting *frame_setting = NULL;
00355 cpl_image *data = NULL;
00356 cpl_image *variance = NULL;
00357 cpl_image *temp = NULL;
00358 cpl_propertylist *header = NULL;
00359 cpl_table *overscans = NULL;
00360 cpl_mask *non_saturated = NULL;
00361 const char *filename;
00362 int extension= 0;
00363 const int plane = 0;
00364 double ocorr = 0.0;
00365 int has_overscans = 0;
00366 int i;
00367
00368 assure( frame != NULL, return image, NULL );
00369
00370 assure( setting != NULL, return image, NULL );
00371 filename = cpl_frame_get_filename(frame);
00372 assure( filename != NULL, return image,
00373 "NULL filename received");
00374
00375 cpl_msg_info(cpl_func, "Loading %s: %s",
00376
00377 (cpl_frame_get_tag(frame) != NULL) ?
00378 cpl_frame_get_tag(frame) : "NULL",
00379 filename);
00380
00381
00382 fors_setting_verify(setting, frame, &frame_setting);
00383 assure( !cpl_error_get_code(), return image,
00384 "Could not verify %s setting",
00385 filename);
00386
00387
00388
00389 header = cpl_propertylist_load(filename, extension);
00390 assure( !cpl_error_get_code(), return image,
00391 "Could not load %s extension %d header",
00392 filename, extension);
00393
00394
00395 data = cpl_image_load(filename,
00396 FORS_IMAGE_TYPE, plane, extension);
00397
00398 assure( !cpl_error_get_code(), return image,
00399 "Could not load image from %s extension %d",
00400 filename, extension);
00401
00402
00403 {
00404 int xlow, ylow, xhig, yhig;
00405
00406
00407 overscans = mos_load_overscans_fors(header);
00408
00409
00410
00411 assure( !cpl_error_get_code(), return image,
00412 "Could not read overscan information from %s extension %d",
00413 filename, extension);
00414
00415 for (i = 1; i < cpl_table_get_nrow(overscans); i++) {
00416
00417
00418
00419
00420
00421 xlow = cpl_table_get_int(overscans, "xlow", i, NULL);
00422 ylow = cpl_table_get_int(overscans, "ylow", i, NULL);
00423 xhig = cpl_table_get_int(overscans, "xhig", i, NULL);
00424 yhig = cpl_table_get_int(overscans, "yhig", i, NULL);
00425
00426 temp = cpl_image_extract(data, xlow+1, ylow+1, xhig, yhig);
00427
00428 ocorr += cpl_image_get_median(temp);
00429
00430 cpl_image_delete(temp); temp = NULL;
00431 }
00432
00433 if (cpl_table_get_nrow(overscans) > 1) {
00434 has_overscans = 1;
00435 ocorr /= cpl_table_get_nrow(overscans) - 1;
00436 }
00437
00438 xlow = cpl_table_get_int(overscans, "xlow", 0, NULL);
00439 ylow = cpl_table_get_int(overscans, "ylow", 0, NULL);
00440 xhig = cpl_table_get_int(overscans, "xhig", 0, NULL);
00441 yhig = cpl_table_get_int(overscans, "yhig", 0, NULL);
00442
00443 cpl_table_delete(overscans); overscans = NULL;
00444
00445 temp = cpl_image_duplicate(data);
00446 cpl_image_delete(data);
00447 data = cpl_image_extract(temp, xlow+1, ylow+1, xhig, yhig);
00448
00449 cpl_image_delete(temp); temp = NULL;
00450 }
00451
00452 cpl_propertylist_delete(header); header = NULL;
00453
00454
00455 if (cpl_frame_get_nextensions(frame) == 0 || bias != NULL) {
00456
00457
00458
00459
00460
00461
00462 variance = cpl_image_new(
00463 cpl_image_get_size_x(data),
00464 cpl_image_get_size_y(data),
00465 FORS_IMAGE_TYPE);
00466
00467 if (cpl_frame_get_group(frame) == CPL_FRAME_GROUP_CALIB) {
00468 cpl_msg_warning(cpl_func,
00469 "No error bars provided for calibration frame %s, "
00470 "assuming no errors. For complete error propagation, "
00471 "you may recreate this frame with this pipeline",
00472 filename);
00473 } else {
00474 cpl_image_add_scalar(variance, frame_setting->ron*frame_setting->ron);
00475 }
00476 }
00477 else {
00478
00479 extension = 1;
00480
00481
00482 variance = cpl_image_load(filename,
00483 FORS_IMAGE_TYPE, plane, extension);
00484
00485 assure( !cpl_error_get_code(), return image,
00486 "Could not load image from %s extension %d",
00487 filename, extension);
00488
00489 cpl_image_power(variance, 2);
00490
00491 assure( cpl_image_get_min(variance) >= 0, return image,
00492 "Illegal minimum variance: %g",
00493 cpl_image_get_min(variance));
00494
00495 cpl_image_delete(temp); temp = NULL;
00496 }
00497
00498 image = fors_image_new(data, variance);
00499
00500
00501 if (saturated != NULL) {
00502 double lo_cut = 0.5;
00503 double hi_cut = 65534.5;
00504 non_saturated = cpl_mask_threshold_image_create(
00505 data, lo_cut, hi_cut);
00506
00507 *saturated = (cpl_image_get_size_x(data) *
00508 cpl_image_get_size_y(data) -
00509 cpl_mask_count(non_saturated)) * 100.0 /
00510 (cpl_image_get_size_x(data) *
00511 cpl_image_get_size_y(data));
00512
00513 cpl_mask_delete(non_saturated); non_saturated = NULL;
00514
00515 cpl_msg_debug(cpl_func,
00516 "%f %% saturated pixels", *saturated);
00517 }
00518
00519 if (bias == NULL) {
00520
00521 }
00522 else {
00523 assure( cpl_frame_get_group(frame) == CPL_FRAME_GROUP_RAW,
00524 return image,
00525 "Refusing to subtract bias from non-raw (%s) input frame: %s",
00526 fors_frame_get_group_string(frame),
00527 filename);
00528
00529 cpl_msg_debug(cpl_func, "Subtracting bias from %s", filename);
00530
00531 fors_image_subtract(image, bias);
00532
00533 assure( !cpl_error_get_code(), return image,
00534 "Bias subtraction failed" );
00535
00536 if (has_overscans) {
00537
00538
00539
00540
00541
00542 ocorr -= cpl_image_get_median(bias->data);
00543
00544 cpl_msg_info(cpl_func,
00545 "Overscan correction applied: %.2f ADUs", ocorr);
00546
00547 fors_image_subtract_scalar(image, ocorr, -1);
00548 }
00549
00550
00551
00552
00553
00554
00555
00556 double conad = 1.0 / frame_setting->average_gain;
00557
00558 temp = cpl_image_divide_scalar_create(image->data, conad);
00559 cpl_image_abs(temp);
00560
00561 cpl_image_add(image->variance, temp);
00562 }
00563
00564 cleanup;
00565 return image;
00566 }
00567
00568
00569 #undef cleanup
00570 #define cleanup \
00571 do { \
00572 cpl_image_delete(sigma); \
00573 } while(0)
00574
00583 void
00584 fors_image_save(const fors_image *image, const cpl_propertylist *header,
00585 const char *filename)
00586 {
00587 cpl_propertylist *extension_header = NULL;
00588 cpl_image *sigma = NULL;
00589
00590 assure( image != NULL, return, NULL );
00591
00592 assure( filename != NULL, return, NULL );
00593
00594 cpl_image_save(image->data, filename, CPL_BPP_IEEE_FLOAT, header,
00595 CPL_IO_DEFAULT);
00596 assure( !cpl_error_get_code(), return,
00597 "Cannot save product %s", filename);
00598
00599 sigma = cpl_image_power_create(image->variance, 0.5);
00600
00601
00602 cpl_image_save(sigma, filename, CPL_BPP_IEEE_FLOAT, extension_header,
00603 CPL_IO_EXTEND);
00604 assure( !cpl_error_get_code(), return,
00605 "Cannot save product %s", filename);
00606
00607 cleanup;
00608 return;
00609 }
00610
00611
00612 #undef cleanup
00613 #define cleanup \
00614 do { \
00615 cpl_image_delete(var_bkg); \
00616 cpl_image_delete(sigma_bkg); \
00617 } while(0)
00618
00629 void
00630 fors_image_save_sex(const fors_image *image, const cpl_propertylist *header,
00631 const char *filename_dat,
00632 const char *filename_var,
00633 int radius)
00634 {
00635 cpl_propertylist *extension_header = NULL;
00636 cpl_image *sigma_bkg = NULL;
00637 cpl_image *var_bkg = NULL;
00638
00639 assure( image != NULL, return, NULL );
00640
00641 assure( filename_dat != NULL, return, NULL );
00642 assure( filename_var != NULL, return, NULL );
00643
00644 cpl_image_save(image->data, filename_dat, CPL_BPP_IEEE_FLOAT, header,
00645 CPL_IO_DEFAULT);
00646 assure( !cpl_error_get_code(), return,
00647 "Cannot save product %s", filename_dat);
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657 cpl_msg_info(cpl_func, "Creating background error map");
00658
00659 bool filter_data = false;
00660 int xstep = radius/2;
00661
00662
00663
00664
00665
00666
00667 int ystep = radius/2;
00668 int xstart = 1;
00669 int ystart = 1;
00670 int xend = fors_image_get_size_x(image);
00671 int yend = fors_image_get_size_y(image);
00672
00673
00674 var_bkg = fors_image_filter_median_create(image,
00675 radius,
00676 radius,
00677 xstart, ystart,
00678 xend, yend,
00679 xstep, ystep,
00680 filter_data);
00681 assure( !cpl_error_get_code(), return,
00682 "Median filtering failed");
00683
00684 sigma_bkg = cpl_image_power_create(var_bkg, 0.5);
00685
00686 cpl_image_save(sigma_bkg, filename_var,
00687 CPL_BPP_IEEE_FLOAT, extension_header,
00688 CPL_IO_DEFAULT);
00689 assure( !cpl_error_get_code(), return,
00690 "Cannot save product %s", filename_var);
00691
00692 cleanup;
00693 return;
00694 }
00695
00696 #undef cleanup
00697 #define cleanup
00698
00703 int fors_image_get_size_x(const fors_image *image)
00704 {
00705 assure( image != NULL, return -1, NULL );
00706 return cpl_image_get_size_x(image->data);
00707 }
00708
00709 #undef cleanup
00710 #define cleanup
00711
00716 int fors_image_get_size_y(const fors_image *image)
00717 {
00718 assure( image != NULL, return -1, NULL );
00719 return cpl_image_get_size_y(image->data);
00720 }
00721
00722 #undef cleanup
00723 #define cleanup
00724
00728 const float *fors_image_get_data_const(const fors_image *image)
00729 {
00730 assure( image != NULL, return NULL, NULL );
00731
00732 assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return NULL, NULL );
00733
00734
00735
00736 return cpl_image_get_data_float(image->data);
00737 }
00738
00739 #undef cleanup
00740 #define cleanup
00741
00748 void
00749 fors_image_abs(fors_image *image)
00750 {
00751 assure( image != NULL, return, NULL );
00752
00753 cpl_image_abs(image->data);
00754
00755 return;
00756 }
00757
00758 #undef cleanup
00759 #define cleanup
00760
00767 void
00768 fors_image_square(fors_image *image)
00769 {
00770 assure( image != NULL, return, NULL );
00771
00772 cpl_image_multiply(image->data, image->data);
00773
00774
00775
00776
00777 cpl_image_multiply_scalar(image->variance, 2);
00778
00779 return;
00780 }
00781
00782
00783 #undef cleanup
00784 #define cleanup \
00785 do { \
00786 cpl_image_delete(temp); \
00787 } while(0)
00788
00796 void
00797 fors_image_subtract(fors_image *left, const fors_image *right)
00798 {
00799 cpl_image *temp = NULL;
00800 assure( left != NULL, return, NULL );
00801 assure( right != NULL, return, NULL );
00802
00803 cpl_image_subtract(left->data, right->data);
00804
00805
00806 cpl_image_add(left->variance, right->variance);
00807
00808 cleanup;
00809 return;
00810 }
00811
00812 #undef cleanup
00813 #define cleanup
00814
00824 void
00825 fors_image_multiply_noerr(fors_image *left, const cpl_image *right)
00826 {
00827 assure( left != NULL, return, NULL );
00828 assure( right != NULL, return, NULL );
00829 assure( cpl_image_get_size_x(left->data) == cpl_image_get_size_x(right) &&
00830 cpl_image_get_size_y(left->data) == cpl_image_get_size_y(right),
00831 return, "Incompatible image sizes: %dx%d and %dx%d",
00832 cpl_image_get_size_x(left->data),
00833 cpl_image_get_size_y(left->data),
00834 cpl_image_get_size_x(right),
00835 cpl_image_get_size_y(right));
00836
00837 cpl_image_multiply(left->data, right);
00838 cpl_image_multiply(left->variance, right);
00839 cpl_image_multiply(left->variance, right);
00840
00841 return;
00842 }
00843
00844 #undef cleanup
00845 #define cleanup
00846
00862 void
00863 fors_image_divide_noerr(fors_image *left, cpl_image *right)
00864 {
00865 assure( left != NULL, return, NULL );
00866 assure( right != NULL, return, NULL );
00867 assure( cpl_image_get_size_x(left->data) == cpl_image_get_size_x(right) &&
00868 cpl_image_get_size_y(left->data) == cpl_image_get_size_y(right),
00869 return, "Incompatible image sizes: %dx%d and %dx%d",
00870 cpl_image_get_size_x(left->data),
00871 cpl_image_get_size_y(left->data),
00872 cpl_image_get_size_x(right),
00873 cpl_image_get_size_y(right));
00874
00875 int x, y;
00876 int nx = cpl_image_get_size_x(right);
00877 int ny = cpl_image_get_size_y(right);
00878 float *datal = cpl_image_get_data_float(left->data);
00879 float *datav = cpl_image_get_data_float(left->variance);
00880 float *datar = cpl_image_get_data_float(right);
00881 for (y = 0; y < ny; y++) {
00882 for (x = 0; x < nx; x++) {
00883 if (datar[x + nx*y] == 0) {
00884 datar[x + nx*y] = 1;
00885 datal[x + nx*y] = 1;
00886
00887 datav[x + nx*y] = FORS_IMAGE_TYPE_MAX;
00888 }
00889 }
00890 }
00891
00892 cpl_image_divide(left->data, right);
00893 cpl_image_divide(left->variance, right);
00894 cpl_image_divide(left->variance, right);
00895
00896 return;
00897 }
00898
00899 #undef cleanup
00900 #define cleanup \
00901 do { \
00902 fors_image_delete(&dupl); \
00903 } while(0)
00904
00924 void
00925 fors_image_divide(fors_image *left, const fors_image *right)
00926 {
00927 fors_image *dupl = NULL;
00928
00929 assure( left != NULL, return, NULL );
00930 assure( right != NULL, return, NULL );
00931
00932 dupl = fors_image_duplicate(right);
00933
00934 cpl_image_divide(left->data, dupl->data);
00935
00936
00937 cpl_image_multiply(dupl->variance, left->data);
00938 cpl_image_multiply(dupl->variance, left->data);
00939
00940
00941
00942 cpl_image_add(left->variance, dupl->variance);
00943
00944
00945
00946 cpl_image_divide(left->variance, dupl->data);
00947 cpl_image_divide(left->variance, dupl->data);
00948
00949
00950
00951 int x, y;
00952 int nx = cpl_image_get_size_x(left->data);
00953 int ny = cpl_image_get_size_y(left->data);
00954 float *datal = cpl_image_get_data_float(left->data);
00955 float *datav = cpl_image_get_data_float(left->variance);
00956 float *datar = cpl_image_get_data_float(right->data);
00957 for (y = 0; y < ny; y++) {
00958 for (x = 0; x < nx; x++) {
00959 if (datar[x + nx*y] == 0) {
00960 datal[x + nx*y] = 1;
00961 datav[x + nx*y] = FORS_IMAGE_TYPE_MAX;
00962 }
00963 }
00964 }
00965
00966 cleanup;
00967 return;
00968 }
00969
00970 #undef cleanup
00971 #define cleanup \
00972 do { \
00973 cpl_image_delete(s22d12); \
00974 } while(0)
00975
00986 void
00987 fors_image_multiply(fors_image *left, const fors_image *right)
00988 {
00989 cpl_image *s22d12 = NULL;
00990
00991 assure( left != NULL, return, NULL );
00992 assure( right != NULL, return, NULL );
00993
00994 s22d12 = cpl_image_duplicate(right->variance);
00995 cpl_image_multiply(s22d12, left->data);
00996 cpl_image_multiply(s22d12, left->data);
00997
00998 cpl_image_multiply(left->variance, right->data);
00999 cpl_image_multiply(left->variance, right->data);
01000 cpl_image_add(left->variance, s22d12);
01001
01002 cpl_image_multiply(left->data, right->data);
01003
01004 cleanup;
01005 return;
01006 }
01007
01008
01009 #undef cleanup
01010 #define cleanup
01011
01023 void fors_image_subtract_scalar(fors_image *image, double s, double ds)
01024 {
01025 assure( image != NULL, return, NULL );
01026 assure( ds <= 0, return, "Unsupported");
01027
01028 cpl_image_subtract_scalar(image->data, s);
01029
01030 return;
01031 }
01032
01033
01034 #undef cleanup
01035 #define cleanup
01036
01048 void fors_image_divide_scalar(fors_image *image, double s, double ds)
01049 {
01050 assure( image != NULL, return, NULL );
01051 assure( s != 0, return, "Division by zero");
01052 assure( ds <= 0, return, "Unsupported");
01053
01054 cpl_image_divide_scalar(image->data, s);
01055 cpl_image_divide_scalar(image->variance, s*s);
01056
01057 return;
01058 }
01059
01060 #undef cleanup
01061 #define cleanup
01062
01074 void fors_image_multiply_scalar(fors_image *image, double s, double ds)
01075 {
01076 assure( image != NULL, return, NULL );
01077 assure( ds <= 0, return, "Unsupported");
01078
01079 cpl_image_multiply_scalar(image->data, s);
01080 cpl_image_multiply_scalar(image->variance, s*s);
01081
01082 return;
01083 }
01084
01085 #undef cleanup
01086 #define cleanup \
01087 do { \
01088 cpl_image_delete(temp); \
01089 } while(0)
01090
01103 void fors_image_exponential(fors_image *image, double b, double db)
01104 {
01105 cpl_image *temp = NULL;
01106
01107 assure( image != NULL, return, NULL );
01108 assure( b >= 0, return, "Negative base: %f", b);
01109 assure( db <= 0, return, "Unsupported");
01110
01111 cpl_image_exponential(image->data, b);
01112
01113 double lnb = log(b);
01114
01115 cpl_image_multiply_scalar(image->variance, lnb*lnb);
01116 cpl_image_multiply(image->variance, image->data);
01117 cpl_image_multiply(image->variance, image->data);
01118
01119 return;
01120 }
01121
01122
01123 #undef cleanup
01124 #define cleanup
01125
01130 double
01131 fors_image_get_min(const fors_image *image)
01132 {
01133 assure( image != NULL, return 0, NULL );
01134
01135 return cpl_image_get_min(image->data);
01136 }
01137
01138 #undef cleanup
01139 #define cleanup
01140
01145 double
01146 fors_image_get_max(const fors_image *image)
01147 {
01148 assure( image != NULL, return 0, NULL );
01149
01150 return cpl_image_get_max(image->data);
01151 }
01152
01153 #undef cleanup
01154 #define cleanup
01155
01161 double
01162 fors_image_get_mean(const fors_image *image, double *dmean)
01163 {
01164 assure( image != NULL, return 0, NULL );
01165 assure( dmean == NULL, return 0, "Unsupported");
01166
01167 return cpl_image_get_mean(image->data);
01168 }
01169
01170 #undef cleanup
01171 #define cleanup
01172
01178 double
01179 fors_image_get_median(const fors_image *image, double *dmedian)
01180 {
01181 assure( image != NULL, return 0, NULL );
01182 assure( dmedian == NULL, return 0, "Unsupported");
01183
01184 return cpl_image_get_median(image->data);
01185 }
01186
01187
01188 #undef cleanup
01189 #define cleanup
01190
01204 void fors_image_crop(fors_image *image,
01205 int xlo, int ylo,
01206 int xhi, int yhi)
01207 {
01208
01209
01210 assure( image != NULL, return, NULL );
01211 assure( 1 <= xlo && xlo <= xhi && xhi <= fors_image_get_size_x(image) &&
01212 1 <= ylo && ylo <= yhi && yhi <= fors_image_get_size_y(image),
01213 return, "Cannot extraction region (%d, %d) - (%d, %d) of "
01214 "%dx%d image",
01215 xlo, ylo, xhi, yhi,
01216 fors_image_get_size_x(image),
01217 fors_image_get_size_y(image));
01218
01219 cpl_image *new_data = cpl_image_extract(image->data,
01220 xlo, ylo,
01221 xhi, yhi);
01222 cpl_image_delete(image->data);
01223
01224 cpl_image* new_variance = cpl_image_extract(image->variance,
01225 xlo, ylo,
01226 xhi, yhi);
01227 cpl_image_delete(image->variance);
01228
01229 image->data = new_data;
01230 image->variance = new_variance;
01231
01232 return;
01233 }
01234
01260 cpl_image *
01261 fors_image_filter_median_create(const fors_image *image,
01262 int xradius,
01263 int yradius,
01264 int xstart,
01265 int ystart,
01266 int xend,
01267 int yend,
01268 int xstep,
01269 int ystep,
01270 bool use_data)
01271 {
01272 const cpl_image *input = NULL;
01273 cpl_image *smooth = NULL;
01274 int nx, ny;
01275
01276 assure( image != NULL, return smooth, NULL );
01277 passure( image->data != NULL, return smooth );
01278 passure( image->variance != NULL, return smooth );
01279
01280 input = (use_data) ? image->data : image->variance;
01281
01282 nx = cpl_image_get_size_x(input);
01283 ny = cpl_image_get_size_y(input);
01284
01285 if (xstep < 1) xstep = 1;
01286 if (ystep < 1) ystep = 1;
01287
01288 assure( 1 <= xstart && xstart <= xend && xend <= nx &&
01289 1 <= ystart && ystart <= yend && yend <= ny, return smooth,
01290 "Illegal region (%d, %d) - (%d, %d) of %dx%d image",
01291 xstart, ystart,
01292 xend, yend,
01293 nx, ny);
01294
01295 smooth = cpl_image_duplicate(input);
01296
01297
01298 assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return smooth, NULL );
01299
01300 const float *input_data = cpl_image_get_data_float_const(input);
01301 float *smooth_data = cpl_image_get_data_float(smooth);
01302 float *data = cpl_malloc((2*yradius + 1)*(2*xradius + 1)*sizeof(*data));
01303
01304 int y;
01305 for (y = ystart; y < yend; y++) {
01306
01307
01308
01309
01310
01311
01312 int ylo = y - (yradius/ystep) * ystep;
01313 int yhi = y + (yradius/ystep) * ystep;
01314
01315 while (ylo < ystart) ylo += ystep;
01316 while (yhi > yend ) yhi -= ystep;
01317
01318 int x;
01319 for (x = xstart; x < xend; x++) {
01320 int xlo = x - (xradius/xstep) * xstep;
01321 int xhi = x + (xradius/xstep) * xstep;
01322
01323 while (xlo < xstart) xlo += xstep;
01324 while (xhi > xend ) xhi -= xstep;
01325
01326
01327 int k = 0;
01328 int j, i;
01329 for (j = ylo; j <= yhi; j += ystep) {
01330 for (i = xlo; i <= xhi; i += xstep) {
01331 data[k++] = input_data[ (i-1) + (j-1)*nx ];
01332 }
01333 }
01334
01335
01336 smooth_data[ (x-1) + (y-1)*nx ] =
01337 fors_tools_get_median_float(data, k);
01338 }
01339 }
01340
01341 cpl_free(data);
01342 return smooth;
01343 }
01344
01345 #undef cleanup
01346 #define cleanup \
01347 do { \
01348 cpl_image_delete(input); \
01349 } while(0)
01350 cpl_image *
01351 fors_image_flat_fit_create(fors_image *image,
01352 int step,
01353 int degree,
01354 float level)
01355 {
01356 cpl_image *temp = NULL;
01357 cpl_image *input = NULL;
01358 cpl_image *smooth = NULL;
01359 int nx, ny;
01360
01361 assure( image != NULL, return smooth, NULL );
01362 passure( image->data != NULL, return smooth );
01363 assure( step > 0, return smooth, NULL );
01364 assure( degree >= 0, return smooth, NULL );
01365
01366
01367 temp = image->data;
01368
01369 nx = cpl_image_get_size_x(temp);
01370 ny = cpl_image_get_size_y(temp);
01371
01372
01373
01374
01375
01376 assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return smooth, NULL );
01377
01378
01379
01380
01381
01382 input = mos_image_filter_median(image->data, 3, 3);
01383
01384 const float *input_data = cpl_image_get_data_float_const(input);
01385
01386
01387
01388
01389
01390 int x, y, pos;
01391 int count = 0;
01392 for (y = 0; y < ny; y += step) {
01393 pos = y*nx;
01394 for (x = 0; x < nx; x += step, pos += step) {
01395 if (input_data[pos] > level) {
01396 count++;
01397 }
01398 }
01399 }
01400
01401 if (count < (degree+1)*(degree+2)) {
01402 step = sqrt((nx*nx)/((degree+1)*(degree+2))) / 2;
01403 if (step == 0)
01404 step = 1;
01405 cpl_msg_error(cpl_func, "Flat field image too small (%dx%d). "
01406 "Please provide a smaller resampling step (a good "
01407 "value would be %d)", nx, ny, step);
01408 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
01409 cleanup;
01410 return NULL;
01411 }
01412
01413
01414
01415
01416
01417
01418 cpl_bivector *positions = cpl_bivector_new(count);
01419 double *xpos = cpl_bivector_get_x_data(positions);
01420 double *ypos = cpl_bivector_get_y_data(positions);
01421 cpl_vector *fluxes = cpl_vector_new(count);
01422 double *flux = cpl_vector_get_data(fluxes);
01423
01424 count = 0;
01425 for (y = 0; y < ny; y += step) {
01426 pos = y*nx;
01427 for (x = 0; x < nx; x += step, pos += step) {
01428 if (input_data[pos] > level) {
01429 xpos[count] = x;
01430 ypos[count] = y;
01431 flux[count] = input_data[pos];
01432 count++;
01433 }
01434 }
01435 }
01436
01437 cpl_image_delete(input); input = NULL;
01438
01439
01440
01441
01442
01443
01444 cpl_polynomial *model = cpl_polynomial_fit_2d_create(positions,
01445 fluxes,
01446 degree,
01447 NULL);
01448
01449 cpl_bivector_delete(positions);
01450 cpl_vector_delete(fluxes);
01451
01452 smooth = cpl_image_new(nx, ny, FORS_IMAGE_TYPE);
01453 float *smooth_data = cpl_image_get_data_float(smooth);
01454
01455 cpl_vector *point = cpl_vector_new(2);
01456 double *dpoint = cpl_vector_get_data(point);
01457
01458 for (y = 0; y < ny; y++) {
01459 pos = y*nx;
01460 dpoint[1] = y;
01461 for (x = 0; x < nx; x++, pos++) {
01462 dpoint[0] = x;
01463 smooth_data[pos] = cpl_polynomial_eval(model, point);
01464 }
01465 }
01466
01467 cpl_polynomial_delete(model);
01468 cpl_vector_delete(point);
01469
01470 cleanup;
01471 return smooth;
01472
01473 }
01474
01475 #undef cleanup
01476 #define cleanup
01477
01493 cpl_image *
01494 fors_image_filter_max_create(const fors_image *image,
01495 int xradius,
01496 int yradius,
01497 bool use_data)
01498 {
01499 const cpl_image *input = NULL;
01500 cpl_image *hmaxima = NULL;
01501 cpl_image *maxima = NULL;
01502 int nx, ny;
01503
01504 assure( image != NULL, return maxima, NULL );
01505 passure( image->data != NULL, return maxima );
01506 passure( image->variance != NULL, return maxima );
01507
01508 input = (use_data) ? image->data : image->variance;
01509
01510 nx = cpl_image_get_size_x(input);
01511 ny = cpl_image_get_size_y(input);
01512
01513
01514
01515
01516
01517 hmaxima = cpl_image_duplicate(input);
01518
01519
01520 assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return maxima, NULL );
01521
01522 float *input_data = (float *)cpl_image_get_data_float_const(input);
01523 float *maxima_data = cpl_image_get_data_float(hmaxima);
01524
01525 int y;
01526 for (y = 0; y < ny; y++) {
01527 const float *irow = input_data + y * nx;
01528 float *orow = maxima_data + y * nx;
01529 max_filter(irow, orow, nx, 2*xradius+1);
01530 }
01531
01532 cpl_image_turn(hmaxima, 1);
01533
01534
01535
01536
01537
01538 maxima = cpl_image_duplicate(hmaxima);
01539 input_data = cpl_image_get_data_float(hmaxima);
01540 maxima_data = cpl_image_get_data_float(maxima);
01541
01542
01543
01544
01545
01546 int x;
01547 for (x = 0; x < nx; x++) {
01548 const float *irow = input_data + x * ny;
01549 float *orow = maxima_data + x * ny;
01550 max_filter(irow, orow, ny, 2*yradius+1);
01551 }
01552
01553 cpl_image_delete(hmaxima);
01554
01555 cpl_image_turn(maxima, -1);
01556
01557 return maxima;
01558 }
01559
01560 #undef cleanup
01561 #define cleanup
01562
01568 double
01569 fors_image_get_stdev(const fors_image *image, double *dstdev)
01570 {
01571 assure( image != NULL, return 0, NULL );
01572 assure( dstdev == NULL, return 0, "Unsupported");
01573
01574 return cpl_image_get_stdev(image->data);
01575 }
01576 #undef cleanup
01577 #define cleanup \
01578 do { \
01579 cpl_mask_delete(rejected); \
01580 cpl_image_delete(im); \
01581 } while (0)
01582
01590 double fors_image_get_stdev_robust(const fors_image *image,
01591 double cut,
01592 double *dstdev)
01593 {
01594 cpl_mask *rejected = NULL;
01595 cpl_image *im = NULL;
01596
01597 assure( image != NULL, return 0, NULL );
01598 assure( cut > 0, return 0, "Illegal cut: %f", cut );
01599 assure( dstdev == NULL, return 0, "Unsupported");
01600
01601 double median = fors_image_get_median(image, NULL);
01602
01603 im = cpl_image_duplicate(image->data);
01604 cpl_image_subtract_scalar(im, median);
01605 cpl_image_power(im, 2);
01606
01607
01608 rejected = cpl_mask_threshold_image_create(image->data,
01609 median - cut,
01610 median + cut);
01611 cpl_mask_not(rejected);
01612 cpl_image_reject_from_mask(im, rejected);
01613
01614 double robust_stdev = sqrt(cpl_image_get_mean(im));
01615
01616 cleanup;
01617 return robust_stdev;
01618 }
01619
01620 #undef cleanup
01621 #define cleanup
01622
01632 double
01633 fors_image_get_error_mean(const fors_image *image, double *dmean)
01634 {
01635 double avg;
01636
01637 assure( image != NULL, return 0, NULL );
01638 assure( dmean == NULL, return 0, "Unsupported");
01639
01640 avg = cpl_image_get_mean(image->variance);
01641
01642
01643 assure( avg >= 0, return -1, "Average variance is %f", avg);
01644
01645 return sqrt(avg);
01646 }
01647
01648
01649 #undef cleanup
01650 #define cleanup \
01651 do { \
01652 cpl_imagelist_delete(datlist); \
01653 cpl_imagelist_delete(varlist); \
01654 } while (0)
01655
01664 fors_image *
01665 fors_image_collapse_create(const fors_image_list *images)
01666 {
01667 cpl_imagelist *datlist = NULL;
01668 cpl_imagelist *varlist = NULL;
01669 cpl_image *data = NULL;
01670 cpl_image *variance = NULL;
01671 const fors_image *i;
01672 int N = 0;
01673
01674 assure( images != NULL, return NULL, NULL );
01675 assure( fors_image_list_size(images) > 0, return NULL,
01676 "Cannot stack zero images");
01677
01678 i = fors_image_list_first_const(images);
01679
01680 datlist = cpl_imagelist_new();
01681 varlist = cpl_imagelist_new();
01682
01683 while(i != NULL) {
01684
01685
01686 cpl_imagelist_set(datlist,
01687 cpl_image_duplicate(i->data),
01688 cpl_imagelist_get_size(datlist));
01689 cpl_imagelist_set(varlist,
01690 cpl_image_duplicate(i->variance),
01691 cpl_imagelist_get_size(varlist));
01692 i = fors_image_list_next_const(images);
01693 N++;
01694 }
01695
01696 #ifdef CPL_IS_NOT_CRAP
01697 data = cpl_imagelist_collapse_create(datlist);
01698
01699 variance = cpl_imagelist_collapse_create(varlist);
01700 #else
01701 data = fors_imagelist_collapse_create(datlist);
01702
01703 variance = fors_imagelist_collapse_create(varlist);
01704 #endif
01705
01706 cpl_image_divide_scalar(variance, N);
01707
01708 cleanup;
01709 return fors_image_new(data, variance);
01710 }
01711
01712
01713 #undef cleanup
01714 #define cleanup \
01715 do { \
01716 cpl_imagelist_delete(datlist); \
01717 cpl_imagelist_delete(varlist); \
01718 } while (0)
01719
01730 fors_image *
01731 fors_image_collapse_minmax_create(const fors_image_list *images,
01732 int low, int high)
01733 {
01734 cpl_imagelist *datlist = NULL;
01735 cpl_imagelist *varlist = NULL;
01736 cpl_image *data = NULL;
01737 cpl_image *variance = NULL;
01738 const fors_image *i;
01739 int N = 0;
01740
01741 assure( images != NULL, return NULL, NULL );
01742 assure( fors_image_list_size(images) > low + high, return NULL,
01743 "Cannot reject more images than there are");
01744 assure( low*high >= 0 && low+high > 0, return NULL,
01745 "Invalid minmax rejection criteria");
01746
01747 i = fors_image_list_first_const(images);
01748
01749 datlist = cpl_imagelist_new();
01750 varlist = cpl_imagelist_new();
01751
01752 while(i != NULL) {
01753
01754
01755 cpl_imagelist_set(datlist,
01756 cpl_image_duplicate(i->data),
01757 cpl_imagelist_get_size(datlist));
01758 cpl_imagelist_set(varlist,
01759 cpl_image_duplicate(i->variance),
01760 cpl_imagelist_get_size(varlist));
01761 i = fors_image_list_next_const(images);
01762 N++;
01763 }
01764
01765 data = cpl_imagelist_collapse_minmax_create(datlist, low, high);
01766 variance = cpl_imagelist_collapse_minmax_create(varlist, low, high);
01767
01768 cpl_image_divide_scalar(variance, N);
01769
01770 cleanup;
01771 return fors_image_new(data, variance);
01772 }
01773
01786 fors_image *
01787 fors_image_collapse_ksigma_create(const fors_image_list *images,
01788 int low, int high, int iter)
01789 {
01790 cpl_imagelist *datlist = NULL;
01791 cpl_imagelist *varlist = NULL;
01792 cpl_image *data = NULL;
01793 cpl_image *variance = NULL;
01794 cpl_image *ngood = NULL;
01795 const fors_image *i;
01796
01797 assure( images != NULL, return NULL, NULL );
01798
01799 i = fors_image_list_first_const(images);
01800
01801 datlist = cpl_imagelist_new();
01802 varlist = cpl_imagelist_new();
01803
01804 while(i != NULL) {
01805
01806
01807 cpl_imagelist_set(datlist,
01808 cpl_image_duplicate(i->data),
01809 cpl_imagelist_get_size(datlist));
01810 cpl_imagelist_set(varlist,
01811 cpl_image_duplicate(i->variance),
01812 cpl_imagelist_get_size(varlist));
01813 i = fors_image_list_next_const(images);
01814 }
01815
01816 data = mos_ksigma_stack(datlist, low, high, iter, &ngood);
01817 variance = cpl_imagelist_collapse_create(varlist);
01818
01819 cpl_image_divide(variance, ngood);
01820
01821 cpl_image_delete(ngood);
01822 cleanup;
01823
01824 return fors_image_new(data, variance);
01825 }
01826
01838 fors_image *
01839 fors_image_collapse_median_create(const fors_image_list *images)
01840 {
01841 cpl_imagelist *datlist = NULL;
01842 cpl_imagelist *varlist = NULL;
01843 cpl_image *data = NULL;
01844 cpl_image *variance = NULL;
01845 const fors_image *i;
01846 int N = 0;
01847
01848 assure( images != NULL, return NULL, NULL );
01849 assure( fors_image_list_size(images) > 0, return NULL,
01850 "Cannot stack zero images");
01851
01852 i = fors_image_list_first_const(images);
01853
01854 datlist = cpl_imagelist_new();
01855 varlist = cpl_imagelist_new();
01856 while(i != NULL) {
01857
01858 cpl_imagelist_set(datlist,
01859 cpl_image_duplicate(i->data),
01860 cpl_imagelist_get_size(datlist));
01861 cpl_imagelist_set(varlist,
01862 cpl_image_duplicate(i->variance),
01863 cpl_imagelist_get_size(varlist));
01864
01865 i = fors_image_list_next_const(images);
01866 N++;
01867 }
01868
01869 #ifdef CPL_IS_NOT_CRAP
01870 data = cpl_imagelist_collapse_median_create(datlist);
01871
01872 variance = cpl_imagelist_collapse_create(varlist);
01873 #else
01874 data = fors_imagelist_collapse_median_create(datlist);
01875
01876 variance = fors_imagelist_collapse_create(varlist);
01877 #endif
01878
01879 cpl_image_divide_scalar(variance, N);
01880
01881 cpl_image_multiply_scalar(variance,
01882 fors_utils_median_corr(N) *
01883 fors_utils_median_corr(N));
01884
01885 cleanup;
01886 return fors_image_new(data, variance);
01887 }
01888
01889 #undef cleanup
01890 #define cleanup
01891
01908 void fors_image_draw(fors_image *image, int type,
01909 double x, double y,
01910 int radius, double color)
01911 {
01912 assure( image != NULL, return, NULL );
01913
01914 assure( type == 0 || type == 1 || type == 2,
01915 return , "Unsupported type %d", type);
01916
01917 assure( radius > 0, return, NULL );
01918
01919 if (type == 2) {
01920 int i;
01921 for (i = 0; i < 360; i++) {
01922
01923
01924 int px = x + radius*cos(i/(2*M_PI));
01925 int py = y + radius*sin(i/(2*M_PI));
01926
01927 if (1 <= px && px <= cpl_image_get_size_x(image->data) &&
01928 1 <= py && py <= cpl_image_get_size_y(image->data)) {
01929 cpl_image_set(image->data, px, py, color);
01930 cpl_image_set(image->variance, px, py, color > 0 ? color : 0);
01931 }
01932 }
01933 }
01934 else {
01935 int i;
01936
01937 for (i = -radius; i <= radius; i++) {
01938
01939 int px, py;
01940
01941 if (type == 0) {
01942 px = x + i;
01943 py = y;
01944 }
01945 else {
01946 px = x;
01947 py = y + i;
01948 }
01949
01950 if (1 <= px && px <= cpl_image_get_size_x(image->data) &&
01951 1 <= py && py <= cpl_image_get_size_y(image->data)) {
01952 cpl_image_set(image->data , px, py, color);
01953 cpl_image_set(image->variance, px, py, color > 0 ? color : 0);
01954 }
01955 }
01956 }
01957
01958 return;
01959 }
01960
01961 #define LIST_DEFINE
01962 #undef LIST_ELEM
01963 #define LIST_ELEM fors_image
01964 #include <list.h>
01965