ERIS Pipeline Reference Manual 1.9.2
eris_ifu_distortion.c
1/* $Id: eris_ifu_distortion.c,v 0.1 2019-06-11 08:13:17 06:06:06 agudo Exp $
2 *
3 * This file is part of the ERIS 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: agudo $
23 * $Date: 2018-06-11 06:06:06 $
24 * $Revision: 0.1 $
25 * $Name: not supported by cvs2svn $
26 */
27
28#ifdef HAVE_CONFIG_H
29#include <config.h> /* allows the program compilation */
30#endif
31
32
33/*-----------------------------------------------------------------------------
34 Includes
35 ----------------------------------------------------------------------------*/
36#include <strings.h>
37#include <string.h>
38#include <stdio.h>
39#include <math.h>
40
41#include <time.h>
42
43#include <cpl.h>
44#include <hdrl.h>
45#include <irplib_utils.h>
46
47#include "eris_ifu_dfs.h"
48#include "eris_ifu_error.h"
49#include "eris_ifu_debug.h"
50#include "eris_ifu_functions.h"
51#include "eris_ifu_utils.h"
52#include "eris_ifu_distortion_static.h"
53#include "eris_ifu_flat_static.h"
54#include "eris_utils.h"
55/*-----------------------------------------------------------------------------
56 Static variables
57 -----------------------------------------------------------------------------*/
58static char eris_ifu_distortion_description[] = "\
59This recipe determines the optical distortions and the slitlets distances.\n\
60\n\
61-----------------------------------------------------------------------------\n\
62Input files:\n\
63 DO CATG Explanation Required #Frames\n\
64 ------- ----------- -------- -------\n\
65 FIBRE_NS Fibre exposures Y [1,75]\n\
66 FLAT_NS Flatlamp on/off exposures Y 2 \n\
67 WAVE_NS Arclamp on/off exposures Y >=2 \n\
68 DARK_NS Dark exposure N [0,1]\n\
69 REF_LINE_ARC Band-specific reference arc line list Y 1 \n\
70 WAVE_SETUP Table to configure wave calibration Y 1 \n\
71 FIRST_WAVE_FIT Table for the first attempt to fit ARClines Y 1 \n\
72\n\
73Output files:\n\
74 DO CATG Explanation\n\
75 ------- -----------\n\
76 DISTANCES Table with slitlet distances\n\
77 BPM_DIST Badpixel frame\n\
78 SLITLET_POS Table with slitlet edge positions\n\
79 DISTORTION Table with parameters for distortion correction\n\
80 REF_LINE_ARC Table reference arc line values\n\
81 WAVE_SETUP Table with guess wavelength calib solution values\n\
82 FIRST_WAVE_FIT Table with first fit solution\n\
83-----------------------------------------------------------------------------\n\
84\n\
85Information on relevant parameters may be found with\n\
86 esorex --params "REC_NAME_DISTORTION"\n\
87 esorex --help "REC_NAME_DISTORTION"\n";
88
89/*-----------------------------------------------------------------------------
90 Private function prototypes
91 -----------------------------------------------------------------------------*/
92cpl_recipe_define(eris_ifu_distortion, ERIS_BINARY_VERSION, "Alex Agudo Berbel",
93 PACKAGE_BUGREPORT, "2019",
94 "This recipe performs distortion correction",
95 eris_ifu_distortion_description);
96
97cpl_error_code eris_ifu_dist_save_aux_products(
98 cpl_frameset *frameset,
99 const cpl_parameterlist *parlist,
100 cpl_propertylist *pl,
101 cpl_polynomial **distortion_poly,
102 cpl_table *minmax_borders,
103 hdrl_image *fibre_div_img );
104/*-----------------------------------------------------------------------------
105 Functions code
106 ----------------------------------------------------------------------------*/
107
108/*---------------------------------------------------------------------------*/
116/*---------------------------------------------------------------------------*/
117static cpl_error_code eris_ifu_distortion_fill_parameterlist(cpl_parameterlist *pl)
118{
119 cpl_error_code err = CPL_ERROR_NONE;
120 cpl_parameter *p = NULL;
121
122 cpl_ensure_code(pl, CPL_ERROR_NULL_INPUT);
123
124 TRY
125 {
126 /* --instrument & --product_depth*/
128 eris_parlist_config_add_all_recipes(pl, REC_NAME_DISTORTION));
129
130 /* Override: set default instrument to NONE (to be removed when
131 * final detector settings are found and real data is available) */
133 p = cpl_parameterlist_find(pl,
134 "eris.eris_ifu_distortion.instrument"));
136 cpl_parameter_set_default_string(p, "NONE"));
137
138 /* add common bpm-parameters */
140 eris_parlist_config_add_bpm(pl, REC_NAME_DISTORTION));
141
142 /* Override: set default collapse-method to MEAN */
144 p = cpl_parameterlist_find(pl,
145 "eris.eris_ifu_distortion.collapse.method"));
147 cpl_parameter_set_default_string(p, "MEAN"));
148
149 /* add common flat-parameters */
151 eris_parlist_config_add_flat(pl, REC_NAME_DISTORTION));
152
153 /* add distortion parameters */
155 p = cpl_parameter_new_value(
156 "eris.eris_ifu_distortion.distortion.arcs.thresh_factor",
157 CPL_TYPE_DOUBLE,
158 "median_value(image)+ kappa*sigma is the minimum intensity "
159 "threshold of accepted image pixels",
160 "eris_ifu_distortion.distortion.arcs",
161 0.33333));
163 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
164 "distortion.arcs.thresh_factor"));
166 cpl_parameterlist_append(pl, p));
167
169 p = cpl_parameter_new_value(
170 "eris.eris_ifu_distortion.distortion.arcs.min_arclen_factor",
171 CPL_TYPE_DOUBLE,
172 "factor which sets minimum arc length (1.0-2)",
173 "eris_ifu_distortion.distortion.arcs",
174 1.19));
176 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
177 "distortion.arcs.min_arclen_factor"));
179 cpl_parameterlist_append(pl, p));
180
182 p = cpl_parameter_new_value(
183 "eris.eris_ifu_distortion.distortion.arcs.window_size",
184 CPL_TYPE_INT,
185 "Size of window for low pass filter used in an horizontal "
186 "low pass filter to remove unwanted arcs (5-64)",
187 "eris_ifu_distortion.distortion.arcs",
188 14));
190 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
191 "distortion.arcs.window_size"));
193 cpl_parameterlist_append(pl, p));
194
196 p = cpl_parameter_new_value(
197 "eris.eris_ifu_distortion.distortion.smooth_rad",
198 CPL_TYPE_INT,
199 "Size of smoothing factor (1-11) used to prevent for "
200 "possible intensity drops from detector electronics on "
201 "fibre illuminated slitlets (1-11)",
202 "eris_ifu_distortion.distortion",
203 3));
205 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "distortion.smooth_rad"));
207 cpl_parameterlist_append(pl, p));
208
210 p = cpl_parameter_new_value(
211 "eris.eris_ifu_distortion.wave.div",
212 CPL_TYPE_BOOL,
213 "Divide masterflat from subtracted wave frame",
214 "eris_ifu_distortion.wave",
215 TRUE));
217 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
218 "wave.div"));
220 cpl_parameterlist_append(pl, p));
221
222
223 BRK_IF_NULL(p = cpl_parameter_new_value("eris.eris_ifu_distortion.pixel_saturation",
224 CPL_TYPE_DOUBLE,"Pixel saturation level ",
225 "eris_ifu_distortion", 18000.));
226 BRK_IF_ERROR(cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
227 "pixel_saturation"));
228 cpl_parameterlist_append(pl, p);
229 }
230 CATCH
231 {
232 CATCH_MSGS();
233 err = cpl_error_get_code();
234 }
235
236 return err;
237}
238
239/*---------------------------------------------------------------------------*/
247/*---------------------------------------------------------------------------*/
248static int
249eris_ifu_distortion(cpl_frameset *frameset, const cpl_parameterlist *parlist)
250{
251 int productDepth = 0;
252 char *str = NULL;
253 const char *instr_tmp;
254 const char *fn = NULL,
255 *instrument = NULL,
256 *ins = NULL,
257 *band = NULL,
258 *dpr_type = NULL;
259 cpl_image *qualityImage = NULL,
260 *bp_img_flat = NULL,
261 *errorImage = NULL,
262 *contribMap = NULL;
263 const cpl_image *masterFlatImage = NULL;
264 cpl_frameset *frameset_flat = NULL,
265 *frameset_fibre = NULL;
266 const cpl_frame *fr = NULL;
267 cpl_boolean cut_off_left = FALSE,
268 cut_off_right = FALSE;
269 int do_wave_flat_div = FALSE;
270 cpl_mask *bp_mask_flat = NULL;
271 cpl_polynomial **distortion_poly = NULL,
272 **distortion_poly_full = NULL;
273 hdrl_image *masterFlatHdrlImg_lo = NULL,
274 *tmp_img = NULL,
275 *fibre_on_img = NULL,
276 *fibre_div_img = NULL,
277 *dark_img = NULL,
278 *warped_img_wave = NULL,
279 *warped_img_full = NULL,
280 *wave_on_img = NULL,
281 *wave_off_img = NULL;
282 hdrl_imagelist *fibre_imglist = NULL,
283 *wave_imglist = NULL,
284 *cube = NULL,
285 *cube_sorted = NULL;
286 hdrl_parameter *pcollapse = NULL;
287 cpl_table **centers_fitted = NULL,
288 **slit_edges = NULL,
289 *minmax_borders = NULL,
290 *valid_arc_lines = NULL;
291 cpl_propertylist **qc = NULL,
292 *pl = NULL,
293 *qc_list = NULL;
294 cpl_table *qclog = NULL;
295 cpl_imagelist *tmpImgList = NULL;
296 flatMode mode = FLAT_MODE_NONE;
297 ifsPreopticsScale scale = UNDEFINED_SCALE;
298
299 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
300 cpl_ensure_code(parlist, CPL_ERROR_NULL_INPUT);
301 cpl_ensure_code(cpl_frameset_is_empty(frameset) == FALSE,
302 CPL_ERROR_NULL_INPUT);
303
304
305 /* check required input tags are present */
306 /* Temporarily suppress check on required input tags
307 const int ntags = 6;
308 const char* required_tags[6] = {
309 ERIS_IFU_RAW_FIBRE_NS,
310 ERIS_IFU_CALIB_FIRST_FIT,
311 ERIS_IFU_RAW_FLAT_NS,
312 ERIS_IFU_CALIB_REF_LINES,
313 ERIS_IFU_RAW_WAVE_NS,
314 ERIS_IFU_CALIB_WAVE_SETUP
315 };
316
317
318 cpl_ensure_code(CPL_ERROR_NONE ==
319 eris_dfs_check_input_tags(frameset, required_tags, ntags, 1),
320 CPL_ERROR_ILLEGAL_INPUT);
321 */
322
323 cpl_ensure_code(cpl_frameset_count_tags(frameset, ERIS_IFU_RAW_FIBRE_NS) >= 1,
324 CPL_ERROR_ILLEGAL_INPUT);
325 cpl_ensure_code((cpl_frameset_count_tags(frameset, ERIS_IFU_RAW_FLAT_NS) == 2) ||
326 (cpl_frameset_count_tags(frameset, ERIS_IFU_RAW_FLAT_NS_ON) == 1 &&
327 cpl_frameset_count_tags(frameset, ERIS_IFU_RAW_FLAT_NS_OFF)),
328 CPL_ERROR_ILLEGAL_INPUT);
329 cpl_ensure_code((cpl_frameset_count_tags(frameset, ERIS_IFU_RAW_WAVE_NS) >= 2) ||
330 (cpl_frameset_count_tags(frameset, ERIS_IFU_RAW_WAVE_NS_ON) >= 1 &&
331 cpl_frameset_count_tags(frameset, ERIS_IFU_RAW_WAVE_NS_OFF) >= 1),
332 CPL_ERROR_ILLEGAL_INPUT);
333
334 TRY
335 {
336 /* -----------------------------------------------------------------
337 * Setup
338 * ----------------------------------------------------------------- */
339 /* --instrument */
341 instrument = cpl_parameter_get_string(
342 cpl_parameterlist_find_const(parlist,
343 "eris.eris_ifu_distortion.instrument")));
344
346 fr = cpl_frameset_find_const(frameset, ERIS_IFU_RAW_FIBRE_NS));
348 fn = cpl_frame_get_filename(fr));
350 pl = cpl_propertylist_load(fn, 0));
351
352 /* Override: default instrument is set to NONE (to be removed when
353 * final detector settings are found and real data is available)
354 * when NONE set to ERIS for all bands except H/J (there it'll be
355 * SINFONI) */
356 if (strcmp(instrument, INSTRUMENT_NONE) == 0) {
358 ins = cpl_propertylist_get_string(pl, "INSTRUME"));
359 if (strcmp(ins, INSTRUMENT_SINFONI) == 0) {
360 // we have SINFONI-data
362 band = cpl_propertylist_get_string(pl, FHDR_S_FILTER_NAME));
363
364 if ((strcmp(band, S_GRATING_H_BAND) == 0) ||
365 (strcmp(band, S_GRATING_J_BAND) == 0))
366 {
367 instr_tmp = INSTRUMENT_SINFONI;
368 } else {
369 instr_tmp = INSTRUMENT_ERIS;
370 }
371
372 } else {
373 instr_tmp = INSTRUMENT_ERIS;
374 }
375 } else {
376 // either we have ERIS-data or we don't mind what data we have and
377 // we process it like ERIS-data
378 instr_tmp = instrument;
379 }
380
381 cpl_msg_info(cpl_func, "Processing %s frames", instr_tmp);
382
383
385 scale = eris_ifu_get_preopticsScale(pl);
386 cpl_msg_info(cpl_func, "Band: %s, scale: %s", band,
388
389// cpl_boolean is25mas = (scale == S25MAS);
390// cpl_boolean isK = ('K' == band[0]);
391// cpl_boolean isH = ('H' == band[0]);
392
393 /* Identify the RAW and CALIB frames in the input frameset */
395
396 /* save additional products if requested via productDepth argument */
397 productDepth = cpl_parameter_get_int(
398 cpl_parameterlist_find_const(parlist,
399 "eris.eris_ifu_distortion.product_depth"));
401
402 // check if collapse-method is MINMAX, not allowed here
403 const char *collapse_method = NULL;
405 collapse_method = cpl_parameter_get_string(
406 cpl_parameterlist_find_const(parlist,
407 "eris.eris_ifu_distortion.collapse.method")));
408 if (strcmp(collapse_method, "MINMAX") == 0) {
409 SET_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
410 "collapse.method == MINMAX isn't allowed");
412 }
413
414 /* -----------------------------------------------------------------
415 * Performing master-flat calculation
416 * ----------------------------------------------------------------- */
417
418 if (cpl_frameset_count_tags(frameset, ERIS_IFU_RAW_FLAT_NS) > 0) {
419 frameset_flat = eris_ifu_get_frameset_by_tag(frameset,
420 ERIS_IFU_RAW_FLAT_NS);
421 } else if ( (cpl_frameset_count_tags(frameset, ERIS_IFU_RAW_FLAT_NS_ON) > 0) &&
422 (cpl_frameset_count_tags(frameset, ERIS_IFU_RAW_FLAT_NS_OFF) > 0) ) {
423 cpl_frameset* frameset_flat_off = NULL;
424 frameset_flat = eris_ifu_get_frameset_by_tag(frameset, ERIS_IFU_RAW_FLAT_NS_ON);
425
426 frameset_flat_off = eris_ifu_get_frameset_by_tag(frameset, ERIS_IFU_RAW_FLAT_NS_OFF);
427
428 cpl_frameset_join(frameset_flat, frameset_flat_off);
429 cpl_frameset_delete(frameset_flat_off);
430 }
431
432
433 if (cpl_frameset_count_tags(frameset, ERIS_IFU_CALIB_FLATFIELD) != 0) {
434//AA this goes probably away when flat-segment-procedure is implemented. Ask erw
435
436 // overide any raw flat exposures and provide own masterflat and BPM
437
438 cpl_msg_info(cpl_func, "Using ERIS_IFU_CALIB_FLATFIELD and"
439 "ERIS_IFU_PRO_FLAT_BPM");
440// bp_mask_flat = eris_ifu_load_badpixel_mask(
441// frameset, ERIS_IFU_PRO_FLAT_BPM, 0);
442 const char *fn1;
443 fn1 = cpl_frame_get_filename(
444 cpl_frameset_find_const(frameset, ERIS_IFU_CALIB_FLATFIELD));
445 cpl_image *flatFieldImg = cpl_image_load(fn1, CPL_TYPE_DOUBLE, 0, 0);
446 if (cpl_frameset_count_tags(frameset, ERIS_IFU_PRO_FLAT_BPM) != 0) {
447 fn1 = cpl_frame_get_filename(
448 cpl_frameset_find_const(frameset, ERIS_IFU_PRO_FLAT_BPM));
449 bp_mask_flat = cpl_mask_load(fn1, 0, 0);
450 cpl_image_set_bpm(flatFieldImg, bp_mask_flat);
451 }
452 cpl_image *ffErrorImg = cpl_image_new(2048, 2048, CPL_TYPE_DOUBLE);
453 masterFlatHdrlImg_lo = hdrl_image_create(flatFieldImg, ffErrorImg);
454 cpl_image_delete(flatFieldImg);
455 cpl_image_delete(ffErrorImg);
457 qc_list = cpl_propertylist_new());
458 } else {
459 // get flat-mode
460 const char *tmp = cpl_parameter_get_string(
461 cpl_parameterlist_find_const(parlist,
462 "eris.eris_ifu_distortion.mode"));
463 if (!strcmp(tmp, flatModes[0])) {
464 mode = FLAT_MODE_SEGMENT;
465 } else if (!strcmp(tmp, flatModes[1])) {
466 mode = FLAT_MODE_HDRL;
467 } else if (!strcmp(tmp, flatModes[2])) {
468 mode = FLAT_MODE_FAST;
469 } else {
470 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT, "Wrong mode provided.");
471 }
473
475 eris_ifu_flat_static(frameset_flat,
476 parlist,
477 mode,
478 productDepth,
479 ERIS_IFU_PRO_DIST_DBG_MASTER_FLAT_LAMP,
480 REC_NAME_DISTORTION,
481 "DIST",
482 instr_tmp,
483 &qc_list,
484 &masterFlatHdrlImg_lo,
485 &qualityImage));
486
487 /* fetch master flat image */
489 masterFlatImage = hdrl_image_get_image_const(masterFlatHdrlImg_lo));
490 /* fetch noise image */
492 errorImage = hdrl_image_get_error(masterFlatHdrlImg_lo));
493
494 if ((masterFlatImage != NULL) && (errorImage != NULL) &&
495 (qualityImage != NULL) && ((productDepth & 1) != 0))
496 {
498 cpl_propertylist_set_string(qc_list, CPL_DFS_PRO_CATG,
499 ERIS_IFU_PRO_DIST_DBG_MASTER_FLAT_LAMP));
500 // save masterflat image
502 eris_ifu_save_deq_image(frameset, NULL, parlist, frameset, NULL,
503 REC_NAME_DISTORTION,
504 qc_list, NULL,
505 ERIS_IFU_PRO_DIST_DBG_MASTER_FLAT_LAMP_FN,
506 masterFlatImage, errorImage, rmse,
507 qualityImage, flag16bit, UNITLESS));
508 }
509
511 bp_mask_flat = hdrl_image_get_mask(masterFlatHdrlImg_lo));
512 }
513
514 // save bpm image
515 if (bp_mask_flat != NULL) {
517 bp_img_flat = cpl_image_new_from_mask(bp_mask_flat));
518 eris_ifu_get_badpix_qc_from_ima(bp_img_flat, qc_list, "DISTORTION");
519
521 eris_ifu_save_image(frameset, qc_list, parlist,
522 REC_NAME_DISTORTION,
523 ERIS_IFU_PRO_DIST_BPM,
524 ERIS_IFU_PRO_DIST_BPM_FN,
525 CPL_TYPE_USHORT,
526 bp_img_flat));
527 }
528
530
531 /* -----------------------------------------------------------------
532 * Load dark frame if present
533 * ----------------------------------------------------------------- */
535 qc_list = cpl_propertylist_new());
536
537 // load DARK_NS frame (optional)
538 fr = cpl_frameset_find_const(frameset, ERIS_IFU_RAW_DARK_NS);
539 if (fr != NULL) {
541 fn = cpl_frame_get_filename(fr));
545 dark_img = eris_ifu_load_exposure_file(fn, 0, NULL));
546 if (bp_mask_flat != NULL) {
548 hdrl_image_reject_from_mask(dark_img, bp_mask_flat));
549 }
550 if ((productDepth & 1) != 0) {
551 // save dark image
553 ERIS_IFU_PRO_DIST_DBG_DARK_FN,
554 TRUE, NULL);
555 }
556 }
557
558 /* -----------------------------------------------------------------
559 * Stack fibre frames
560 * ----------------------------------------------------------------- */
561 cpl_msg_info(cpl_func, "Performing fibre-exposure calculation...");
562
563 // load all FIBRE_NS frames
565 frameset_fibre = eris_ifu_get_frameset_by_tag(frameset,
566 ERIS_IFU_RAW_FIBRE_NS));
567
568 if (cpl_propertylist_has(pl, FHDR_DPR_TYPE)) {
570 dpr_type = cpl_propertylist_get_string(pl, FHDR_DPR_TYPE));
571 }
572 if ((strcmp(dpr_type, "NS,SLIT") != 0) &&
573 (cpl_frameset_get_size(frameset_fibre) < 75))
574 {
575 // only for mask-mode we expect 75 frames
576 cpl_msg_warning(cpl_func, "Normally 75 FIBRE_NS frames are provided!"
577 " (instead of %d)",
578 (int)cpl_frameset_get_size(frameset_fibre));
579 }
580
582 fibre_imglist = hdrl_imagelist_new());
583
585 fr = cpl_frameset_find_const(frameset_fibre,
586 ERIS_IFU_RAW_FIBRE_NS));
587
588 while (fr != NULL) {
590 fn = cpl_frame_get_filename(fr));
594 tmp_img = eris_ifu_load_exposure_file(fn, 0, NULL));
595 if (bp_mask_flat != NULL) {
597 hdrl_image_reject_from_mask(tmp_img, bp_mask_flat));
598 }
600 hdrl_imagelist_set(fibre_imglist, tmp_img,
601 hdrl_imagelist_get_size(fibre_imglist)));
602
603 /* next frame */
604 fr = cpl_frameset_find_const(frameset_fibre, NULL);
605 }
606
607 // collapse FIBRE_NS frames
609 parlist, "eris.eris_ifu_distortion.collapse");
611 hdrl_imagelist_collapse(fibre_imglist, pcollapse,
612 &fibre_on_img, &contribMap));
614 eris_ifu_free_image(&contribMap);
615
616 if (productDepth & 1) {
617 // save fibre_on image
618 eris_ifu_save_hdrl_image_dbg(fibre_on_img,
619 ERIS_IFU_PRO_DIST_DBG_STACKED_ON_FN,
620 TRUE, NULL);
621 }
622
623 if (dark_img != NULL) {
624 // subtract fibre_on & dark_img
626 hdrl_image_sub_image(fibre_on_img, dark_img));
627 eris_ifu_free_hdrl_image(&dark_img);
628 }
629
631 fibre_div_img = hdrl_image_duplicate(fibre_on_img));
632
633 // divide master flat
635 hdrl_image_div_image(fibre_div_img, masterFlatHdrlImg_lo));
636
637 if ((productDepth & 1) != 0) {
638 // save dark-subtracted and flat-divided fibre_on image
639 eris_ifu_save_hdrl_image_dbg(fibre_div_img,
640 ERIS_IFU_PRO_DIST_DBG_STACKED_FN,
641 TRUE, NULL);
642 }
643
644 /* ---------------------------------------------------------
645 * Load and subtract wavecal
646 * --------------------------------------------------------- */
647 cpl_msg_info(cpl_func, "Performing wave-cal calculation...");
648 cpl_frameset* frameset_wave = NULL;
649 if (cpl_frameset_count_tags(frameset, ERIS_IFU_RAW_WAVE_NS) > 0) {
650 frameset_wave = eris_ifu_get_frameset_by_tag(frameset,
651 ERIS_IFU_RAW_WAVE_NS);
652 } else if ( (cpl_frameset_count_tags(frameset, ERIS_IFU_RAW_WAVE_NS_ON) > 0) &&
653 (cpl_frameset_count_tags(frameset, ERIS_IFU_RAW_WAVE_NS_OFF) > 0) ) {
654
655 cpl_frameset* frameset_wave_off = NULL;
656 frameset_wave = eris_ifu_get_frameset_by_tag(frameset, ERIS_IFU_RAW_WAVE_NS_ON);
657
658 frameset_wave_off = eris_ifu_get_frameset_by_tag(frameset, ERIS_IFU_RAW_WAVE_NS_OFF);
659
660 cpl_frameset_join(frameset_wave, frameset_wave_off);
661 cpl_frameset_delete(frameset_wave_off);
662 }
664 wave_imglist = hdrl_imagelist_new());
665
666
667
668 cpl_size frameCnt = cpl_frameset_get_size(frameset_wave);
669 for (cpl_size i = 0 ; i < frameCnt ; i++) {
670
671 fr = cpl_frameset_get_position_const(frameset_wave, i) ;
672 fn = cpl_frame_get_filename(fr);
673
675
676 tmp_img = eris_ifu_load_exposure_file(fn, 0, NULL);
677 if (bp_mask_flat != NULL) {
678
679 hdrl_image_reject_from_mask(tmp_img, bp_mask_flat);
680 }
681 if (!eris_ifu_frame_is_on(fr)) {
682 if (wave_off_img != NULL) {
683 // an off-image has already been loaded
684 eris_ifu_free_hdrl_image(&wave_off_img);
685 }
686 wave_off_img = tmp_img;
687 } else {
688
689 hdrl_imagelist_set(wave_imglist, tmp_img,
690 hdrl_imagelist_get_size(wave_imglist));
691 }
692
693 }
694 cpl_frameset_delete(frameset_wave);
695
696 // collapse on WAVE_NS frames
698 parlist, "eris.eris_ifu_distortion.collapse");
700 hdrl_imagelist_collapse(wave_imglist, pcollapse,
701 &wave_on_img, &contribMap));
703 eris_ifu_free_image(&contribMap);
704
705 if ((productDepth & 2) != 0) {
707 "eris_ifu_distortion_dbg_wave_on",
708 TRUE, NULL);
709 eris_ifu_save_hdrl_image_dbg(wave_off_img,
710 "eris_ifu_distortion_dbg_wave_off",
711 TRUE, NULL);
712 }
713
714 hdrl_image_sub_image(wave_on_img, wave_off_img);
715
716 eris_ifu_free_hdrl_image(&wave_off_img);
717 eris_ifu_free_hdrl_imagelist(&wave_imglist);
718
719 if ((productDepth & 2) != 0) {
721 "eris_ifu_distortion_dbg_wave_sub",
722 TRUE, NULL);
723 }
724
725 /* save additional products if requested via productDepth argument */
726 do_wave_flat_div = cpl_parameter_get_bool(
727 cpl_parameterlist_find_const(parlist,
728 "eris.eris_ifu_distortion.wave.div"));
730
731 if (do_wave_flat_div) {
732 // divide master flat
734 hdrl_image_div_image(wave_on_img, masterFlatHdrlImg_lo));
735
736 if ((productDepth & 2) != 0) {
738 "eris_ifu_distortion_dbg_wave_div",
739 TRUE, NULL);
740 }
741 }
742
743 /* -----------------------------------------------------------------
744 * Measure center positions based on fibre_on
745 * ----------------------------------------------------------------- */
746 cpl_msg_info(cpl_func, "Performing trace detection of slit-mask/fibre...");
747
748 // vertical arc detection --> return centers (20 per arc)
750 centers_fitted = eris_ifu_dist_calc_centers(fibre_div_img, fibre_on_img,
751 /*is25mas, isK, */productDepth));
752
753 /* -----------------------------------------------------------------
754 * Calculate slitlet positions based on wave_cal
755 * ----------------------------------------------------------------- */
756 cpl_msg_info(cpl_func, "Performing slitlet edge detection...");
757
758//AAA
759 cpl_image **arcImgs = NULL;
760 int arcImgCnt = 0;
762 valid_arc_lines = eris_ifu_dist_wave(frameset, centers_fitted,
763 productDepth, &arcImgs, &arcImgCnt, parlist, &qclog));
764 // left/right edge detection --> return edges (as many as there are lines)
766 slit_edges = eris_ifu_dist_calc_slitpos(arcImgs, centers_fitted,
767 valid_arc_lines,
768// NULL,
769 productDepth,
770 &cut_off_left, &cut_off_right/*, isH*/,
771 frameset,parlist));
772 for (int ix = 0; ix < arcImgCnt; ix++) {
773 cpl_image *tmpImg = arcImgs[ix];
774 eris_ifu_free_image(&tmpImg);
775 }
776 cpl_free(arcImgs);
777 /* -----------------------------------------------------------------
778 * Calculate distortion
779 * ----------------------------------------------------------------- */
780 cpl_msg_info(cpl_func, "Performing calculation of distortion (slit)");
782 distortion_poly = eris_ifu_dist_calc_distortion(slit_edges,
783 centers_fitted,
784 productDepth,
785 cut_off_left,
786 cut_off_right,
787 &minmax_borders,
788 &qc, pl,
789 frameset, parlist));
791 eris_ifu_dist_save_distortion(distortion_poly,
792 minmax_borders,
793 ERIS_IFU_PRO_DIST_DISTORTION_FN,
794 frameset, parlist, qc));
795
796 /* ---------------------------------------------------------
797 * Apply distortion
798 * --------------------------------------------------------- */
799
800 if (productDepth == PD_AUXILLIARY || productDepth == PD_DEBUG) {
802 eris_ifu_dist_save_aux_products(frameset, parlist, pl,
803 distortion_poly, minmax_borders, fibre_div_img));
804 }
805 if (productDepth & 4) {
806 cpl_msg_info(cpl_func, "Distorting arc-frame by slitlet...") ;
808 warped_img_wave = eris_ifu_dist_warp_image(wave_on_img,
809 distortion_poly,
810 minmax_borders));
812 eris_ifu_save_image(frameset, qc_list, parlist,
813 REC_NAME_DISTORTION,
814 ERIS_IFU_PRO_DIST_DBG_WARPED_WAVE,
815 ERIS_IFU_PRO_DIST_DBG_WARPED_WAVE_FN,
816 CPL_TYPE_DOUBLE,
817 hdrl_image_get_image_const(warped_img_wave)));
818 }
819 if (productDepth & 16) {
820 cpl_msg_info(cpl_func, "Performing calculation of distortion (full)");
822 distortion_poly_full = eris_ifu_dist_calc_distortion_full(slit_edges,
823 centers_fitted,
824 productDepth,
825 cut_off_left,
826 cut_off_right));
828 eris_ifu_dist_save_distortion(distortion_poly_full,
829 minmax_borders,
830 "eris_ifu_distortion_distortion_full.fits",
831 frameset, parlist, qc));
832
833 cpl_msg_info(cpl_func, "Distorting fibre-frame full...") ;
835 warped_img_full = eris_ifu_dist_warp_image_full(fibre_div_img,
836 distortion_poly_full,
837 productDepth));
838
840 eris_ifu_save_image(frameset, qc_list, parlist,
841 REC_NAME_DISTORTION,
842 ERIS_IFU_PRO_DIST_DBG_WARPED_FULL,
843 ERIS_IFU_PRO_DIST_DBG_WARPED_FULL_FN,
844 CPL_TYPE_DOUBLE,
845 hdrl_image_get_image_const(warped_img_full)));
846
848 cube = eris_ifu_stack_warped(warped_img_full, rowIndicesDet));
849
851 tmpImgList = eris_ifu_hdrl_get_imagelist(cube, eris_hdrl_data));
854 ERIS_IFU_PRO_DIST_DBG_WARPED_CUBE_FULL_FN, CPL_IO_CREATE));
855
857 cube_sorted = eris_ifu_stack_warped(warped_img_full, rowIndices));
858
859 eris_ifu_free_imagelist(&tmpImgList);
861 tmpImgList = eris_ifu_hdrl_get_imagelist(cube_sorted, eris_hdrl_data));
864 ERIS_IFU_PRO_DIST_DBG_WARPED_CUBE_FULL_FN, CPL_IO_EXTEND));
865 }
866 }
867 CATCH
868 {
869 //ATCH_MSGS();
870 }
871
872
873
874 eris_ifu_free_imagelist(&tmpImgList);
875 cpl_table_delete(qclog);
876 //eris_ifu_free_table(&qclog);
879 eris_ifu_free_frameset(&frameset_flat);
880 eris_ifu_free_frameset(&frameset_fibre);
881 eris_ifu_free_hdrl_image(&masterFlatHdrlImg_lo);
882 eris_ifu_free_image(&qualityImage);
883 eris_ifu_free_image(&bp_img_flat);
884 eris_ifu_free_table(&valid_arc_lines);
885 eris_ifu_free_hdrl_imagelist(&fibre_imglist);
886 eris_ifu_free_table(&minmax_borders);
887 eris_ifu_free_hdrl_imagelist(&wave_imglist);
889 eris_ifu_free_hdrl_imagelist(&cube_sorted);
890 eris_ifu_free_hdrl_image(&dark_img);
891 eris_ifu_free_hdrl_image(&fibre_on_img);
892 eris_ifu_free_hdrl_image(&fibre_div_img);
893 eris_ifu_free_hdrl_image(&warped_img_full);
894 eris_ifu_free_hdrl_image(&wave_on_img);
895 eris_ifu_free_hdrl_image(&wave_off_img);
896 eris_ifu_free_hdrl_image(&warped_img_wave);
897 eris_ifu_free_hdrl_image(&warped_img_full);
899 eris_ifu_free_image(&contribMap);
901
902 if (centers_fitted != NULL) {
903 for (int j = 0; j < SLITLET_CNT; j++) {
904 eris_ifu_free_table(&centers_fitted[j]);
905 }
906 cpl_free(centers_fitted); centers_fitted = NULL;
907 }
908 if (slit_edges != NULL) {
909 for (int j = 0; j < SLITLET_CNT; j++) {
910 eris_ifu_free_table(&slit_edges[j]);
911 }
912 cpl_free(slit_edges); slit_edges = NULL;
913 }
914 if (distortion_poly != NULL) {
915 for (int j = 0; j < SLITLET_CNT; j++) {
916 eris_ifu_free_polynomial(&distortion_poly[j]);
917 }
918 cpl_free(distortion_poly); distortion_poly = NULL;
919 }
920 if (qc != NULL) {
921 for (int i = 0; i < SLITLET_CNT; i++) {
923 }
924 cpl_free(qc); qc = NULL;
925 }
926
927 return (int) cpl_error_get_code();
928}
929
930
931
932/*---------------------------------------------------------------------------*/
943/*---------------------------------------------------------------------------*/
944
945cpl_error_code eris_ifu_dist_save_aux_products(
946 cpl_frameset *frameset,
947 const cpl_parameterlist *parlist,
948 cpl_propertylist *pl,
949 cpl_polynomial **distortion_poly,
950 cpl_table *minmax_borders,
951 hdrl_image *fibre_div_img )
952{
953 cpl_propertylist *qc_list = NULL;
954 cpl_image *tmp_cpl = NULL;
955
956 hdrl_image *warped_img = NULL,
957 *tmp_hdrl = NULL;
958 hdrl_imagelist*cube = NULL;
959
960 TRY {
962 qc_list = cpl_propertylist_new());
963
964 cpl_msg_info(cpl_func, "Distorting fibre-frame by slitlet...") ;
965
967 warped_img = eris_ifu_dist_warp_image(fibre_div_img,
968 distortion_poly,
969 minmax_borders));
971 eris_ifu_save_image(frameset, qc_list, parlist,
972 REC_NAME_DISTORTION,
973 ERIS_IFU_PRO_DIST_DBG_WARPED,
974 ERIS_IFU_PRO_DIST_DBG_WARPED_FN,
975 CPL_TYPE_DOUBLE,
976 hdrl_image_get_image_const(warped_img)));
977
979 cube = eris_ifu_stack_warped(warped_img, rowIndicesDet));
980
981 cpl_imagelist *tmpImgList = NULL;
983 tmpImgList = eris_ifu_hdrl_get_imagelist(cube, eris_hdrl_data));
986 ERIS_IFU_PRO_DIST_DBG_WARPED_CUBE_FN,
987 CPL_IO_CREATE));
988 eris_ifu_free_imagelist(&tmpImgList);
989
991 hdrl_imagelist_collapse_mean(cube, &tmp_hdrl, &tmp_cpl));
992 //PIPPO
993 cpl_propertylist_set_string(pl,FHDR_PRO_CATG,
994 ERIS_IFU_PRO_DIST_DBG_WARPED_CUBE_FLAT_MEAN);
995 cpl_propertylist_set_string(pl,"PIPEFILE",
996 ERIS_IFU_PRO_DIST_DBG_WARPED_CUBE_FLAT_MEAN_FN);
999 ERIS_IFU_PRO_DIST_DBG_WARPED_CUBE_FLAT_MEAN_FN,
1000 CPL_IO_CREATE, pl));
1001 eris_ifu_free_hdrl_image(&tmp_hdrl);
1002 eris_ifu_free_image(&tmp_cpl);
1003
1004
1007 cube = eris_ifu_stack_warped(warped_img, rowIndices));
1008
1010 tmpImgList = eris_ifu_hdrl_get_imagelist(cube, eris_hdrl_data));
1012 eris_ifu_save_imagelist_dbg(tmpImgList,
1013 ERIS_IFU_PRO_DIST_DBG_WARPED_CUBE_FN,
1014 CPL_IO_EXTEND));
1015 eris_ifu_free_imagelist(&tmpImgList);
1016
1017
1019 hdrl_imagelist_collapse_mean(cube, &tmp_hdrl, &tmp_cpl));
1020
1023 ERIS_IFU_PRO_DIST_DBG_WARPED_CUBE_FLAT_MEAN_FN,
1024 CPL_IO_EXTEND, pl));
1025 eris_ifu_free_hdrl_image(&tmp_hdrl);
1026 eris_ifu_free_image(&tmp_cpl);
1027
1029 eris_ifu_dist_warp_stats(warped_img, qc_list, pl, frameset, parlist));
1030
1031 } CATCH {
1032 }
1034 eris_ifu_free_hdrl_image(&warped_img);
1036
1037 return cpl_error_get_code();
1038}
1039
ifsPreopticsScale eris_ifu_get_preopticsScale(cpl_propertylist *header)
Return the the pre-optics scaling.
cpl_error_code eris_ifu_dfs_set_groups(cpl_frameset *self)
Set the frame group (RAW, CALIB, or PRODUCT) for all frames in a frameset.
Definition: eris_ifu_dfs.c:89
cpl_error_code eris_ifu_save_deq_image(cpl_frameset *allframes, cpl_propertylist *header, const cpl_parameterlist *parlist, const cpl_frameset *usedframes, const cpl_frame *inherit, const char *recipe, const cpl_propertylist *applist, const char *remregexp, const char *filename, const cpl_image *image, const cpl_image *error, deqErrorType errorType, const cpl_image *dataQualityMask, deqQualityType dataQualityType, const char *unit)
Save a DFS-compliant image product with data, error, and quality extensions.
Definition: eris_ifu_dfs.c:367
ifsBand eris_ifu_get_band(const cpl_propertylist *header)
Determine preoptic band.
bool eris_ifu_frame_is_on(const cpl_frame *fr)
Determine if a frame has calibration lamps ON or OFF.
cpl_error_code eris_ifu_dist_warp_stats(const hdrl_image *hdrlWarpedImg, cpl_propertylist *qc_list, cpl_propertylist *pl, cpl_frameset *frameset, const cpl_parameterlist *parlist)
Compute QC statistics on warped image.
hdrl_image * eris_ifu_dist_warp_image_full(const hdrl_image *hdrl_img_in, cpl_polynomial **poly_u, int productDepth)
Warp full image using distortion polynomials (alternative method)
cpl_table ** eris_ifu_dist_calc_centers(const hdrl_image *fibre_div, const hdrl_image *fibre_on, int productDepth)
Calculate slitlet centers across the detector.
hdrl_image * eris_ifu_dist_warp_image(const hdrl_image *imgIn, cpl_polynomial **poly_u, const cpl_table *borders)
Warp full detector image by warping each slitlet.
cpl_error_code eris_ifu_dist_save_distortion(cpl_polynomial **poly2d, const cpl_table *minmax_borders, const char *fn, cpl_frameset *frameset, const cpl_parameterlist *parlist, cpl_propertylist **qc)
Save distortion polynomials to FITS file.
cpl_table ** eris_ifu_dist_calc_slitpos(cpl_image **arcImg, cpl_table **centers_array, cpl_table *valid_arc_lines, int productDepth, cpl_boolean *cut_off_left, cpl_boolean *cut_off_right, const cpl_frameset *frameset, const cpl_parameterlist *parlist)
Calculate slitlet edge positions from arc lamp images.
cpl_polynomial ** eris_ifu_dist_calc_distortion(cpl_table **slit_edges, cpl_table **centers, int productDepth, cpl_boolean cut_off_left, cpl_boolean cut_off_right, cpl_table **minmax_borders, cpl_propertylist ***qc, cpl_propertylist *pl, cpl_frameset *frameset, const cpl_parameterlist *parlist)
Calculate distortion polynomials for all slitlets.
cpl_table * eris_ifu_dist_wave(cpl_frameset *fs, cpl_table **centers_fitted, int productDepth, cpl_image ***arcImgs, int *imgCnt, const cpl_parameterlist *parlist, cpl_table **qclog)
Perform wavelength calibration to identify valid arc lines.
hdrl_imagelist * eris_ifu_stack_warped(const hdrl_image *imgIn, const int *rowIx)
Stack warped image into cube format.
cpl_polynomial ** eris_ifu_dist_calc_distortion_full(cpl_table **slit_edges, cpl_table **centers, int productDepth, cpl_boolean cut_off_left, cpl_boolean cut_off_right)
Calculate distortion polynomials (alternative method)
#define SET_ERROR_MSG(code, msg)
Set a new error code together with a custom error message.
#define BRK_IF_ERROR(function)
If function is or returns an error != CPL_ERROR_NONE, then the try-block is exited.
#define CHECK_ERROR_STATE(void)
Check the CPL error state, and exit the try-block if not CPL_ERROR_NONE.
#define BRK_WITH_ERROR_MSG(code,...)
Set a new CPL error, and exit the try-block.
#define TRY
Beginning of a TRY-block.
#define CATCH
End of a TRY-block, beginning of a CATCH-block.
#define BRK_IF_NULL(function)
If function is or returns a NULL pointer, then the try-block is exited.
#define CATCH_MSGS()
Displays an error message stack.
cpl_error_code eris_parlist_config_add_flat(cpl_parameterlist *pl, const char *recname)
Add flat field configuration parameters to parameter list.
cpl_error_code eris_parlist_config_add_all_recipes(cpl_parameterlist *pl, const char *recname)
Add common configuration parameters for all recipes.
cpl_error_code eris_parlist_config_add_bpm(cpl_parameterlist *pl, const char *recname)
Add bad pixel mask configuration parameters to parameter list.
hdrl_image * eris_ifu_load_exposure_file(const char *filename, int exposureCorrectionMode, cpl_image *dqi)
Load a raw detector exposure from file with corrections and noise.
void eris_ifu_free_frameset(cpl_frameset **item)
Free memory and set pointer to null.
cpl_error_code eris_ifu_save_imagelist_dbg(const cpl_imagelist *imglist, const char *filename, int create)
Save CPL imagelist for debugging (quick, no DFS overhead)
void eris_ifu_free_propertylist(cpl_propertylist **item)
Free memory and set pointer to null.
void eris_ifu_free_string(char **item)
Free memory and set pointer to null.
cpl_error_code eris_ifu_save_image_dbg(const cpl_image *img, const char *filename, int create, const cpl_propertylist *pl)
Save image for debugging (quick, no DFS overhead)
void eris_ifu_free_table(cpl_table **item)
Free memory and set pointer to null.
const char * eris_ifu_get_bandString(ifsBand band)
Convert band enum to string.
cpl_error_code eris_ifu_file_exists(const char *filename)
‍**
cpl_error_code eris_ifu_get_badpix_qc_from_ima(const cpl_image *image, cpl_propertylist *qc_list, const char *prefix)
compute QC keyword with number of bad pixels and fraction to total
void eris_ifu_free_polynomial(cpl_polynomial **item)
Free memory and set pointer to null.
cpl_imagelist * eris_ifu_hdrl_get_imagelist(const hdrl_imagelist *hdrl_imglist, enum hdrl_t type)
Extract from an HDRL imagelist a specific CPL imagelist.
void eris_ifu_free_imagelist(cpl_imagelist **item)
Free memory and set pointer to null.
void eris_ifu_free_hdrl_imagelist(hdrl_imagelist **item)
Free memory and set pointer to null.
cpl_error_code eris_ifu_save_hdrl_image_dbg(const hdrl_image *hdrl_img, const char *filename, int singlefile, const cpl_propertylist *pl)
Save HDRL image for debugging (data + error + mask)
void eris_ifu_free_hdrl_image(hdrl_image **item)
Free memory and set pointer to null.
void eris_ifu_free_image(cpl_image **item)
Free memory and set pointer to null.
cpl_frameset * eris_ifu_get_frameset_by_tag(const cpl_frameset *frameset, const char *tag)
Get frames with given tag from frameset.
const char * eris_ifu_get_preopticsScaleString(ifsPreopticsScale scale)
Convert pre-optics scale enum to string.
cpl_error_code eris_ifu_save_image(cpl_frameset *fs, const cpl_propertylist *plist, const cpl_parameterlist *parlist, const char *recipe, const char *procatg, const char *filename, cpl_type type, const cpl_image *image)
Save image with DFS compliance.
void eris_ifu_free_hdrl_parameter(hdrl_parameter **item)
Free memory and set pointer to null.
hdrl_parameter * hdrl_collapse_parameter_parse_parlist(const cpl_parameterlist *parlist, const char *prefix)
parse parameterlist for imagelist reduction method
cpl_error_code hdrl_image_sub_image(hdrl_image *self, const hdrl_image *other)
Subtract two images, store the result in the first image.
cpl_error_code hdrl_image_reject_from_mask(hdrl_image *self, const cpl_mask *map)
set bpm of hdrl_image
Definition: hdrl_image.c:407
cpl_error_code hdrl_image_div_image(hdrl_image *self, const hdrl_image *other)
Divide two images, store the result in the first image.
hdrl_image * hdrl_image_duplicate(const hdrl_image *himg)
copy hdrl_image
Definition: hdrl_image.c:391
cpl_mask * hdrl_image_get_mask(hdrl_image *himg)
get cpl bad pixel mask from image
Definition: hdrl_image.c:157
cpl_image * hdrl_image_get_error(hdrl_image *himg)
get error as cpl image
Definition: hdrl_image.c:131
hdrl_image * hdrl_image_create(const cpl_image *image, const cpl_image *error)
create a new hdrl_image from to existing images by copying them
Definition: hdrl_image.c:295
cpl_image * hdrl_image_get_image(hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:105
const cpl_image * hdrl_image_get_image_const(const hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:118
cpl_error_code hdrl_imagelist_collapse_mean(const hdrl_imagelist *himlist, hdrl_image **out, cpl_image **contrib)
Mean collapsing of image list.
cpl_error_code hdrl_imagelist_set(hdrl_imagelist *himlist, hdrl_image *himg, cpl_size pos)
Insert an image into an imagelist.
cpl_size hdrl_imagelist_get_size(const hdrl_imagelist *himlist)
Get the number of images in the imagelist.
cpl_error_code hdrl_imagelist_collapse(const hdrl_imagelist *himlist, const hdrl_parameter *param, hdrl_image **out, cpl_image **contrib)
collapsing of image list
hdrl_imagelist * hdrl_imagelist_new(void)
Create an empty imagelist.