uves_backsub.c

00001 /*                                                                              *
00002  *   This file is part of the ESO UVES Pipeline                                 *
00003  *   Copyright (C) 2004,2005 European Southern Observatory                      *
00004  *                                                                              *
00005  *   This library is free software; you can redistribute it and/or modify       *
00006  *   it under the terms of the GNU General Public License as published by       *
00007  *   the Free Software Foundation; either version 2 of the License, or          *
00008  *   (at your option) any later version.                                        *
00009  *                                                                              *
00010  *   This program is distributed in the hope that it will be useful,            *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of             *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
00013  *   GNU General Public License for more details.                               *
00014  *                                                                              *
00015  *   You should have received a copy of the GNU General Public License          *
00016  *   along with this program; if not, write to the Free Software                *
00017  *   Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA       *
00018  *                                                                              */
00019 
00020 /*
00021  * $Author: amodigli $
00022  * $Date: 2012/03/02 16:23:31 $
00023  * $Revision: 1.53 $
00024  * $Name: uves-5_0_0 $
00025  * $Log: uves_backsub.c,v $
00026  * Revision 1.53  2012/03/02 16:23:31  amodigli
00027  * fixed compiler warnings related to CPL6 upgrade
00028  *
00029  * Revision 1.52  2011/12/08 13:58:44  amodigli
00030  * Fox warnings with CPL6
00031  *
00032  * Revision 1.51  2010/09/24 09:32:02  amodigli
00033  * put back QFITS dependency to fix problem spot by NRI on FIBER mode (with MIDAS calibs) data
00034  *
00035  * Revision 1.49  2010/03/08 13:58:54  amodigli
00036  * now background image has value as computed-no positivity check
00037  *
00038  * Revision 1.48  2010/01/04 14:01:53  amodigli
00039  * less verbose bkg subtraction
00040  *
00041  * Revision 1.47  2008/09/29 06:55:06  amodigli
00042  * add #include <string.h>
00043  *
00044  * Revision 1.46  2008/09/17 14:50:58  amodigli
00045  * use cpl_table_erase_selected in place of uves_table_erase_selected_dfs02356
00046  *
00047  * Revision 1.45  2007/11/20 16:12:51  amodigli
00048  * replaced round by uves_round_double
00049  *
00050  * Revision 1.44  2007/10/17 14:36:59  amodigli
00051  * resale radius_y by frame bin size
00052  *
00053  * Revision 1.43  2007/08/21 13:08:26  jmlarsen
00054  * Removed irplib_access module, largely deprecated by CPL-4
00055  *
00056  * Revision 1.42  2007/06/06 08:17:33  amodigli
00057  * replace tab with 4 spaces
00058  *
00059  * Revision 1.41  2007/05/22 11:29:39  jmlarsen
00060  * Removed MIDAS flag for good
00061  *
00062  * Revision 1.40  2007/04/24 12:50:29  jmlarsen
00063  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00064  *
00065  * Revision 1.39  2007/04/10 07:06:17  jmlarsen
00066  * Changed interface of polynomial_regression_2d()
00067  *
00068  * Revision 1.38  2007/03/28 11:38:21  jmlarsen
00069  * Killed MIDAS flag, removed dead code
00070  *
00071  * Revision 1.37  2007/02/12 10:04:24  jmlarsen
00072  * Added debugging statements
00073  *
00074  * Revision 1.36  2007/02/09 08:50:58  jmlarsen
00075  * Use define's rather than hard-coded recipe names
00076  *
00077  * Revision 1.35  2007/01/15 08:46:48  jmlarsen
00078  * Shortened lines
00079  *
00080  * Revision 1.34  2006/11/15 15:02:14  jmlarsen
00081  * Implemented const safe workarounds for CPL functions
00082  *
00083  * Revision 1.32  2006/11/15 14:04:08  jmlarsen
00084  * Removed non-const version of parameterlist_get_first/last/next which is
00085  * already in CPL, added const-safe wrapper, unwrapper and deallocator functions
00086  *
00087  * Revision 1.31  2006/11/06 15:19:41  jmlarsen
00088  * Removed unused include directives
00089  *
00090  * Revision 1.30  2006/09/20 12:53:57  jmlarsen
00091  * Replaced stringcat functions with uves_sprintf()
00092  *
00093  * Revision 1.29  2006/09/11 08:20:44  jmlarsen
00094  * Renamed identifier reserved by POSIX
00095  *
00096  * Revision 1.28  2006/08/23 09:33:03  jmlarsen
00097  * Renamed local variables shadowing POSIX reserved names
00098  *
00099  * Revision 1.27  2006/08/17 13:56:52  jmlarsen
00100  * Reduced max line length
00101  *
00102  * Revision 1.26  2006/08/11 14:36:11  jmlarsen
00103  * Implemented workaround for slow cpl_table_erase_selected
00104  *
00105  * Revision 1.25  2006/08/07 11:35:35  jmlarsen
00106  * Disabled parameter environment variable mode
00107  *
00108  * Revision 1.24  2006/07/14 12:18:33  jmlarsen
00109  * Disable compiler warning
00110  *
00111  * Revision 1.23  2006/07/03 12:57:50  jmlarsen
00112  * Threshold background image to positive
00113  *
00114  * Revision 1.22  2006/06/13 11:54:24  jmlarsen
00115  * Don't threshold to zero
00116  *
00117  * Revision 1.21  2006/06/01 13:04:11  jmlarsen
00118  * Moved doxygen marker to exclude documentation of #define's
00119  *
00120  * Revision 1.20  2006/04/06 08:29:06  jmlarsen
00121  * Minor doc change
00122  *
00123  * Revision 1.19  2006/03/24 13:54:27  jmlarsen
00124  * Use different smoothing default values depending on type of frame (flat or science)
00125  *
00126  * Revision 1.18  2006/03/09 10:51:14  jmlarsen
00127  * Changed order of for loops
00128  *
00129  * Revision 1.17  2006/03/03 13:54:11  jmlarsen
00130  * Changed syntax of check macro
00131  *
00132  * Revision 1.16  2006/02/28 09:15:22  jmlarsen
00133  * Minor update
00134  *
00135  * Revision 1.15  2006/02/17 10:12:32  jmlarsen
00136  * Removed mixed code-declarations
00137  *
00138  * Revision 1.14  2006/02/15 13:19:15  jmlarsen
00139  * Reduced source code max. line length
00140  *
00141  * Revision 1.13  2005/12/19 16:17:55  jmlarsen
00142  * Replaced bool -> int
00143  *
00144  */
00145 
00146 #ifdef HAVE_CONFIG_H
00147 #  include <config.h>
00148 #endif
00149 
00150 /*----------------------------------------------------------------------------*/
00157 /*----------------------------------------------------------------------------*/
00158 
00159 
00160 #include <uves_backsub.h>
00161 
00162 #include <uves_parameters.h>
00163 #include <uves_pfits.h>
00164 #include <uves_dump.h>
00165 #include <uves_utils.h>
00166 #include <uves_utils_wrappers.h>
00167 #include <uves_utils_cpl.h>
00168 #include <uves_error.h>
00169 #include <uves_msg.h>
00170 #include <uves.h>
00171 
00172 #include <cpl.h>
00173 #include <string.h>
00174 #include <stdbool.h>
00175 #include <float.h>
00176 /*-----------------------------------------------------------------------------
00177                             Functions prototypes
00178  -----------------------------------------------------------------------------*/
00179 static int first_order(const polynomial *order_locations, int nx);
00180 static int last_order (const polynomial *order_locations, int nx, int ny);
00181 static cpl_error_code lower_to_average(cpl_image *image, int RADX, int RADY);
00182 static double sample_background(const cpl_image *image, int x0, double y_0,
00183                 int radius_x, int radius_y, int nx, int ny,
00184                 background_measure_method BM_METHOD);
00185 static cpl_error_code subtract_background(cpl_image *image, cpl_image *background_im, 
00186                       const polynomial *background_pol);
00187 
00188 /*-----------------------------------------------------------------------------
00189                                 Defines
00190  -----------------------------------------------------------------------------*/
00191 
00192 /* This is sort of ugly, because we fine tune parameters depending on
00193    wavelength and also different for masterflat/science exposures.
00194    A 'perfect' background subtraction algorithm should not need to
00195    know about its context.
00196 */ 
00197 
00198 #define BACKSUB_FLAT_SMOOTHX_BLUE (25.0/4096)
00199 #define BACKSUB_FLAT_SMOOTHX_RED  (50.0/4096)
00200 #define BACKSUB_FLAT_SMOOTHY_BLUE (100.0/2048)
00201 #define BACKSUB_FLAT_SMOOTHY_RED  (300.0/2048)
00202 
00203 #define BACKSUB_SCI_SMOOTHX_BLUE  (300.0/4096)
00204 #define BACKSUB_SCI_SMOOTHX_RED   (300.0/4096)
00205 #define BACKSUB_SCI_SMOOTHY_BLUE  (200.0/2048)
00206 #define BACKSUB_SCI_SMOOTHY_RED   (500.0/2048)
00207 
00208 #define BACKSUB_SMOOTHY_WLEN 859.9
00209 
00212 /*-----------------------------------------------------------------------------
00213                             Implementation
00214  -----------------------------------------------------------------------------*/
00215 
00216 /*----------------------------------------------------------------------------*/
00224 /*----------------------------------------------------------------------------*/
00225 
00226 cpl_parameterlist *
00227 uves_backsub_define_parameters(void)
00228 {
00229     const char *name = "";
00230     char *full_name = NULL;
00231     cpl_parameterlist *parameters = NULL;
00232     cpl_parameter *p = NULL;
00233 
00234     parameters = cpl_parameterlist_new();
00235     
00236     //
00237     name = "mmethod";
00238     full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00239     
00240     uves_parameter_new_enum(p, full_name,
00241                    CPL_TYPE_STRING,
00242                    "Background measuring method. If equal to 'median' "
00243                    "the background is sampled using the median of a subwindow. "
00244                    "If 'minimum', the subwindow minimum value is used. "
00245                    "If 'no', no background subtraction is done.",
00246                    UVES_BACKSUB_ID,
00247                    "median",                        /* Default */
00248                    3,                               /* Number of options */
00249                    "median", "minimum", "no");      /* List of options */
00250     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00251     cpl_parameterlist_append(parameters, p);
00252     cpl_free(full_name);
00253 
00254     //
00255     name = "npoints";
00256     full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00257     uves_parameter_new_range(p, full_name,
00258                  CPL_TYPE_INT,
00259                  "This is the number of columns in interorder space "
00260                  "used to sample the background.",
00261                  UVES_BACKSUB_ID,
00262                  82, 0, INT_MAX);
00263     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00264     cpl_parameterlist_append(parameters, p);
00265     cpl_free(full_name);
00266     
00267     //
00268     name = "radiusy";
00269     full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00270     uves_parameter_new_range(p, full_name,
00271                 CPL_TYPE_INT,
00272                 "The height (in pixels) of the background sampling "
00273                 "window is (2*radiusy + 1). "
00274                 "This parameter is not corrected for binning.",
00275                 UVES_BACKSUB_ID,
00276                 2, 0, INT_MAX);
00277     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00278     cpl_parameterlist_append(parameters, p);
00279     cpl_free(full_name);
00280     
00281     //
00282     name = "sdegree";
00283     full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00284     uves_parameter_new_range(p, full_name,
00285                  CPL_TYPE_INT,
00286                  "Degree of interpolating splines. Currently "
00287                  "only degree = 1 is supported",
00288                  UVES_BACKSUB_ID,
00289                  1, 0, INT_MAX);
00290     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00291     cpl_parameterlist_append(parameters, p);
00292     cpl_free(full_name);
00293 
00294     //
00295     name = "smoothx";
00296     full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00297     uves_parameter_new_range(p, full_name,
00298                  CPL_TYPE_DOUBLE,
00299                  "If spline interpolation is used to measure the background, "
00300                  "the x-radius of the post-smoothing window is "
00301                  "(smoothx * image_width). Here, 'image_width' is the image "
00302                  "width after binning. If negative, the default values are used: "
00303                  make_str(BACKSUB_FLAT_SMOOTHX_BLUE) " for blue flat-field frames, "
00304                  make_str(BACKSUB_FLAT_SMOOTHX_RED) " for red flat-field frames, "
00305                  make_str(BACKSUB_SCI_SMOOTHX_BLUE) " for blue science frames and "
00306                  make_str(BACKSUB_SCI_SMOOTHX_RED) " for red science frames.",
00307                  UVES_BACKSUB_ID,
00308                  -1.0, -DBL_MAX, DBL_MAX);
00309     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00310     cpl_parameterlist_append(parameters, p);
00311     cpl_free(full_name);
00312     
00313     //
00314     name = "smoothy";
00315     full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00316     uves_parameter_new_range(p, full_name,
00317                  CPL_TYPE_DOUBLE,
00318                  "If spline interpolation is used to measure the "
00319                  "background, the y-radius of the post-smoothing "
00320                  "window is (smoothy * image_height). Here, "
00321                  "'image_height' is the image height after binning. "
00322                  "If negative, the default values are used: "
00323                  make_str(BACKSUB_FLAT_SMOOTHY_BLUE) " for blue flat-field frames, "
00324                  make_str(BACKSUB_FLAT_SMOOTHY_RED) " for red flat-field frames, "
00325                  make_str(BACKSUB_SCI_SMOOTHY_BLUE) " for blue science frames and "
00326                  make_str(BACKSUB_SCI_SMOOTHY_RED) " for red science frames.",
00327                  UVES_BACKSUB_ID,
00328                  -1.0, -DBL_MAX, DBL_MAX);
00329     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00330     cpl_parameterlist_append(parameters, p);
00331     cpl_free(full_name);
00332 
00333     if (cpl_error_get_code() != CPL_ERROR_NONE)
00334     {
00335         cpl_msg_error(__func__, "Creation of spline background subtraction "
00336               "parameters failed: '%s'", cpl_error_get_where());
00337         cpl_parameterlist_delete(parameters);
00338         return NULL;
00339     }
00340     else
00341     {
00342         return parameters;
00343     }
00344 }
00345 
00346 /*----------------------------------------------------------------------------*/
00356 /*----------------------------------------------------------------------------*/
00357 background_measure_method
00358 uves_get_bm_method(const cpl_parameterlist *parameters, const char *context, 
00359            const char *subcontext)
00360 {
00361     const char *bm = "";
00362     background_measure_method result = 0;
00363 
00364     check( uves_get_parameter(parameters, context, subcontext, "mmethod", CPL_TYPE_STRING, &bm),
00365        "Could not read parameter");
00366     
00367     if      (strcmp(bm, "median" ) == 0) result = BM_MEDIAN;
00368     else if (strcmp(bm, "minimum") == 0) result = BM_MINIMUM;
00369     else if (strcmp(bm, "no"     ) == 0) result = BM_NO;
00370     else
00371     {
00372         /* Impossible */ assure(false, CPL_ERROR_ILLEGAL_INPUT, 
00373                     "No such background measuring method: '%s'", bm);
00374     }
00375     
00376   cleanup:
00377     return result;
00378 }
00379     
00380 /*----------------------------------------------------------------------------*/
00414 /*----------------------------------------------------------------------------*/
00415 
00416 cpl_error_code
00417 uves_backsub_spline(cpl_image *image, const uves_propertylist *raw_header,
00418             const cpl_table *ordertable, const polynomial *order_locations,
00419             const cpl_parameterlist *parameters, const char *context, 
00420             enum uves_chip chip,
00421             bool flat_field,
00422             cpl_image **background)
00423 {
00424     /* Recipe parameters */
00425     background_measure_method BM_METHOD;
00426     int npoints;
00427     int radius_y;
00428     int bin_x=1;
00429     int bin_y=1;
00430 
00431     int sdegree;
00432     double SMOOTHX;
00433     double SMOOTHY;
00434     
00435     /* Local variables */
00436     int nx, ny;
00437     int x, y;
00438     int stepx;
00439     int radius_x;
00440     int smooth_x, smooth_y;        /* Window radius in pixels */
00441     
00442     passure( image != NULL, " ");
00443     passure( raw_header != NULL, " ");
00444     passure( ordertable != NULL, " ");
00445     passure( order_locations != NULL, " ");
00446     passure( parameters != NULL, " ");
00447     passure( context != NULL, " ");
00448     passure( uves_polynomial_get_dimension(order_locations) == 2, 
00449          "%d", uves_polynomial_get_dimension(order_locations));
00450     passure( background != NULL, " ");
00451 
00452     /* Get recipe parameters */
00453     check( BM_METHOD = uves_get_bm_method(parameters, context, UVES_BACKSUB_ID),
00454        "Error getting background measuring method");
00455     
00456     check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00457                   "npoints", CPL_TYPE_INT   , &npoints) , "Could not read parameter");
00458     check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00459                   "radiusy", CPL_TYPE_INT   , &radius_y), "Could not read parameter");
00460 
00461     check(bin_x=uves_pfits_get_binx(raw_header),"error getting %s",UVES_BINX);
00462     check(bin_y=uves_pfits_get_biny(raw_header),"error getting %s",UVES_BINY);
00463 
00464     radius_y = uves_round_double((double)radius_y/bin_y);
00465  
00466     check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00467                   "sdegree", CPL_TYPE_INT   , &sdegree) , "Could not read parameter");
00468     check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00469                   "smoothx", CPL_TYPE_DOUBLE, &SMOOTHX) , "Could not read parameter");
00470     check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00471                   "smoothy", CPL_TYPE_DOUBLE, &SMOOTHY) , "Could not read parameter");
00472 
00473    
00474     /* Get other parameters */
00475     nx = cpl_image_get_size_x(image);
00476     ny = cpl_image_get_size_y(image);
00477 
00478 
00479     if (BM_METHOD == BM_NO)
00480     {
00481         uves_msg("Skipping background subtraction");
00482 
00483         /* Calculate a zero-background */
00484         check( *background = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE),
00485            "Error allocating image");
00486     }
00487     else {
00488     /* If negative, set default values for smoothx, smoothy */
00489     if (SMOOTHX < 0)
00490         {
00491         if (chip == UVES_CHIP_BLUE)
00492             {
00493             SMOOTHX = (flat_field) ? 
00494                 BACKSUB_FLAT_SMOOTHX_BLUE : BACKSUB_SCI_SMOOTHX_BLUE;
00495             }
00496         else
00497             {
00498             SMOOTHX = (flat_field) ? 
00499                 BACKSUB_FLAT_SMOOTHX_RED : BACKSUB_SCI_SMOOTHX_RED;
00500             }
00501         }
00502     if (SMOOTHY < 0)
00503         {
00504         double wlen;
00505         
00506         /* Read wavelength from raw header */
00507         
00508         check( wlen = uves_pfits_get_gratwlen(raw_header, chip),
00509                "Error reading central wavelength");
00510         
00511         /* The criterion is not if the chip is BLUE/RED,
00512            but whether the wlen is < 860A */
00513         if (wlen < BACKSUB_SMOOTHY_WLEN)
00514             {
00515             SMOOTHY = (flat_field) ? 
00516                 BACKSUB_FLAT_SMOOTHY_BLUE : BACKSUB_SCI_SMOOTHY_BLUE;
00517             }
00518         else
00519             {
00520             SMOOTHY = (flat_field) ? 
00521                 BACKSUB_FLAT_SMOOTHY_RED : BACKSUB_SCI_SMOOTHY_RED;
00522             }
00523         }
00524     
00525     assure( 0 < SMOOTHX, CPL_ERROR_ILLEGAL_INPUT, "Illegal smoothx factor: %e", SMOOTHX);
00526     assure( 0 < SMOOTHY, CPL_ERROR_ILLEGAL_INPUT, "Illegal smoothy factor: %e", SMOOTHY);
00527     
00528     smooth_x = uves_round_double(SMOOTHX * nx - 0.5);
00529     smooth_y = uves_round_double(SMOOTHY * ny - 0.5);
00530     
00531     assure( 0 < npoints, CPL_ERROR_ILLEGAL_INPUT, 
00532         "Illegal number of sample points: %d", npoints);
00533     stepx = nx / npoints;
00534     assure( 0 < stepx, CPL_ERROR_ILLEGAL_INPUT, "Illegal step size: %d", stepx);
00535     radius_x = stepx/2;
00536     assure( 0 < radius_x, CPL_ERROR_ILLEGAL_INPUT, "Illegal x sample radius: %d", radius_x);
00537     assure( 0 < radius_y, CPL_ERROR_ILLEGAL_INPUT, "Illegal y sample radius: %d", radius_y);
00538     assure( 0 < smooth_x, CPL_ERROR_ILLEGAL_INPUT, "Illegal x sample smooth: %d", smooth_x);
00539     assure( 0 < smooth_y, CPL_ERROR_ILLEGAL_INPUT, "Illegal y sample smooth: %d", smooth_y);
00540     assure( sdegree == 1, CPL_ERROR_UNSUPPORTED_MODE, 
00541         "Spline degree must be 1. It is %d", sdegree);
00542     
00543     uves_msg("Sample window (pixels): radx, rady = %d, %d", radius_x, radius_y);
00544     
00545     check( *background = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE), 
00546            "Error allocating background image");
00547     
00548     /* Process */
00549     
00550     for (x = stepx; x <= nx; x += stepx) {
00551         int order, minorder, maxorder;
00552         /* Find min. and max. order where background positions are inside image  */
00553             
00554         minorder = cpl_table_get_column_min(ordertable, "Order");
00555             
00556         /* If outside image, move to inside image */
00557         while (uves_round_double(
00558                uves_polynomial_evaluate_2d(order_locations, x + radius_x, minorder - 0.5)
00559                ) - radius_y < 1 ||
00560            uves_round_double(
00561                uves_polynomial_evaluate_2d(order_locations, x - radius_x, minorder - 0.5))
00562            - radius_y < 1  )
00563         {
00564             int sign;
00565 
00566             for (sign = -1; sign <= 1; sign += 2)
00567             {
00568                 assure( 
00569                 uves_polynomial_evaluate_2d(order_locations,
00570                                 x + sign*radius_x, minorder+1 - 0.5) >
00571                 uves_polynomial_evaluate_2d(order_locations,
00572                                 x + sign*radius_x, minorder   - 0.5),
00573                 CPL_ERROR_ILLEGAL_INPUT,
00574                 "Order polynomial is not well-formed: "
00575                 "p(%d, %f) = %e; p(%d, %f) = %e",
00576                 x + sign*radius_x, minorder+1 - 0.5, uves_polynomial_evaluate_2d(
00577                     order_locations, x + sign*radius_x, minorder+1 - 0.5
00578                     ),
00579                 x + sign*radius_x, minorder   - 0.5, uves_polynomial_evaluate_2d(
00580                     order_locations, x + sign*radius_x, minorder   - 0.5)
00581                 );
00582             }
00583 
00584             minorder += 1;
00585         }
00586             
00587         maxorder = cpl_table_get_column_max(ordertable, "Order");
00588         
00589         /* If outside image, move to inside image */
00590         while (uves_round_double( 
00591                uves_polynomial_evaluate_2d(order_locations, x + radius_x, maxorder + 0.5)
00592                ) + radius_y > ny ||
00593            uves_round_double( 
00594                uves_polynomial_evaluate_2d(order_locations, x - radius_x, maxorder + 0.5)
00595                ) + radius_y > ny  ) {
00596         int sign;
00597         for (sign = -1; sign <= 1; sign += 2)
00598             {
00599             assure( 
00600                 uves_polynomial_evaluate_2d(
00601                 order_locations, x + sign*radius_x, maxorder-1 - 0.5) <
00602                 uves_polynomial_evaluate_2d(order_locations, 
00603                             x + sign*radius_x, maxorder   - 0.5), 
00604                 CPL_ERROR_ILLEGAL_INPUT,
00605                 "Order polynomial is not well-formed: "
00606                 "p(%d, %f) = %e; p(%d, %f) = %e",
00607                 x + sign*radius_x, maxorder-1 - 0.5, uves_polynomial_evaluate_2d(
00608                 order_locations, x + sign*radius_x, maxorder-1 - 0.5),
00609                 x + sign*radius_x, maxorder   - 0.5, uves_polynomial_evaluate_2d(
00610                 order_locations, x + sign*radius_x, maxorder   - 0.5)
00611                 );
00612             }
00613                 
00614         maxorder -= 1;
00615         }
00616         
00617             /* Move to min. order inside image */
00618             while (uves_round_double(uves_polynomial_evaluate_2d(
00619                                          order_locations, x + radius_x, minorder - 1.5)
00620                        ) - radius_y >= 1 &&
00621                    uves_round_double(uves_polynomial_evaluate_2d(
00622                                          order_locations, x - radius_x, minorder - 1.5)
00623                        ) - radius_y >= 1  )
00624                 {
00625                     int sign;
00626                     for (sign = -1; sign <= 1; sign += 2)
00627                         {
00628                             assure( 
00629                                 uves_polynomial_evaluate_2d(
00630                                     order_locations, x + sign*radius_x, minorder-1 - 1.5) <
00631                                 uves_polynomial_evaluate_2d(
00632                                     order_locations, x + sign*radius_x, minorder   - 1.5), 
00633                                 CPL_ERROR_ILLEGAL_INPUT,
00634                                 "Order polynomial is not well-formed: "
00635                                 "p(%d, %f) = %e ; p(%d, %f) = %e",
00636                                 x + sign*radius_x, minorder-1 - 1.5, 
00637                                 uves_polynomial_evaluate_2d(
00638                                     order_locations, x + sign*radius_x, minorder-1 - 1.5),
00639                                 x + sign*radius_x, minorder   - 1.5,
00640                                 uves_polynomial_evaluate_2d(
00641                                     order_locations, x + sign*radius_x, minorder   - 1.5));
00642                         }
00643                     
00644                     minorder -= 1;
00645                 }
00646             
00647             /* Move to max. order inside image */
00648             while (uves_round_double( uves_polynomial_evaluate_2d(
00649                                           order_locations, x + radius_x, maxorder + 1.5)
00650                        ) + radius_y <= ny &&
00651                    uves_round_double( uves_polynomial_evaluate_2d(
00652                                           order_locations, x - radius_x, maxorder + 1.5)
00653                        ) + radius_y <= ny  ) {
00654                 int sign;
00655                 for (sign = -1; sign <= 1; sign += 2)
00656                     {
00657                         assure( 
00658                             uves_polynomial_evaluate_2d(
00659                                 order_locations, x + sign*radius_x, maxorder+1 + 1.5)
00660                             >
00661                             uves_polynomial_evaluate_2d(
00662                                 order_locations, x + sign*radius_x, maxorder   + 1.5),
00663                             CPL_ERROR_ILLEGAL_INPUT,
00664                             "Order polynomial is not well-formed: "
00665                             "p(%d, %f) = %e ; p(%d, %f) = %e",
00666                             x + sign*radius_x, maxorder+1 + 1.5,
00667                             uves_polynomial_evaluate_2d(
00668                                 order_locations, x + sign*radius_x, maxorder+1 + 1.5),
00669                             x + sign*radius_x, maxorder   + 1.5,
00670                             uves_polynomial_evaluate_2d(
00671                                 order_locations, x + sign*radius_x, maxorder   + 1.5));
00672                     }
00673                 
00674                 maxorder += 1;
00675             }
00676         
00677         uves_msg_debug("(x, order) = (%d, %f - %f)  ", x, minorder-.5, maxorder+.5);
00678         
00679         for (order = minorder; order <= maxorder; order++) {
00680         int ylo, yhi;
00681         double backlo, backhi;
00682             
00683         /* Sample background above and below order using the median of a window
00684          * with size (2*radius_x + 1) * (2*radius_y + 1)
00685          */
00686             
00687         ylo = uves_round_double( 
00688             uves_polynomial_evaluate_2d(order_locations, x, order - 0.5) );
00689         yhi = uves_round_double(
00690             uves_polynomial_evaluate_2d(order_locations, x, order + 0.5) );
00691 
00692         /* Fail cleanly if input polynomial is corrupted */
00693         assure( yhi > ylo, CPL_ERROR_ILLEGAL_INPUT,
00694             "Order polynomial is not well-formed: "
00695             "p(%d, %f) = %d ; p(%d, %f) = %d",
00696             x, order - 0.5, ylo,
00697             x, order + 0.5, yhi);
00698             
00699             
00700         check( backlo = 
00701                sample_background(
00702                image, x, ylo, radius_x, radius_y, nx, ny, BM_METHOD),
00703                "Error sampling background level");
00704             
00705         check( backhi = sample_background(
00706                image, x, yhi, radius_x, radius_y, nx, ny, BM_METHOD),
00707                "Error sampling background level");
00708                    
00709         uves_msg_debug("Background sample at (x, y, order) = (%d, %d, %f) = %f",
00710                    x, ylo, order-0.5, backlo);
00711         uves_msg_debug("Background sample at (x, y, order) = (%d, %d, %f) = %f",
00712                    x, yhi, order+0.5, backhi);
00713     
00714         /* Extrapolate (linearly, or constant if MIDAS) if first order */
00715         if (order == minorder) {
00716             for (y = 1; y <= ylo; y++) {
00717             double back = backlo + (backhi - backlo)*(y - ylo)/(yhi - ylo);
00718             cpl_image_set(*background, x, y, back);
00719 
00720                         cpl_image_set(*background, x, y, back);
00721             }
00722         }
00723             
00724         /* Make a linear interpolation (1-degree, no-smooth spline) from ylo to yhi */
00725         for (y = ylo; y <= yhi; y++) {
00726             double back;
00727             back = backlo + (backhi - backlo) * (y - ylo) / (yhi - ylo);
00728             /* We know that yhi > ylo */
00729             cpl_image_set(*background, x, y, back);
00730         }
00731             
00732         /* Extrapolate (linearly, or constant if MIDAS) if last order */
00733         if (order == maxorder) {
00734             for (y = yhi; y <= ny; y++) {
00735             double back;
00736             back = backlo + (backhi - backlo) * (y - ylo) / (yhi - ylo);
00737 
00738                         cpl_image_set(*background, x, y, back);
00739                     }
00740         }
00741         }
00742     }/* For column...  */
00743 
00744     /* Now interpolate between columns */
00745     for (y = 1; y <= ny; y++) {
00746         int col;
00747         for (col = stepx; col+stepx <= nx; col += stepx) {
00748         int pis_rejected; /* Not used, all pixels read are good; they've just been set */
00749             
00750         double backlo, backhi;
00751             
00752         /* Read this and next column */
00753         backlo = cpl_image_get(*background, col      , y, &pis_rejected);
00754         backhi = cpl_image_get(*background, col+stepx, y, &pis_rejected);
00755         
00756         /* Extrapolate (linear) before first column */
00757         if (col == stepx)
00758             for (x = 1; x <= col; x++)
00759             {
00760                 double back = backlo + (backhi - backlo) * (x - col) / stepx;
00761                 cpl_image_set(*background, x, y, back);
00762             }
00763             
00764         /* Interpolate between columns */
00765         for (x = col; x <= col + stepx; x++)
00766             {
00767             double back = backlo + (backhi - backlo) * (x - col) / stepx;
00768             cpl_image_set(*background, x, y, back);
00769             }
00770 
00771         /* Extrapolate (linear) after last column */
00772         if (col+stepx+stepx > nx)
00773             for (x = col; x <= nx; x++)
00774             {
00775                 double back = backlo + (backhi - backlo) * (x - col) / stepx;
00776                 cpl_image_set(*background, x, y, back);
00777             }
00778         }
00779     }
00780 
00781     /* All pixels in background image have been set.
00782      * Smooth background. 
00783      */
00784 
00785     uves_msg("Smoothing window (pixels): smox, smoy = %d, %d", smooth_x, smooth_y);
00786     check( uves_filter_image_average(*background, smooth_x, smooth_y), 
00787            "Error applying average filter to background image");
00788 
00789     uves_msg("Subtracting background image");
00790 
00791     check( subtract_background(image, *background, NULL),
00792            "Error subtracting background image");
00793 
00794 
00795    } /* BM_METHOD was not 'no' */
00796  
00797 
00798   cleanup:
00799     return cpl_error_get_code();
00800 }
00801 
00802 /*----------------------------------------------------------------------------*/
00847 /*----------------------------------------------------------------------------*/
00848 cpl_error_code
00849 uves_backsub_poly(cpl_image *image,
00850           const cpl_table *orders, const polynomial *order_locations, 
00851           background_measure_method BM_METHOD,
00852           int NPOINTS,
00853           int radius_y,
00854           int DEGX, 
00855           int DEGY,
00856           double KAPPA)
00857 {
00858     cpl_table  *t          = NULL;
00859     polynomial *background = NULL;
00860     int nx, ny;
00861     int stepx, stepy;                   /* Step size */
00862     int radius_x;                       /* Sample window x-radius */
00863     double mse, rmse;                   /* mse, rms of fit */
00864     cpl_size total_clipped = 0;
00865     
00866     if (BM_METHOD == BM_NO)
00867     {
00868         uves_msg("Skipping background subtraction");
00869     }
00870     else
00871     {
00872         passure( image != NULL, " ");
00873         passure( orders == NULL || order_locations == NULL, " ");
00874         
00875         nx = cpl_image_get_size_x(image);
00876         ny = cpl_image_get_size_y(image);
00877         
00878         assure( NPOINTS < nx, CPL_ERROR_ILLEGAL_INPUT,
00879             "Number of sample columns (%d) larger than image width (%d pixels)", 
00880             NPOINTS, nx);
00881         
00882         stepx = nx/NPOINTS;
00883         stepy = ny/NPOINTS;
00884 
00885         radius_x = stepx/2;
00886     
00887         /* First sample background */
00888         if (orders != NULL)
00889         {
00890             /* Using the order table */
00891 
00892             int x, ordersrow, row;
00893         
00894             /* Check input */
00895             passure( cpl_table_has_column(orders, "Slope"), " ");
00896             passure( cpl_table_has_column(orders, "Intersept"), " ");
00897 
00898             passure( cpl_table_get_column_type(orders, "Slope") == CPL_TYPE_DOUBLE,
00899                  "%s", 
00900                  uves_tostring_cpl_type(cpl_table_get_column_type(orders, "Slope")));
00901         
00902             passure( cpl_table_get_column_type(orders, "Intersept") == CPL_TYPE_DOUBLE,
00903                  "%s",
00904                  uves_tostring_cpl_type(cpl_table_get_column_type(orders, "Slope")));
00905         
00906             /* This check is computationally cheap because 
00907                there are never very many order lines */
00908             passure( uves_table_is_sorted_double(orders, "Intersept", false), " ");
00909         
00910             /* Need at least two lines to identify inter-order region */
00911             assure ( cpl_table_get_nrow(orders) >= 2, CPL_ERROR_ILLEGAL_INPUT, 
00912                  "Only %" CPL_SIZE_FORMAT " line(s) in order table", cpl_table_get_nrow(orders));
00913         
00914             t = cpl_table_new( (nx/stepx + 1)*(cpl_table_get_nrow(orders) + 1) );
00915             cpl_table_new_column(t, "X", CPL_TYPE_INT);
00916             cpl_table_new_column(t, "Y", CPL_TYPE_INT);
00917             cpl_table_new_column(t, "Z", CPL_TYPE_DOUBLE);
00918         
00919             row = 0;
00920             for (ordersrow = -1; ordersrow < cpl_table_get_nrow(orders); ordersrow++)
00921             {
00922                 double slope, intersept;
00923             
00924                 /* Sample positions between this and the next orderline */
00925             
00926                 /* Lowest and highest orders are special cases */
00927                 if (ordersrow == -1)
00928                 {
00929                     slope     = cpl_table_get_double(
00930                     orders, "Slope"    , 0, NULL);
00931 
00932                     /* Interorder space below lowest order line is at: 
00933                        intersept0 - (intersept1-intersept0)/2 */
00934                     intersept =    
00935                     0.5*cpl_table_get_double(orders, "Intersept", 0, NULL) -
00936                     0.5*cpl_table_get_double(orders, "Intersept", 1, NULL) ;
00937                 }
00938                 else if (ordersrow == cpl_table_get_nrow(orders) - 1)
00939                 {
00940                     slope     = cpl_table_get_double(
00941                     orders, "Slope"    , ordersrow, NULL);
00942                     
00943                     /* Interorder space above highest order line is at:
00944                        intersept(N) + (intersept(N)-intersept(N-1))/2 */
00945                     intersept =    
00946                     0.5*cpl_table_get_double(
00947                         orders, "Intersept", ordersrow, NULL) -
00948                     0.5*cpl_table_get_double(
00949                         orders, "Intersept", ordersrow-1, NULL) ;
00950                 }
00951                 else   /* The most common case */
00952                 {
00953                     slope = 
00954                     (cpl_table_get_double(
00955                         orders, "Slope", ordersrow  , NULL) +
00956                      cpl_table_get_double(
00957                          orders, "Slope", ordersrow+1, NULL) ) / 2;
00958                     
00959                     intersept      = 
00960                     (cpl_table_get_double(
00961                         orders, "Intersept", ordersrow  , NULL) +
00962                      cpl_table_get_double(
00963                          orders, "Intersept", ordersrow+1, NULL) ) / 2;
00964                 }
00965             
00966                 /* Sample the interorder space */
00967                 for (x = 1 + stepx/2; x <= nx; x += stepx)
00968                 {
00969                     int y = uves_round_double(intersept + slope * x);
00970                 
00971                     if (1 <= y && y <= ny)
00972                     {
00973                         double z;
00974                     
00975                         check( z = sample_background(
00976                                image, 
00977                                x, y,
00978                                radius_x, radius_y,
00979                                nx, ny,
00980                                BM_METHOD),
00981                            "Error sampling background "
00982                            "(x, y) = (%d, %d)", x, y);
00983 
00984                         cpl_table_set_int   (t, "X" , row, x);
00985                         cpl_table_set_int   (t, "Y" , row, y);
00986                         cpl_table_set_double(t, "Z" , row, z);
00987                         row++;
00988                     }
00989                 }
00990             } /* for ordersrow... */
00991         
00992             cpl_table_set_size(t, row);
00993 
00994         }/* if  orders != NULL */
00995         
00996         else if (order_locations != NULL)
00997         {
00998             /* Sample background using the polynomial */
00999 
01000             int x, minorder, maxorder, order;
01001             int row;        /* Pointing to row in temporary table */
01002         
01003             /* Check input */
01004             assure( uves_polynomial_get_dimension(order_locations) == 2, 
01005                 CPL_ERROR_ILLEGAL_INPUT,
01006                 "Order location polynomial must be 2d. It is %d!", 
01007                 uves_polynomial_get_dimension(order_locations));
01008             
01009             check(( minorder = first_order(order_locations, nx),
01010                 maxorder = last_order(order_locations, nx, ny)),
01011                "Error getting min. and max. order numbers");
01012 
01013             t = cpl_table_new( (nx/stepx + 1) * (maxorder-minorder+1));
01014             cpl_table_new_column(t, "X", CPL_TYPE_INT);
01015             cpl_table_new_column(t, "Y", CPL_TYPE_INT);
01016             cpl_table_new_column(t, "Z", CPL_TYPE_DOUBLE);
01017         
01018             row = 0;
01019             for (order = minorder; order <= maxorder; order++) {
01020             /* Sample the interorder space from (minorder+0.5) to (maxorder+0.5) */
01021             for (x = 1+stepx/2; x <= nx; x += stepx) {
01022                 int y = uves_round_double(
01023                 uves_polynomial_evaluate_2d(order_locations, x, order + 0.5));
01024                 
01025                 if (1 <= y && y <= ny) {
01026                 double z;
01027                 
01028                 check( z = sample_background(image, 
01029                                  x, y,
01030                                  radius_x, radius_y,
01031                                  nx, ny,
01032                                  BM_METHOD),
01033                        "Error sampling background (x, order) = (%d, %d+0.5)",
01034                        x, order);
01035                 
01036                 cpl_table_set_int   (t, "X" , row, x);
01037                 cpl_table_set_int   (t, "Y" , row, y);
01038                 cpl_table_set_double(t, "Z" , row, z);
01039                 row++;
01040                 }
01041             }
01042             }
01043             
01044             cpl_table_set_size(t, row);
01045         }
01046         else
01047         { 
01048             /* Grid sampling (order positions unknown) */
01049             int x, y, row;
01050         
01051             t = cpl_table_new((nx/stepx + 1) * (ny/stepy + 1));
01052             cpl_table_new_column(t, "X" , CPL_TYPE_INT);
01053             cpl_table_new_column(t, "Y" , CPL_TYPE_INT);
01054             cpl_table_new_column(t, "Z" , CPL_TYPE_DOUBLE);
01055         
01056             row = 0;
01057             for (y = 1 + stepy/2; y <= ny; y += stepy) 
01058             {
01059                 for (x = 1+stepx/2; x <= nx; x += stepx) 
01060                 {
01061                     double z;
01062                 
01063                     check( z = sample_background(image, 
01064                                  x, y,
01065                                  radius_x, radius_y,
01066                                  nx, ny,
01067                                  BM_METHOD),
01068                        "Error sampling background (x, y) = (%d, %d)", x, y);
01069                 
01070                     cpl_table_set_int   (t, "X" , row, x);
01071                     cpl_table_set_int   (t, "Y" , row, y);
01072                     cpl_table_set_double(t, "Z" , row, z);
01073                     row++;
01074                 }
01075             }
01076             cpl_table_set_size(t, row);
01077         }
01078         
01079         /* Sampling done. Fit poly. */
01080 
01081         total_clipped = 0;
01082         {
01083         cpl_size n_clipped;
01084         cpl_size deg_xy=(DEGX + 1)*(DEGY + 1);
01085         do {
01086             assure( cpl_table_get_nrow(t) > (DEGX + 1)*(DEGY + 1), 
01087                 CPL_ERROR_ILLEGAL_OUTPUT,
01088                 "Too few sample points available (%" CPL_SIZE_FORMAT " point(s)) to make the fit "
01089                 "(more than %" CPL_SIZE_FORMAT " points needed). "
01090                 "Increase number of sample points or increase kappa",
01091                 cpl_table_get_nrow(t),  deg_xy);
01092         
01093             /* Fit, calculate Zfit */
01094             uves_polynomial_delete(&background);
01095             check( background = uves_polynomial_regression_2d(
01096                    t, "X", "Y", "Z", NULL,
01097                    DEGX, DEGY, "Zfit", NULL, NULL, &mse,
01098                    NULL, NULL, -1, -1),
01099                "Error fitting polynomial");
01100         
01101             /* Residual := Z - Zfit */
01102             cpl_table_duplicate_column(t, "Residual", t, "Z");
01103             cpl_table_subtract_columns(t, "Residual", "Zfit");
01104         
01105             /* Compute residuals w.r.t. median of Z 
01106                (i.e. subtract median(residual) from all residuals),
01107                then get stdev based on this new mean/median value.
01108                This is to make kappa sigma clipping more robust */
01109 
01110             cpl_table_subtract_scalar(t, "Residual", 
01111                           cpl_table_get_column_median(t, "Residual"));
01112             rmse = cpl_table_get_column_stdev(t, "Residual");
01113 
01114             /* One-sided kappa-sigma clipping */
01115             if (KAPPA > 0)
01116             {
01117                 check( n_clipped = uves_select_table_rows(
01118                        t,  "Residual", CPL_GREATER_THAN, KAPPA * rmse),
01119                    "Error selecting rows");
01120             }
01121             else
01122             {
01123                 n_clipped = 0;
01124             }
01125             
01126             total_clipped += n_clipped;
01127         
01128             uves_msg_debug("RMS = %f. %" CPL_SIZE_FORMAT " of %" CPL_SIZE_FORMAT " points rejected in kappa-sigma clipping",
01129                    rmse, n_clipped, cpl_table_get_nrow(t));
01130             
01131             cpl_table_erase_selected(t);
01132 
01133             if (n_clipped > 0)
01134             {
01135                 cpl_table_erase_column(t, "Zfit");
01136                 cpl_table_erase_column(t, "Residual");
01137             }
01138         
01139         } while (n_clipped > 0);
01140         }
01141 
01142         /* Try to do some quality checking of the background subtraction.
01143            The number of rejected points (the signal) is often around 10-20 %  */
01144         {
01145         double percentage = 
01146             100.0 * ( (double)total_clipped ) / (total_clipped + cpl_table_get_nrow(t));
01147         
01148         if (KAPPA > 0) {
01149             uves_msg("%" CPL_SIZE_FORMAT " of %" CPL_SIZE_FORMAT " points (%.2f %%) were rejected in "
01150                  "kappa-sigma clipping. RMS = %.2f ADU", 
01151                  total_clipped,
01152                  cpl_table_get_nrow(t) + total_clipped,
01153                  percentage,
01154                  sqrt(mse));
01155         }
01156         
01157         /* For grid sampling: */
01158         if (orders == NULL && order_locations == NULL) 
01159             {
01160             if (total_clipped == 0)
01161                 {
01162                 uves_msg_warning("No points rejected during background "
01163                          "estimation. Background subtraction is "
01164                          "uncertain. Try to decrease KAPPA "
01165                          "(current value is %f)", KAPPA);
01166                 }
01167             if (percentage > 40)
01168                 {
01169                 uves_msg_warning("%f %% of the sample points were "
01170                          "rejected during "
01171                          "background estimation", percentage);
01172                 }
01173             }
01174         }
01175         
01176         check( subtract_background(image, NULL, background),
01177            "Error subtracting background polynomial");
01178     } /* BM_METHOD wasn't 'no' */
01179     
01180   cleanup:
01181     uves_free_table(&t);
01182     uves_polynomial_delete(&background);
01183     
01184     return cpl_error_get_code();
01185 }
01186 
01187 /*----------------------------------------------------------------------------*/
01201 /*----------------------------------------------------------------------------*/
01202 /* Recipe parameter creation code for this function
01203 / * Backsmoothx, Backsmoothy * /
01204     uves_parameter_new_range(p, uves_orderpos.preproc.backsmoothx,
01205                 CPL_TYPE_INT,
01206                 "Radius of window used for average filtering in the "
01207                 "background subtraction (mode=smooth) step",
01208                 uves_orderpos.preproc,
01209                 5, 0, INT_MAX);
01210     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "backsmoothx");
01211     cpl_parameterlist_append(recipe->parameters, p);
01212     
01213     uves_parameter_new_range(p, uves_orderpos.preproc.backsmoothy,
01214                 CPL_TYPE_INT,
01215                 "Radius of window used for average filtering in the "
01216                 "background subtraction (mode=smooth) step",
01217                 uves_orderpos.preproc,
01218                 30, 0, INT_MAX);
01219     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "backsmoothy");
01220     cpl_parameterlist_append(recipe->parameters, p);
01221 
01222 / * Backsmoothiter * /
01223     uves_parameter_new_range(p, uves_orderpos.preproc.backsmoothiter,
01224                 CPL_TYPE_INT,
01225                 "Number of iterations when estimating the background "
01226                 "(mode=smooth)",
01227                 uves_orderpos.preproc,
01228                 10, 1, INT_MAX);
01229     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "backsmoothiter");
01230     cpl_parameterlist_append(recipe->parameters, p);
01231 */
01232 cpl_error_code
01233 uves_backsub_smooth(cpl_image *image, int RADX, int RADY, int ITER)
01234 {
01235     cpl_image  *background  = NULL;
01236     int i;
01237     
01238     assure( RADX >= 0 && RADY >= 0, CPL_ERROR_ILLEGAL_INPUT,
01239         "Negative radius ((%d)x(%d))", RADX, RADY);
01240     assure( ITER >= 1, CPL_ERROR_ILLEGAL_INPUT, 
01241         "Non-positive number of iterations (%d)", ITER);
01242     
01243     /* First estimate background */
01244     background = cpl_image_duplicate(image);
01245     
01246     for (i = 0; i < ITER; i++) {
01247       //uves_msg_debug("i=%d,%d ...",i, ITER);
01248     uves_msg("i = %d", i);
01249     check( lower_to_average(background,
01250                 RADX, RADY), "Error smoothing image");
01251     }
01252     
01253     /* Then subtract background */
01254     check( cpl_image_subtract(image, background), "Could not subtract background image");
01255     
01256   cleanup:
01257     uves_free_image(&background);
01258 
01259     return cpl_error_get_code();
01260 }
01261 
01262 /*----------------------------------------------------------------------------*/
01281 /*----------------------------------------------------------------------------*/
01282 
01283 static double
01284 sample_background(const cpl_image *image, int x0, double y_0,
01285           int radius_x, int radius_y, int nx, int ny,
01286           background_measure_method BM_METHOD)
01287 {
01288     double result = 0;
01289     /* Use a table to calculate the median. Invalid rows are ignored */
01290     cpl_table *temp = NULL;
01291     bool found_good = false;
01292     int row;
01293     int x, y;
01294 
01295     check( 
01296     (temp = cpl_table_new( (2*radius_x + 1) * (2*radius_y + 1) ),
01297      row = 0,
01298      cpl_table_new_column(temp, "Flux", CPL_TYPE_DOUBLE)),
01299     "Error allocating table");
01300 
01301     for(y = y_0 - radius_y; y <= y_0 + radius_y; y++)
01302     {
01303         for (x = x0 - radius_x; x <= x0 + radius_x; x++)
01304         {
01305             if (1 <= x && x <= nx &&
01306             1 <= y && y <= ny)
01307             {
01308                 int pis_rejected;
01309                 double flux = cpl_image_get(image, x, y, &pis_rejected);
01310                 if( !pis_rejected )
01311                 {
01312                     cpl_table_set(temp, "Flux", row, flux);
01313                     found_good = true;
01314                 }
01315                 else
01316                 {
01317                     cpl_table_set_invalid(temp, "Flux", row);
01318                 }
01319             }
01320             else
01321             {
01322                 cpl_table_set_invalid(temp, "Flux", row);
01323             }
01324             
01325             row++;
01326         }
01327     }
01328 
01329     assure( found_good, CPL_ERROR_ILLEGAL_INPUT, "No valid pixels in sample window");
01330 
01331     if (BM_METHOD == BM_MEDIAN)
01332     {
01333         result = cpl_table_get_column_median(temp, "Flux");
01334     }
01335     else if (BM_METHOD == BM_MINIMUM)
01336     {
01337         result = cpl_table_get_column_min(temp, "Flux");
01338     }
01339     else
01340     {
01341         assure( false, CPL_ERROR_UNSUPPORTED_MODE,
01342             "Unsupported background sample method: %d", BM_METHOD);
01343     }
01344 
01345   cleanup:
01346     uves_free_table(&temp);
01347     return result;
01348 }
01349 
01350 /*----------------------------------------------------------------------------*/
01359 /*----------------------------------------------------------------------------*/
01360 static int
01361 first_order(const polynomial *order_locations, int nx)
01362 {
01363     int result;
01364     
01365     result = 0;
01366     while (uves_polynomial_evaluate_2d(order_locations, 1 , result + 0.5) < 1 ||
01367        uves_polynomial_evaluate_2d(order_locations, nx, result + 0.5) < 1 )
01368     {
01369         result++;
01370     }
01371 
01372     while (uves_polynomial_evaluate_2d(order_locations, 1 , result - 0.5) >= 1 ||
01373        uves_polynomial_evaluate_2d(order_locations, nx, result - 0.5) >= 1 )
01374     {
01375         result -= 1;
01376         
01377         /* Fail cleanly even if 'order_locations' is corrupted */
01378         assure( result > -100000, 
01379             CPL_ERROR_CONTINUE,
01380             "Invalid polynomial: p(x=1, order=%d) = %f  p(x=%d, order=%d) = %f",
01381             result, uves_polynomial_evaluate_2d(order_locations, 1.0, result),
01382             nx, result, uves_polynomial_evaluate_2d(order_locations, nx, result));
01383     }
01384     
01385   cleanup:
01386     return result;
01387 }
01388 
01389 
01390 /*----------------------------------------------------------------------------*/
01400 /*----------------------------------------------------------------------------*/
01401 static int
01402 last_order(const polynomial *order_locations, int nx, int ny)
01403 {
01404     int result;
01405     
01406     result = 0;
01407     while (uves_polynomial_evaluate_2d(order_locations, 1 , result - 0.5) > ny ||
01408        uves_polynomial_evaluate_2d(order_locations, nx, result - 0.5) > ny )
01409     {
01410         result--;
01411     }
01412 
01413     while (uves_polynomial_evaluate_2d(order_locations, 1 , result + 1.5) <= ny ||
01414        uves_polynomial_evaluate_2d(order_locations, nx, result + 1.5) <= ny )
01415     {
01416         result += 1;
01417         
01418         /* Fail cleanly even if 'order_locations' is corrupted */
01419         assure( result < 100000, 
01420             CPL_ERROR_CONTINUE,
01421             "Invalid polynomial: p(x=1, order=%d) = %f  p(x=%d, order=%d) = %f",
01422             result, uves_polynomial_evaluate_2d(order_locations, 1.0, result),
01423             nx, result, uves_polynomial_evaluate_2d(order_locations, nx, result));
01424     }
01425     
01426   cleanup:
01427     return result;
01428 }
01429 
01430 /*----------------------------------------------------------------------------*/
01442 /*----------------------------------------------------------------------------*/
01443 static cpl_error_code
01444 lower_to_average(cpl_image *image, int RADX, int RADY)
01445 {
01446     cpl_image  *average = NULL;
01447     double *image_data = NULL;
01448     double *average_data = NULL;
01449     int nx, ny;
01450     int x, y;
01451     
01452     passure( image != NULL, "Null image");
01453     nx = cpl_image_get_size_x(image);
01454     ny = cpl_image_get_size_y(image);
01455     
01456     /* Create smoothed image */
01457     uves_msg("Filtering...");
01458     check( average    = cpl_image_duplicate(image), "Error copying image");
01459     check( uves_filter_image_average(average, RADX, RADY), "Error applying average filter");
01460     uves_msg("done");
01461     
01462     image_data   = cpl_image_get_data(image);
01463     average_data = cpl_image_get_data(average);
01464     uves_msg("Lowering...");
01465     for (y = 0; y < ny; y++)
01466     {
01467         for (x = 0; x < nx; x++)
01468         {
01469             if (image_data[x + y*nx] > average_data[x + y*nx]) 
01470             {
01471                 image_data[x + y*nx] = average_data[x + y*nx];
01472             }
01473         }
01474     }
01475     uves_msg("done");
01476     
01477   cleanup:
01478     uves_free_image(&average);
01479     
01480     return cpl_error_get_code();
01481 }
01482 
01483 /*----------------------------------------------------------------------------*/
01495 /*----------------------------------------------------------------------------*/
01496     
01497 static cpl_error_code
01498 subtract_background(cpl_image *image, cpl_image *background_im, 
01499             const polynomial *background_pol)
01500 {
01501     int nx, ny;
01502     int x, y;
01503 
01504     double *image_data;
01505     double *background_data = NULL;
01506 
01507     passure(image != NULL, " ");
01508     /* Exactly one of 'background_im' and 'background_pol' must be non-NULL */
01509     passure((background_im == NULL) != (background_pol == NULL), " ");
01510 
01511     /* For efficiency, don't call cpl_image_get() */
01512     assure(cpl_image_count_rejected(image) == 0, 
01513        CPL_ERROR_UNSUPPORTED_MODE, "Input image contains bad pixels");
01514     assure(cpl_image_get_type(image) == CPL_TYPE_DOUBLE,
01515        CPL_ERROR_UNSUPPORTED_MODE, 
01516        "Input image is of type %s. double expected", 
01517        uves_tostring_cpl_type(cpl_image_get_type(image)));
01518 
01519     if (background_im != NULL)
01520     {
01521         assure(cpl_image_count_rejected(background_im) == 0, 
01522            CPL_ERROR_UNSUPPORTED_MODE, "Background image contains bad pixels");
01523         assure(cpl_image_get_type(background_im) == CPL_TYPE_DOUBLE, 
01524            CPL_ERROR_UNSUPPORTED_MODE, 
01525            "Background image is of type %s. double expected", 
01526            uves_tostring_cpl_type(cpl_image_get_type(background_im)));
01527     }
01528 
01529     image_data = cpl_image_get_data_double(image);
01530     if (background_im != NULL)
01531     {
01532         background_data = cpl_image_get_data_double(background_im);
01533     }
01534 
01535     nx = cpl_image_get_size_x(image);
01536     ny = cpl_image_get_size_y(image);
01537 
01538     for (y = 1; y <= ny; y++)
01539     {
01540         for (x = 1; x <= nx; x++)
01541         {
01542             double back;
01543             double flux, new_flux;
01544             
01545             if (background_im != NULL)
01546             {
01547                 /* Slow:  back = cpl_image_get(background_im, x, y, &pis_rejected); */
01548                 back = background_data[(x-1) + (y-1) * nx]; 
01549             }
01550             else
01551             {
01552                 /* Evaluate at (x,y) */
01553                 back = uves_polynomial_evaluate_2d(background_pol, 
01554                                    x,
01555                                    y);
01556             }
01557             
01558             /* Slow: flux = cpl_image_get(image, x, y, &pis_rejected);  */
01559             flux = image_data[(x-1) + (y-1) * nx];
01560             
01561 /* Exclude these sanity checks for backwards compatibility */
01562 #if 0
01563             /* Make sure the estimated background is between zero and flux-value */
01564             if (back < 0)
01565             {
01566                 back = 0.0;
01567             }
01568             if (back > flux)
01569             {
01570                 back = flux;
01571             }
01572             
01573             /* Then subtract the background.
01574              * Pixel flux may be negative. Make sure the result is non-negative.
01575              */
01576                     new_flux = uves_max_double(0, flux - back);
01577 #else
01578             new_flux = flux-back;            
01579 #endif
01580             
01581             /* Slow: cpl_image_set(image, x, y, new_flux); */
01582             image_data[(x-1) + (y-1) * nx] = new_flux; 
01583             
01584             if (background_im != NULL)
01585             {
01586                 /* Slow: cpl_image_set(background_im, x, y, flux - new_flux); */
01587                 background_data[(x-1) + (y-1) * nx] = flux - new_flux;
01588             }
01589         }
01590     }/* for each pixel... */
01591     
01592   cleanup:
01593     return cpl_error_get_code();
01594 }

Generated on 9 Mar 2012 for UVES Pipeline Reference Manual by  doxygen 1.6.1