38#include "visir_recipe.h"
39#include "irplib_flat.h"
45#define PAFCOPY "^(DATE-OBS|ARCFILE|ESO TPL ID|ESO DET DIT|MJD-OBS)$"
46#define PAF_IMG "^(ESO INS FILT1 NAME|ESO INS PFOV)$"
47#define PAF_SPC "^(ESO INS FILT2 NAME|ESO INS RESOL|ESO INS SLIT1 WID" \
48 "|ESO INS GRAT1 WLEN|ESO INS GRAT1 NAME)$"
50#ifndef VISIR_IMG_FF_BORDER
51#define VISIR_IMG_FF_BORDER 64
55#define visir_ff_mode_default (1<<0)
56#define visir_ff_mode_spc (1<<1)
57#define visir_ff_mode_tech (1<<2)
59#define RECIPE_STRING "visir_img_ff"
65static cpl_imagelist * visir_img_ff_reduce(
const irplib_framelist *);
67static cpl_error_code visir_img_ff_qc(cpl_propertylist *,
69 const irplib_framelist *);
71static cpl_error_code visir_img_ff_save(cpl_frameset *,
72 const cpl_parameterlist *,
73 const cpl_propertylist *,
74 const cpl_propertylist *,
75 const cpl_imagelist *,
78VISIR_RECIPE_DEFINE(visir_img_ff, VISIR_PARAM_LOWLIM | VISIR_PARAM_HIGHLIM,
80 "This recipe computes the flatfield.\n"
81 "The files listed in the Set Of Frames (sof-file) must be "
83 "VISIR-flatfield-raw-file.fits " VISIR_IMG_FF_RAW
" or\n"
84 "VISIR-flatfield-raw-file.fits " VISIR_IMG_TECH_FF_RAW
86 "VISIR-flatfield-raw-file.fits " VISIR_SPC_FF_RAW
" or\n"
87 "VISIR-flatfield-raw-file.fits " VISIR_SPC_TECH_FF_RAW
"\n"
89 "The corresponding primary product will have a FITS card\n"
90 "'HIERARCH ESO PRO CATG' with a value of\n"
91 VISIR_IMG_FF_PROCATG
" or\n"
92 VISIR_IMG_TECH_FF_PROCATG
" or\n"
93 VISIR_SPC_FF_PROCATG
" or\n"
94 VISIR_SPC_TECH_FF_PROCATG
101const unsigned visir_img_ff_border = VISIR_IMG_FF_BORDER;
103enum _visir_ff_mode_ {
105 visir_ff_img = visir_ff_mode_default,
106 visir_ff_spc = visir_ff_mode_default | visir_ff_mode_spc,
107 visir_ff_img_tech = visir_ff_mode_default | visir_ff_mode_tech,
108 visir_ff_spc_tech = visir_ff_mode_default | visir_ff_mode_tech
112typedef enum _visir_ff_mode_ visir_ff_mode;
116 visir_ff_mode img_mode;
117 double bpm_lo_thresh;
118 double bpm_hi_thresh;
120 const char * procatg_ff;
121 const char * procatg_bpm;
127} visir_img_ff_config;
146static int visir_img_ff(cpl_frameset * framelist,
147 const cpl_parameterlist * parlist)
149 irplib_framelist * allframes = NULL;
150 irplib_framelist * rawframes = NULL;
151 cpl_propertylist * qclist = cpl_propertylist_new();
152 cpl_propertylist * paflist = cpl_propertylist_new();
153 cpl_imagelist * flat = NULL;
154 cpl_image * bpm_int = NULL;
155 cpl_mask * bpm = NULL;
159 visir_img_ff_config.bpm_lo_thresh =
161 visir_img_ff_config.bpm_hi_thresh =
170 allframes = irplib_framelist_cast(framelist);
171 skip_if(allframes == NULL);
172 rawframes = irplib_framelist_extract_regexp(allframes,
"^(" VISIR_IMG_FF_RAW
173 "|" VISIR_IMG_TECH_FF_RAW
174 "|" VISIR_SPC_TECH_FF_RAW
175 "|" VISIR_SPC_FF_RAW
")$",
177 skip_if (rawframes == NULL);
178 irplib_framelist_empty(allframes);
180 skip_if(irplib_framelist_load_propertylist_all(rawframes, 0,
181 visir_property_regexp,
187 visir_img_ff_config.img_mode = visir_ff_none;
188 if (cpl_frameset_find(framelist, VISIR_IMG_FF_RAW)) {
189 visir_img_ff_config.img_mode = visir_ff_img;
190 visir_img_ff_config.procatg_ff = VISIR_IMG_FF_PROCATG;
191 visir_img_ff_config.procatg_bpm = VISIR_IMG_FF_BPM_PROCATG;
193 if (cpl_frameset_find(framelist, VISIR_SPC_FF_RAW)) {
194 skip_if (visir_img_ff_config.img_mode);
195 visir_img_ff_config.img_mode = visir_ff_spc;
196 visir_img_ff_config.procatg_ff = VISIR_SPC_FF_PROCATG;
197 visir_img_ff_config.procatg_bpm = VISIR_SPC_FF_BPM_PROCATG;
199 if (cpl_frameset_find(framelist, VISIR_IMG_TECH_FF_RAW)) {
200 skip_if (visir_img_ff_config.img_mode);
201 visir_img_ff_config.img_mode = visir_ff_img_tech;
202 visir_img_ff_config.procatg_ff = VISIR_IMG_TECH_FF_PROCATG;
203 visir_img_ff_config.procatg_bpm = VISIR_IMG_TECH_FF_BPM_PROCATG;
205 if (cpl_frameset_find(framelist, VISIR_SPC_TECH_FF_RAW)) {
206 skip_if (visir_img_ff_config.img_mode);
207 visir_img_ff_config.img_mode = visir_ff_spc_tech;
208 visir_img_ff_config.procatg_ff = VISIR_SPC_TECH_FF_PROCATG;
209 visir_img_ff_config.procatg_bpm = VISIR_SPC_TECH_FF_BPM_PROCATG;
213 cpl_msg_info(cpl_func,
"Compute the flatfield");
214 if ((flat = visir_img_ff_reduce(rawframes)) == NULL) {
215 cpl_msg_error(cpl_func,
"Could not compute the flatfield image");
220 cpl_msg_info(cpl_func,
"Compute the bad pixels map");
221 bpm = cpl_mask_threshold_image_create(cpl_imagelist_get(flat, 0),
222 visir_img_ff_config.bpm_lo_thresh,
223 visir_img_ff_config.bpm_hi_thresh);
225 cpl_msg_error(cpl_func,
"Could not compute the bad pixel map");
228 skip_if (cpl_mask_not(bpm));
229 visir_img_ff_config.bpm_nb_bad = cpl_mask_count(bpm);
230 bpm_int = cpl_image_new_from_mask(bpm);
233 skip_if (cpl_image_threshold(cpl_imagelist_get(flat, 0),
234 visir_img_ff_config.bpm_lo_thresh,
235 visir_img_ff_config.bpm_hi_thresh,
238 skip_if (visir_img_ff_qc(qclist, paflist, rawframes));
239 irplib_framelist_empty(rawframes);
241 skip_if (visir_img_ff_save(framelist, parlist, qclist, paflist, flat,
246 cpl_propertylist_delete(paflist);
247 cpl_propertylist_delete(qclist);
248 irplib_framelist_delete(allframes);
249 irplib_framelist_delete(rawframes);
250 cpl_imagelist_delete(flat);
251 cpl_mask_delete(bpm);
252 cpl_image_delete(bpm_int);
254 return cpl_error_get_code();
264static cpl_imagelist * visir_img_ff_reduce(
const irplib_framelist * rawframes)
266 cpl_imagelist * iset = NULL;
267 cpl_imagelist * fitted = NULL;
268 cpl_image * diff = NULL;
269 cpl_image * prev = NULL;
270 cpl_image * image = NULL;
271 const cpl_propertylist * plist;
276 bug_if (rawframes == NULL);
278 plist = irplib_framelist_get_propertylist_const(rawframes, 0);
279 bug_if(plist == NULL);
283 skip_if (sval == NULL);
284 visir_img_ff_config.is_lamp
285 = strstr(sval,
"SKY") == NULL ? CPL_TRUE : CPL_FALSE;
288 iset = irplib_imagelist_load_framelist(rawframes, CPL_TYPE_FLOAT, 0, 0);
289 skip_if (iset == NULL);
292 fitted = irplib_flat_fit_set(iset, 1);
294 skip_if (fitted == NULL);
296 if (visir_img_ff_config.is_lamp) {
299 double upright_x, upright_y;
302 upright_x = cpl_image_get_size_x(cpl_imagelist_get(iset, 0));
303 upright_y = cpl_image_get_size_y(cpl_imagelist_get(iset, 0));
304 upright_x -= visir_img_ff_border;
305 upright_y -= visir_img_ff_border;
306 skip_if(upright_x <= visir_img_ff_border);
307 skip_if(upright_y <= visir_img_ff_border);
309 for (i=0; i < 4 && i < cpl_imagelist_get_size(iset); i++) {
314 cpl_image_delete(prev);
316 image = cpl_image_extract(cpl_imagelist_get(iset, i),
321 bug_if (image == NULL);
323 if (i == 0)
continue;
325 diff = cpl_image_subtract_create(prev, image);
326 bug_if (diff == NULL);
328 bug_if(cpl_flux_get_noise_window(diff, NULL, -1, -1,
331 std_diff[i-1] = noise * noise;
333 cpl_msg_debug(cpl_func,
"SQ-Noise(%d): %g", i, std_diff[i-1]);
336 const double median = cpl_image_get_median(diff);
340 skip_if (ditval <= 0.0);
342 visir_img_ff_config.lamp_flux = median / ditval;
343 cpl_msg_info(cpl_func,
"Lamp Flux: %g",
344 visir_img_ff_config.lamp_flux);
347 cpl_image_delete(diff);
355 const double square = std_diff[0] - std_diff[1] - std_diff[2];
356 visir_img_ff_config.fp_noise = square > 0.0 ? sqrt(square) : 0.0;
358 cpl_msg_info(cpl_func,
"Noise: %g",
359 visir_img_ff_config.fp_noise);
366 cpl_image_delete(diff);
367 cpl_image_delete(image);
368 cpl_image_delete(prev);
369 cpl_imagelist_delete(iset);
384static cpl_error_code visir_img_ff_qc(cpl_propertylist * qclist,
385 cpl_propertylist * paflist,
386 const irplib_framelist * rawframes)
389 const cpl_propertylist * reflist
390 = irplib_framelist_get_propertylist_const(rawframes, 0);
395 skip_if (visir_qc_append_capa(qclist, rawframes));
398 bug_if(cpl_propertylist_append_int(qclist,
"ESO QC NBBADPIX",
399 visir_img_ff_config.bpm_nb_bad));
401 if (visir_img_ff_config.is_lamp) {
402 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC FPNOISE",
403 visir_img_ff_config.fp_noise));
404 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC LAMPFLUX",
405 visir_img_ff_config.lamp_flux));
408 bug_if (cpl_propertylist_append(paflist, qclist));
410 bug_if (cpl_propertylist_copy_property_regexp(paflist, reflist,
411 (visir_img_ff_config.img_mode & visir_ff_mode_spc)
412 ? PAFCOPY
"|" PAF_SPC : PAFCOPY
"|" PAF_IMG, 0));
415 bug_if (cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,
416 visir_img_ff_config.procatg_ff));
418 bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist,
419 "^(" VISIR_PFITS_FF_COPY
426 return cpl_error_get_code();
443static cpl_error_code visir_img_ff_save(cpl_frameset * set,
444 const cpl_parameterlist * parlist,
445 const cpl_propertylist * qclist,
446 const cpl_propertylist * paflist,
447 const cpl_imagelist * flat,
448 const cpl_image * bpm)
451 skip_if (irplib_dfs_save_image(set, parlist, set,
452 cpl_imagelist_get_const(flat, 0),
453 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
454 visir_img_ff_config.procatg_ff, qclist, NULL,
455 visir_pipe_id, RECIPE_STRING CPL_DFS_FITS));
458 skip_if (irplib_dfs_save_image(set, parlist, set, bpm, CPL_BPP_32_SIGNED,
459 RECIPE_STRING, visir_img_ff_config.procatg_bpm,
460 qclist, NULL, visir_pipe_id,
461 RECIPE_STRING
"_bpm" CPL_DFS_FITS));
464 skip_if (cpl_dfs_save_paf(
"VISIR", RECIPE_STRING, paflist,
465 RECIPE_STRING CPL_DFS_PAF));
467 bug_if(paflist == NULL);
472 return cpl_error_get_code();
const char * irplib_pfits_get_dpr_type(const cpl_propertylist *self)
The data type.
cpl_error_code irplib_pfits_set_airmass(cpl_propertylist *self, const irplib_framelist *rawframes)
Update/Set the AIRMASS property.
cpl_error_code visir_dfs_check_framelist_tag(const irplib_framelist *self)
Check the tags in a frameset (group raw only)
int visir_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
double visir_parameterlist_get_double(const cpl_parameterlist *self, const char *recipe, visir_parameter bitmask)
Retrieve the value of a VISIR parameter of type double.
double visir_pfits_get_dit(const cpl_propertylist *self)
The DIT.