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

Generated on 8 Mar 2011 for UVES Pipeline Reference Manual by  doxygen 1.6.1