HAWKI Pipeline Reference Manual 1.8.12
hawki_step_detect_obj.c
00001 /* $Id: hawki_step_detect_obj.c,v 1.27 2012/11/30 14:50:51 cgarcia Exp $
00002  *
00003  * This file is part of the HAWKI Pipeline
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: cgarcia $
00023  * $Date: 2012/11/30 14:50:51 $
00024  * $Revision: 1.27 $
00025  * $Name: hawki-1_8_12 $
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 <cpl.h>
00038 #include <string.h>
00039 
00040 #include "irplib_utils.h"
00041 #include "irplib_calib.h"
00042 
00043 #include "hawki_utils.h"
00044 #include "hawki_obj_det.h"
00045 #include "hawki_mask.h"
00046 #include "hawki_image_stats.h"
00047 #include "hawki_calib.h"
00048 #include "hawki_load.h"
00049 #include "hawki_save.h"
00050 #include "hawki_pfits.h"
00051 #include "hawki_dfs.h"
00052 
00053 /*-----------------------------------------------------------------------------
00054                             Functions prototypes
00055  -----------------------------------------------------------------------------*/
00056 
00057 #ifdef __cplusplus
00058 extern "C"
00059 #endif
00060 int cpl_plugin_get_info(cpl_pluginlist * list);
00061 
00062 static int hawki_step_detect_obj_create(cpl_plugin *) ;
00063 static int hawki_step_detect_obj_exec(cpl_plugin *) ;
00064 static int hawki_step_detect_obj_destroy(cpl_plugin *) ;
00065 static int hawki_step_detect_obj(cpl_parameterlist *, cpl_frameset *) ;
00066 
00067 static void hawki_step_detect_obj_init_output(void);
00068 static void hawki_step_detect_obj_get_pscale
00069 (cpl_frameset * combframes);
00070 static int hawki_step_detect_obj_retrieve_input_param
00071 (cpl_parameterlist  *  parlist);
00072 static cpl_apertures  ** hawki_step_detect_obj_mask_and_apertures
00073 (cpl_frameset    *  combframes,
00074  cpl_image       ** mask_image,
00075  cpl_image       ** comb_image);
00076 static int hawki_step_detect_obj_aper_params
00077 (cpl_image      **  combined_images, 
00078  cpl_apertures  **  apertures,
00079  cpl_table      **  obj_charac);
00080 static int hawki_step_detect_obj_save
00081 (cpl_image           **  mask_images,
00082  cpl_table           **  obj_charac,
00083  cpl_propertylist    **  obj_stats,
00084  cpl_parameterlist   *   parlist,
00085  cpl_frameset        *   framelist);
00086 
00087 /*-----------------------------------------------------------------------------
00088                             Static variables
00089  -----------------------------------------------------------------------------*/
00090 
00091 static struct 
00092 {
00093     /* Inputs */
00094     double sigma_det;
00095     int    growing_radius;
00096 } hawki_step_detect_obj_config;
00097 
00098 static struct 
00099 {
00100     /* Outputs */
00101     double          pixscale;
00102     double          iq[HAWKI_NB_DETECTORS] ;
00103     int             nbobjs[HAWKI_NB_DETECTORS] ;
00104     double          fwhm_pix[HAWKI_NB_DETECTORS] ;
00105     double          fwhm_arcsec[HAWKI_NB_DETECTORS] ;
00106     double          fwhm_mode[HAWKI_NB_DETECTORS] ;
00107     double          pos_x[HAWKI_NB_DETECTORS] ;
00108     double          pos_y[HAWKI_NB_DETECTORS] ;
00109 } hawki_step_detect_obj_output;
00110 
00111 static char hawki_step_detect_obj_description[] =
00112 "hawki_step_detect_obj -- hawki detect objects recipe.\n"
00113 "This recipe detects objects from the combined image creating a mask\n"
00114 "and a list of object properties\n"
00115 "The input of the recipe files listed in the Set Of Frames (sof-file)\n"
00116 "must be tagged as:\n"
00117 "combined.fits "HAWKI_CALPRO_COMBINED"\n"
00118 "The recipe creates as an output:\n"
00119 "hawki_step_detect_obj_mask.fits ("HAWKI_CALPRO_OBJ_MASK"): A mask with 1 where the objects are present and 0 elsewhere\n"
00120 "hawki_step_detect_obj_stars.fits ("HAWKI_CALPRO_OBJ_PARAM"): A table with the detected objects characteristics\n"
00121 "Return code:\n"
00122 "esorex exits with an error code of 0 if the recipe completes successfully\n"
00123 "or 1 otherwise";
00124 
00125 
00126 
00127 /*-----------------------------------------------------------------------------
00128                                 Functions code
00129  -----------------------------------------------------------------------------*/
00130 
00131 /*----------------------------------------------------------------------------*/
00139 /*----------------------------------------------------------------------------*/
00140 int cpl_plugin_get_info(cpl_pluginlist * list)
00141 {
00142     cpl_recipe  *   recipe = cpl_calloc(1, sizeof(*recipe)) ;
00143     cpl_plugin  *   plugin = &recipe->interface ;
00144 
00145     cpl_plugin_init(plugin,
00146                     CPL_PLUGIN_API,
00147                     HAWKI_BINARY_VERSION,
00148                     CPL_PLUGIN_TYPE_RECIPE,
00149                     "hawki_step_detect_obj",
00150                     "Object detection recipe",
00151                     hawki_step_detect_obj_description,
00152                     "Cesar Enrique Garcia Dabo",
00153                     PACKAGE_BUGREPORT,  
00154                     hawki_get_license(),
00155                     hawki_step_detect_obj_create,
00156                     hawki_step_detect_obj_exec,
00157                     hawki_step_detect_obj_destroy) ;
00158 
00159     cpl_pluginlist_append(list, plugin) ;
00160     
00161     return 0;
00162 }
00163 
00164 /*----------------------------------------------------------------------------*/
00173 /*----------------------------------------------------------------------------*/
00174 static int hawki_step_detect_obj_create(cpl_plugin * plugin)
00175 {
00176     cpl_recipe      * recipe ;
00177     cpl_parameter   * p ;
00178 
00179     /* Get the recipe out of the plugin */
00180     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00181         recipe = (cpl_recipe *)plugin ;
00182     else return -1 ;
00183 
00184     /* Create the parameters list in the cpl_recipe object */
00185     recipe->parameters = cpl_parameterlist_new() ;
00186     if (recipe->parameters == NULL)
00187         return 1;
00188 
00189     /* Fill the parameters list */
00190     /* --sigma_det */
00191     p = cpl_parameter_new_value("hawki.hawki_step_detect_obj.sigma_det", 
00192                                 CPL_TYPE_DOUBLE, "detection level",
00193                                 "hawki.hawki_step_detect_obj", 6.);
00194     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sigma_det");
00195     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00196     cpl_parameterlist_append(recipe->parameters, p);
00197 
00198     /* --growing_radius */
00199     p = cpl_parameter_new_value("hawki.hawki_step_detect_obj.growing_radius", 
00200                                 CPL_TYPE_INT,
00201                                 "radius of convolution kernel to apply to objects",
00202                                 "hawki.hawki_step_detect_obj", 5);
00203     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "growing_radius");
00204     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00205     cpl_parameterlist_append(recipe->parameters, p);
00206 
00207     /* Return */
00208     return 0;
00209 }
00210 
00211 /*----------------------------------------------------------------------------*/
00217 /*----------------------------------------------------------------------------*/
00218 static int hawki_step_detect_obj_exec(cpl_plugin * plugin)
00219 {
00220     cpl_recipe  *   recipe ;
00221 
00222     /* Get the recipe out of the plugin */
00223     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00224         recipe = (cpl_recipe *)plugin ;
00225     else return -1 ;
00226 
00227     /* Issue a banner */
00228     hawki_print_banner();
00229 
00230     return hawki_step_detect_obj(recipe->parameters, recipe->frames) ;
00231 }
00232 
00233 /*----------------------------------------------------------------------------*/
00239 /*----------------------------------------------------------------------------*/
00240 static int hawki_step_detect_obj_destroy(cpl_plugin * plugin)
00241 {
00242     cpl_recipe  *   recipe ;
00243 
00244     /* Get the recipe out of the plugin */
00245     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00246         recipe = (cpl_recipe *)plugin ;
00247     else return -1 ;
00248 
00249     cpl_parameterlist_delete(recipe->parameters) ;
00250     return 0 ;
00251 }
00252 
00253 /*----------------------------------------------------------------------------*/
00260 /*----------------------------------------------------------------------------*/
00261 static int hawki_step_detect_obj(
00262         cpl_parameterlist   *   parlist, 
00263         cpl_frameset        *   framelist)
00264 {
00265     cpl_frameset     *   combframes;
00266     cpl_image        **  mask_image;
00267     cpl_image        **  comb_image;
00268     cpl_apertures    **  apertures;
00269     cpl_table        **  obj_charac;
00270     cpl_propertylist **  obj_stats;
00271     int                  idet;
00272     
00273     /* Initialise */
00274     hawki_step_detect_obj_init_output();
00275 
00276     /* Retrieve input parameters */
00277     if(hawki_step_detect_obj_retrieve_input_param(parlist))
00278     {
00279         cpl_msg_error(__func__, "Wrong parameters");
00280         return -1;
00281     }
00282 
00283     /* Identify the RAW and CALIB frames in the input frameset */
00284     if (hawki_dfs_set_groups(framelist)) {
00285         cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00286         return -1 ;
00287     }
00288 
00289     /* Retrieve raw frames */
00290     combframes = hawki_extract_frameset(framelist, HAWKI_CALPRO_COMBINED) ;
00291     if (combframes == NULL) 
00292     {
00293         cpl_msg_error(__func__, "Cannot find combined images in the input (%s)",
00294                 HAWKI_CALPRO_COMBINED);
00295         return -1 ;
00296     }
00297     if (cpl_frameset_get_size(combframes) != 1)
00298     {
00299         cpl_msg_error(__func__, "Only one combined image must be provided");
00300         return -1 ;
00301     }
00302 
00303     /* Get info from the headers */
00304     hawki_step_detect_obj_get_pscale(combframes);
00305     
00306     /* Get the mask with the points above the background 
00307      * and the associated apertures*/
00308     cpl_msg_info(__func__, "Getting the object masks") ;
00309     mask_image = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_image *));
00310     comb_image = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_image *));
00311     apertures =  hawki_step_detect_obj_mask_and_apertures
00312         (combframes, mask_image, comb_image);
00313     if(apertures == NULL)
00314     {
00315         cpl_msg_error(__func__,"Could not detect objects in image");
00316         cpl_frameset_delete(combframes);
00317         cpl_free(mask_image);
00318         cpl_free(comb_image);
00319         return -1;
00320     }
00321     
00322     /* Get object characterizations and statistics */
00323     cpl_msg_info(__func__, "Getting object parameters") ;
00324     obj_charac = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_table *)) ;
00325     obj_stats  = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist *));
00326     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
00327     {
00328         obj_charac[idet] = cpl_table_new
00329             (cpl_apertures_get_size(apertures[idet]));
00330         obj_stats[idet] = cpl_propertylist_new();
00331     }
00332     hawki_step_detect_obj_aper_params(comb_image, apertures, obj_charac);
00333  
00334     /* Statistics of the detected objects in the QC */
00335     hawki_obj_prop_stats(obj_charac, obj_stats);
00336 
00337     /* Save the products */
00338     cpl_msg_info(__func__, "Save the products") ;
00339     if (hawki_step_detect_obj_save(mask_image, obj_charac, obj_stats,
00340                                    parlist, framelist) == -1)
00341     {
00342         cpl_msg_warning(__func__, "Some data could not be saved. "
00343                         "Check permisions or disk space") ;
00344         for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) 
00345         {
00346             cpl_table_delete(obj_charac[idet]);
00347             cpl_propertylist_delete(obj_stats[idet]);
00348             cpl_apertures_delete(apertures[idet]);
00349         }
00350         cpl_free(apertures);
00351         cpl_free(obj_charac);
00352         cpl_free(obj_stats);
00353         cpl_frameset_delete(combframes);
00354         for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) 
00355         {
00356             cpl_image_delete(mask_image[idet]);
00357             cpl_image_delete(comb_image[idet]);
00358         }
00359         cpl_free(mask_image);
00360         cpl_free(comb_image);
00361         return -1 ;
00362     }
00363     
00364     /* Return */
00365     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) 
00366     {
00367         cpl_table_delete(obj_charac[idet]);
00368         cpl_propertylist_delete(obj_stats[idet]);
00369         cpl_apertures_delete(apertures[idet]);
00370         cpl_image_delete(mask_image[idet]);
00371         cpl_image_delete(comb_image[idet]);
00372     }
00373     cpl_free(apertures);
00374     cpl_free(obj_charac);
00375     cpl_free(obj_stats);
00376     cpl_frameset_delete(combframes);
00377     cpl_free(mask_image);
00378     cpl_free(comb_image);
00379 
00380     /* Return */
00381     if (cpl_error_get_code())
00382     {
00383         cpl_msg_error(__func__,
00384                       "HAWK-I pipeline could not recover from previous errors");
00385         return -1 ;
00386     }
00387     else return 0 ;
00388 }
00389 
00390 int hawki_step_detect_obj_retrieve_input_param
00391 (cpl_parameterlist  *  parlist)
00392 {
00393     cpl_parameter   *   par ;
00394 
00395     par = NULL ;
00396     par = cpl_parameterlist_find
00397         (parlist, "hawki.hawki_step_detect_obj.sigma_det");
00398     hawki_step_detect_obj_config.sigma_det = cpl_parameter_get_double(par);
00399     par = cpl_parameterlist_find
00400         (parlist, "hawki.hawki_step_detect_obj.growing_radius");
00401     hawki_step_detect_obj_config.growing_radius = cpl_parameter_get_int(par);
00402     if(hawki_step_detect_obj_config.growing_radius > 100)
00403     {
00404         cpl_msg_error(__func__,"The maximum radius allowed is 100");
00405         return -1;
00406     }
00407     if(hawki_step_detect_obj_config.sigma_det <= 0 )
00408     {
00409         cpl_msg_error(__func__,"Detection sigma has to be greater than 0");
00410         return -1;
00411     }
00412 
00413     return 0;
00414 }
00415 
00416 
00417 
00418 /*----------------------------------------------------------------------------*/
00428 /*----------------------------------------------------------------------------*/
00429 static cpl_apertures  ** hawki_step_detect_obj_mask_and_apertures
00430 (cpl_frameset    *  combframes,
00431  cpl_image       ** mask_image,
00432  cpl_image       ** comb_image)
00433 {
00434     cpl_apertures   **  apertures;
00435     int                 idet;
00436 
00437     /* Create output object */
00438     apertures = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_apertures *));
00439   
00440     /* Loop on the detectors */
00441     cpl_msg_indent_more();
00442     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
00443     {
00444         cpl_image  * chip_image;
00445         cpl_image  * chip_image_sort;
00446         cpl_mask   * object_mask;
00447         cpl_mask   * kernel_op;
00448         cpl_matrix * kernel;
00449         cpl_image  * labels;
00450         cpl_size     nobj;
00451         double       bkg_level;
00452         double       bkg_noise;
00453         double       threshold;
00454         int          kernel_size;
00455         int          ix;
00456         int          iy;
00457 
00458         cpl_msg_info(__func__, "Detecting objects on chip number %d", idet+1) ;
00459         cpl_msg_indent_more();
00460         
00461         /* Load the input data */
00462         cpl_msg_info(__func__, "Load the input data") ;
00463         chip_image = hawki_load_image(combframes, 0, idet+1, CPL_TYPE_FLOAT);
00464         if (chip_image == NULL) 
00465         {
00466             cpl_msg_error(__func__, "Cannot load chip %d", idet+1) ;
00467             cpl_msg_indent_less() ;
00468             cpl_free(apertures);
00469             return NULL ;
00470         }
00471         
00472         /* Subtract the median of the frame first */
00473         chip_image_sort = cpl_image_duplicate(chip_image);
00474         bkg_level = cpl_image_get_median(chip_image);
00475         bkg_noise = hawki_image_float_get_sigma_from_quartile(chip_image_sort); 
00476         cpl_image_delete(chip_image_sort);
00477         threshold = bkg_level + hawki_step_detect_obj_config.sigma_det * bkg_noise;        
00478         cpl_msg_info(__func__, "Background:       %f",bkg_level);
00479         cpl_msg_info(__func__, "Background noise: %f",bkg_noise);
00480         
00481         /* Create the mask */
00482         cpl_msg_info(__func__, "Mask creation with threshold: %f",threshold);
00483         object_mask = cpl_mask_threshold_image_create
00484             (chip_image, threshold, DBL_MAX);
00485 
00486         /* Apply a morphological opening to remove single pixel detections */
00487         cpl_msg_info(__func__, "Removing single pixel detections");
00488         kernel_op = cpl_mask_new(3, 3); 
00489         cpl_mask_not(kernel_op);
00490         if (cpl_mask_filter(object_mask, object_mask, kernel_op, 
00491                             CPL_FILTER_OPENING, 
00492                             CPL_BORDER_ZERO) != CPL_ERROR_NONE)
00493         {
00494             cpl_mask_delete(object_mask);
00495             cpl_mask_delete(kernel_op);
00496             return NULL;
00497         }
00498         cpl_mask_delete(kernel_op);
00499         
00500         /* Apply dilation to the mask */
00501         if(hawki_step_detect_obj_config.growing_radius>0)
00502         {
00503             cpl_msg_info(__func__, "Growing the mask with radius %d",
00504                     hawki_step_detect_obj_config.growing_radius);
00505             kernel_size = hawki_step_detect_obj_config.growing_radius*2+1;
00506             kernel = cpl_matrix_new(kernel_size, kernel_size);
00507             for(ix=0;ix<kernel_size;++ix)
00508                 for(iy=0;iy<kernel_size;++iy)
00509                 {
00510                     double xpos = ix+0.5-kernel_size/2.;
00511                     double ypos = iy+0.5-kernel_size/2.;
00512                     double kernel_func = 1-sqrt(xpos*xpos+ypos*ypos)/
00513                     hawki_step_detect_obj_config.growing_radius;
00514                     if(kernel_func<0)
00515                         kernel_func = 0;
00516                     cpl_matrix_set(kernel, ix, iy, kernel_func);
00517                 }
00518             if (hawki_mask_convolve(object_mask, kernel) != CPL_ERROR_NONE) {
00519                 cpl_mask_delete(object_mask) ;
00520                 cpl_matrix_delete(kernel) ;
00521                 return NULL;
00522             }
00523             cpl_matrix_delete(kernel);
00524         }
00525     
00526         /* Put the mask and the chip image in the imagelist */
00527         mask_image[idet] =  cpl_image_new_from_mask(object_mask);
00528         comb_image[idet] =  chip_image;
00529         
00530         /* Labelise the different detected apertures */
00531         cpl_msg_info(__func__, "Labelise mask") ;
00532         labels = cpl_image_labelise_mask_create(object_mask, &nobj);
00533         if (labels == NULL) 
00534         {
00535             int jdet;
00536             cpl_free(apertures);
00537             cpl_mask_delete(object_mask);
00538             for (jdet=0 ; jdet<idet + 1 ; jdet++)
00539             {
00540                 cpl_image_delete(mask_image[jdet]);
00541                 cpl_image_delete(comb_image[jdet]);
00542             }
00543         }
00544         cpl_msg_info(__func__, "Number of objects detected: %"CPL_SIZE_FORMAT,
00545                      nobj) ;
00546 
00547         /* Create the detected apertures list */
00548         cpl_msg_info(__func__, "Create apertures") ;
00549         apertures[idet] = cpl_apertures_new_from_image(chip_image, labels);
00550         if (apertures[idet] == NULL)
00551         {
00552             int jdet;
00553             cpl_free(apertures);
00554             cpl_mask_delete(object_mask);
00555             for (jdet=0 ; jdet<idet + 1 ; jdet++)
00556             {
00557                 cpl_image_delete(mask_image[jdet]);
00558                 cpl_image_delete(comb_image[jdet]);
00559             }
00560             return NULL;
00561         }
00562         
00563         /* Free */
00564         cpl_mask_delete(object_mask);
00565         cpl_image_delete(labels);
00566         cpl_msg_indent_less();
00567     }
00568 
00569     /* Free and return */
00570     cpl_msg_indent_less();
00571     return apertures;
00572 }
00573 
00574 /*----------------------------------------------------------------------------*/
00581 /*----------------------------------------------------------------------------*/
00582 static int hawki_step_detect_obj_aper_params
00583 (cpl_image      **  combined_images, 
00584  cpl_apertures  **  apertures,
00585  cpl_table      **  obj_charac)
00586 {
00587     int                 nb_objs ;
00588     double              angle ;
00589     double          *   fwhms_x ;
00590     double          *   fwhms_y ;
00591     cpl_bivector    *   iqe ;
00592     int                 nb_good ;
00593     cpl_vector      *   fwhms_good ;
00594     double          *   fwhms_good_data ;
00595     double              f_min, f_max, fr, fx, fy ;
00596     int                 chip;
00597     int                 iobj;
00598     int                 j;
00599     
00600     /* Initialise */
00601     double              seeing_min_arcsec = 0.1 ;
00602     double              seeing_max_arcsec = 5.0 ;
00603     double              seeing_fwhm_var   = 0.2 ;
00604 
00605     /* Check entries */
00606     if (combined_images  == NULL) return -1 ;
00607     if (obj_charac       == NULL) return -1 ;
00608 
00609     /* Loop on the HAWK-I detectors */
00610     cpl_msg_indent_more();
00611     for (chip=0 ; chip<HAWKI_NB_DETECTORS ; chip++) 
00612     {
00613 
00614         /* Number of detected objects */
00615         nb_objs = cpl_apertures_get_size(apertures[chip]);
00616         cpl_msg_info(__func__, "%d objects detected on chip %d",nb_objs,chip+1);
00617         hawki_step_detect_obj_output.nbobjs[chip] = nb_objs ;
00618         fwhms_x = cpl_malloc(nb_objs * sizeof(double)) ;
00619         fwhms_y = cpl_malloc(nb_objs * sizeof(double)) ;
00620         
00621         /* Initialize the output table */
00622         cpl_table_set_size(obj_charac[chip], nb_objs);
00623         cpl_table_new_column
00624             (obj_charac[chip], HAWKI_COL_OBJ_POSX, CPL_TYPE_DOUBLE);
00625         cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_POSX,"pix");
00626         cpl_table_new_column
00627             (obj_charac[chip], HAWKI_COL_OBJ_POSY, CPL_TYPE_DOUBLE);
00628         cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_POSY,"pix");
00629         cpl_table_new_column
00630             (obj_charac[chip], HAWKI_COL_OBJ_ANGLE, CPL_TYPE_DOUBLE);
00631         cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_ANGLE,"grad");
00632         cpl_table_new_column
00633             (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MAJAX, CPL_TYPE_DOUBLE);
00634         cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_FWHM_MAJAX,"pix");
00635         cpl_table_new_column
00636             (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MINAX, CPL_TYPE_DOUBLE);
00637         cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_FWHM_MINAX,"pix");
00638         cpl_table_new_column
00639             (obj_charac[chip], HAWKI_COL_OBJ_ELLIP, CPL_TYPE_DOUBLE);
00640         cpl_table_new_column
00641             (obj_charac[chip], HAWKI_COL_OBJ_FLUX, CPL_TYPE_DOUBLE);
00642         cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_FLUX,"ADU");
00643         for (iobj=0 ; iobj<nb_objs ; iobj++)
00644         {
00645             /* Fill with the already known information */
00646             cpl_table_set_double(obj_charac[chip], HAWKI_COL_OBJ_POSX, iobj, 
00647                                  cpl_apertures_get_centroid_x(apertures[chip],
00648                                                               iobj+1));
00649             cpl_table_set_double(obj_charac[chip], HAWKI_COL_OBJ_POSY, iobj, 
00650                                  cpl_apertures_get_centroid_y(apertures[chip],
00651                                                               iobj+1));
00652             cpl_table_set_double(obj_charac[chip], HAWKI_COL_OBJ_FLUX, iobj, 
00653                                  cpl_apertures_get_flux(apertures[chip],
00654                                                         iobj+1));
00655             /* Compute the FWHM informations */
00656             iqe = cpl_image_iqe(combined_images[chip], 
00657                 (int)cpl_apertures_get_centroid_x(apertures[chip], iobj+1)- 10,
00658                 (int)cpl_apertures_get_centroid_y(apertures[chip], iobj+1)- 10,
00659                 (int)cpl_apertures_get_centroid_x(apertures[chip], iobj+1)+ 10,
00660                 (int)cpl_apertures_get_centroid_y(apertures[chip], iobj+1)+ 10);
00661             if (iqe == NULL)
00662             {
00663                 cpl_error_reset() ;
00664                 cpl_msg_debug(__func__, "Cannot get FWHM for obj at pos %g %g",
00665                               cpl_apertures_get_centroid_x(apertures[chip],
00666                                                            iobj+1),
00667                               cpl_apertures_get_centroid_y(apertures[chip],
00668                                                            iobj+1)) ;
00669                 fwhms_x[iobj] = -1.0 ;
00670                 fwhms_y[iobj] = -1.0 ;
00671                 angle = 0.0 ;
00672             }
00673             else 
00674             {
00675                 fwhms_x[iobj] = cpl_vector_get(cpl_bivector_get_x(iqe), 2) ;
00676                 fwhms_y[iobj] = cpl_vector_get(cpl_bivector_get_x(iqe), 3) ;
00677                 angle = cpl_vector_get(cpl_bivector_get_x(iqe), 4) ;
00678                 cpl_bivector_delete(iqe) ;
00679                 cpl_msg_debug(__func__,
00680                               "FWHM for obj at pos %g %g: %g x %g (%g)",
00681                               cpl_apertures_get_centroid_x(apertures[chip],
00682                                                            iobj+1),
00683                               cpl_apertures_get_centroid_y(apertures[chip],
00684                                                            iobj+1),
00685                               fwhms_x[iobj], fwhms_y[iobj], angle) ;
00686             }
00687             cpl_table_set_double
00688                 (obj_charac[chip], HAWKI_COL_OBJ_ANGLE, iobj, angle) ;
00689             cpl_table_set_double
00690                 (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MAJAX, iobj,
00691                  fwhms_x[iobj]);
00692             cpl_table_set_double
00693                 (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MINAX, iobj,
00694                  fwhms_y[iobj]);
00695             cpl_table_set_double
00696                 (obj_charac[chip], HAWKI_COL_OBJ_ELLIP, iobj,
00697                  1 - fwhms_y[iobj] / fwhms_x[iobj]);
00698         }
00699 
00700         /* Get the number of good values */
00701         nb_good = 0 ;
00702         for (iobj=0 ; iobj<nb_objs ; iobj++) 
00703         {
00704             if ((fwhms_x[iobj] > 0.0) && (fwhms_y[iobj] > 0.0)) nb_good++ ;
00705         }
00706         if (nb_good == 0) 
00707         {
00708             cpl_msg_warning
00709                 (__func__, "No objects to compute mean FWHM on chip %d",chip+1);
00710             cpl_free(fwhms_x) ;
00711             cpl_free(fwhms_y) ;
00712             continue;
00713         }
00714     
00715         /* Get the good values */
00716         fwhms_good = cpl_vector_new(nb_good) ;
00717         fwhms_good_data = cpl_vector_get_data(fwhms_good) ;
00718         j=0 ;
00719         for (iobj=0 ; iobj<nb_objs ; iobj++) 
00720         {
00721             if ((fwhms_x[iobj] > 0.0) && (fwhms_y[iobj] > 0.0)) 
00722             {
00723                 fwhms_good_data[j] = (fwhms_x[iobj]+fwhms_y[iobj])/2.0 ;
00724                 j++ ;
00725             }
00726         }
00727    
00728         /* Compute the fwhm */
00729         if (nb_good < 3) 
00730         {
00731             /* Too few values to compute the median */
00732             hawki_step_detect_obj_output.fwhm_pix[chip] = fwhms_good_data[0] ;
00733             cpl_msg_warning
00734                 (__func__, "Fewer than 3 objects, using the first object FWHM");
00735         } 
00736         else 
00737         {
00738             /* Compute the median */
00739             hawki_step_detect_obj_output.fwhm_pix[chip] =
00740                 cpl_vector_get_median_const(fwhms_good);
00741         }
00742         hawki_step_detect_obj_output.fwhm_arcsec[chip] = 
00743             hawki_step_detect_obj_output.fwhm_pix[chip] *
00744                 hawki_step_detect_obj_output.pixscale ;
00745 
00746         /* Compute the mode of the FWHMs */
00747         if (nb_good > 5)
00748         {
00749             hawki_step_detect_obj_output.fwhm_mode[chip] =
00750                 hawki_vector_get_mode(fwhms_good);
00751             hawki_step_detect_obj_output.fwhm_mode[chip] *= 
00752                 hawki_step_detect_obj_output.pixscale;
00753         }
00754         cpl_vector_delete(fwhms_good);
00755     
00756         /* IQ is the median of the (fwhm_x+fwhm_y/2) of the good stars */
00757         /* Compute f_min and f_max */
00758         f_min = seeing_min_arcsec / hawki_step_detect_obj_output.pixscale;
00759         f_max = seeing_max_arcsec / hawki_step_detect_obj_output.pixscale; 
00760 
00761         /* Get the number of good values */
00762         nb_good = 0 ;
00763         for (iobj=0 ; iobj<nb_objs ; iobj++) 
00764         {
00765             fx = fwhms_x[iobj] ;
00766             fy = fwhms_y[iobj] ;
00767             fr = 2.0 * fabs(fx-fy) / (fx+fy) ;
00768             if ((fx > f_min) && (fx < f_max) && (fy > f_min) && (fy < f_max) &&
00769                     (fr < seeing_fwhm_var)) nb_good++ ;
00770         }
00771         if (nb_good == 0) 
00772         {
00773             cpl_msg_warning(__func__, "No objects to compute IQ on chip %d",
00774                             chip+1);
00775             cpl_free(fwhms_x) ;
00776             cpl_free(fwhms_y) ;
00777             continue;
00778         }
00779 
00780         /* Get the good values */
00781         fwhms_good = cpl_vector_new(nb_good) ;
00782         fwhms_good_data = cpl_vector_get_data(fwhms_good) ;
00783         j=0 ;
00784         for (iobj=0 ; iobj<nb_objs ; iobj++) 
00785         {
00786             fx = fwhms_x[iobj] ;
00787             fy = fwhms_y[iobj] ;
00788             fr = 2.0 * fabs(fx-fy) / (fx+fy) ;
00789             if ((fx > f_min) && (fx < f_max) && (fy > f_min) && (fy < f_max) &&
00790                     (fr < seeing_fwhm_var)) 
00791             {
00792                 fwhms_good_data[j] = (fx + fy)/2.0 ;
00793                 j++ ;
00794             }
00795         }
00796         cpl_free(fwhms_x) ;
00797         cpl_free(fwhms_y) ;
00798     
00799         /* Compute the fwhm */
00800         if (nb_good < 3) 
00801         {
00802             /* Too few values to compute the median */
00803             hawki_step_detect_obj_output.iq[chip] = fwhms_good_data[0] ;
00804         }
00805         else 
00806         {
00807             /* Compute the median */
00808             hawki_step_detect_obj_output.iq[chip] = 
00809                 cpl_vector_get_median_const(fwhms_good) ;
00810         }
00811         cpl_vector_delete(fwhms_good);
00812         hawki_step_detect_obj_output.iq[chip] *= 
00813             hawki_step_detect_obj_output.pixscale;
00814     }
00815     cpl_msg_indent_less();
00816     
00817     return 0;
00818 }
00819         
00820         
00821 /*----------------------------------------------------------------------------*/
00830 /*----------------------------------------------------------------------------*/
00831 static int hawki_step_detect_obj_save
00832 (cpl_image           **  mask_images,
00833  cpl_table           **  obj_charac,
00834  cpl_propertylist    **  obj_stats,
00835  cpl_parameterlist   *   parlist,
00836  cpl_frameset        *   framelist)
00837 {
00838     const cpl_frame     *   ref_frame ;
00839     cpl_propertylist    **  qclists;
00840     int                     ext_nb ;
00841     const char          *   recipe_name = "hawki_step_detect_obj" ;
00842     int                     i;
00843     cpl_errorstate          error_prevstate = cpl_errorstate_get();
00844     
00845 
00846 
00847     /* Load the WCS keys */
00848     ref_frame = irplib_frameset_get_first_from_group
00849         (framelist, CPL_FRAME_GROUP_RAW);
00850 
00851     /* Create the QC lists */
00852     qclists = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
00853     for (i=0 ; i<HAWKI_NB_DETECTORS ; i++)
00854     {
00855         cpl_propertylist    *   inputlist;
00856         cpl_propertylist    *   offsetlist;
00857         cpl_propertylist    *   wcslist;
00858 
00859         /* Get the extension number */
00860         ext_nb=hawki_get_ext_from_detector(cpl_frame_get_filename(ref_frame), i+1);
00861         qclists[i] = cpl_propertylist_new() ;
00862 
00863         /* Fill the QC */
00864         cpl_propertylist_append_int
00865             (qclists[i], "ESO QC NBOBJS", 
00866              hawki_step_detect_obj_output.nbobjs[i]);
00867         cpl_propertylist_append_double
00868             (qclists[i], "ESO QC IQ", hawki_step_detect_obj_output.iq[i]);
00869         cpl_propertylist_append_double
00870             (qclists[i], "ESO QC FWHM PIX",
00871              hawki_step_detect_obj_output.fwhm_pix[i]);
00872         cpl_propertylist_append_double
00873             (qclists[i], "ESO QC FWHM ARCSEC",
00874              hawki_step_detect_obj_output.fwhm_arcsec[i]);
00875         cpl_propertylist_append_double
00876             (qclists[i], "ESO QC FWHM MODE",
00877              hawki_step_detect_obj_output.fwhm_mode[i]);
00878 
00879         /* Propagate some keywords from input raw frame extensions */
00880         inputlist = cpl_propertylist_load_regexp(
00881                 cpl_frame_get_filename(ref_frame), ext_nb,
00882                 HAWKI_HEADER_EXT_FORWARD, 0);
00883         offsetlist = cpl_propertylist_load_regexp(
00884                 cpl_frame_get_filename(ref_frame), ext_nb,
00885                 HAWKI_HEADER_COMB_OFFSETS, 0);
00886         wcslist = cpl_propertylist_load_regexp(
00887                 cpl_frame_get_filename(ref_frame), ext_nb,
00888                 HAWKI_HEADER_WCS, 0);
00889         cpl_propertylist_append(qclists[i], inputlist);
00890         cpl_propertylist_append(qclists[i], offsetlist);
00891         cpl_propertylist_append(qclists[i], wcslist);
00892         cpl_propertylist_delete(inputlist);
00893         cpl_propertylist_delete(offsetlist);
00894         cpl_propertylist_delete(wcslist);
00895         
00896         /* Add the object statistics keywords */
00897         cpl_propertylist_append(qclists[i], obj_stats[i]);
00898     }
00899 
00900 
00901     /* Write the object mask */
00902     hawki_images_save(framelist,
00903                       parlist,
00904                       framelist, 
00905                       (const cpl_image**)mask_images, 
00906                       recipe_name,
00907                       HAWKI_CALPRO_OBJ_MASK, 
00908                       HAWKI_PROTYPE_OBJ_MASK,
00909                       NULL,
00910                       (const cpl_propertylist**)qclists,
00911                       "hawki_step_detect_obj_mask.fits") ;
00912 
00913     /* Write the FITS table with the objects statistics */
00914     hawki_tables_save(framelist,
00915                       parlist,
00916                       framelist,    
00917                       (const cpl_table **)obj_charac,
00918                       recipe_name,
00919                       HAWKI_CALPRO_OBJ_PARAM,
00920                       HAWKI_PROTYPE_OBJ_PARAM,
00921                       NULL,
00922                       (const cpl_propertylist**)qclists,
00923                       "hawki_step_detect_obj_stars.fits") ;
00924 
00925 
00926     /* Free and return */
00927     for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) {
00928         cpl_propertylist_delete(qclists[i]) ;
00929     }
00930     cpl_free(qclists) ;
00931     if(!cpl_errorstate_is_equal(error_prevstate))
00932     {
00933         cpl_errorstate_set(CPL_ERROR_NONE);
00934         return -1;
00935     }
00936     return  0;
00937 }
00938 
00939 static void hawki_step_detect_obj_init_output(void)
00940 {
00941     int    idet;
00942     
00943     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) 
00944     {
00945         hawki_step_detect_obj_output.iq[idet] = -1.0 ;
00946         hawki_step_detect_obj_output.nbobjs[idet] = -1 ;
00947         hawki_step_detect_obj_output.fwhm_pix[idet] = -1.0 ;
00948         hawki_step_detect_obj_output.fwhm_arcsec[idet] = -1.0 ;
00949         hawki_step_detect_obj_output.fwhm_mode[idet] = -1.0 ;
00950         hawki_step_detect_obj_output.pos_x[idet] = -1.0 ;
00951         hawki_step_detect_obj_output.pos_y[idet] = -1.0 ;
00952     }
00953     hawki_step_detect_obj_output.pixscale = -1.0;
00954 }
00955 
00956 static void hawki_step_detect_obj_get_pscale
00957 (cpl_frameset * combframes)
00958 {
00959     cpl_propertylist  * plist;
00960     cpl_frame         * firstframe;
00961     cpl_errorstate      error_prevstate = cpl_errorstate_get();
00962     
00963     /* Get the header infos */
00964     firstframe = cpl_frameset_get_frame(combframes, 0) ;
00965     plist=cpl_propertylist_load(cpl_frame_get_filename(firstframe), 0) ;
00966     hawki_step_detect_obj_output.pixscale = hawki_pfits_get_pixscale(plist);
00967     cpl_propertylist_delete(plist) ;
00968     if(!cpl_errorstate_is_equal(error_prevstate))
00969     {
00970         cpl_msg_error(__func__, "Missing PIXSCALE keyword in FITS header") ;
00971         cpl_errorstate_set(CPL_ERROR_NONE);
00972         return;
00973     }
00974 }
00975