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
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 #ifdef HAVE_CONFIG_H
00126 # include <config.h>
00127 #endif
00128
00129
00136
00137
00138
00139 #include <uves_backsub.h>
00140
00141 #include <uves_parameters.h>
00142 #include <uves_pfits.h>
00143 #include <uves_dump.h>
00144 #include <uves_utils.h>
00145 #include <uves_utils_wrappers.h>
00146 #include <uves_utils_cpl.h>
00147 #include <uves_error.h>
00148 #include <uves_msg.h>
00149 #include <uves.h>
00150
00151 #include <cpl.h>
00152
00153 #include <stdbool.h>
00154 #include <float.h>
00155
00156
00157
00158 static int first_order(const polynomial *order_locations, int nx);
00159 static int last_order (const polynomial *order_locations, int nx, int ny);
00160 static cpl_error_code lower_to_average(cpl_image *image, int RADX, int RADY);
00161 static double sample_background(const cpl_image *image, int x0, double y_0,
00162 int radius_x, int radius_y, int nx, int ny,
00163 background_measure_method BM_METHOD);
00164 static cpl_error_code subtract_background(cpl_image *image, cpl_image *background_im,
00165 const polynomial *background_pol);
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 #define BACKSUB_FLAT_SMOOTHX_BLUE (25.0/4096)
00178 #define BACKSUB_FLAT_SMOOTHX_RED (50.0/4096)
00179 #define BACKSUB_FLAT_SMOOTHY_BLUE (100.0/2048)
00180 #define BACKSUB_FLAT_SMOOTHY_RED (300.0/2048)
00181
00182 #define BACKSUB_SCI_SMOOTHX_BLUE (300.0/4096)
00183 #define BACKSUB_SCI_SMOOTHX_RED (300.0/4096)
00184 #define BACKSUB_SCI_SMOOTHY_BLUE (200.0/2048)
00185 #define BACKSUB_SCI_SMOOTHY_RED (500.0/2048)
00186
00187 #define BACKSUB_SMOOTHY_WLEN 859.9
00188
00191
00192
00193
00194
00195
00203
00204
00205 cpl_parameterlist *
00206 uves_backsub_define_parameters(void)
00207 {
00208 const char *name = "";
00209 char *full_name = NULL;
00210 cpl_parameterlist *parameters = NULL;
00211 cpl_parameter *p = NULL;
00212
00213 parameters = cpl_parameterlist_new();
00214
00215
00216 name = "mmethod";
00217 full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00218
00219 uves_parameter_new_enum(p, full_name,
00220 CPL_TYPE_STRING,
00221 "Background measuring method. If equal to 'median' "
00222 "the background is sampled using the median of a subwindow. "
00223 "If 'minimum', the subwindow minimum value is used. "
00224 "If 'no', no background subtraction is done.",
00225 UVES_BACKSUB_ID,
00226 "median",
00227 3,
00228 "median", "minimum", "no");
00229 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00230 cpl_parameterlist_append(parameters, p);
00231 cpl_free(full_name);
00232
00233
00234 name = "npoints";
00235 full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00236 uves_parameter_new_range(p, full_name,
00237 CPL_TYPE_INT,
00238 "This is the number of columns in interorder space "
00239 "used to sample the background.",
00240 UVES_BACKSUB_ID,
00241 82, 0, INT_MAX);
00242 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00243 cpl_parameterlist_append(parameters, p);
00244 cpl_free(full_name);
00245
00246
00247 name = "radiusy";
00248 full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00249 uves_parameter_new_range(p, full_name,
00250 CPL_TYPE_INT,
00251 "The height (in pixels) of the background sampling "
00252 "window is (2*radiusy + 1). "
00253 "This parameter is not corrected for binning.",
00254 UVES_BACKSUB_ID,
00255 2, 0, INT_MAX);
00256 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00257 cpl_parameterlist_append(parameters, p);
00258 cpl_free(full_name);
00259
00260
00261 name = "sdegree";
00262 full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00263 uves_parameter_new_range(p, full_name,
00264 CPL_TYPE_INT,
00265 "Degree of interpolating splines. Currently "
00266 "only degree = 1 is supported",
00267 UVES_BACKSUB_ID,
00268 1, 0, INT_MAX);
00269 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00270 cpl_parameterlist_append(parameters, p);
00271 cpl_free(full_name);
00272
00273
00274 name = "smoothx";
00275 full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00276 uves_parameter_new_range(p, full_name,
00277 CPL_TYPE_DOUBLE,
00278 "If spline interpolation is used to measure the background, "
00279 "the x-radius of the post-smoothing window is "
00280 "(smoothx * image_width). Here, 'image_width' is the image "
00281 "width after binning. If negative, the default values are used: "
00282 make_str(BACKSUB_FLAT_SMOOTHX_BLUE) " for blue flat-field frames, "
00283 make_str(BACKSUB_FLAT_SMOOTHX_RED) " for red flat-field frames, "
00284 make_str(BACKSUB_SCI_SMOOTHX_BLUE) " for blue science frames and "
00285 make_str(BACKSUB_SCI_SMOOTHX_RED) " for red science frames.",
00286 UVES_BACKSUB_ID,
00287 -1.0, -DBL_MAX, DBL_MAX);
00288 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00289 cpl_parameterlist_append(parameters, p);
00290 cpl_free(full_name);
00291
00292
00293 name = "smoothy";
00294 full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00295 uves_parameter_new_range(p, full_name,
00296 CPL_TYPE_DOUBLE,
00297 "If spline interpolation is used to measure the "
00298 "background, the y-radius of the post-smoothing "
00299 "window is (smoothy * image_height). Here, "
00300 "'image_height' is the image height after binning. "
00301 "If negative, the default values are used: "
00302 make_str(BACKSUB_FLAT_SMOOTHY_BLUE) " for blue flat-field frames, "
00303 make_str(BACKSUB_FLAT_SMOOTHY_RED) " for red flat-field frames, "
00304 make_str(BACKSUB_SCI_SMOOTHY_BLUE) " for blue science frames and "
00305 make_str(BACKSUB_SCI_SMOOTHY_RED) " for red science frames.",
00306 UVES_BACKSUB_ID,
00307 -1.0, -DBL_MAX, DBL_MAX);
00308 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00309 cpl_parameterlist_append(parameters, p);
00310 cpl_free(full_name);
00311
00312 if (cpl_error_get_code() != CPL_ERROR_NONE)
00313 {
00314 cpl_msg_error(__func__, "Creation of spline background subtraction "
00315 "parameters failed: '%s'", cpl_error_get_where());
00316 cpl_parameterlist_delete(parameters);
00317 return NULL;
00318 }
00319 else
00320 {
00321 return parameters;
00322 }
00323 }
00324
00325
00335
00336 background_measure_method
00337 uves_get_bm_method(const cpl_parameterlist *parameters, const char *context,
00338 const char *subcontext)
00339 {
00340 const char *bm = "";
00341 background_measure_method result = 0;
00342
00343 check( uves_get_parameter(parameters, context, subcontext, "mmethod", CPL_TYPE_STRING, &bm),
00344 "Could not read parameter");
00345
00346 if (strcmp(bm, "median" ) == 0) result = BM_MEDIAN;
00347 else if (strcmp(bm, "minimum") == 0) result = BM_MINIMUM;
00348 else if (strcmp(bm, "no" ) == 0) result = BM_NO;
00349 else
00350 {
00351 assure(false, CPL_ERROR_ILLEGAL_INPUT,
00352 "No such background measuring method: '%s'", bm);
00353 }
00354
00355 cleanup:
00356 return result;
00357 }
00358
00359
00393
00394
00395 cpl_error_code
00396 uves_backsub_spline(cpl_image *image, const uves_propertylist *raw_header,
00397 const cpl_table *ordertable, const polynomial *order_locations,
00398 const cpl_parameterlist *parameters, const char *context,
00399 enum uves_chip chip,
00400 bool flat_field,
00401 cpl_image **background)
00402 {
00403
00404 background_measure_method BM_METHOD;
00405 int npoints;
00406 int radius_y;
00407 int bin_x=1;
00408 int bin_y=1;
00409
00410 int sdegree;
00411 double SMOOTHX;
00412 double SMOOTHY;
00413
00414
00415 int nx, ny;
00416 int x, y;
00417 int stepx;
00418 int radius_x;
00419 int smooth_x, smooth_y;
00420
00421 passure( image != NULL, " ");
00422 passure( raw_header != NULL, " ");
00423 passure( ordertable != NULL, " ");
00424 passure( order_locations != NULL, " ");
00425 passure( parameters != NULL, " ");
00426 passure( context != NULL, " ");
00427 passure( uves_polynomial_get_dimension(order_locations) == 2,
00428 "%d", uves_polynomial_get_dimension(order_locations));
00429 passure( background != NULL, " ");
00430
00431
00432 check( BM_METHOD = uves_get_bm_method(parameters, context, UVES_BACKSUB_ID),
00433 "Error getting background measuring method");
00434
00435 check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00436 "npoints", CPL_TYPE_INT , &npoints) , "Could not read parameter");
00437 check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00438 "radiusy", CPL_TYPE_INT , &radius_y), "Could not read parameter");
00439
00440 check(bin_x=uves_pfits_get_binx(raw_header),"error getting %s",UVES_BINX);
00441 check(bin_y=uves_pfits_get_biny(raw_header),"error getting %s",UVES_BINY);
00442
00443 radius_y = uves_round_double((double)radius_y/bin_y);
00444
00445 check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00446 "sdegree", CPL_TYPE_INT , &sdegree) , "Could not read parameter");
00447 check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00448 "smoothx", CPL_TYPE_DOUBLE, &SMOOTHX) , "Could not read parameter");
00449 check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00450 "smoothy", CPL_TYPE_DOUBLE, &SMOOTHY) , "Could not read parameter");
00451
00452
00453
00454 nx = cpl_image_get_size_x(image);
00455 ny = cpl_image_get_size_y(image);
00456
00457
00458 if (BM_METHOD == BM_NO)
00459 {
00460 uves_msg("Skipping background subtraction");
00461
00462
00463 check( *background = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE),
00464 "Error allocating image");
00465 }
00466 else {
00467
00468 if (SMOOTHX < 0)
00469 {
00470 if (chip == UVES_CHIP_BLUE)
00471 {
00472 SMOOTHX = (flat_field) ?
00473 BACKSUB_FLAT_SMOOTHX_BLUE : BACKSUB_SCI_SMOOTHX_BLUE;
00474 }
00475 else
00476 {
00477 SMOOTHX = (flat_field) ?
00478 BACKSUB_FLAT_SMOOTHX_RED : BACKSUB_SCI_SMOOTHX_RED;
00479 }
00480 }
00481 if (SMOOTHY < 0)
00482 {
00483 double wlen;
00484
00485
00486
00487 check( wlen = uves_pfits_get_gratwlen(raw_header, chip),
00488 "Error reading central wavelength");
00489
00490
00491
00492 if (wlen < BACKSUB_SMOOTHY_WLEN)
00493 {
00494 SMOOTHY = (flat_field) ?
00495 BACKSUB_FLAT_SMOOTHY_BLUE : BACKSUB_SCI_SMOOTHY_BLUE;
00496 }
00497 else
00498 {
00499 SMOOTHY = (flat_field) ?
00500 BACKSUB_FLAT_SMOOTHY_RED : BACKSUB_SCI_SMOOTHY_RED;
00501 }
00502 }
00503
00504 assure( 0 < SMOOTHX, CPL_ERROR_ILLEGAL_INPUT, "Illegal smoothx factor: %e", SMOOTHX);
00505 assure( 0 < SMOOTHY, CPL_ERROR_ILLEGAL_INPUT, "Illegal smoothy factor: %e", SMOOTHY);
00506
00507 smooth_x = uves_round_double(SMOOTHX * nx - 0.5);
00508 smooth_y = uves_round_double(SMOOTHY * ny - 0.5);
00509
00510 assure( 0 < npoints, CPL_ERROR_ILLEGAL_INPUT,
00511 "Illegal number of sample points: %d", npoints);
00512 stepx = nx / npoints;
00513 assure( 0 < stepx, CPL_ERROR_ILLEGAL_INPUT, "Illegal step size: %d", stepx);
00514 radius_x = stepx/2;
00515 assure( 0 < radius_x, CPL_ERROR_ILLEGAL_INPUT, "Illegal x sample radius: %d", radius_x);
00516 assure( 0 < radius_y, CPL_ERROR_ILLEGAL_INPUT, "Illegal y sample radius: %d", radius_y);
00517 assure( 0 < smooth_x, CPL_ERROR_ILLEGAL_INPUT, "Illegal x sample smooth: %d", smooth_x);
00518 assure( 0 < smooth_y, CPL_ERROR_ILLEGAL_INPUT, "Illegal y sample smooth: %d", smooth_y);
00519 assure( sdegree == 1, CPL_ERROR_UNSUPPORTED_MODE,
00520 "Spline degree must be 1. It is %d", sdegree);
00521
00522 uves_msg("Sample window (pixels): radx, rady = %d, %d", radius_x, radius_y);
00523
00524 check( *background = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE),
00525 "Error allocating background image");
00526
00527
00528
00529 for (x = stepx; x <= nx; x += stepx) {
00530 int order, minorder, maxorder;
00531
00532
00533 minorder = cpl_table_get_column_min(ordertable, "Order");
00534
00535
00536 while (uves_round_double(
00537 uves_polynomial_evaluate_2d(order_locations, x + radius_x, minorder - 0.5)
00538 ) - radius_y < 1 ||
00539 uves_round_double(
00540 uves_polynomial_evaluate_2d(order_locations, x - radius_x, minorder - 0.5))
00541 - radius_y < 1 )
00542 {
00543 int sign;
00544
00545 for (sign = -1; sign <= 1; sign += 2)
00546 {
00547 assure(
00548 uves_polynomial_evaluate_2d(order_locations,
00549 x + sign*radius_x, minorder+1 - 0.5) >
00550 uves_polynomial_evaluate_2d(order_locations,
00551 x + sign*radius_x, minorder - 0.5),
00552 CPL_ERROR_ILLEGAL_INPUT,
00553 "Order polynomial is not well-formed: "
00554 "p(%d, %f) = %e; p(%d, %f) = %e",
00555 x + sign*radius_x, minorder+1 - 0.5, uves_polynomial_evaluate_2d(
00556 order_locations, x + sign*radius_x, minorder+1 - 0.5
00557 ),
00558 x + sign*radius_x, minorder - 0.5, uves_polynomial_evaluate_2d(
00559 order_locations, x + sign*radius_x, minorder - 0.5)
00560 );
00561 }
00562
00563 minorder += 1;
00564 }
00565
00566 maxorder = cpl_table_get_column_max(ordertable, "Order");
00567
00568
00569 while (uves_round_double(
00570 uves_polynomial_evaluate_2d(order_locations, x + radius_x, maxorder + 0.5)
00571 ) + radius_y > ny ||
00572 uves_round_double(
00573 uves_polynomial_evaluate_2d(order_locations, x - radius_x, maxorder + 0.5)
00574 ) + radius_y > ny ) {
00575 int sign;
00576 for (sign = -1; sign <= 1; sign += 2)
00577 {
00578 assure(
00579 uves_polynomial_evaluate_2d(
00580 order_locations, x + sign*radius_x, maxorder-1 - 0.5) <
00581 uves_polynomial_evaluate_2d(order_locations,
00582 x + sign*radius_x, maxorder - 0.5),
00583 CPL_ERROR_ILLEGAL_INPUT,
00584 "Order polynomial is not well-formed: "
00585 "p(%d, %f) = %e; p(%d, %f) = %e",
00586 x + sign*radius_x, maxorder-1 - 0.5, uves_polynomial_evaluate_2d(
00587 order_locations, x + sign*radius_x, maxorder-1 - 0.5),
00588 x + sign*radius_x, maxorder - 0.5, uves_polynomial_evaluate_2d(
00589 order_locations, x + sign*radius_x, maxorder - 0.5)
00590 );
00591 }
00592
00593 maxorder -= 1;
00594 }
00595
00596
00597 while (uves_round_double(uves_polynomial_evaluate_2d(
00598 order_locations, x + radius_x, minorder - 1.5)
00599 ) - radius_y >= 1 &&
00600 uves_round_double(uves_polynomial_evaluate_2d(
00601 order_locations, x - radius_x, minorder - 1.5)
00602 ) - radius_y >= 1 )
00603 {
00604 int sign;
00605 for (sign = -1; sign <= 1; sign += 2)
00606 {
00607 assure(
00608 uves_polynomial_evaluate_2d(
00609 order_locations, x + sign*radius_x, minorder-1 - 1.5) <
00610 uves_polynomial_evaluate_2d(
00611 order_locations, x + sign*radius_x, minorder - 1.5),
00612 CPL_ERROR_ILLEGAL_INPUT,
00613 "Order polynomial is not well-formed: "
00614 "p(%d, %f) = %e ; p(%d, %f) = %e",
00615 x + sign*radius_x, minorder-1 - 1.5,
00616 uves_polynomial_evaluate_2d(
00617 order_locations, x + sign*radius_x, minorder-1 - 1.5),
00618 x + sign*radius_x, minorder - 1.5,
00619 uves_polynomial_evaluate_2d(
00620 order_locations, x + sign*radius_x, minorder - 1.5));
00621 }
00622
00623 minorder -= 1;
00624 }
00625
00626
00627 while (uves_round_double( uves_polynomial_evaluate_2d(
00628 order_locations, x + radius_x, maxorder + 1.5)
00629 ) + radius_y <= ny &&
00630 uves_round_double( uves_polynomial_evaluate_2d(
00631 order_locations, x - radius_x, maxorder + 1.5)
00632 ) + radius_y <= ny ) {
00633 int sign;
00634 for (sign = -1; sign <= 1; sign += 2)
00635 {
00636 assure(
00637 uves_polynomial_evaluate_2d(
00638 order_locations, x + sign*radius_x, maxorder+1 + 1.5)
00639 >
00640 uves_polynomial_evaluate_2d(
00641 order_locations, x + sign*radius_x, maxorder + 1.5),
00642 CPL_ERROR_ILLEGAL_INPUT,
00643 "Order polynomial is not well-formed: "
00644 "p(%d, %f) = %e ; p(%d, %f) = %e",
00645 x + sign*radius_x, maxorder+1 + 1.5,
00646 uves_polynomial_evaluate_2d(
00647 order_locations, x + sign*radius_x, maxorder+1 + 1.5),
00648 x + sign*radius_x, maxorder + 1.5,
00649 uves_polynomial_evaluate_2d(
00650 order_locations, x + sign*radius_x, maxorder + 1.5));
00651 }
00652
00653 maxorder += 1;
00654 }
00655
00656 uves_msg_debug("(x, order) = (%d, %f - %f) ", x, minorder-.5, maxorder+.5);
00657
00658 for (order = minorder; order <= maxorder; order++) {
00659 int ylo, yhi;
00660 double backlo, backhi;
00661
00662
00663
00664
00665
00666 ylo = uves_round_double(
00667 uves_polynomial_evaluate_2d(order_locations, x, order - 0.5) );
00668 yhi = uves_round_double(
00669 uves_polynomial_evaluate_2d(order_locations, x, order + 0.5) );
00670
00671
00672 assure( yhi > ylo, CPL_ERROR_ILLEGAL_INPUT,
00673 "Order polynomial is not well-formed: "
00674 "p(%d, %f) = %d ; p(%d, %f) = %d",
00675 x, order - 0.5, ylo,
00676 x, order + 0.5, yhi);
00677
00678
00679 check( backlo =
00680 sample_background(
00681 image, x, ylo, radius_x, radius_y, nx, ny, BM_METHOD),
00682 "Error sampling background level");
00683
00684 check( backhi = sample_background(
00685 image, x, yhi, radius_x, radius_y, nx, ny, BM_METHOD),
00686 "Error sampling background level");
00687
00688 uves_msg_debug("Background sample at (x, y, order) = (%d, %d, %f) = %f",
00689 x, ylo, order-0.5, backlo);
00690 uves_msg_debug("Background sample at (x, y, order) = (%d, %d, %f) = %f",
00691 x, yhi, order+0.5, backhi);
00692
00693
00694 if (order == minorder) {
00695 for (y = 1; y <= ylo; y++) {
00696 double back = backlo + (backhi - backlo)*(y - ylo)/(yhi - ylo);
00697 cpl_image_set(*background, x, y, back);
00698
00699 cpl_image_set(*background, x, y, back);
00700 }
00701 }
00702
00703
00704 for (y = ylo; y <= yhi; y++) {
00705 double back;
00706 back = backlo + (backhi - backlo) * (y - ylo) / (yhi - ylo);
00707
00708 cpl_image_set(*background, x, y, back);
00709 }
00710
00711
00712 if (order == maxorder) {
00713 for (y = yhi; y <= ny; y++) {
00714 double back;
00715 back = backlo + (backhi - backlo) * (y - ylo) / (yhi - ylo);
00716
00717 cpl_image_set(*background, x, y, back);
00718 }
00719 }
00720 }
00721 }
00722
00723
00724 for (y = 1; y <= ny; y++) {
00725 int col;
00726 for (col = stepx; col+stepx <= nx; col += stepx) {
00727 int pis_rejected;
00728
00729 double backlo, backhi;
00730
00731
00732 backlo = cpl_image_get(*background, col , y, &pis_rejected);
00733 backhi = cpl_image_get(*background, col+stepx, y, &pis_rejected);
00734
00735
00736 if (col == stepx)
00737 for (x = 1; x <= col; x++)
00738 {
00739 double back = backlo + (backhi - backlo) * (x - col) / stepx;
00740 cpl_image_set(*background, x, y, back);
00741 }
00742
00743
00744 for (x = col; x <= col + stepx; x++)
00745 {
00746 double back = backlo + (backhi - backlo) * (x - col) / stepx;
00747 cpl_image_set(*background, x, y, back);
00748 }
00749
00750
00751 if (col+stepx+stepx > nx)
00752 for (x = col; x <= nx; x++)
00753 {
00754 double back = backlo + (backhi - backlo) * (x - col) / stepx;
00755 cpl_image_set(*background, x, y, back);
00756 }
00757 }
00758 }
00759
00760
00761
00762
00763
00764 uves_msg("Smoothing window (pixels): smox, smoy = %d, %d", smooth_x, smooth_y);
00765
00766 check( uves_filter_image_average(*background, smooth_x, smooth_y),
00767 "Error applying average filter to background image");
00768
00769 uves_msg("Subtracting background image");
00770
00771 check( subtract_background(image, *background, NULL),
00772 "Error subtracting background image");
00773 }
00774
00775 cleanup:
00776 return cpl_error_get_code();
00777 }
00778
00779
00824
00825 cpl_error_code
00826 uves_backsub_poly(cpl_image *image,
00827 const cpl_table *orders, const polynomial *order_locations,
00828 background_measure_method BM_METHOD,
00829 int NPOINTS,
00830 int radius_y,
00831 int DEGX,
00832 int DEGY,
00833 double KAPPA)
00834 {
00835 cpl_table *t = NULL;
00836 polynomial *background = NULL;
00837 int nx, ny;
00838 int stepx, stepy;
00839 int radius_x;
00840 double mse, rmse;
00841 int total_clipped = 0;
00842
00843 if (BM_METHOD == BM_NO)
00844 {
00845 uves_msg("Skipping background subtraction");
00846 }
00847 else
00848 {
00849 passure( image != NULL, " ");
00850 passure( orders == NULL || order_locations == NULL, " ");
00851
00852 nx = cpl_image_get_size_x(image);
00853 ny = cpl_image_get_size_y(image);
00854
00855 assure( NPOINTS < nx, CPL_ERROR_ILLEGAL_INPUT,
00856 "Number of sample columns (%d) larger than image width (%d pixels)",
00857 NPOINTS, nx);
00858
00859 stepx = nx/NPOINTS;
00860 stepy = ny/NPOINTS;
00861
00862 radius_x = stepx/2;
00863
00864
00865 if (orders != NULL)
00866 {
00867
00868
00869 int x, ordersrow, row;
00870
00871
00872 passure( cpl_table_has_column(orders, "Slope"), " ");
00873 passure( cpl_table_has_column(orders, "Intersept"), " ");
00874
00875 passure( cpl_table_get_column_type(orders, "Slope") == CPL_TYPE_DOUBLE,
00876 "%s",
00877 uves_tostring_cpl_type(cpl_table_get_column_type(orders, "Slope")));
00878
00879 passure( cpl_table_get_column_type(orders, "Intersept") == CPL_TYPE_DOUBLE,
00880 "%s",
00881 uves_tostring_cpl_type(cpl_table_get_column_type(orders, "Slope")));
00882
00883
00884
00885 passure( uves_table_is_sorted_double(orders, "Intersept", false), " ");
00886
00887
00888 assure ( cpl_table_get_nrow(orders) >= 2, CPL_ERROR_ILLEGAL_INPUT,
00889 "Only %d line(s) in order table", cpl_table_get_nrow(orders));
00890
00891 t = cpl_table_new( (nx/stepx + 1)*(cpl_table_get_nrow(orders) + 1) );
00892 cpl_table_new_column(t, "X", CPL_TYPE_INT);
00893 cpl_table_new_column(t, "Y", CPL_TYPE_INT);
00894 cpl_table_new_column(t, "Z", CPL_TYPE_DOUBLE);
00895
00896 row = 0;
00897 for (ordersrow = -1; ordersrow < cpl_table_get_nrow(orders); ordersrow++)
00898 {
00899 double slope, intersept;
00900
00901
00902
00903
00904 if (ordersrow == -1)
00905 {
00906 slope = cpl_table_get_double(
00907 orders, "Slope" , 0, NULL);
00908
00909
00910
00911 intersept =
00912 0.5*cpl_table_get_double(orders, "Intersept", 0, NULL) -
00913 0.5*cpl_table_get_double(orders, "Intersept", 1, NULL) ;
00914 }
00915 else if (ordersrow == cpl_table_get_nrow(orders) - 1)
00916 {
00917 slope = cpl_table_get_double(
00918 orders, "Slope" , ordersrow, NULL);
00919
00920
00921
00922 intersept =
00923 0.5*cpl_table_get_double(
00924 orders, "Intersept", ordersrow, NULL) -
00925 0.5*cpl_table_get_double(
00926 orders, "Intersept", ordersrow-1, NULL) ;
00927 }
00928 else
00929 {
00930 slope =
00931 (cpl_table_get_double(
00932 orders, "Slope", ordersrow , NULL) +
00933 cpl_table_get_double(
00934 orders, "Slope", ordersrow+1, NULL) ) / 2;
00935
00936 intersept =
00937 (cpl_table_get_double(
00938 orders, "Intersept", ordersrow , NULL) +
00939 cpl_table_get_double(
00940 orders, "Intersept", ordersrow+1, NULL) ) / 2;
00941 }
00942
00943
00944 for (x = 1 + stepx/2; x <= nx; x += stepx)
00945 {
00946 int y = uves_round_double(intersept + slope * x);
00947
00948 if (1 <= y && y <= ny)
00949 {
00950 double z;
00951
00952 check( z = sample_background(
00953 image,
00954 x, y,
00955 radius_x, radius_y,
00956 nx, ny,
00957 BM_METHOD),
00958 "Error sampling background "
00959 "(x, y) = (%d, %d)", x, y);
00960
00961 cpl_table_set_int (t, "X" , row, x);
00962 cpl_table_set_int (t, "Y" , row, y);
00963 cpl_table_set_double(t, "Z" , row, z);
00964 row++;
00965 }
00966 }
00967 }
00968
00969 cpl_table_set_size(t, row);
00970
00971 }
00972
00973 else if (order_locations != NULL)
00974 {
00975
00976
00977 int x, minorder, maxorder, order;
00978 int row;
00979
00980
00981 assure( uves_polynomial_get_dimension(order_locations) == 2,
00982 CPL_ERROR_ILLEGAL_INPUT,
00983 "Order location polynomial must be 2d. It is %d!",
00984 uves_polynomial_get_dimension(order_locations));
00985
00986 check(( minorder = first_order(order_locations, nx),
00987 maxorder = last_order(order_locations, nx, ny)),
00988 "Error getting min. and max. order numbers");
00989
00990 t = cpl_table_new( (nx/stepx + 1) * (maxorder-minorder+1));
00991 cpl_table_new_column(t, "X", CPL_TYPE_INT);
00992 cpl_table_new_column(t, "Y", CPL_TYPE_INT);
00993 cpl_table_new_column(t, "Z", CPL_TYPE_DOUBLE);
00994
00995 row = 0;
00996 for (order = minorder; order <= maxorder; order++) {
00997
00998 for (x = 1+stepx/2; x <= nx; x += stepx) {
00999 int y = uves_round_double(
01000 uves_polynomial_evaluate_2d(order_locations, x, order + 0.5));
01001
01002 if (1 <= y && y <= ny) {
01003 double z;
01004
01005 check( z = sample_background(image,
01006 x, y,
01007 radius_x, radius_y,
01008 nx, ny,
01009 BM_METHOD),
01010 "Error sampling background (x, order) = (%d, %d+0.5)",
01011 x, order);
01012
01013 cpl_table_set_int (t, "X" , row, x);
01014 cpl_table_set_int (t, "Y" , row, y);
01015 cpl_table_set_double(t, "Z" , row, z);
01016 row++;
01017 }
01018 }
01019 }
01020
01021 cpl_table_set_size(t, row);
01022 }
01023 else
01024 {
01025
01026 int x, y, row;
01027
01028 t = cpl_table_new((nx/stepx + 1) * (ny/stepy + 1));
01029 cpl_table_new_column(t, "X" , CPL_TYPE_INT);
01030 cpl_table_new_column(t, "Y" , CPL_TYPE_INT);
01031 cpl_table_new_column(t, "Z" , CPL_TYPE_DOUBLE);
01032
01033 row = 0;
01034 for (y = 1 + stepy/2; y <= ny; y += stepy)
01035 {
01036 for (x = 1+stepx/2; x <= nx; x += stepx)
01037 {
01038 double z;
01039
01040 check( z = sample_background(image,
01041 x, y,
01042 radius_x, radius_y,
01043 nx, ny,
01044 BM_METHOD),
01045 "Error sampling background (x, y) = (%d, %d)", x, y);
01046
01047 cpl_table_set_int (t, "X" , row, x);
01048 cpl_table_set_int (t, "Y" , row, y);
01049 cpl_table_set_double(t, "Z" , row, z);
01050 row++;
01051 }
01052 }
01053 cpl_table_set_size(t, row);
01054 }
01055
01056
01057
01058 total_clipped = 0;
01059 {
01060 int n_clipped;
01061 do {
01062 assure( cpl_table_get_nrow(t) > (DEGX + 1)*(DEGY + 1),
01063 CPL_ERROR_ILLEGAL_OUTPUT,
01064 "Too few sample points available (%d point(s)) to make the fit "
01065 "(more than %d points needed). "
01066 "Increase number of sample points or increase kappa",
01067 cpl_table_get_nrow(t), (DEGX + 1)*(DEGY + 1));
01068
01069
01070 uves_polynomial_delete(&background);
01071 check( background = uves_polynomial_regression_2d(
01072 t, "X", "Y", "Z", NULL,
01073 DEGX, DEGY, "Zfit", NULL, NULL, &mse,
01074 NULL, NULL, -1, -1),
01075 "Error fitting polynomial");
01076
01077
01078 cpl_table_duplicate_column(t, "Residual", t, "Z");
01079 cpl_table_subtract_columns(t, "Residual", "Zfit");
01080
01081
01082
01083
01084
01085
01086 cpl_table_subtract_scalar(t, "Residual",
01087 cpl_table_get_column_median(t, "Residual"));
01088 rmse = cpl_table_get_column_stdev(t, "Residual");
01089
01090
01091 if (KAPPA > 0)
01092 {
01093 check( n_clipped = uves_select_table_rows(
01094 t, "Residual", CPL_GREATER_THAN, KAPPA * rmse),
01095 "Error selecting rows");
01096 }
01097 else
01098 {
01099 n_clipped = 0;
01100 }
01101
01102 total_clipped += n_clipped;
01103
01104 uves_msg_debug("RMS = %f. %d of %d points rejected in kappa-sigma clipping",
01105 rmse, n_clipped, cpl_table_get_nrow(t));
01106
01107 uves_table_erase_selected_dfs02356(t);
01108
01109 if (n_clipped > 0)
01110 {
01111 cpl_table_erase_column(t, "Zfit");
01112 cpl_table_erase_column(t, "Residual");
01113 }
01114
01115 } while (n_clipped > 0);
01116 }
01117
01118
01119
01120 {
01121 double percentage =
01122 100.0 * ( (double)total_clipped ) / (total_clipped + cpl_table_get_nrow(t));
01123
01124 if (KAPPA > 0) {
01125 uves_msg("%d of %d points (%.2f %%) were rejected in "
01126 "kappa-sigma clipping. RMS = %.2f ADU",
01127 total_clipped,
01128 cpl_table_get_nrow(t) + total_clipped,
01129 percentage,
01130 sqrt(mse));
01131 }
01132
01133
01134 if (orders == NULL && order_locations == NULL)
01135 {
01136 if (total_clipped == 0)
01137 {
01138 uves_msg_warning("No points rejected during background "
01139 "estimation. Background subtraction is "
01140 "uncertain. Try to decrease KAPPA "
01141 "(current value is %f)", KAPPA);
01142 }
01143 if (percentage > 40)
01144 {
01145 uves_msg_warning("%f %% of the sample points were "
01146 "rejected during "
01147 "background estimation", percentage);
01148 }
01149 }
01150 }
01151
01152 check( subtract_background(image, NULL, background),
01153 "Error subtracting background polynomial");
01154 }
01155
01156 cleanup:
01157 uves_free_table(&t);
01158 uves_polynomial_delete(&background);
01159
01160 return cpl_error_get_code();
01161 }
01162
01163
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208 cpl_error_code
01209 uves_backsub_smooth(cpl_image *image, int RADX, int RADY, int ITER)
01210 {
01211 cpl_image *background = NULL;
01212 int i;
01213
01214 assure( RADX >= 0 && RADY >= 0, CPL_ERROR_ILLEGAL_INPUT,
01215 "Negative radius ((%d)x(%d))", RADX, RADY);
01216 assure( ITER >= 1, CPL_ERROR_ILLEGAL_INPUT,
01217 "Non-positive number of iterations (%d)", ITER);
01218
01219
01220 background = cpl_image_duplicate(image);
01221
01222 for (i = 0; i < ITER; i++) {
01223 uves_msg_progress(i, ITER, "..");
01224 uves_msg("i = %d", i);
01225 check( lower_to_average(background,
01226 RADX, RADY), "Error smoothing image");
01227 }
01228
01229
01230 check( cpl_image_subtract(image, background), "Could not subtract background image");
01231
01232 cleanup:
01233 uves_free_image(&background);
01234
01235 return cpl_error_get_code();
01236 }
01237
01238
01257
01258
01259 static double
01260 sample_background(const cpl_image *image, int x0, double y_0,
01261 int radius_x, int radius_y, int nx, int ny,
01262 background_measure_method BM_METHOD)
01263 {
01264 double result = 0;
01265
01266 cpl_table *temp = NULL;
01267 bool found_good = false;
01268 int row;
01269 int x, y;
01270
01271 check(
01272 (temp = cpl_table_new( (2*radius_x + 1) * (2*radius_y + 1) ),
01273 row = 0,
01274 cpl_table_new_column(temp, "Flux", CPL_TYPE_DOUBLE)),
01275 "Error allocating table");
01276
01277 for(y = y_0 - radius_y; y <= y_0 + radius_y; y++)
01278 {
01279 for (x = x0 - radius_x; x <= x0 + radius_x; x++)
01280 {
01281 if (1 <= x && x <= nx &&
01282 1 <= y && y <= ny)
01283 {
01284 int pis_rejected;
01285 double flux = cpl_image_get(image, x, y, &pis_rejected);
01286 if( !pis_rejected )
01287 {
01288 cpl_table_set(temp, "Flux", row, flux);
01289 found_good = true;
01290 }
01291 else
01292 {
01293 cpl_table_set_invalid(temp, "Flux", row);
01294 }
01295 }
01296 else
01297 {
01298 cpl_table_set_invalid(temp, "Flux", row);
01299 }
01300
01301 row++;
01302 }
01303 }
01304
01305 assure( found_good, CPL_ERROR_ILLEGAL_INPUT, "No valid pixels in sample window");
01306
01307 if (BM_METHOD == BM_MEDIAN)
01308 {
01309 result = cpl_table_get_column_median(temp, "Flux");
01310 }
01311 else if (BM_METHOD == BM_MINIMUM)
01312 {
01313 result = cpl_table_get_column_min(temp, "Flux");
01314 }
01315 else
01316 {
01317 assure( false, CPL_ERROR_UNSUPPORTED_MODE,
01318 "Unsupported background sample method: %d", BM_METHOD);
01319 }
01320
01321 cleanup:
01322 uves_free_table(&temp);
01323 return result;
01324 }
01325
01326
01335
01336 static int
01337 first_order(const polynomial *order_locations, int nx)
01338 {
01339 int result;
01340
01341 result = 0;
01342 while (uves_polynomial_evaluate_2d(order_locations, 1 , result + 0.5) < 1 ||
01343 uves_polynomial_evaluate_2d(order_locations, nx, result + 0.5) < 1 )
01344 {
01345 result++;
01346 }
01347
01348 while (uves_polynomial_evaluate_2d(order_locations, 1 , result - 0.5) >= 1 ||
01349 uves_polynomial_evaluate_2d(order_locations, nx, result - 0.5) >= 1 )
01350 {
01351 result -= 1;
01352
01353
01354 assure( result > -100000,
01355 CPL_ERROR_CONTINUE,
01356 "Invalid polynomial: p(x=1, order=%d) = %f p(x=%d, order=%d) = %f",
01357 result, uves_polynomial_evaluate_2d(order_locations, 1.0, result),
01358 nx, result, uves_polynomial_evaluate_2d(order_locations, nx, result));
01359 }
01360
01361 cleanup:
01362 return result;
01363 }
01364
01365
01366
01376
01377 static int
01378 last_order(const polynomial *order_locations, int nx, int ny)
01379 {
01380 int result;
01381
01382 result = 0;
01383 while (uves_polynomial_evaluate_2d(order_locations, 1 , result - 0.5) > ny ||
01384 uves_polynomial_evaluate_2d(order_locations, nx, result - 0.5) > ny )
01385 {
01386 result--;
01387 }
01388
01389 while (uves_polynomial_evaluate_2d(order_locations, 1 , result + 1.5) <= ny ||
01390 uves_polynomial_evaluate_2d(order_locations, nx, result + 1.5) <= ny )
01391 {
01392 result += 1;
01393
01394
01395 assure( result < 100000,
01396 CPL_ERROR_CONTINUE,
01397 "Invalid polynomial: p(x=1, order=%d) = %f p(x=%d, order=%d) = %f",
01398 result, uves_polynomial_evaluate_2d(order_locations, 1.0, result),
01399 nx, result, uves_polynomial_evaluate_2d(order_locations, nx, result));
01400 }
01401
01402 cleanup:
01403 return result;
01404 }
01405
01406
01418
01419 static cpl_error_code
01420 lower_to_average(cpl_image *image, int RADX, int RADY)
01421 {
01422 cpl_image *average = NULL;
01423 double *image_data = NULL;
01424 double *average_data = NULL;
01425 int nx, ny;
01426 int x, y;
01427
01428 passure( image != NULL, "Null image");
01429 nx = cpl_image_get_size_x(image);
01430 ny = cpl_image_get_size_y(image);
01431
01432
01433 uves_msg("Filtering...");
01434 check( average = cpl_image_duplicate(image), "Error copying image");
01435 check( uves_filter_image_average(average, RADX, RADY), "Error applying average filter");
01436 uves_msg("done");
01437
01438 image_data = cpl_image_get_data(image);
01439 average_data = cpl_image_get_data(average);
01440 uves_msg("Lowering...");
01441 for (y = 0; y < ny; y++)
01442 {
01443 for (x = 0; x < nx; x++)
01444 {
01445 if (image_data[x + y*nx] > average_data[x + y*nx])
01446 {
01447 image_data[x + y*nx] = average_data[x + y*nx];
01448 }
01449 }
01450 }
01451 uves_msg("done");
01452
01453 cleanup:
01454 uves_free_image(&average);
01455
01456 return cpl_error_get_code();
01457 }
01458
01459
01471
01472
01473 static cpl_error_code
01474 subtract_background(cpl_image *image, cpl_image *background_im,
01475 const polynomial *background_pol)
01476 {
01477 int nx, ny;
01478 int x, y;
01479
01480 double *image_data;
01481 double *background_data = NULL;
01482
01483 passure(image != NULL, " ");
01484
01485 passure((background_im == NULL) != (background_pol == NULL), " ");
01486
01487
01488 assure(cpl_image_count_rejected(image) == 0,
01489 CPL_ERROR_UNSUPPORTED_MODE, "Input image contains bad pixels");
01490 assure(cpl_image_get_type(image) == CPL_TYPE_DOUBLE,
01491 CPL_ERROR_UNSUPPORTED_MODE,
01492 "Input image is of type %s. double expected",
01493 uves_tostring_cpl_type(cpl_image_get_type(image)));
01494
01495 if (background_im != NULL)
01496 {
01497 assure(cpl_image_count_rejected(background_im) == 0,
01498 CPL_ERROR_UNSUPPORTED_MODE, "Background image contains bad pixels");
01499 assure(cpl_image_get_type(background_im) == CPL_TYPE_DOUBLE,
01500 CPL_ERROR_UNSUPPORTED_MODE,
01501 "Background image is of type %s. double expected",
01502 uves_tostring_cpl_type(cpl_image_get_type(background_im)));
01503 }
01504
01505 image_data = cpl_image_get_data_double(image);
01506 if (background_im != NULL)
01507 {
01508 background_data = cpl_image_get_data_double(background_im);
01509 }
01510
01511 nx = cpl_image_get_size_x(image);
01512 ny = cpl_image_get_size_y(image);
01513
01514 for (y = 1; y <= ny; y++)
01515 {
01516 for (x = 1; x <= nx; x++)
01517 {
01518 double back;
01519 double flux, new_flux;
01520
01521 if (background_im != NULL)
01522 {
01523
01524 back = background_data[(x-1) + (y-1) * nx];
01525 }
01526 else
01527 {
01528
01529 back = uves_polynomial_evaluate_2d(background_pol,
01530 x,
01531 y);
01532 }
01533
01534
01535 flux = image_data[(x-1) + (y-1) * nx];
01536
01537
01538 #if 0
01539
01540 if (back < 0)
01541 {
01542 back = 0.0;
01543 }
01544 if (back > flux)
01545 {
01546 back = flux;
01547 }
01548
01549
01550
01551
01552 new_flux = uves_max_double(0, flux - back);
01553 #else
01554 new_flux = flux-back;
01555 #endif
01556
01557
01558 image_data[(x-1) + (y-1) * nx] = new_flux;
01559
01560 if (background_im != NULL)
01561 {
01562
01563 background_data[(x-1) + (y-1) * nx] =
01564 uves_max_double(0, flux - new_flux);
01565 }
01566 }
01567 }
01568
01569 cleanup:
01570 return cpl_error_get_code();
01571 }