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

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