FORS Pipeline Reference Manual 4.9.9
|
00001 /* $Id: fors_image.c,v 1.60 2010/09/14 07:49:30 cizzo Exp $ 00002 * 00003 * This file is part of the FORS Library 00004 * Copyright (C) 2002-2010 European Southern Observatory 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 /* 00022 * $Author: cizzo $ 00023 * $Date: 2010/09/14 07:49:30 $ 00024 * $Revision: 1.60 $ 00025 * $Name: fors-4_9_9 $ 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 /* Invariants: 00068 The CPL images are non-NULL. 00069 The variance image is everywhere non-negative. 00070 The CPL image types are FORS_IMAGE_TYPE. 00071 The CPL image bad pixel masks are unused 00072 */ 00073 }; 00074 00078 const cpl_type FORS_IMAGE_TYPE = CPL_TYPE_FLOAT; 00079 #define FORS_IMAGE_TYPE_MAX FLT_MAX /* Use a #define rather than a variable here 00080 to avoid type casting */ 00081 00082 #undef cleanup 00083 00084 /* 00085 * The following static function passes a max filter of given box 00086 * size on the input data buffer. The output data buffer must be 00087 * pre-allocated. The box size must be a positive odd integer. 00088 * Returns 0 on success. 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 /* not used */ 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 /* fixme: make sure input is consistent */ 00290 00291 /* Compute overall percentage as mean of each percentage. 00292 Valid because input frames have same size. */ 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 /* bias may be NULL */ 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 /* fors_frame_get_group_string(frame), */ 00377 (cpl_frame_get_tag(frame) != NULL) ? 00378 cpl_frame_get_tag(frame) : "NULL", 00379 filename); 00380 00381 /* Verify instrument setting */ 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 /* Get header */ 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 /* Get data */ 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 /* Read, remove overscan areas */ 00403 { 00404 int xlow, ylow, xhig, yhig; 00405 /* bool check_consistency = false; */ 00406 00407 overscans = mos_load_overscans_fors(header); 00408 /* Uses always ESO.DET.OUT1.* which is fine even 00409 for old FORS data */ 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 * Overscan correction 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 /* Define variance */ 00455 if (cpl_frame_get_nextensions(frame) == 0 || bias != NULL) { 00456 00457 /* No error bars provided, assume RON only. 00458 If frame is not a bias, add photon noise later. 00459 */ 00460 00461 /* Define read-out-noise */ 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 /* Get error bars */ 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 /* Count saturated pixels */ 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 /* Done. No bias to subtract */ 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 * Overscan correction 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 /* Variance is now (ron**2 + bias_noise**2). 00551 Add photonic noise: 00552 00553 variance := variance + |f|/conad 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 /* header may be NULL */ 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 /* This would probably be faster if sqrt() is used rather than pow */ 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 /* header may be NULL */ 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 /* Sextractor wants as input the background error bars, 00650 i.e. excluding sources. 00651 Therefore filter away sources but keep the sharp edges 00652 between the illuminated / non-illuminated areas. 00653 00654 I.e. use a median filter, average filter would not work. 00655 */ 00656 00657 cpl_msg_info(cpl_func, "Creating background error map"); 00658 00659 bool filter_data = false; /* filter the variance image */ 00660 int xstep = radius/2; /* 25 points sampling grid 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 /* This function (including API) would need to change 00734 if the pixel type changes */ 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 /* It is an undocumented feature of CPL that you 00774 can pass the same image to cpl_image_multiply and get 00775 the right answer. Let us hope it does not change... 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 /* variance_left := variance_left + variance_right */ 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 /* This CPL function divides by zero by setting x/0 = 1 for all x */ 00936 00937 cpl_image_multiply(dupl->variance, left->data); 00938 cpl_image_multiply(dupl->variance, left->data); 00939 00940 /* Now dupl->variance = sigma2^2 * data1^2 / data2^2 */ 00941 00942 cpl_image_add(left->variance, dupl->variance); 00943 00944 /* Now left->variance = sigma1^2 + sigma2^2 * data1^2 / data2^2 */ 00945 00946 cpl_image_divide(left->variance, dupl->data); 00947 cpl_image_divide(left->variance, dupl->data); 00948 /* QED */ 00949 00950 /* Handle division by zero */ 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 /* CPL is missing the function to locally extract an image, 01209 so this this inefficient CPL function */ 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 /* For efficiency reasons, assume that the image type is float */ 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 Sample kernel on grid which always contains the central pixel 01308 01309 Trim window (note: this will cause fewer values to 01310 be used for the median near the region borders 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 /* Collect data */ 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 /* Get median */ 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 * For efficiency reasons, assume that the image type is float 01374 */ 01375 01376 assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return smooth, NULL ); 01377 01378 /* 01379 * Apply light median filter, to eliminate big outliers from fit 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 * First of all, count how many points will have to be fitted 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 * Fill position and flux vectors with appropriate values 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 * Do the fit, and fill the output image with the model 01441 * values in all pixels. 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 * Allocate space for horizontal max filter result. 01515 */ 01516 01517 hmaxima = cpl_image_duplicate(input); 01518 01519 /* For efficiency reasons, assume that the image type is float */ 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 * Allocate space for vertical max filter result. 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 * Now nx is the y size of the rotated image... 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 /* Now squared residuals wrt median */ 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 /* This should never happen, but avoid sqrt of negative value in any case */ 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 /* Append current image to image lists */ 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 /* Append current image to image lists */ 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 /* Append current image to image lists */ 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 /* Append to image lists */ 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 /* Step size of 1 degree is arbitrary */ 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