CR2RE Pipeline Reference Manual 1.7.0
irplib_mkmaster.c
1/* $Id: irplib_mkmaster.c,v 1.6 2013-02-27 16:00:51 jtaylor Exp $
2 *
3 * This file is part of the irplib package
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., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19 */
20
21/*
22 * $Author: jtaylor $
23 * $Date: 2013-02-27 16:00:51 $
24 * $Revision: 1.6 $
25 * $Name: not supported by cvs2svn $
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 <string.h>
38#include "irplib_mkmaster.h"
39
40/*----------------------------------------------------------------------------*/
44/*----------------------------------------------------------------------------*/
45
47/*---------------------------------------------------------------------------*/
54/*---------------------------------------------------------------------------*/
55
56/*-------------------------------------------------------------------------*/
68/*--------------------------------------------------------------------------*/
69static cpl_vector *
70irplib_imagelist_get_clean_mean_levels(const cpl_imagelist *iml,
71 const double kappa,
72 const int nclip,
73 const double tolerance)
74{
75 int size = 0;
76 int i = 0;
77 cpl_vector *levels = NULL;
78 double *pval = NULL;
79 double mean = 0;
80 double stdev = 0;
81
82
83 cpl_error_ensure(iml != NULL, CPL_ERROR_NULL_INPUT, return (levels),
84 "Null input image list");
85 cpl_error_ensure(kappa >= 0, CPL_ERROR_ILLEGAL_INPUT, return (levels),
86 "Must be kappa>0");
87
88 size = cpl_imagelist_get_size(iml);
89 levels = cpl_vector_new(size);
90 pval = cpl_vector_get_data(levels);
91
92 for (i = 0; i < size; i++) {
93 const cpl_image *img = cpl_imagelist_get_const(iml, i);
94 irplib_ksigma_clip(img, 1, 1, cpl_image_get_size_x(img),
95 cpl_image_get_size_y(img), nclip, kappa, tolerance,
96 &mean, &stdev);
97 cpl_msg_info(cpl_func, "Ima %d mean level: %g", i + 1, mean);
98 pval[i] = mean;
99 }
100
101
102 return levels;
103}
104
105/*-------------------------------------------------------------------------*/
113/*--------------------------------------------------------------------------*/
114static cpl_error_code
115irplib_imagelist_subtract_values(cpl_imagelist **iml, cpl_vector *values)
116{
117 int size = 0;
118 int i = 0;
119 double *pval = NULL;
120
121 size = cpl_imagelist_get_size(*iml);
122 pval = cpl_vector_get_data(values);
123
124 for (i = 0; i < size; i++) {
125 cpl_image *img = cpl_imagelist_get(*iml, i);
126 cpl_image_subtract_scalar(img, pval[i]);
127 cpl_imagelist_set(*iml, img, i);
128 }
129
130 return cpl_error_get_code();
131}
132
133/*---------------------------------------------------------------------------*/
146/*---------------------------------------------------------------------------*/
147static double
148irplib_vector_ksigma(cpl_vector *values,
149 const double klow,
150 const double khigh,
151 int kiter)
152{
153 double mean /*= 0.0*/; /* Comment out to suppress cppcheck warning. */
154 double sigma = 0.0;
155 double *data = cpl_vector_get_data(values);
156 int n = cpl_vector_get_size(values);
157 int ngood = n;
158 int i;
159
160 /*
161 * At first iteration the mean is taken as the median, and the
162 * standard deviation relative to this value is computed.
163 */
164
165 mean = cpl_vector_get_median(values);
166
167 for (i = 0; i < n; i++) {
168 sigma += (mean - data[i]) * (mean - data[i]);
169 }
170 sigma = sqrt(sigma / (n - 1));
171
172 while (kiter) {
173 cpl_vector *accepted;
174 int count = 0;
175 for (i = 0; i < ngood; i++) {
176 if (data[i] - mean < khigh * sigma &&
177 mean - data[i] < klow * sigma) {
178 data[count] = data[i];
179 ++count;
180 }
181 }
182
183 if (count == 0) // This cannot happen at first iteration.
184 break; // So we can break: we have already computed a mean.
185
186 /*
187 * The mean must be computed even if no element was rejected
188 * (count == ngood), because at first iteration median instead
189 * of mean was computed.
190 */
191
192 accepted = cpl_vector_wrap(count, data);
193 mean = cpl_vector_get_mean(accepted);
194 if (count > 1) {
195 sigma = cpl_vector_get_stdev(accepted);
196 }
197 cpl_vector_unwrap(accepted);
198
199 if (count == ngood) {
200 break;
201 }
202 ngood = count;
203 --kiter;
204 }
205
206 return mean;
207}
208
209
227
228static cpl_image *
229irplib_imagelist_ksigma_stack(const cpl_imagelist *imlist,
230 double klow,
231 double khigh,
232 int kiter)
233{
234 cpl_size ni, nx, ny, npix;
235 cpl_image *out_ima = NULL;
236 cpl_imagelist *loc_iml = NULL;
237 double *pout_ima = NULL;
238 cpl_image *image = NULL;
239 const double **data = NULL;
240 double *med = NULL;
241 cpl_vector *time_line = NULL;
242
243 double *ptime_line = NULL;
244 cpl_size i, j;
245 double mean_of_medians = 0;
246
247 cpl_error_ensure(imlist != NULL, CPL_ERROR_NULL_INPUT, return (out_ima),
248 "Null input image list");
249
250 ni = cpl_imagelist_get_size(imlist);
251 loc_iml = cpl_imagelist_duplicate(imlist);
252 image = cpl_imagelist_get(loc_iml, 0);
253 nx = cpl_image_get_size_x(image);
254 ny = cpl_image_get_size_y(image);
255 npix = nx * ny;
256
257 out_ima = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
258 pout_ima = cpl_image_get_data_double(out_ima);
259
260 time_line = cpl_vector_new(ni);
261
262 ptime_line = cpl_vector_get_data(time_line);
263
264 cpl_error_ensure(ni < (cpl_size)(SIZE_MAX / sizeof(double *)),
265 CPL_ERROR_INCOMPATIBLE_INPUT, return (NULL),
266 "Image to big for allocation");
267 data = cpl_calloc((size_t)ni, sizeof(double *));
268 med = cpl_calloc((size_t)ni, sizeof(double));
269
270 for (i = 0; i < ni; i++) {
271 image = cpl_imagelist_get(loc_iml, i);
272 med[i] = cpl_image_get_median(image);
273 cpl_image_subtract_scalar(image, med[i]);
274 data[i] = cpl_image_get_data_double(image);
275 mean_of_medians += med[i];
276 }
277 mean_of_medians /= ni;
278
279 for (i = 0; i < npix; i++) {
280 for (j = 0; j < ni; j++) {
281 ptime_line[j] = data[j][i];
282 }
283 pout_ima[i] = irplib_vector_ksigma(time_line, klow, khigh, kiter);
284 }
285
286 cpl_image_add_scalar(out_ima, mean_of_medians);
287
288
289 cpl_free(data);
290 cpl_free(med);
291 cpl_vector_delete(time_line);
292 cpl_imagelist_delete(loc_iml);
293
294 return out_ima;
295}
296
297
298/*-------------------------------------------------------------------------*/
310/*--------------------------------------------------------------------------*/
311cpl_image *
312irplib_mkmaster_mean(cpl_imagelist *images,
313 const double kappa,
314 const int nclip,
315 const double tolerance,
316 const double klow,
317 const double khigh,
318 const int niter)
319{
320 cpl_image *master = NULL;
321 cpl_vector *levels = NULL;
322 double mean = 0;
323 cpl_imagelist *iml = NULL;
324
325 cpl_msg_info(cpl_func, "method mean");
326 iml = cpl_imagelist_duplicate(images);
327 levels =
328 irplib_imagelist_get_clean_mean_levels(iml, kappa, nclip, tolerance);
329 mean = cpl_vector_get_mean(levels);
330 cpl_msg_info(cpl_func, "Master mean level: %g", mean);
331
332 irplib_imagelist_subtract_values(&iml, levels);
333
334 master = irplib_imagelist_ksigma_stack(iml, klow, khigh, niter);
335 cpl_image_add_scalar(master, mean);
336
337 cpl_vector_delete(levels);
338 cpl_imagelist_delete(iml);
339 return master;
340}
341
342/*-------------------------------------------------------------------------*/
354/*--------------------------------------------------------------------------*/
355cpl_image *
356irplib_mkmaster_median(cpl_imagelist *images,
357 const double kappa,
358 const int nclip,
359 const double tolerance)
360{
361 cpl_image *master = NULL;
362 cpl_vector *levels = NULL;
363 double mean = 0;
364 cpl_imagelist *iml = NULL;
365
366 cpl_msg_info(cpl_func, "method median");
367 iml = cpl_imagelist_duplicate(images);
368 levels =
369 irplib_imagelist_get_clean_mean_levels(iml, kappa, nclip, tolerance);
370
371 mean = cpl_vector_get_mean(levels);
372 cpl_msg_info(cpl_func, "Master mean level: %g", mean);
373 irplib_imagelist_subtract_values(&iml, levels);
374
375 master = cpl_imagelist_collapse_median_create(iml);
376
377 cpl_image_add_scalar(master, mean);
378
379 cpl_vector_delete(levels);
380 cpl_imagelist_delete(iml);
381
382 return master;
383}
384
385/* Work in progress */
386static cpl_error_code
387irplib_mkmaster_dark_qc(const cpl_imagelist *raw_images,
388 cpl_imagelist *preproc_images,
389 const cpl_parameterlist *parameters,
390 const int pr_num_x,
391 const int pr_num_y,
392 const int pr_box_sx,
393 const int pr_box_sy,
394 const char *recipe_id,
395 cpl_table *qclog)
396{
397 cpl_ensure_code(qclog != NULL, CPL_ERROR_NULL_INPUT);
398 cpl_ensure_code(recipe_id != NULL, CPL_ERROR_NULL_INPUT);
399 cpl_ensure_code(parameters != NULL, CPL_ERROR_NULL_INPUT);
400
401 if (pr_num_x != 0 && pr_num_y != 0 && pr_box_sx != 0 && pr_box_sy != 0) {
402 int i;
403 for (i = 0; i < cpl_imagelist_get_size(raw_images); i++) {
404 cpl_image *current_dark =
405 cpl_image_duplicate(cpl_imagelist_get_const(preproc_images, i));
406 cpl_msg_info(cpl_func,
407 "Calculating QC parameters on raw dark frame %d", i);
408 /* Here To be defined more general way to qc-log */
409 /* UVES specific stuff: may be this function should not be put in irplib
410 irplib_mdark_region_qc(current_dark, parameters, raw_images, recipe_id,qclog);
411 */
412 /* FIXME: still safe if irplib_mdark_region_qc is commented in? */
413 cpl_image_delete(current_dark);
414 }
415 }
416 return cpl_error_get_code();
417}
418
419/*-------------------------------------------------------------------------*/
429/*-------------------------------------------------------------------------*/
430static double
431irplib_head_get_exptime(const cpl_propertylist *plist)
432{
433 double result = 0; /* Conversion from electrons to ADUs */
434
435 result = cpl_propertylist_get_double(plist, "EXPTIME");
436 cpl_ensure_code(result >= 0, CPL_ERROR_ILLEGAL_OUTPUT);
437
438 return result;
439}
440
441/*-------------------------------------------------------------------------*/
449/*-------------------------------------------------------------------------*/
450static cpl_error_code
451irplib_head_set_exptime(cpl_propertylist *plist, double exptime)
452{
453 cpl_propertylist_update_double(plist, "EXPTIME", exptime);
454 cpl_propertylist_set_comment(plist, "EXPTIME", "Total integration time");
455
456 return cpl_error_get_code();
457}
458
459static cpl_imagelist *
460irplib_mkmaster_dark_fill_imagelist(const cpl_imagelist *raw_images,
461 cpl_propertylist **raw_headers,
462 const cpl_image *master_bias,
463 double *mean_exptime)
464{
465 /* First process each input image and store the results in a
466 new image list */
467
468 cpl_imagelist *preproc_images = NULL;
469 int i = 0;
470 double min_exptime = 0;
471 double max_exptime = 0;
472
473 preproc_images = cpl_imagelist_new();
474 for (i = 0; i < cpl_imagelist_get_size(raw_images); i++) {
475 double exposure_time = 0.0;
476 cpl_image *current_dark = NULL;
477 const cpl_propertylist *current_header;
478
479 current_dark =
480 cpl_image_duplicate(cpl_imagelist_get_const(raw_images, i));
481 current_header = raw_headers[i];
482
483 /* Subtract master bias */
484 if (master_bias != NULL) {
485 cpl_msg_info(cpl_func, "Subtracting master bias");
486 cpl_image_subtract(current_dark, master_bias);
487 }
488 else {
489 cpl_msg_info(cpl_func, "Skipping bias subtraction");
490 }
491
492 exposure_time = irplib_head_get_exptime(current_header);
493
494 /* Initialize/update min/max exposure time*/
495 if (i == 0 || exposure_time < min_exptime) {
496 min_exptime = exposure_time;
497 }
498 if (i == 0 || exposure_time > max_exptime) {
499 max_exptime = exposure_time;
500 }
501
502 /* Do not normalize to unit exposure time */
503 /* If this is uncommented, then remember to also calculate the
504 correct master dark exposure time below.
505 irplib_msg("Normalizing from %f s to unit exposure time", exposure_time);
506 check( cpl_image_divide_scalar(current_dark, exposure_time),
507 "Error normalizing dark frame"); */
508
509 /* Append to imagelist */
510 cpl_imagelist_set(preproc_images, current_dark, i);
511
512 /* Don't deallocate the image. It will be deallocated when
513 the image list is deallocated */
514 current_dark = NULL;
515 }
516
517
518 /* Check exposure times */
519 cpl_msg_info(cpl_func,
520 "Exposure times range from %e s to %e s (%e %% variation)",
521 min_exptime, max_exptime,
522 100 * (max_exptime - min_exptime) / min_exptime);
523
524 if ((max_exptime - min_exptime) / min_exptime > .001) {
525 cpl_msg_warning(cpl_func, "Exposure times differ by %e %%",
526 100 * (max_exptime - min_exptime) / min_exptime);
527 }
528
529 /* compute correct exposure time */
530 *mean_exptime = 0.5 * (max_exptime + min_exptime);
531 return preproc_images;
532}
533
534
535cpl_image *
536irplib_mdark_process_chip(const cpl_imagelist *raw_images,
537 cpl_propertylist **raw_headers,
538 const cpl_image *master_bias,
539 cpl_propertylist *mdark_header,
540 const cpl_parameterlist *parameters,
541 const char *recipe_id,
542 cpl_table *qclog,
543 const int do_qc,
544 const char *STACK_METHOD,
545 const double STACK_KLOW,
546 const double STACK_KHIGH,
547 const int STACK_NITER,
548 const int pr_num_x,
549 const int pr_num_y,
550 const int pr_box_sx,
551 const int pr_box_sy)
552{
553 cpl_image *master_dark = NULL; /* Result */
554 cpl_image *current_dark = NULL;
555 cpl_imagelist *preproc_images = NULL;
556 double mean_exptime = 0;
557
558 /* First process each input image and store the results in a
559 new image list */
560 preproc_images =
561 irplib_mkmaster_dark_fill_imagelist(raw_images, raw_headers,
562 master_bias, &mean_exptime);
563 if (do_qc) {
564 /* Here we should compute QC but a a better way to log it is TBD */
565 irplib_mkmaster_dark_qc(raw_images, preproc_images, parameters,
566 pr_num_x, pr_num_y, pr_box_sx, pr_box_sy,
567 recipe_id, qclog);
568 }
569 /* Get median stack of input darks */
570 if (strcmp(STACK_METHOD, "MEDIAN") == 0) {
571 cpl_msg_info(cpl_func, "Calculating stack median");
572 master_dark = cpl_imagelist_collapse_median_create(preproc_images);
573 }
574 else {
575 cpl_msg_info(cpl_func, "Calculating stack mean");
576 master_dark = irplib_imagelist_ksigma_stack(preproc_images, STACK_KLOW,
577 STACK_KHIGH, STACK_NITER);
578 }
579 irplib_head_set_exptime(mdark_header, mean_exptime);
580
581 cpl_image_delete(current_dark);
582 cpl_imagelist_delete(preproc_images);
583 if (cpl_error_get_code() != CPL_ERROR_NONE) {
584 cpl_image_delete(master_dark);
585 master_dark = NULL;
586 }
587
588 return master_dark;
589}
590
cpl_image * irplib_mkmaster_mean(cpl_imagelist *images, const double kappa, const int nclip, const double tolerance, const double klow, const double khigh, const int niter)
Computes master frame by clean stack mean of the input imagelist.
cpl_image * irplib_mkmaster_median(cpl_imagelist *images, const double kappa, const int nclip, const double tolerance)
Computes master frame by clean stack median of the input imagelist.