uves_orderpos_hough.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: 2007/06/06 08:17:33 $
00023  * $Revision: 1.18 $
00024  * $Name: uves-3_3_1 $
00025  * $Log: uves_orderpos_hough.c,v $
00026  * Revision 1.18  2007/06/06 08:17:33  amodigli
00027  * replace tab with 4 spaces
00028  *
00029  * Revision 1.17  2007/04/24 12:50:29  jmlarsen
00030  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00031  *
00032  * Revision 1.16  2007/04/20 14:44:47  jmlarsen
00033  * Minor output message change
00034  *
00035  * Revision 1.15  2007/04/17 09:34:38  jmlarsen
00036  * Parametrize the assumption about consecutive orders (for FLAMES support)
00037  *
00038  * Revision 1.14  2007/04/12 12:02:41  jmlarsen
00039  * Added assertions for documentation purposes
00040  *
00041  * Revision 1.13  2007/04/10 07:08:30  jmlarsen
00042  * Make sure that detected orders are always consecutive
00043  *
00044  * Revision 1.12  2006/11/15 15:02:14  jmlarsen
00045  * Implemented const safe workarounds for CPL functions
00046  *
00047  * Revision 1.10  2006/11/15 14:04:08  jmlarsen
00048  * Removed non-const version of parameterlist_get_first/last/next which is
00049  * already in CPL, added const-safe wrapper, unwrapper and deallocator functions
00050  *
00051  * Revision 1.9  2006/11/06 15:19:41  jmlarsen
00052  * Removed unused include directives
00053  *
00054  * Revision 1.8  2006/08/17 13:56:53  jmlarsen
00055  * Reduced max line length
00056  *
00057  * Revision 1.7  2006/06/08 08:42:53  jmlarsen
00058  * Added support for computing Hough transform on image subwindow
00059  *
00060  * Revision 1.6  2006/06/01 14:43:17  jmlarsen
00061  * Added missing documentation
00062  *
00063  * Revision 1.5  2006/04/06 08:45:15  jmlarsen
00064  * Changed number of significant digits when printing percentage
00065  *
00066  * Revision 1.4  2006/03/09 13:58:26  jmlarsen
00067  * Minor optimization of Hough calculation
00068  *
00069  * Revision 1.3  2006/03/03 13:54:11  jmlarsen
00070  * Changed syntax of check macro
00071  *
00072  * Revision 1.2  2006/02/15 13:19:15  jmlarsen
00073  * Reduced source code max. line length
00074  *
00075  * Revision 1.1  2006/02/03 07:46:30  jmlarsen
00076  * Moved recipe implementations to ./uves directory
00077  *
00078  * Revision 1.24  2005/12/19 16:17:55  jmlarsen
00079  * Replaced bool -> int
00080  *
00081  */
00082 #ifdef HAVE_CONFIG_H
00083 #  include <config.h>
00084 #endif
00085 
00086 /*----------------------------------------------------------------------------*/
00090 /*----------------------------------------------------------------------------*/
00091 
00092 /*-----------------------------------------------------------------------------
00093                                 Includes
00094  -----------------------------------------------------------------------------*/
00095 
00096 #include <uves_orderpos_hough.h>
00097 
00098 #include <uves_utils.h>
00099 #include <uves_utils_wrappers.h>
00100 #include <uves_error.h>
00101 #include <uves_msg.h>
00102 
00103 #include <irplib_access.h>
00104 #include <cpl.h>
00105 
00106 /*-----------------------------------------------------------------------------
00107                                 Defines
00108  -----------------------------------------------------------------------------*/
00109 
00110 /* Define macros that map from x-coordinate (integer) in Hough space to slope 
00111    in image space (double) and the inverse function  */
00112 #define SLOPE(hx)    (   MINSLOPE + ( ((double)(hx)) / SLOPERES  )   ) * (MAXSLOPE - MINSLOPE)
00113 #define SLOPEINV(a) \
00114    uves_round_double( SLOPERES * ( ((double)(a)) - MINSLOPE ) / (MAXSLOPE - MINSLOPE))
00115 
00116 /* Convert from pixel coordinate to intersept, and the other way */
00117 #define INTERSEPT(hy) (minintersept + hy)
00118 #define INTERSEPTINV(b) (b - minintersept)
00119 
00121 /*-----------------------------------------------------------------------------
00122                                 Forward declarations
00123  -----------------------------------------------------------------------------*/
00124 
00125 static cpl_table *detect_lines(cpl_image *htrans, int minintersept,
00126                    const cpl_image *inputimage, 
00127                    int NORDERS, bool norders_is_guess, int SAMPLEWIDTH, 
00128                    double PTHRES, double MINSLOPE, double MAXSLOPE, int SLOPERES,
00129                                bool consecutive);
00130 static cpl_error_code delete_peak(cpl_image *htrans, int minintersept, int hxmax, int hymax,
00131                   int SPACING, int imagewidth, int SAMPLEWIDTH, 
00132                   double MINSLOPE, double MAXSLOPE, int SLOPERES);
00133 static int firsttrace(int nx, int SAMPLEWIDTH);
00134 static int calculate_spacing(const cpl_image *, int x);
00135 static double autocorr(const cpl_image *image, int x, int shift);
00136 static cpl_error_code update_max(const cpl_image *htrans, /* Hough image */
00137                  int *xmax,               /* peak location */
00138                  int *ymax,
00139                  int SPACING,       /* inter-order seperation */
00140                  int imagewidth,    /* width of input image */
00141                  int SAMPLEWIDTH,   /* seperation of traces in input image */
00142                  double MINSLOPE,
00143                  double MAXSLOPE,
00144                  int SLOPERES);
00145 
00146 /*----------------------------------------------------------------------------*/
00178 /*----------------------------------------------------------------------------*/
00179 
00180 cpl_table *uves_hough(const cpl_image *image, int ymin, int ymax, int NORDERS, 
00181               bool norders_is_guess,
00182               int SAMPLEWIDTH, double PTHRES, double MINSLOPE, double MAXSLOPE,
00183               int SLOPERES, bool consecutive,
00184                       cpl_image **htrans, cpl_image **htrans_original)
00185 {
00186 
00187     cpl_table *ordertable = NULL;   /* The result table */
00188     
00189     int nx = 0;   /* Dimensions of input image */
00190     int ny = 0;
00191     int minintersept = 0;  /* The intersepts represented by the Hough image are 
00192                   all integer values */
00193     int maxintersept = 0;  /* in the interval ] minintersept ; maxintersept ] */
00194     int firstcol;
00195     const double *image_data = NULL;    /* For efficiency */
00196     double *htrans_data = NULL;
00197 
00198     *htrans = NULL;                /* Hough transform image (peaks deleted), returned */
00199     *htrans_original = NULL;       /* Hough transform image, returned */
00200     
00201     /* Check input */
00202     assure_nomsg( image != NULL, CPL_ERROR_NULL_INPUT);
00203     assure( cpl_image_get_type(image) == CPL_TYPE_DOUBLE, CPL_ERROR_INVALID_TYPE, 
00204         "Input image has wrong type. Must be of type double");
00205     assure( 0 <= MINSLOPE, CPL_ERROR_ILLEGAL_INPUT,
00206             "minslope = %f must be non-negative", MINSLOPE);
00207     assure( 0 <= MAXSLOPE, CPL_ERROR_ILLEGAL_INPUT, 
00208             "maxslope = %f must be non-negative", MAXSLOPE);
00209     assure( MINSLOPE < MAXSLOPE, CPL_ERROR_INCOMPATIBLE_INPUT, "minslope = %f; maxslope = %f",
00210             MINSLOPE, MAXSLOPE);
00211     assure( 0 < SLOPERES, CPL_ERROR_ILLEGAL_INPUT,
00212             "Hough image width = %d, must be positive", SLOPERES);
00213 
00214     /* For efficiency don't support bad pixels (possible to do
00215        later if needed) */
00216     assure (cpl_image_count_rejected(image) == 0,
00217         CPL_ERROR_UNSUPPORTED_MODE, "Input image has %d bad pixels",
00218         cpl_image_count_rejected(image));
00219 
00220     if (MAXSLOPE > 0.5) 
00221     {
00222         uves_msg_warning("Max possible slope is %f, which is larger than 0.5. "
00223                  "Results might be unreliable", MAXSLOPE);
00224     }
00225     
00226     nx = cpl_image_get_size_x(image);
00227     ny = cpl_image_get_size_y(image);
00228 
00229     assure( 1 <= ymin && ymin <= ymax && ymax <= ny, CPL_ERROR_ILLEGAL_INPUT,
00230         "Illegal y-range: %d - %d (image height is %d)", ymin, ymax, ny);
00231 
00232     /* Calculate min. and max. intersepts represented.
00233        For simplicity, the Hough image is always full size,
00234        even if not (ymin == 1 && ymax == ny)  */
00235     maxintersept = ny;
00236     minintersept = uves_round_double(0 - nx*MAXSLOPE);
00237 
00238     /* Create the Hough image. Pixels are initialsed to zero */
00239     check( *htrans = cpl_image_new(SLOPERES,                      /* Image width */
00240                    maxintersept - minintersept,   /* Image height */
00241                    CPL_TYPE_DOUBLE),
00242        "Could not create image");
00243     
00244     check_nomsg( image_data = irplib_image_get_data_double_const(image) );
00245     check_nomsg( htrans_data = irplib_image_get_data_double(*htrans) );
00246 
00247     uves_msg("Calculating Hough transform");
00248     
00249     /* Locate the leftmost trace column */
00250     firstcol = firsttrace(nx, SAMPLEWIDTH);    
00251 
00252     UVES_TIME_START("The loop");
00253 
00254     /* Loop through input image subwindow and calculate the Hough image */
00255     {
00256     int x, y;
00257     for (y = ymin; y <= ymax; y += 1)
00258         {
00259         uves_msg_progress(y - 1, ny, "Calculating Hough transform");
00260         
00261         for (x = firstcol; x <= nx; x += SAMPLEWIDTH)
00262             {
00263             /* Transform image point at (x,y) to line in Hough space */
00264             double pixelvalue;
00265             int hx, hy;
00266 
00267             for (hx = 1; hx <= SLOPERES; hx++)
00268                 {
00269                 hy = INTERSEPTINV(uves_round_double(y - x*SLOPE(hx)));
00270                 /* y = intersept + slope * x */
00271                 
00272                                 /* Slow: check( pixelvalue = 
00273                    cpl_image_get(image, x, y, &pis_rejected),
00274                    "Could not read pixel at (%d, %d) in input image", x, y); */
00275                 pixelvalue = image_data[(x-1) + (y-1)*nx];
00276                 
00277                 /* Add the pixelvalue to Hough image (hx, hy) */
00278                 /* Not supported for now: if (!pis_rejected) */
00279                 
00280                 /* Slow: check( current = 
00281                    cpl_image_get(*htrans, hx, hy, &pis_rejected),
00282                    "Could not read pixel at (%d, %d) in Hough image", hx, hy);
00283                    check(           
00284                    cpl_image_set(*htrans, hx, hy, current + pixelvalue), 
00285                    "Could not update pixel at (%d, %d) in Hough image", 
00286                    hx, hy); */
00287 
00288                 htrans_data[(hx-1) + (hy-1)*SLOPERES] += pixelvalue;
00289                 }
00290             }
00291         }
00292     }
00293 
00294     UVES_TIME_END;
00295     
00296     check( *htrans_original = cpl_image_duplicate(*htrans), "Error copying hough image");
00297 
00298     /* Calculate order table from Hough image */
00299     check( ordertable = detect_lines(*htrans,
00300                      minintersept,
00301                      image,
00302                      NORDERS,
00303                      norders_is_guess,
00304                      SAMPLEWIDTH,
00305                      PTHRES,
00306                      MINSLOPE,
00307                      MAXSLOPE,
00308                      SLOPERES,
00309                                      consecutive),
00310        "Could not detect lines in hough image");
00311     
00312     passure( cpl_table_get_ncol(ordertable) == 4, "%d", cpl_table_get_ncol(ordertable));
00313     passure( cpl_table_has_column(ordertable, "Slope"), " ");
00314     passure( cpl_table_has_column(ordertable, "Intersept"), " ");
00315     passure( cpl_table_has_column(ordertable, "Spacing"), " ");
00316     passure( cpl_table_has_column(ordertable, "Order"), " ");
00317     
00318   cleanup:
00319     if (cpl_error_get_code() != CPL_ERROR_NONE)
00320     {
00321         uves_free_image(htrans);
00322         uves_free_image(htrans_original);
00323         uves_free_table(&ordertable);
00324     }
00325     return ordertable;
00326 }
00327 
00328 /*----------------------------------------------------------------------------*/
00377 /*----------------------------------------------------------------------------*/
00378 
00379 static cpl_table *detect_lines(cpl_image *htrans, int minintersept, 
00380                    const cpl_image *inputimage, int NORDERS,
00381                    bool norders_is_guess,
00382                    int SAMPLEWIDTH, double PTHRES, double MINSLOPE, 
00383                    double MAXSLOPE, int SLOPERES,
00384                                bool consecutive)
00385 {
00386     cpl_table *results = NULL;   /* The result order table */
00387     
00388     /* Local variables */
00389     cpl_stats *stats = NULL;      /* Used for finding peaks in Hough image */
00390     uves_propertylist *pl = NULL;  /* Used for sorting the order table */
00391     
00392     bool automatic = false;        /* Flag indicating automatic mode */
00393     int tablesize = 0;
00394     double intensity = 0;         /* Line intensity */
00395     double prev_intensity = 0;    /* Intensity of previously detected line */
00396     int norders_detected = 0;     /* Peaks detected so far */
00397     int SPACING = 0;              /* Interorder spacing   */
00398     double globmax = 0;           /* Global maximum value */
00399 
00400     /* Check input */
00401     passure( htrans != NULL, " ");
00402     passure( inputimage != NULL, " ");
00403     passure( NORDERS >= 0, "%d", NORDERS);
00404     passure( SAMPLEWIDTH > 0, "%d", SAMPLEWIDTH);
00405     passure( 0 <= PTHRES && PTHRES <= 1, "%f", PTHRES);
00406     passure( SLOPERES > 0, "%d", SLOPERES);
00407 
00408     /* Do we know how many orders to detect?
00409        If not, enter automatic mode */
00410     if (NORDERS == 0)
00411     {
00412         uves_msg("Could not find information about predicted number of orders. "
00413              "Entering automatic mode (threshold = %f)", PTHRES);
00414         automatic = true;
00415     }
00416     else
00417     {
00418         uves_msg("Searching for %d (%s) order lines", 
00419              NORDERS, (norders_is_guess) ? "or less" : "exactly");
00420         automatic = false;
00421     }
00422     
00423     /* Allocate memory */
00424     if (automatic)
00425     {
00426         /* The input image height is a (conservative) upper limit
00427            on the number of echelle orders in the image */
00428         tablesize = cpl_image_get_size_y(inputimage);
00429     }
00430     else 
00431     {
00432         tablesize = NORDERS;
00433     }
00434     
00435     /* Initialize order table */
00436     check(( results = cpl_table_new(tablesize),
00437         cpl_table_new_column(results, "Slope", CPL_TYPE_DOUBLE),
00438         cpl_table_new_column(results, "Intersept", CPL_TYPE_DOUBLE),
00439         cpl_table_new_column(results, "Spacing", CPL_TYPE_INT)),
00440        "Could not initialize order table");
00441     
00442     /* Find maximum in Hough image */
00443     check( stats = cpl_stats_new_from_image(htrans, CPL_STATS_MAX | CPL_STATS_MAXPOS), 
00444        "Could not get statistics on Hough image");
00445     
00446     /*
00447      *  Remember the first (i.e. global) maximum.
00448      *  In 1st iteration, prev_intensity == intensity 
00449      */
00450     check( globmax = cpl_stats_get_max(stats), 
00451        "Could not locate first maximum in hough image" );
00452 
00453     prev_intensity = globmax;
00454 
00455     /*  Repeat until the predicted number of orders is found,
00456      *   or (in automatic mode) until the line intensity is less than threshold 
00457      */
00458     while (   (!automatic && 
00459            (norders_detected < NORDERS &&
00460         (!norders_is_guess || cpl_stats_get_max(stats) >= PTHRES*prev_intensity)))
00461           || (automatic 
00462           && cpl_stats_get_max(stats) >= PTHRES*prev_intensity)
00463     )
00464     {
00465         int xmax = 0;
00466         int ymax = 0;
00467         double slope = 0;
00468         double isept = 0;
00469         
00470         norders_detected += 1;
00471         check((intensity = cpl_stats_get_max(stats),
00472            xmax      = cpl_stats_get_max_x(stats),
00473            ymax      = cpl_stats_get_max_y(stats)),
00474         "Could not locate maximum");
00475         
00476         /* Print (normalized) intensity of detection */
00477         uves_msg_debug("%d. detection: intensity = %f",
00478                norders_detected, intensity/globmax * 100);
00479 
00480         /* Warn if intensity suddenly dropped */
00481         if (intensity < PTHRES * prev_intensity)
00482         {
00483             uves_msg_warning("Intensity of %d. line is only "
00484                      "%f %% of %d. line. Detecting too many orders?",
00485                      norders_detected, intensity / prev_intensity * 100,
00486                      norders_detected - 1);
00487         }
00488         prev_intensity = intensity;
00489         
00490         /* After detecting the first peak, estimate the approximate average order spacing */
00491         if (norders_detected == 1) 
00492         {
00493             if (!automatic) 
00494             {
00495                 SPACING = uves_round_double( 
00496                 cpl_image_get_size_y(inputimage) / NORDERS );
00497             }
00498             else
00499             {  /* If the number of orders to detect is unknown, 
00500                   derive the interorder spacing from the peak locations
00501                   in the Hough image */
00502                 check( SPACING = calculate_spacing(htrans, xmax), 
00503                    "Could not estimate interorder spacing");
00504             }
00505             
00506             uves_msg("Estimated order spacing is %d pixels", SPACING);
00507         }
00508         
00509         /* Get a more precise peak location */
00510         check( update_max(htrans,
00511                   &xmax,
00512                   &ymax,
00513                   SPACING,
00514                   cpl_image_get_size_x(inputimage),
00515                   SAMPLEWIDTH,
00516                   MINSLOPE,
00517                   MAXSLOPE,
00518                   SLOPERES), "Could not update peak position");
00519         
00520         check( delete_peak(htrans, 
00521                    minintersept, xmax, ymax, SPACING,
00522                    cpl_image_get_size_x(inputimage), 
00523                    SAMPLEWIDTH, 
00524                    MINSLOPE, MAXSLOPE, SLOPERES), 
00525            "Could not delete peak in hough image");
00526 
00527         slope = SLOPE(xmax);
00528         isept = minintersept + ymax;
00529 
00530         /* Make sure that the detection terminates if caller specified 'bad' parameters */
00531         assure( norders_detected <= tablesize, CPL_ERROR_ILLEGAL_OUTPUT,
00532             "%d orders detected. This is way too many. "
00533             "Try to decrease NORDERS (from %d) or increase PTHRES (from %f)", 
00534             norders_detected, NORDERS, PTHRES);
00535         
00536         check(( cpl_table_set_double(results, "Slope"       , norders_detected - 1, slope),
00537             cpl_table_set_double(results, "Intersept"   , norders_detected - 1, isept),
00538             cpl_table_set_int   (results, "Spacing"     , norders_detected - 1, SPACING)),
00539            "Could add order line to order table");
00540         
00541         /* Locate the next potential line */
00542         check(( uves_free_stats(&stats),
00543             stats = cpl_stats_new_from_image(htrans, CPL_STATS_MAX | CPL_STATS_MAXPOS)), 
00544             "Could not get statistics on hough image");
00545     }
00546     
00547     uves_msg("The intensity of the faintest line is %f of "
00548          "the intensity of the brightest line", intensity / globmax);
00549     uves_msg("Intensity of next (undetected) line is %f of the "
00550          "intensity of the brightest line", cpl_stats_get_max(stats)/globmax);
00551 
00552     if ( cpl_stats_get_max(stats) > 0.5 * intensity )
00553     {
00554         uves_msg_warning("Brightest undetected line with intensity %.2f %% "
00555                  "of faintest line. Detecting too few orders?",
00556                  cpl_stats_get_max(stats) / intensity * 100);
00557     }
00558     
00559     /* Clean up table */
00560     check( cpl_table_set_size(results, norders_detected), 
00561        "Could not remove extra rows from order table");
00562 
00563     /* Sort the order table so that order numbers increase from 
00564        bottom (low y) to top (high y) of image */
00565     check( uves_sort_table_1(results, "Intersept", false),    /* reverse flag = false */
00566        "Could not sort order table");
00567 
00568     /* Number orders, starting from 1 */
00569     {
00570     int i;
00571     cpl_table_new_column(results, "Order", CPL_TYPE_INT);
00572     for (i = 0; i < cpl_table_get_nrow(results); i++)
00573         {
00574             cpl_table_set_int(results, "Order", i, i+1);
00575         }
00576     }
00577 
00578     if (consecutive)
00579     /* Make sure we have consecutive orders.
00580        This assumes that the order separation varies with less than
00581        50 % from one order to the next */
00582     {
00583         int i;
00584         double dist = 0;
00585         int minorder, maxorder;
00586         int n_removed;
00587 
00588         /* From middle and up */
00589         maxorder = -1;        
00590         for (i = cpl_table_get_nrow(results)/2;
00591              i <= cpl_table_get_nrow(results) - 2 && maxorder < 0; 
00592              i++)
00593             {
00594                 if (i == cpl_table_get_nrow(results)/2)
00595                     /* initialize dist */
00596                     {
00597                         dist =
00598                             cpl_table_get_double(results, "Intersept", i+1, NULL)-
00599                             cpl_table_get_double(results, "Intersept", i, NULL);
00600                     }
00601                 else
00602                     {
00603                         double new_dist = 
00604                             cpl_table_get_double(results, "Intersept", i+1, NULL)-
00605                             cpl_table_get_double(results, "Intersept", i, NULL);
00606                         
00607                         uves_msg_debug("Order %d - %d separation = %.4f pixels", 
00608                                        cpl_table_get_int(results, "Order", i, NULL),
00609                                        cpl_table_get_int(results, "Order", i+1, NULL),
00610                                        new_dist);
00611 
00612                         if (0.5*dist <= new_dist && new_dist <= 1.5*dist)
00613                             {
00614                                 /* OK. It's probably the next consecutive order */
00615                             }
00616                         else
00617                             {
00618                                 /* Something's wrong. Stop */
00619                                 maxorder = cpl_table_get_int(results, "Order", i, NULL);
00620                                 
00621                                 uves_msg_warning("Order separation jumps from %.2f pixels to "
00622                                                  "%.2f pixels. Discarding order(s) %d and above",
00623                                                  dist, new_dist, 
00624                                                  maxorder+1);
00625                             }
00626                     }
00627             }
00628 
00629         /* From middle and down */
00630         minorder = -1;
00631         for (i = cpl_table_get_nrow(results)/2;
00632              i >= 1 && minorder < 0;
00633              i--)
00634             {
00635                 if (i == cpl_table_get_nrow(results)/2)
00636                     /* initialize dist */
00637                     {
00638                         dist =
00639                             cpl_table_get_double(results, "Intersept", i, NULL)-
00640                             cpl_table_get_double(results, "Intersept", i-1, NULL);
00641                     }
00642                 else
00643                     {
00644                         double new_dist = 
00645                             cpl_table_get_double(results, "Intersept", i, NULL)-
00646                             cpl_table_get_double(results, "Intersept", i-1, NULL);
00647                         
00648                         uves_msg_debug("Order %d - %d separation = %.4f pixels", 
00649                                        cpl_table_get_int(results, "Order", i-1, NULL),
00650                                        cpl_table_get_int(results, "Order", i, NULL),
00651                                        new_dist);
00652 
00653                         if (0.5*dist <= new_dist && new_dist <= 1.5*dist)
00654                             {
00655                                 /* OK. It's probably the next consecutive order */
00656                             }
00657                         else
00658                             {
00659                                 /* Something's wrong. Stop */
00660                                 minorder = cpl_table_get_int(results, "Order", i, NULL);
00661                                 
00662                                 uves_msg_warning("Order separation jumps from %.2f pixels to "
00663                                                  "%.2f pixels. Discarding order(s) %d and below",
00664                                                  dist, new_dist, 
00665                                                  minorder-1);
00666                             }
00667                     }
00668             }
00669 
00670         n_removed = 0;
00671         if (maxorder > 0)
00672             {
00673                 check_nomsg( n_removed += uves_erase_table_rows(results, "Order",
00674                                                                 CPL_GREATER_THAN, maxorder));
00675             }
00676         if (minorder > 0)
00677             {
00678                 check_nomsg( n_removed += uves_erase_table_rows(results, "Order",
00679                                                                 CPL_LESS_THAN, minorder));
00680             }
00681         
00682         uves_msg_debug("%d order(s) removed", n_removed);
00683         norders_detected -= n_removed;
00684     }
00685 
00686     /* Renumber orders, starting from 1 */
00687     {
00688     int i;
00689     for (i = 0; i < cpl_table_get_nrow(results); i++)
00690         {
00691             cpl_table_set_int(results, "Order", i, i+1);
00692         }
00693     }
00694     
00695     uves_msg("Hough transform detected %d orders", norders_detected);
00696     
00697     passure( norders_detected == cpl_table_get_nrow(results), "%d %d", 
00698          norders_detected, cpl_table_get_nrow(results));
00699 
00700   cleanup:
00701     uves_free_stats(&stats);
00702     uves_free_propertylist(&pl);
00703     if (cpl_error_get_code() != CPL_ERROR_NONE)
00704     {
00705         uves_free_table(&results);
00706     }
00707     
00708     return results;
00709 }
00710 
00711     
00712 /*----------------------------------------------------------------------------*/
00736 /*----------------------------------------------------------------------------*/
00737 static cpl_error_code update_max(const cpl_image *htrans,
00738                  int *xmax,              
00739                  int *ymax,
00740                  int SPACING,
00741                  int imagewidth,
00742                  int SAMPLEWIDTH,
00743                  double MINSLOPE,
00744                  double MAXSLOPE,
00745                  int SLOPERES)
00746 {
00747     const int nx = cpl_image_get_size_x(htrans);
00748     const int ny = cpl_image_get_size_y(htrans);
00749     const int slope = -imagewidth/2;             /* slope of line in hough space */
00750     const double numberoftraces = 1 + imagewidth/SAMPLEWIDTH;
00751     int pis_rejected;
00752 
00753     /* Only look at pixel values above this threshold  */
00754     double threshold = (1 - 0.5 / numberoftraces) * 
00755     cpl_image_get(htrans, *xmax, *ymax, &pis_rejected);
00756     if (threshold < 0.99) threshold = 0.99;
00757     
00758     assure (cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(), 
00759         "Could not read Hough image data");
00760     
00761     {
00762     double sum = 0;
00763     double mx  = 0;
00764     double my  = 0;
00765     int hx, hy;    
00766     for (hx = 1; hx <= SLOPERES; hx++)
00767         {
00768         int rowcenter = 
00769             uves_round_double(
00770             *ymax + slope*(hx - *xmax)/((double)SLOPERES)*(MAXSLOPE - MINSLOPE));
00771         
00772         /* It would be more correct to look at pixels from (rowcenter - LINEWIDTH/2)
00773            to (rowcenter + LINEWIDTH/2) where LINEWIDTH is the echelle line width 
00774            (i.e. different from SPACING) But empirically it doesn't really make
00775            a difference if we just use the pixel at rowcenter (for each x)    */
00776 
00777         for (hy = rowcenter - 0*SPACING/2; hy <= rowcenter + 0*SPACING/2; hy++) 
00778             {
00779             if (1 <= hx && hx <= nx &&
00780                 1 <= hy && hy <= ny)
00781                 {
00782                 double pixelvalue = cpl_image_get(
00783                     htrans, hx, hy, &pis_rejected);
00784                 if (!pis_rejected && pixelvalue >= threshold) 
00785                     {
00786                     mx  += hx*pixelvalue;
00787                     my  += hy*pixelvalue;
00788                     sum +=    pixelvalue;
00789                     }
00790                 }
00791             }
00792         
00793         }
00794     
00795     uves_msg_debug("Peak position in Hough space changed from (%d, %d)", *xmax, *ymax);
00796     *xmax = uves_round_double(mx/sum);
00797     *ymax = uves_round_double(my/sum);
00798     uves_msg_debug("to (%d, %d)", *xmax, *ymax);
00799     }
00800     
00801   cleanup:
00802     return cpl_error_get_code();
00803 }
00804 
00805 /*----------------------------------------------------------------------------*/
00816 /*----------------------------------------------------------------------------*/
00817 
00818 static int calculate_spacing(const cpl_image *image, int x)
00819 {
00820     int shift = 0;
00821     double autoc = autocorr(image, x, shift);
00822     double previous;
00823     assure (cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(), 
00824         "Could not calculate autocorrelation function");
00825 
00826     uves_msg_debug("Autocorrelation(shift=%d) = %f", shift, autoc);
00827     
00828     do{
00829     previous = autoc;
00830     shift += 1;
00831     check( autoc = autocorr(image, x, shift), 
00832            "Could not calculate autocorrelation function");
00833     uves_msg_debug("Autocorrelation(shift=%d) = %f", shift, autoc);
00834     } while (autoc <= previous);
00835     
00836   cleanup:
00837     return 2*(shift - 1);
00838     /* First minimum of the autocorrelation function is half spacing */
00839 }
00840 
00841 
00842 /*----------------------------------------------------------------------------*/
00855 /*----------------------------------------------------------------------------*/
00856 static double autocorr(const cpl_image *image, const int x, const int shift)
00857 {
00858     double result = 0;
00859     const int ny = cpl_image_get_size_y(image);
00860     assure (cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(), 
00861         "Could not read image dimensions");
00862     
00863     if( shift >= ny ) return 0;
00864     
00865     {
00866     double sum = 0;
00867     int y;    
00868     int number_of_points = 0;
00869     for (y = 1; y <= ny - shift; y++){
00870         int pis_rejected;
00871         double pixelvalue;
00872 
00873         pixelvalue = cpl_image_get(image, x, y,         &pis_rejected) *
00874                  cpl_image_get(image, x, y + shift, &pis_rejected);
00875 
00876         if (!pis_rejected){
00877         sum += pixelvalue;
00878         number_of_points += 1;
00879         }
00880     }
00881     assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
00882         "Error reading image pixel values");
00883     
00884     if (number_of_points > 0) 
00885         {
00886         result = sum / number_of_points;
00887         }
00888     else
00889         {
00890         result = 0;
00891         }
00892     }
00893     
00894   cleanup:
00895     return result;
00896 }
00897 
00898 /*----------------------------------------------------------------------------*/
00910 /*----------------------------------------------------------------------------*/
00911 static int firsttrace(int nx, int SAMPLEWIDTH)
00912 {
00913     int result = nx/2;
00914 
00915     while(result - SAMPLEWIDTH >= 1)
00916     {
00917         result -= SAMPLEWIDTH;
00918     }
00919 
00920     return result;
00921 }
00922 
00923 /*----------------------------------------------------------------------------*/
00946 /*----------------------------------------------------------------------------*/
00947 static cpl_error_code delete_peak(cpl_image *htrans, int minintersept,
00948                   int hxmax, int hymax, 
00949                   int SPACING, int imagewidth, int SAMPLEWIDTH, 
00950                   double MINSLOPE, double MAXSLOPE, int SLOPERES)
00951 {
00952     const int ny = cpl_image_get_size_y(htrans);
00953     int tracecol;
00954     int firstcol = firsttrace(imagewidth, SAMPLEWIDTH);
00955     
00956     assure (cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(), 
00957         "Could not read hough image data");
00958     
00959     /* We reverse the calculation of the Hough transform */
00960     for (tracecol = firstcol; tracecol <= imagewidth; tracecol += SAMPLEWIDTH){
00961     /* Get y-coordinate in raw image */
00962     double slope = SLOPE(hxmax);
00963     double intersept = minintersept + hymax;
00964     double imagey = intersept + slope*tracecol;
00965     
00966     /* Now erase all points in the Hough image that were caused
00967        by the point (tracecol, imagey) in the input image */
00968     int hx, hy;
00969     for (hx = 1; hx <= SLOPERES; hx++){
00970         slope = SLOPE(hx);
00971         intersept = imagey - slope*tracecol;
00972         for (hy = (intersept - minintersept) - SPACING/3;
00973          hy <= (intersept - minintersept) + SPACING/3; 
00974          hy++) {
00975         if (0 < hy && hy <= ny) {
00976             check( cpl_image_set(htrans, hx, hy, 0), 
00977                "Could not write pixel at (%d, %d)", hx, hy);
00978         }
00979         }
00980     }
00981     }
00982     
00983   cleanup:
00984     return cpl_error_get_code();
00985 }
00986 
00987 /*----------------------------------------------------------------------------*/
00998 /*----------------------------------------------------------------------------*/
00999 cpl_error_code uves_draw_orders(const cpl_table *ordertable, cpl_image *image)
01000 {
01001     double penvalue;
01002     int nx;
01003     int ny;
01004     cpl_stats *stats = NULL;
01005     int nrows;
01006     int i;
01007 
01008     /* Check input */
01009     passure( image != NULL, " ");
01010     passure( ordertable != NULL, " ");
01011     passure( cpl_table_has_column(ordertable, "Intersept"), " ");
01012     passure( cpl_table_has_column(ordertable, "Slope"    ), " ");
01013 
01014     nx = cpl_image_get_size_x(image);
01015     ny = cpl_image_get_size_y(image);
01016     
01017     /* Calculate pen value */
01018     check( stats = cpl_stats_new_from_image(image, CPL_STATS_MAX), 
01019        "Could not get statistics on input image");
01020     check( penvalue = 2*cpl_stats_get_max(stats),
01021        "Could not find image maximum value" );
01022 
01023     /* Draw lines in ordertable on image */
01024     check  ( nrows = cpl_table_get_nrow(ordertable), 
01025          "Could not read number of rows in ordertable");
01026     for (i = 0; i < nrows; i++)
01027     {
01028         int x;
01029         double intersept, slope;
01030         
01031         check(( intersept = cpl_table_get_double(ordertable, "Intersept", i, NULL),
01032             slope     = cpl_table_get_double(ordertable, "Slope", i, NULL)),
01033            "Could not read 'Intersept' and 'Slope' from ordertable");
01034         
01035         for (x = 1; x <= nx; x++){
01036         double yd = intersept + x * slope;
01037         int y = uves_round_double(yd);
01038         
01039         if (0 < y && y <= ny)
01040             {
01041             cpl_image_set(image, x, y, penvalue);
01042             }
01043         }
01044         assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
01045             "Could not draw order in table row #%d", i);
01046     }
01047     
01048   cleanup:
01049     uves_free_stats(&stats);
01050     return cpl_error_get_code();
01051 }

Generated on Tue Jun 19 14:39:16 2007 for UVES Pipeline Reference Manual by  doxygen 1.4.6