HAWKI Pipeline Reference Manual  1.8.12
hawki_step_detect_obj.c
1 /* $Id: hawki_step_detect_obj.c,v 1.27 2012/11/30 14:50:51 cgarcia Exp $
2  *
3  * This file is part of the HAWKI Pipeline
4  * Copyright (C) 2002,2003 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: cgarcia $
23  * $Date: 2012/11/30 14:50:51 $
24  * $Revision: 1.27 $
25  * $Name: hawki-1_8_12 $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include <math.h>
37 #include <cpl.h>
38 #include <string.h>
39 
40 #include "irplib_utils.h"
41 #include "irplib_calib.h"
42 
43 #include "hawki_utils.h"
44 #include "hawki_obj_det.h"
45 #include "hawki_mask.h"
46 #include "hawki_image_stats.h"
47 #include "hawki_calib.h"
48 #include "hawki_load.h"
49 #include "hawki_save.h"
50 #include "hawki_pfits.h"
51 #include "hawki_dfs.h"
52 
53 /*-----------------------------------------------------------------------------
54  Functions prototypes
55  -----------------------------------------------------------------------------*/
56 
57 #ifdef __cplusplus
58 extern "C"
59 #endif
60 int cpl_plugin_get_info(cpl_pluginlist * list);
61 
62 static int hawki_step_detect_obj_create(cpl_plugin *) ;
63 static int hawki_step_detect_obj_exec(cpl_plugin *) ;
64 static int hawki_step_detect_obj_destroy(cpl_plugin *) ;
65 static int hawki_step_detect_obj(cpl_parameterlist *, cpl_frameset *) ;
66 
67 static void hawki_step_detect_obj_init_output(void);
68 static void hawki_step_detect_obj_get_pscale
69 (cpl_frameset * combframes);
70 static int hawki_step_detect_obj_retrieve_input_param
71 (cpl_parameterlist * parlist);
72 static cpl_apertures ** hawki_step_detect_obj_mask_and_apertures
73 (cpl_frameset * combframes,
74  cpl_image ** mask_image,
75  cpl_image ** comb_image);
76 static int hawki_step_detect_obj_aper_params
77 (cpl_image ** combined_images,
78  cpl_apertures ** apertures,
79  cpl_table ** obj_charac);
80 static int hawki_step_detect_obj_save
81 (cpl_image ** mask_images,
82  cpl_table ** obj_charac,
83  cpl_propertylist ** obj_stats,
84  cpl_parameterlist * parlist,
85  cpl_frameset * framelist);
86 
87 /*-----------------------------------------------------------------------------
88  Static variables
89  -----------------------------------------------------------------------------*/
90 
91 static struct
92 {
93  /* Inputs */
94  double sigma_det;
95  int growing_radius;
96 } hawki_step_detect_obj_config;
97 
98 static struct
99 {
100  /* Outputs */
101  double pixscale;
102  double iq[HAWKI_NB_DETECTORS] ;
103  int nbobjs[HAWKI_NB_DETECTORS] ;
104  double fwhm_pix[HAWKI_NB_DETECTORS] ;
105  double fwhm_arcsec[HAWKI_NB_DETECTORS] ;
106  double fwhm_mode[HAWKI_NB_DETECTORS] ;
107  double pos_x[HAWKI_NB_DETECTORS] ;
108  double pos_y[HAWKI_NB_DETECTORS] ;
109 } hawki_step_detect_obj_output;
110 
111 static char hawki_step_detect_obj_description[] =
112 "hawki_step_detect_obj -- hawki detect objects recipe.\n"
113 "This recipe detects objects from the combined image creating a mask\n"
114 "and a list of object properties\n"
115 "The input of the recipe files listed in the Set Of Frames (sof-file)\n"
116 "must be tagged as:\n"
117 "combined.fits "HAWKI_CALPRO_COMBINED"\n"
118 "The recipe creates as an output:\n"
119 "hawki_step_detect_obj_mask.fits ("HAWKI_CALPRO_OBJ_MASK"): A mask with 1 where the objects are present and 0 elsewhere\n"
120 "hawki_step_detect_obj_stars.fits ("HAWKI_CALPRO_OBJ_PARAM"): A table with the detected objects characteristics\n"
121 "Return code:\n"
122 "esorex exits with an error code of 0 if the recipe completes successfully\n"
123 "or 1 otherwise";
124 
125 
126 
127 /*-----------------------------------------------------------------------------
128  Functions code
129  -----------------------------------------------------------------------------*/
130 
131 /*----------------------------------------------------------------------------*/
139 /*----------------------------------------------------------------------------*/
140 int cpl_plugin_get_info(cpl_pluginlist * list)
141 {
142  cpl_recipe * recipe = cpl_calloc(1, sizeof(*recipe)) ;
143  cpl_plugin * plugin = &recipe->interface ;
144 
145  cpl_plugin_init(plugin,
146  CPL_PLUGIN_API,
147  HAWKI_BINARY_VERSION,
148  CPL_PLUGIN_TYPE_RECIPE,
149  "hawki_step_detect_obj",
150  "Object detection recipe",
151  hawki_step_detect_obj_description,
152  "Cesar Enrique Garcia Dabo",
153  PACKAGE_BUGREPORT,
155  hawki_step_detect_obj_create,
156  hawki_step_detect_obj_exec,
157  hawki_step_detect_obj_destroy) ;
158 
159  cpl_pluginlist_append(list, plugin) ;
160 
161  return 0;
162 }
163 
164 /*----------------------------------------------------------------------------*/
173 /*----------------------------------------------------------------------------*/
174 static int hawki_step_detect_obj_create(cpl_plugin * plugin)
175 {
176  cpl_recipe * recipe ;
177  cpl_parameter * p ;
178 
179  /* Get the recipe out of the plugin */
180  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
181  recipe = (cpl_recipe *)plugin ;
182  else return -1 ;
183 
184  /* Create the parameters list in the cpl_recipe object */
185  recipe->parameters = cpl_parameterlist_new() ;
186  if (recipe->parameters == NULL)
187  return 1;
188 
189  /* Fill the parameters list */
190  /* --sigma_det */
191  p = cpl_parameter_new_value("hawki.hawki_step_detect_obj.sigma_det",
192  CPL_TYPE_DOUBLE, "detection level",
193  "hawki.hawki_step_detect_obj", 6.);
194  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sigma_det");
195  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
196  cpl_parameterlist_append(recipe->parameters, p);
197 
198  /* --growing_radius */
199  p = cpl_parameter_new_value("hawki.hawki_step_detect_obj.growing_radius",
200  CPL_TYPE_INT,
201  "radius of convolution kernel to apply to objects",
202  "hawki.hawki_step_detect_obj", 5);
203  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "growing_radius");
204  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
205  cpl_parameterlist_append(recipe->parameters, p);
206 
207  /* Return */
208  return 0;
209 }
210 
211 /*----------------------------------------------------------------------------*/
217 /*----------------------------------------------------------------------------*/
218 static int hawki_step_detect_obj_exec(cpl_plugin * plugin)
219 {
220  cpl_recipe * recipe ;
221 
222  /* Get the recipe out of the plugin */
223  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
224  recipe = (cpl_recipe *)plugin ;
225  else return -1 ;
226 
227  /* Issue a banner */
229 
230  return hawki_step_detect_obj(recipe->parameters, recipe->frames) ;
231 }
232 
233 /*----------------------------------------------------------------------------*/
239 /*----------------------------------------------------------------------------*/
240 static int hawki_step_detect_obj_destroy(cpl_plugin * plugin)
241 {
242  cpl_recipe * recipe ;
243 
244  /* Get the recipe out of the plugin */
245  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
246  recipe = (cpl_recipe *)plugin ;
247  else return -1 ;
248 
249  cpl_parameterlist_delete(recipe->parameters) ;
250  return 0 ;
251 }
252 
253 /*----------------------------------------------------------------------------*/
260 /*----------------------------------------------------------------------------*/
261 static int hawki_step_detect_obj(
262  cpl_parameterlist * parlist,
263  cpl_frameset * framelist)
264 {
265  cpl_frameset * combframes;
266  cpl_image ** mask_image;
267  cpl_image ** comb_image;
268  cpl_apertures ** apertures;
269  cpl_table ** obj_charac;
270  cpl_propertylist ** obj_stats;
271  int idet;
272 
273  /* Initialise */
274  hawki_step_detect_obj_init_output();
275 
276  /* Retrieve input parameters */
277  if(hawki_step_detect_obj_retrieve_input_param(parlist))
278  {
279  cpl_msg_error(__func__, "Wrong parameters");
280  return -1;
281  }
282 
283  /* Identify the RAW and CALIB frames in the input frameset */
284  if (hawki_dfs_set_groups(framelist)) {
285  cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
286  return -1 ;
287  }
288 
289  /* Retrieve raw frames */
290  combframes = hawki_extract_frameset(framelist, HAWKI_CALPRO_COMBINED) ;
291  if (combframes == NULL)
292  {
293  cpl_msg_error(__func__, "Cannot find combined images in the input (%s)",
294  HAWKI_CALPRO_COMBINED);
295  return -1 ;
296  }
297  if (cpl_frameset_get_size(combframes) != 1)
298  {
299  cpl_msg_error(__func__, "Only one combined image must be provided");
300  return -1 ;
301  }
302 
303  /* Get info from the headers */
304  hawki_step_detect_obj_get_pscale(combframes);
305 
306  /* Get the mask with the points above the background
307  * and the associated apertures*/
308  cpl_msg_info(__func__, "Getting the object masks") ;
309  mask_image = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_image *));
310  comb_image = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_image *));
311  apertures = hawki_step_detect_obj_mask_and_apertures
312  (combframes, mask_image, comb_image);
313  if(apertures == NULL)
314  {
315  cpl_msg_error(__func__,"Could not detect objects in image");
316  cpl_frameset_delete(combframes);
317  cpl_free(mask_image);
318  cpl_free(comb_image);
319  return -1;
320  }
321 
322  /* Get object characterizations and statistics */
323  cpl_msg_info(__func__, "Getting object parameters") ;
324  obj_charac = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_table *)) ;
325  obj_stats = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist *));
326  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
327  {
328  obj_charac[idet] = cpl_table_new
329  (cpl_apertures_get_size(apertures[idet]));
330  obj_stats[idet] = cpl_propertylist_new();
331  }
332  hawki_step_detect_obj_aper_params(comb_image, apertures, obj_charac);
333 
334  /* Statistics of the detected objects in the QC */
335  hawki_obj_prop_stats(obj_charac, obj_stats);
336 
337  /* Save the products */
338  cpl_msg_info(__func__, "Save the products") ;
339  if (hawki_step_detect_obj_save(mask_image, obj_charac, obj_stats,
340  parlist, framelist) == -1)
341  {
342  cpl_msg_warning(__func__, "Some data could not be saved. "
343  "Check permisions or disk space") ;
344  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
345  {
346  cpl_table_delete(obj_charac[idet]);
347  cpl_propertylist_delete(obj_stats[idet]);
348  cpl_apertures_delete(apertures[idet]);
349  }
350  cpl_free(apertures);
351  cpl_free(obj_charac);
352  cpl_free(obj_stats);
353  cpl_frameset_delete(combframes);
354  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
355  {
356  cpl_image_delete(mask_image[idet]);
357  cpl_image_delete(comb_image[idet]);
358  }
359  cpl_free(mask_image);
360  cpl_free(comb_image);
361  return -1 ;
362  }
363 
364  /* Return */
365  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
366  {
367  cpl_table_delete(obj_charac[idet]);
368  cpl_propertylist_delete(obj_stats[idet]);
369  cpl_apertures_delete(apertures[idet]);
370  cpl_image_delete(mask_image[idet]);
371  cpl_image_delete(comb_image[idet]);
372  }
373  cpl_free(apertures);
374  cpl_free(obj_charac);
375  cpl_free(obj_stats);
376  cpl_frameset_delete(combframes);
377  cpl_free(mask_image);
378  cpl_free(comb_image);
379 
380  /* Return */
381  if (cpl_error_get_code())
382  {
383  cpl_msg_error(__func__,
384  "HAWK-I pipeline could not recover from previous errors");
385  return -1 ;
386  }
387  else return 0 ;
388 }
389 
390 int hawki_step_detect_obj_retrieve_input_param
391 (cpl_parameterlist * parlist)
392 {
393  cpl_parameter * par ;
394 
395  par = NULL ;
396  par = cpl_parameterlist_find
397  (parlist, "hawki.hawki_step_detect_obj.sigma_det");
398  hawki_step_detect_obj_config.sigma_det = cpl_parameter_get_double(par);
399  par = cpl_parameterlist_find
400  (parlist, "hawki.hawki_step_detect_obj.growing_radius");
401  hawki_step_detect_obj_config.growing_radius = cpl_parameter_get_int(par);
402  if(hawki_step_detect_obj_config.growing_radius > 100)
403  {
404  cpl_msg_error(__func__,"The maximum radius allowed is 100");
405  return -1;
406  }
407  if(hawki_step_detect_obj_config.sigma_det <= 0 )
408  {
409  cpl_msg_error(__func__,"Detection sigma has to be greater than 0");
410  return -1;
411  }
412 
413  return 0;
414 }
415 
416 
417 
418 /*----------------------------------------------------------------------------*/
428 /*----------------------------------------------------------------------------*/
429 static cpl_apertures ** hawki_step_detect_obj_mask_and_apertures
430 (cpl_frameset * combframes,
431  cpl_image ** mask_image,
432  cpl_image ** comb_image)
433 {
434  cpl_apertures ** apertures;
435  int idet;
436 
437  /* Create output object */
438  apertures = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_apertures *));
439 
440  /* Loop on the detectors */
441  cpl_msg_indent_more();
442  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
443  {
444  cpl_image * chip_image;
445  cpl_image * chip_image_sort;
446  cpl_mask * object_mask;
447  cpl_mask * kernel_op;
448  cpl_matrix * kernel;
449  cpl_image * labels;
450  cpl_size nobj;
451  double bkg_level;
452  double bkg_noise;
453  double threshold;
454  int kernel_size;
455  int ix;
456  int iy;
457 
458  cpl_msg_info(__func__, "Detecting objects on chip number %d", idet+1) ;
459  cpl_msg_indent_more();
460 
461  /* Load the input data */
462  cpl_msg_info(__func__, "Load the input data") ;
463  chip_image = hawki_load_image(combframes, 0, idet+1, CPL_TYPE_FLOAT);
464  if (chip_image == NULL)
465  {
466  cpl_msg_error(__func__, "Cannot load chip %d", idet+1) ;
467  cpl_msg_indent_less() ;
468  cpl_free(apertures);
469  return NULL ;
470  }
471 
472  /* Subtract the median of the frame first */
473  chip_image_sort = cpl_image_duplicate(chip_image);
474  bkg_level = cpl_image_get_median(chip_image);
475  bkg_noise = hawki_image_float_get_sigma_from_quartile(chip_image_sort);
476  cpl_image_delete(chip_image_sort);
477  threshold = bkg_level + hawki_step_detect_obj_config.sigma_det * bkg_noise;
478  cpl_msg_info(__func__, "Background: %f",bkg_level);
479  cpl_msg_info(__func__, "Background noise: %f",bkg_noise);
480 
481  /* Create the mask */
482  cpl_msg_info(__func__, "Mask creation with threshold: %f",threshold);
483  object_mask = cpl_mask_threshold_image_create
484  (chip_image, threshold, DBL_MAX);
485 
486  /* Apply a morphological opening to remove single pixel detections */
487  cpl_msg_info(__func__, "Removing single pixel detections");
488  kernel_op = cpl_mask_new(3, 3);
489  cpl_mask_not(kernel_op);
490  if (cpl_mask_filter(object_mask, object_mask, kernel_op,
491  CPL_FILTER_OPENING,
492  CPL_BORDER_ZERO) != CPL_ERROR_NONE)
493  {
494  cpl_mask_delete(object_mask);
495  cpl_mask_delete(kernel_op);
496  return NULL;
497  }
498  cpl_mask_delete(kernel_op);
499 
500  /* Apply dilation to the mask */
501  if(hawki_step_detect_obj_config.growing_radius>0)
502  {
503  cpl_msg_info(__func__, "Growing the mask with radius %d",
504  hawki_step_detect_obj_config.growing_radius);
505  kernel_size = hawki_step_detect_obj_config.growing_radius*2+1;
506  kernel = cpl_matrix_new(kernel_size, kernel_size);
507  for(ix=0;ix<kernel_size;++ix)
508  for(iy=0;iy<kernel_size;++iy)
509  {
510  double xpos = ix+0.5-kernel_size/2.;
511  double ypos = iy+0.5-kernel_size/2.;
512  double kernel_func = 1-sqrt(xpos*xpos+ypos*ypos)/
513  hawki_step_detect_obj_config.growing_radius;
514  if(kernel_func<0)
515  kernel_func = 0;
516  cpl_matrix_set(kernel, ix, iy, kernel_func);
517  }
518  if (hawki_mask_convolve(object_mask, kernel) != CPL_ERROR_NONE) {
519  cpl_mask_delete(object_mask) ;
520  cpl_matrix_delete(kernel) ;
521  return NULL;
522  }
523  cpl_matrix_delete(kernel);
524  }
525 
526  /* Put the mask and the chip image in the imagelist */
527  mask_image[idet] = cpl_image_new_from_mask(object_mask);
528  comb_image[idet] = chip_image;
529 
530  /* Labelise the different detected apertures */
531  cpl_msg_info(__func__, "Labelise mask") ;
532  labels = cpl_image_labelise_mask_create(object_mask, &nobj);
533  if (labels == NULL)
534  {
535  int jdet;
536  cpl_free(apertures);
537  cpl_mask_delete(object_mask);
538  for (jdet=0 ; jdet<idet + 1 ; jdet++)
539  {
540  cpl_image_delete(mask_image[jdet]);
541  cpl_image_delete(comb_image[jdet]);
542  }
543  }
544  cpl_msg_info(__func__, "Number of objects detected: %"CPL_SIZE_FORMAT,
545  nobj) ;
546 
547  /* Create the detected apertures list */
548  cpl_msg_info(__func__, "Create apertures") ;
549  apertures[idet] = cpl_apertures_new_from_image(chip_image, labels);
550  if (apertures[idet] == NULL)
551  {
552  int jdet;
553  cpl_free(apertures);
554  cpl_mask_delete(object_mask);
555  for (jdet=0 ; jdet<idet + 1 ; jdet++)
556  {
557  cpl_image_delete(mask_image[jdet]);
558  cpl_image_delete(comb_image[jdet]);
559  }
560  return NULL;
561  }
562 
563  /* Free */
564  cpl_mask_delete(object_mask);
565  cpl_image_delete(labels);
566  cpl_msg_indent_less();
567  }
568 
569  /* Free and return */
570  cpl_msg_indent_less();
571  return apertures;
572 }
573 
574 /*----------------------------------------------------------------------------*/
581 /*----------------------------------------------------------------------------*/
582 static int hawki_step_detect_obj_aper_params
583 (cpl_image ** combined_images,
584  cpl_apertures ** apertures,
585  cpl_table ** obj_charac)
586 {
587  int nb_objs ;
588  double angle ;
589  double * fwhms_x ;
590  double * fwhms_y ;
591  cpl_bivector * iqe ;
592  int nb_good ;
593  cpl_vector * fwhms_good ;
594  double * fwhms_good_data ;
595  double f_min, f_max, fr, fx, fy ;
596  int chip;
597  int iobj;
598  int j;
599 
600  /* Initialise */
601  double seeing_min_arcsec = 0.1 ;
602  double seeing_max_arcsec = 5.0 ;
603  double seeing_fwhm_var = 0.2 ;
604 
605  /* Check entries */
606  if (combined_images == NULL) return -1 ;
607  if (obj_charac == NULL) return -1 ;
608 
609  /* Loop on the HAWK-I detectors */
610  cpl_msg_indent_more();
611  for (chip=0 ; chip<HAWKI_NB_DETECTORS ; chip++)
612  {
613 
614  /* Number of detected objects */
615  nb_objs = cpl_apertures_get_size(apertures[chip]);
616  cpl_msg_info(__func__, "%d objects detected on chip %d",nb_objs,chip+1);
617  hawki_step_detect_obj_output.nbobjs[chip] = nb_objs ;
618  fwhms_x = cpl_malloc(nb_objs * sizeof(double)) ;
619  fwhms_y = cpl_malloc(nb_objs * sizeof(double)) ;
620 
621  /* Initialize the output table */
622  cpl_table_set_size(obj_charac[chip], nb_objs);
623  cpl_table_new_column
624  (obj_charac[chip], HAWKI_COL_OBJ_POSX, CPL_TYPE_DOUBLE);
625  cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_POSX,"pix");
626  cpl_table_new_column
627  (obj_charac[chip], HAWKI_COL_OBJ_POSY, CPL_TYPE_DOUBLE);
628  cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_POSY,"pix");
629  cpl_table_new_column
630  (obj_charac[chip], HAWKI_COL_OBJ_ANGLE, CPL_TYPE_DOUBLE);
631  cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_ANGLE,"grad");
632  cpl_table_new_column
633  (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MAJAX, CPL_TYPE_DOUBLE);
634  cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_FWHM_MAJAX,"pix");
635  cpl_table_new_column
636  (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MINAX, CPL_TYPE_DOUBLE);
637  cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_FWHM_MINAX,"pix");
638  cpl_table_new_column
639  (obj_charac[chip], HAWKI_COL_OBJ_ELLIP, CPL_TYPE_DOUBLE);
640  cpl_table_new_column
641  (obj_charac[chip], HAWKI_COL_OBJ_FLUX, CPL_TYPE_DOUBLE);
642  cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_FLUX,"ADU");
643  for (iobj=0 ; iobj<nb_objs ; iobj++)
644  {
645  /* Fill with the already known information */
646  cpl_table_set_double(obj_charac[chip], HAWKI_COL_OBJ_POSX, iobj,
647  cpl_apertures_get_centroid_x(apertures[chip],
648  iobj+1));
649  cpl_table_set_double(obj_charac[chip], HAWKI_COL_OBJ_POSY, iobj,
650  cpl_apertures_get_centroid_y(apertures[chip],
651  iobj+1));
652  cpl_table_set_double(obj_charac[chip], HAWKI_COL_OBJ_FLUX, iobj,
653  cpl_apertures_get_flux(apertures[chip],
654  iobj+1));
655  /* Compute the FWHM informations */
656  iqe = cpl_image_iqe(combined_images[chip],
657  (int)cpl_apertures_get_centroid_x(apertures[chip], iobj+1)- 10,
658  (int)cpl_apertures_get_centroid_y(apertures[chip], iobj+1)- 10,
659  (int)cpl_apertures_get_centroid_x(apertures[chip], iobj+1)+ 10,
660  (int)cpl_apertures_get_centroid_y(apertures[chip], iobj+1)+ 10);
661  if (iqe == NULL)
662  {
663  cpl_error_reset() ;
664  cpl_msg_debug(__func__, "Cannot get FWHM for obj at pos %g %g",
665  cpl_apertures_get_centroid_x(apertures[chip],
666  iobj+1),
667  cpl_apertures_get_centroid_y(apertures[chip],
668  iobj+1)) ;
669  fwhms_x[iobj] = -1.0 ;
670  fwhms_y[iobj] = -1.0 ;
671  angle = 0.0 ;
672  }
673  else
674  {
675  fwhms_x[iobj] = cpl_vector_get(cpl_bivector_get_x(iqe), 2) ;
676  fwhms_y[iobj] = cpl_vector_get(cpl_bivector_get_x(iqe), 3) ;
677  angle = cpl_vector_get(cpl_bivector_get_x(iqe), 4) ;
678  cpl_bivector_delete(iqe) ;
679  cpl_msg_debug(__func__,
680  "FWHM for obj at pos %g %g: %g x %g (%g)",
681  cpl_apertures_get_centroid_x(apertures[chip],
682  iobj+1),
683  cpl_apertures_get_centroid_y(apertures[chip],
684  iobj+1),
685  fwhms_x[iobj], fwhms_y[iobj], angle) ;
686  }
687  cpl_table_set_double
688  (obj_charac[chip], HAWKI_COL_OBJ_ANGLE, iobj, angle) ;
689  cpl_table_set_double
690  (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MAJAX, iobj,
691  fwhms_x[iobj]);
692  cpl_table_set_double
693  (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MINAX, iobj,
694  fwhms_y[iobj]);
695  cpl_table_set_double
696  (obj_charac[chip], HAWKI_COL_OBJ_ELLIP, iobj,
697  1 - fwhms_y[iobj] / fwhms_x[iobj]);
698  }
699 
700  /* Get the number of good values */
701  nb_good = 0 ;
702  for (iobj=0 ; iobj<nb_objs ; iobj++)
703  {
704  if ((fwhms_x[iobj] > 0.0) && (fwhms_y[iobj] > 0.0)) nb_good++ ;
705  }
706  if (nb_good == 0)
707  {
708  cpl_msg_warning
709  (__func__, "No objects to compute mean FWHM on chip %d",chip+1);
710  cpl_free(fwhms_x) ;
711  cpl_free(fwhms_y) ;
712  continue;
713  }
714 
715  /* Get the good values */
716  fwhms_good = cpl_vector_new(nb_good) ;
717  fwhms_good_data = cpl_vector_get_data(fwhms_good) ;
718  j=0 ;
719  for (iobj=0 ; iobj<nb_objs ; iobj++)
720  {
721  if ((fwhms_x[iobj] > 0.0) && (fwhms_y[iobj] > 0.0))
722  {
723  fwhms_good_data[j] = (fwhms_x[iobj]+fwhms_y[iobj])/2.0 ;
724  j++ ;
725  }
726  }
727 
728  /* Compute the fwhm */
729  if (nb_good < 3)
730  {
731  /* Too few values to compute the median */
732  hawki_step_detect_obj_output.fwhm_pix[chip] = fwhms_good_data[0] ;
733  cpl_msg_warning
734  (__func__, "Fewer than 3 objects, using the first object FWHM");
735  }
736  else
737  {
738  /* Compute the median */
739  hawki_step_detect_obj_output.fwhm_pix[chip] =
740  cpl_vector_get_median_const(fwhms_good);
741  }
742  hawki_step_detect_obj_output.fwhm_arcsec[chip] =
743  hawki_step_detect_obj_output.fwhm_pix[chip] *
744  hawki_step_detect_obj_output.pixscale ;
745 
746  /* Compute the mode of the FWHMs */
747  if (nb_good > 5)
748  {
749  hawki_step_detect_obj_output.fwhm_mode[chip] =
750  hawki_vector_get_mode(fwhms_good);
751  hawki_step_detect_obj_output.fwhm_mode[chip] *=
752  hawki_step_detect_obj_output.pixscale;
753  }
754  cpl_vector_delete(fwhms_good);
755 
756  /* IQ is the median of the (fwhm_x+fwhm_y/2) of the good stars */
757  /* Compute f_min and f_max */
758  f_min = seeing_min_arcsec / hawki_step_detect_obj_output.pixscale;
759  f_max = seeing_max_arcsec / hawki_step_detect_obj_output.pixscale;
760 
761  /* Get the number of good values */
762  nb_good = 0 ;
763  for (iobj=0 ; iobj<nb_objs ; iobj++)
764  {
765  fx = fwhms_x[iobj] ;
766  fy = fwhms_y[iobj] ;
767  fr = 2.0 * fabs(fx-fy) / (fx+fy) ;
768  if ((fx > f_min) && (fx < f_max) && (fy > f_min) && (fy < f_max) &&
769  (fr < seeing_fwhm_var)) nb_good++ ;
770  }
771  if (nb_good == 0)
772  {
773  cpl_msg_warning(__func__, "No objects to compute IQ on chip %d",
774  chip+1);
775  cpl_free(fwhms_x) ;
776  cpl_free(fwhms_y) ;
777  continue;
778  }
779 
780  /* Get the good values */
781  fwhms_good = cpl_vector_new(nb_good) ;
782  fwhms_good_data = cpl_vector_get_data(fwhms_good) ;
783  j=0 ;
784  for (iobj=0 ; iobj<nb_objs ; iobj++)
785  {
786  fx = fwhms_x[iobj] ;
787  fy = fwhms_y[iobj] ;
788  fr = 2.0 * fabs(fx-fy) / (fx+fy) ;
789  if ((fx > f_min) && (fx < f_max) && (fy > f_min) && (fy < f_max) &&
790  (fr < seeing_fwhm_var))
791  {
792  fwhms_good_data[j] = (fx + fy)/2.0 ;
793  j++ ;
794  }
795  }
796  cpl_free(fwhms_x) ;
797  cpl_free(fwhms_y) ;
798 
799  /* Compute the fwhm */
800  if (nb_good < 3)
801  {
802  /* Too few values to compute the median */
803  hawki_step_detect_obj_output.iq[chip] = fwhms_good_data[0] ;
804  }
805  else
806  {
807  /* Compute the median */
808  hawki_step_detect_obj_output.iq[chip] =
809  cpl_vector_get_median_const(fwhms_good) ;
810  }
811  cpl_vector_delete(fwhms_good);
812  hawki_step_detect_obj_output.iq[chip] *=
813  hawki_step_detect_obj_output.pixscale;
814  }
815  cpl_msg_indent_less();
816 
817  return 0;
818 }
819 
820 
821 /*----------------------------------------------------------------------------*/
830 /*----------------------------------------------------------------------------*/
831 static int hawki_step_detect_obj_save
832 (cpl_image ** mask_images,
833  cpl_table ** obj_charac,
834  cpl_propertylist ** obj_stats,
835  cpl_parameterlist * parlist,
836  cpl_frameset * framelist)
837 {
838  const cpl_frame * ref_frame ;
839  cpl_propertylist ** qclists;
840  int ext_nb ;
841  const char * recipe_name = "hawki_step_detect_obj" ;
842  int i;
843  cpl_errorstate error_prevstate = cpl_errorstate_get();
844 
845 
846 
847  /* Load the WCS keys */
848  ref_frame = irplib_frameset_get_first_from_group
849  (framelist, CPL_FRAME_GROUP_RAW);
850 
851  /* Create the QC lists */
852  qclists = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
853  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++)
854  {
855  cpl_propertylist * inputlist;
856  cpl_propertylist * offsetlist;
857  cpl_propertylist * wcslist;
858 
859  /* Get the extension number */
860  ext_nb=hawki_get_ext_from_detector(cpl_frame_get_filename(ref_frame), i+1);
861  qclists[i] = cpl_propertylist_new() ;
862 
863  /* Fill the QC */
864  cpl_propertylist_append_int
865  (qclists[i], "ESO QC NBOBJS",
866  hawki_step_detect_obj_output.nbobjs[i]);
867  cpl_propertylist_append_double
868  (qclists[i], "ESO QC IQ", hawki_step_detect_obj_output.iq[i]);
869  cpl_propertylist_append_double
870  (qclists[i], "ESO QC FWHM PIX",
871  hawki_step_detect_obj_output.fwhm_pix[i]);
872  cpl_propertylist_append_double
873  (qclists[i], "ESO QC FWHM ARCSEC",
874  hawki_step_detect_obj_output.fwhm_arcsec[i]);
875  cpl_propertylist_append_double
876  (qclists[i], "ESO QC FWHM MODE",
877  hawki_step_detect_obj_output.fwhm_mode[i]);
878 
879  /* Propagate some keywords from input raw frame extensions */
880  inputlist = cpl_propertylist_load_regexp(
881  cpl_frame_get_filename(ref_frame), ext_nb,
882  HAWKI_HEADER_EXT_FORWARD, 0);
883  offsetlist = cpl_propertylist_load_regexp(
884  cpl_frame_get_filename(ref_frame), ext_nb,
885  HAWKI_HEADER_COMB_OFFSETS, 0);
886  wcslist = cpl_propertylist_load_regexp(
887  cpl_frame_get_filename(ref_frame), ext_nb,
888  HAWKI_HEADER_WCS, 0);
889  cpl_propertylist_append(qclists[i], inputlist);
890  cpl_propertylist_append(qclists[i], offsetlist);
891  cpl_propertylist_append(qclists[i], wcslist);
892  cpl_propertylist_delete(inputlist);
893  cpl_propertylist_delete(offsetlist);
894  cpl_propertylist_delete(wcslist);
895 
896  /* Add the object statistics keywords */
897  cpl_propertylist_append(qclists[i], obj_stats[i]);
898  }
899 
900 
901  /* Write the object mask */
902  hawki_images_save(framelist,
903  parlist,
904  framelist,
905  (const cpl_image**)mask_images,
906  recipe_name,
907  HAWKI_CALPRO_OBJ_MASK,
908  HAWKI_PROTYPE_OBJ_MASK,
909  NULL,
910  (const cpl_propertylist**)qclists,
911  "hawki_step_detect_obj_mask.fits") ;
912 
913  /* Write the FITS table with the objects statistics */
914  hawki_tables_save(framelist,
915  parlist,
916  framelist,
917  (const cpl_table **)obj_charac,
918  recipe_name,
919  HAWKI_CALPRO_OBJ_PARAM,
920  HAWKI_PROTYPE_OBJ_PARAM,
921  NULL,
922  (const cpl_propertylist**)qclists,
923  "hawki_step_detect_obj_stars.fits") ;
924 
925 
926  /* Free and return */
927  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) {
928  cpl_propertylist_delete(qclists[i]) ;
929  }
930  cpl_free(qclists) ;
931  if(!cpl_errorstate_is_equal(error_prevstate))
932  {
933  cpl_errorstate_set(CPL_ERROR_NONE);
934  return -1;
935  }
936  return 0;
937 }
938 
939 static void hawki_step_detect_obj_init_output(void)
940 {
941  int idet;
942 
943  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
944  {
945  hawki_step_detect_obj_output.iq[idet] = -1.0 ;
946  hawki_step_detect_obj_output.nbobjs[idet] = -1 ;
947  hawki_step_detect_obj_output.fwhm_pix[idet] = -1.0 ;
948  hawki_step_detect_obj_output.fwhm_arcsec[idet] = -1.0 ;
949  hawki_step_detect_obj_output.fwhm_mode[idet] = -1.0 ;
950  hawki_step_detect_obj_output.pos_x[idet] = -1.0 ;
951  hawki_step_detect_obj_output.pos_y[idet] = -1.0 ;
952  }
953  hawki_step_detect_obj_output.pixscale = -1.0;
954 }
955 
956 static void hawki_step_detect_obj_get_pscale
957 (cpl_frameset * combframes)
958 {
959  cpl_propertylist * plist;
960  cpl_frame * firstframe;
961  cpl_errorstate error_prevstate = cpl_errorstate_get();
962 
963  /* Get the header infos */
964  firstframe = cpl_frameset_get_frame(combframes, 0) ;
965  plist=cpl_propertylist_load(cpl_frame_get_filename(firstframe), 0) ;
966  hawki_step_detect_obj_output.pixscale = hawki_pfits_get_pixscale(plist);
967  cpl_propertylist_delete(plist) ;
968  if(!cpl_errorstate_is_equal(error_prevstate))
969  {
970  cpl_msg_error(__func__, "Missing PIXSCALE keyword in FITS header") ;
971  cpl_errorstate_set(CPL_ERROR_NONE);
972  return;
973  }
974 }
975