irplib_spectrum.c

00001 /* $Id: irplib_spectrum.c,v 1.13 2007/07/23 14:53:14 yjung Exp $
00002  *
00003  * This file is part of the irplib package
00004  * Copyright (C) 2002,2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: yjung $
00023  * $Date: 2007/07/23 14:53:14 $
00024  * $Revision: 1.13 $
00025  * $Name: uves-3_4_5 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033                                 Includes
00034  -----------------------------------------------------------------------------*/
00035 
00036 #include <math.h>
00037 #include <float.h>
00038 #include <cpl.h>
00039 
00040 #include "irplib_spectrum.h"
00041 
00042 /*-----------------------------------------------------------------------------
00043                                    Define
00044  -----------------------------------------------------------------------------*/
00045 
00046 #define SPECTRUM_HW                     16
00047 #define MIN_THRESH_FACT                 0.9
00048 #define MAX_THRESH_FACT                 1.1
00049 #define SPEC_SHADOW_FACT                30.0 /* Negative spectrum intensity*/
00050 #define SPEC_MAXWIDTH                   48
00051 
00052 /*-----------------------------------------------------------------------------
00053                             Functions prototypes
00054  -----------------------------------------------------------------------------*/
00055 
00056 static int select_valid_spectra(cpl_image *, cpl_apertures *, int,
00057         spec_shadows, int, int *, int **) ;
00058 static int valid_spectrum(cpl_image *, cpl_apertures *, int, spec_shadows, int,
00059         int) ;
00060 
00061 /*----------------------------------------------------------------------------*/
00065 /*----------------------------------------------------------------------------*/
00066 
00069 /*----------------------------------------------------------------------------*/
00084 /*----------------------------------------------------------------------------*/
00085 int irplib_spectrum_find_brightest(
00086         const cpl_image     *   in,
00087         int                     offset,
00088         spec_shadows            shadows,
00089         double                  min_bright,
00090         int                     orient,
00091         double              *   pos)
00092 {
00093     cpl_image       *   loc_ima ;
00094     cpl_image       *   filt_image ;
00095     cpl_matrix      *   kernel ;
00096     cpl_image       *   collapsed ;
00097     float           *   pcollapsed ;
00098     cpl_vector      *   line ;
00099     double          *   pline ;
00100     cpl_vector      *   line_filt ;
00101     double              threshold ;
00102     double              median, stdev, max, mean ;
00103     cpl_mask        *   mask ;
00104     cpl_image       *   labels ;
00105     int                 nlabels ;
00106     cpl_apertures   *   aperts ;
00107     int                 n_valid_specs ;
00108     int             *   valid_specs ;
00109     double              brightness, brightest ;
00110     int                 i ;
00111 
00112     /* Test entries */
00113     if (in == NULL) return -1 ;
00114     if (orient!=0 && orient!=1) return -1 ;
00115 
00116     /* Flip the image if necessary */
00117     if (orient == 1) {
00118         loc_ima = cpl_image_duplicate(in) ;
00119         cpl_image_flip(loc_ima, 1) ;
00120     } else {
00121         loc_ima = cpl_image_duplicate(in) ;
00122     }
00123     
00124     /* Get rid of very high frequencies  */
00125     kernel = cpl_matrix_new(3, 3) ;
00126     cpl_matrix_fill(kernel, 1.0) ;
00127     if ((filt_image = cpl_image_filter_median(loc_ima, kernel)) == NULL) {
00128         cpl_matrix_delete(kernel) ;
00129         cpl_image_delete(loc_ima) ;
00130         cpl_msg_error(cpl_func, "cannot filter the image") ;
00131         return -1 ;
00132     }
00133     cpl_image_delete(loc_ima) ;
00134     cpl_matrix_delete(kernel) ;
00135 
00136     /* Collapse the image */
00137     if ((collapsed = cpl_image_collapse_median_create(filt_image, 1, 0,
00138                     0)) == NULL) {
00139         cpl_msg_error(cpl_func, "collapsing image: aborting spectrum detection");
00140         cpl_image_delete(filt_image) ;
00141         return -1 ;
00142     }
00143     cpl_image_delete(filt_image) ;
00144 
00145     /* Subtract low frequency signal */
00146     line = cpl_vector_new_from_image_column(collapsed, 1) ;
00147     cpl_image_delete(collapsed) ;
00148     line_filt = cpl_vector_filter_median_create(line, SPECTRUM_HW) ;
00149     cpl_vector_subtract(line, line_filt) ;
00150     cpl_vector_delete(line_filt) ;
00151 
00152     /* Get relevant stats for thresholding */
00153     median = cpl_vector_get_median_const(line) ;
00154     stdev = cpl_vector_get_stdev(line) ;
00155     max = cpl_vector_get_max(line) ;
00156     mean = cpl_vector_get_mean(line) ;
00157 
00158     /* Set the threshold */
00159     threshold = median + stdev ;
00160     if (threshold > MIN_THRESH_FACT * max)  threshold = MIN_THRESH_FACT * max ;
00161     if (threshold < MAX_THRESH_FACT * mean) threshold = MAX_THRESH_FACT * mean;
00162 
00163     /* Recreate the image */
00164     collapsed = cpl_image_new(1, cpl_vector_get_size(line), CPL_TYPE_FLOAT) ;
00165     pcollapsed = cpl_image_get_data_float(collapsed) ;
00166     pline = cpl_vector_get_data(line) ;
00167     for (i=0 ; i<cpl_vector_get_size(line) ; i++)
00168         pcollapsed[i] = (float)pline[i] ;
00169     cpl_vector_delete(line) ;
00170 
00171     /* Binarise the image */
00172     if ((mask = cpl_mask_threshold_image_create(collapsed, threshold,
00173             DBL_MAX)) == NULL) {
00174         cpl_msg_error(cpl_func, "cannot binarise") ;
00175         cpl_image_delete(collapsed) ;
00176         return -1 ;
00177     }
00178     if (cpl_mask_count(mask) < 1) {
00179         cpl_msg_error(cpl_func, "not enough signal to detect spectra") ;
00180         cpl_image_delete(collapsed) ;
00181         cpl_mask_delete(mask) ;
00182         return -1 ;
00183     }
00184     /* Labelise the different detected apertures */
00185     if ((labels = cpl_image_labelise_mask_create(mask, &nlabels))==NULL) {
00186         cpl_msg_error(cpl_func, "cannot labelise") ;
00187         cpl_image_delete(collapsed) ;
00188         cpl_mask_delete(mask) ;
00189         return -1 ;
00190     }
00191     cpl_mask_delete(mask) ;
00192 
00193     /* Create the detected apertures list */
00194     if ((aperts = cpl_apertures_new_from_image(collapsed, labels)) == NULL) {
00195         cpl_msg_error(cpl_func, "cannot compute apertures") ;
00196         cpl_image_delete(collapsed) ;
00197         cpl_image_delete(labels) ;
00198         return -1 ;
00199     }
00200     cpl_image_delete(labels) ;
00201 
00202     /* Select only relevant specs, create corresponding LUT's */
00203     if (select_valid_spectra(collapsed, aperts, offset, shadows, SPEC_MAXWIDTH,
00204                 &n_valid_specs, &valid_specs) == -1) {
00205         cpl_msg_debug(cpl_func, "cannot select valid spectra") ;
00206         cpl_image_delete(collapsed) ;
00207         cpl_apertures_delete(aperts) ;
00208         return -1 ;
00209     }
00210     cpl_image_delete(collapsed) ;
00211     if (n_valid_specs < 1) {
00212         cpl_msg_error(cpl_func, "no valid spectrum detected") ;
00213         cpl_free(valid_specs) ;
00214         cpl_apertures_delete(aperts) ;
00215         return -1 ;
00216     }
00217 
00218     /* Look for the brightest, among the detected spectra */
00219     *pos = cpl_apertures_get_centroid_y(aperts, valid_specs[0]+1) ;
00220     brightest = valid_specs[0] ;
00221     brightness = cpl_apertures_get_flux(aperts, valid_specs[0]+1) ;
00222     for (i=0 ; i<n_valid_specs ; i++) {
00223         if (cpl_apertures_get_flux(aperts, valid_specs[i]+1) > brightness) {
00224             *pos = cpl_apertures_get_centroid_y(aperts, valid_specs[i]+1) ;
00225             brightest = valid_specs[i] ;
00226             brightness = cpl_apertures_get_flux(aperts, valid_specs[i]+1) ;
00227         }
00228     }
00229     cpl_apertures_delete(aperts) ;
00230     cpl_free(valid_specs) ;
00231 
00232     /* Minimum brightness required */
00233     if (brightness < min_bright) {
00234         cpl_msg_error(cpl_func, "brightness %f too low <%f", brightness,
00235                 min_bright) ;
00236         return -1 ;
00237     }
00238 
00239     /* Return */
00240     return 0 ;
00241 }
00242 
00245 /*----------------------------------------------------------------------------*/
00257 /*----------------------------------------------------------------------------*/
00258 static int select_valid_spectra(
00259         cpl_image       *   in,
00260         cpl_apertures   *   aperts,
00261         int                 offset,
00262         spec_shadows        shadows,
00263         int                 max_spec_width,
00264         int             *   n_valid_specs,
00265         int             **  valid_specs)
00266 {
00267     int                 nb_aperts ;
00268     int                 i, j ;
00269 
00270     /* Initialise */
00271     *valid_specs = NULL ;
00272     nb_aperts = cpl_apertures_get_size(aperts) ;
00273     *n_valid_specs = 0 ;
00274 
00275     /* Test entries */
00276     if (nb_aperts < 1) return -1 ;
00277 
00278     /* Count nb of valid specs */
00279     j = 0 ;
00280     for (i=0 ; i<nb_aperts ; i++)
00281         if (valid_spectrum(in, aperts, offset, shadows, max_spec_width,
00282                     i+1)) (*n_valid_specs)++ ;
00283 
00284     /* Associate to each spectrum, its object number */
00285     if (*n_valid_specs) {
00286         *valid_specs = cpl_calloc(*n_valid_specs, sizeof(int)) ;
00287         j = 0 ;
00288         for (i=0 ; i<nb_aperts ; i++)
00289             if (valid_spectrum(in, aperts, offset, shadows, max_spec_width,
00290                         i+1)) {
00291                 (*valid_specs)[j] = i ;
00292                 j++ ;
00293             }
00294     } else return -1 ;
00295 
00296     return 0 ;
00297 }
00298 
00299 /*---------------------------------------------------------------------------*/
00310 /*----------------------------------------------------------------------------*/
00311 static int valid_spectrum(
00312         cpl_image       *   in,
00313         cpl_apertures   *   aperts,
00314         int                 offset,
00315         spec_shadows        shadows,
00316         int                 max_spec_width,
00317         int                 objnum)
00318 {
00319     int                 objwidth ;
00320     double              valover, valunder, valcenter ;
00321 
00322     /* Find objwidth */
00323     objwidth = cpl_apertures_get_top(aperts, objnum) -
00324         cpl_apertures_get_bottom(aperts, objnum) + 1 ;
00325     if (objwidth > max_spec_width) {
00326         cpl_msg_error(cpl_func, "object is too wide") ;
00327         return 0 ;
00328     }
00329 
00330     /* Object is too small */
00331     if (cpl_apertures_get_npix(aperts, objnum) < 2) return 0 ;
00332 
00333     /* no shadow required */
00334     if (shadows == NO_SHADOW) return 1 ;
00335 
00336     /* Get the median of the object (valcenter) */
00337     valcenter = cpl_apertures_get_median(aperts, objnum) ;
00338 
00339     /* Get the black shadows medians (valunder and valover) */
00340     if (cpl_apertures_get_bottom(aperts, objnum) - offset < 1) valunder = 0.0 ;
00341     else valunder = cpl_image_get_median_window(in, 1,
00342             cpl_apertures_get_bottom(aperts, objnum) - offset, 1, 
00343             cpl_apertures_get_top(aperts, objnum) - offset) ;
00344     
00345     if (cpl_apertures_get_top(aperts, objnum) + offset > 1024) valover = 0.0 ;
00346     else valover = cpl_image_get_median_window(in, 1,
00347             cpl_apertures_get_bottom(aperts, objnum) + offset, 1, 
00348             cpl_apertures_get_top(aperts, objnum) + offset) ;
00349     
00350     switch (shadows) {
00351         case TWO_SHADOWS:
00352         if ((valunder < -fabs(valcenter/SPEC_SHADOW_FACT)) &&
00353             (valover < -fabs(valcenter/SPEC_SHADOW_FACT))    &&
00354             (valunder/valover > 0.5) &&
00355             (valunder/valover < 2.0)) return 1 ;
00356         else return 0 ;
00357 
00358         case ONE_SHADOW:
00359         if ((valunder < -fabs(valcenter/SPEC_SHADOW_FACT)) ||
00360             (valover < -fabs(valcenter/SPEC_SHADOW_FACT))) return 1 ;
00361         else return 0 ;
00362 
00363         case NO_SHADOW:
00364         return 1 ;
00365 
00366         default:
00367         cpl_msg_error(cpl_func, "unknown spec_detect_mode") ;
00368         break ;
00369     }
00370 
00371     return 0 ;
00372 }

Generated on Thu Nov 15 14:32:26 2007 for UVES Pipeline Reference Manual by  doxygen 1.5.1