CR2RE Pipeline Reference Manual 1.6.7
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
76 int size=0;
77 int i=0;
78 cpl_vector* levels=NULL;
79 double* pval=NULL;
80 double mean=0;
81 double stdev=0;
82
83
84 cpl_error_ensure(iml != NULL, CPL_ERROR_NULL_INPUT, return(levels),
85 "Null input image list");
86 cpl_error_ensure(kappa >= 0, CPL_ERROR_ILLEGAL_INPUT, return(levels),
87 "Must be kappa>0");
88
89 size=cpl_imagelist_get_size(iml);
90 levels=cpl_vector_new(size);
91 pval=cpl_vector_get_data(levels);
92
93 for(i=0;i<size;i++) {
94 const cpl_image* img=cpl_imagelist_get_const(iml,i);
95 irplib_ksigma_clip(img,1,1,
96 cpl_image_get_size_x(img),
97 cpl_image_get_size_y(img),
98 nclip,kappa,tolerance,&mean,&stdev);
99 cpl_msg_info(cpl_func,"Ima %d mean level: %g",i+1,mean);
100 pval[i]=mean;
101 }
102
103
104 return levels;
105}
106
107/*-------------------------------------------------------------------------*/
115/*--------------------------------------------------------------------------*/
116static cpl_error_code
117irplib_imagelist_subtract_values(cpl_imagelist** iml, cpl_vector* values)
118{
119
120 int size=0;
121 int i=0;
122 double* pval=NULL;
123
124 size=cpl_imagelist_get_size(*iml);
125 pval=cpl_vector_get_data(values);
126
127 for(i=0;i<size;i++) {
128 cpl_image* img=cpl_imagelist_get(*iml,i);
129 cpl_image_subtract_scalar(img,pval[i]);
130 cpl_imagelist_set(*iml,img,i);
131 }
132
133 return cpl_error_get_code();
134}
135
136/*---------------------------------------------------------------------------*/
149/*---------------------------------------------------------------------------*/
150static double
151irplib_vector_ksigma(cpl_vector *values,
152 const double klow, const double khigh, int kiter)
153{
154 double mean /*= 0.0*/; /* Comment out to suppress cppcheck warning. */
155 double sigma = 0.0;
156 double *data = cpl_vector_get_data(values);
157 int n = cpl_vector_get_size(values);
158 int ngood = n;
159 int i;
160
161 /*
162 * At first iteration the mean is taken as the median, and the
163 * standard deviation relative to this value is computed.
164 */
165
166 mean = cpl_vector_get_median(values);
167
168 for (i = 0; i < n; i++) {
169 sigma += (mean - data[i]) * (mean - data[i]);
170 }
171 sigma = sqrt(sigma / (n - 1));
172
173 while (kiter) {
174 cpl_vector *accepted;
175 int count = 0;
176 for (i = 0; i < ngood; i++) {
177 if (data[i]-mean < khigh*sigma && 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
228static cpl_image *
229irplib_imagelist_ksigma_stack(const cpl_imagelist *imlist,
230 double klow, double khigh, int kiter)
231{
232 int ni, nx, ny, npix;
233 cpl_image *out_ima=NULL;
234 cpl_imagelist *loc_iml=NULL;
235 double *pout_ima=NULL;
236 cpl_image *image=NULL;
237 const double **data=NULL;
238 double *med=NULL;
239 cpl_vector *time_line=NULL;
240
241 double *ptime_line=NULL;
242 int i, j;
243 double mean_of_medians=0;
244
245 cpl_error_ensure(imlist != NULL, CPL_ERROR_NULL_INPUT, return(out_ima),
246 "Null input image list");
247
248 ni = cpl_imagelist_get_size(imlist);
249 loc_iml = cpl_imagelist_duplicate(imlist);
250 image = cpl_imagelist_get(loc_iml, 0);
251 nx = cpl_image_get_size_x(image);
252 ny = cpl_image_get_size_y(image);
253 npix = nx * ny;
254
255 out_ima = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
256 pout_ima = cpl_image_get_data_double(out_ima);
257
258 time_line = cpl_vector_new(ni);
259
260 ptime_line = cpl_vector_get_data(time_line);
261
262 data = cpl_calloc(sizeof(double *), ni);
263 med = cpl_calloc(sizeof(double), ni);
264
265 for (i = 0; i < ni; i++) {
266 image = cpl_imagelist_get(loc_iml, i);
267 med[i]=cpl_image_get_median(image);
268 cpl_image_subtract_scalar(image,med[i]);
269 data[i] = cpl_image_get_data_double(image);
270 mean_of_medians+=med[i];
271 }
272 mean_of_medians/=ni;
273
274 for (i = 0; i < npix; i++) {
275 for (j = 0; j < ni; j++) {
276 ptime_line[j] = data[j][i];
277 }
278 pout_ima[i] = irplib_vector_ksigma(time_line, klow, khigh, kiter);
279 }
280
281 cpl_image_add_scalar(out_ima,mean_of_medians);
282
283
284 cpl_free(data);
285 cpl_free(med);
286 cpl_vector_delete(time_line);
287 cpl_imagelist_delete(loc_iml);
288
289 return out_ima;
290
291}
292
293
294
295
296/*-------------------------------------------------------------------------*/
308/*--------------------------------------------------------------------------*/
309cpl_image*
310irplib_mkmaster_mean(cpl_imagelist* images,const double kappa, const int nclip, const double tolerance,const double klow,const double khigh,const int niter)
311{
312
313 cpl_image* master=NULL;
314 cpl_vector* levels=NULL;
315 double mean=0;
316 cpl_imagelist* iml=NULL;
317
318 cpl_msg_info(cpl_func,"method mean");
319 iml=cpl_imagelist_duplicate(images);
320 levels=irplib_imagelist_get_clean_mean_levels(iml,kappa,nclip,tolerance);
321 mean=cpl_vector_get_mean(levels);
322 cpl_msg_info(cpl_func,"Master mean level: %g",mean);
323
324 irplib_imagelist_subtract_values(&iml,levels);
325
326 master = irplib_imagelist_ksigma_stack(iml,klow,khigh,niter);
327 cpl_image_add_scalar(master,mean);
328
329 cpl_vector_delete(levels);
330 cpl_imagelist_delete(iml);
331 return master;
332
333}
334
335/*-------------------------------------------------------------------------*/
347/*--------------------------------------------------------------------------*/
348cpl_image*
349irplib_mkmaster_median(cpl_imagelist* images,const double kappa, const int nclip, const double tolerance)
350{
351
352 cpl_image* master=NULL;
353 cpl_vector* levels=NULL;
354 double mean=0;
355 cpl_imagelist* iml=NULL;
356
357 cpl_msg_info(cpl_func,"method median");
358 iml=cpl_imagelist_duplicate(images);
359 levels=irplib_imagelist_get_clean_mean_levels(iml,kappa,nclip,tolerance);
360
361 mean=cpl_vector_get_mean(levels);
362 cpl_msg_info(cpl_func,"Master mean level: %g",mean);
363 irplib_imagelist_subtract_values(&iml,levels);
364
365 master = cpl_imagelist_collapse_median_create(iml);
366
367 cpl_image_add_scalar(master,mean);
368
369 cpl_vector_delete(levels);
370 cpl_imagelist_delete(iml);
371
372 return master;
373
374}
375
376/* Work in progress */
377static cpl_error_code
378irplib_mkmaster_dark_qc(const cpl_imagelist* raw_images,
379 cpl_imagelist* preproc_images,
380 const cpl_parameterlist* parameters,
381 const int pr_num_x, const int pr_num_y,
382 const int pr_box_sx, const int pr_box_sy, const char* recipe_id,
383 cpl_table* qclog) {
384
385 cpl_ensure_code(qclog !=NULL, CPL_ERROR_NULL_INPUT);
386 cpl_ensure_code(recipe_id !=NULL, CPL_ERROR_NULL_INPUT);
387 cpl_ensure_code(parameters !=NULL, CPL_ERROR_NULL_INPUT);
388
389 if (pr_num_x != 0 && pr_num_y != 0 && pr_box_sx != 0 && pr_box_sy != 0) {
390 int i;
391 for (i = 0; i < cpl_imagelist_get_size(raw_images); i++) {
392 cpl_image* current_dark = cpl_image_duplicate(
393 cpl_imagelist_get_const(preproc_images, i));
394 cpl_msg_info(cpl_func, "Calculating QC parameters on raw dark frame %d",
395 i);
396 /* Here To be defined more general way to qc-log */
397 /* UVES specific stuff: may be this function should not be put in irplib
398 irplib_mdark_region_qc(current_dark, parameters, raw_images, recipe_id,qclog);
399 */
400 /* FIXME: still safe if irplib_mdark_region_qc is commented in? */
401 cpl_image_delete(current_dark);
402 }
403 }
404 return cpl_error_get_code();
405}
406
407/*-------------------------------------------------------------------------*/
417/*-------------------------------------------------------------------------*/
418static double
419irplib_head_get_exptime(const cpl_propertylist * plist) {
420 double result = 0; /* Conversion from electrons to ADUs */
421
422 result=cpl_propertylist_get_double(plist, "EXPTIME");
423 cpl_ensure_code(result >= 0, CPL_ERROR_ILLEGAL_OUTPUT);
424
425 return result;
426}
427
428/*-------------------------------------------------------------------------*/
436/*-------------------------------------------------------------------------*/
437static cpl_error_code
438irplib_head_set_exptime(cpl_propertylist *plist, double exptime)
439{
440 cpl_propertylist_update_double(plist, "EXPTIME", exptime);
441 cpl_propertylist_set_comment(plist, "EXPTIME", "Total integration time");
442
443 return cpl_error_get_code();
444}
445
446static cpl_imagelist*
447irplib_mkmaster_dark_fill_imagelist(const cpl_imagelist* raw_images,
448 cpl_propertylist** raw_headers, const cpl_image* master_bias,
449 double* mean_exptime) {
450 /* First process each input image and store the results in a
451 new image list */
452
453 cpl_imagelist* preproc_images = NULL;
454 int i = 0;
455 double min_exptime = 0;
456 double max_exptime = 0;
457
458 preproc_images = cpl_imagelist_new();
459 for (i = 0; i < cpl_imagelist_get_size(raw_images); i++) {
460 double exposure_time = 0.0;
461 cpl_image* current_dark = NULL;
462 const cpl_propertylist *current_header;
463
464 current_dark = cpl_image_duplicate(cpl_imagelist_get_const(raw_images, i));
465 current_header = raw_headers[i];
466
467 /* Subtract master bias */
468 if (master_bias != NULL) {
469 cpl_msg_info(cpl_func, "Subtracting master bias");
470 cpl_image_subtract(current_dark, master_bias);
471 } else {
472 cpl_msg_info(cpl_func, "Skipping bias subtraction");
473 }
474
475 exposure_time = irplib_head_get_exptime(current_header);
476
477 /* Initialize/update min/max exposure time*/
478 if (i == 0 || exposure_time < min_exptime) {
479 min_exptime = exposure_time;
480 }
481 if (i == 0 || exposure_time > max_exptime) {
482 max_exptime = exposure_time;
483 }
484
485 /* Do not normalize to unit exposure time */
486 /* If this is uncommented, then remember to also calculate the
487 correct master dark exposure time below.
488 irplib_msg("Normalizing from %f s to unit exposure time", exposure_time);
489 check( cpl_image_divide_scalar(current_dark, exposure_time),
490 "Error normalizing dark frame"); */
491
492 /* Append to imagelist */
493 cpl_imagelist_set(preproc_images, current_dark, i);
494
495 /* Don't deallocate the image. It will be deallocated when
496 the image list is deallocated */
497 current_dark = NULL;
498 }
499
500
501 /* Check exposure times */
502 cpl_msg_info(cpl_func,
503 "Exposure times range from %e s to %e s (%e %% variation)", min_exptime,
504 max_exptime, 100 * (max_exptime - min_exptime) / min_exptime);
505
506 if ((max_exptime - min_exptime) / min_exptime > .001) {
507 cpl_msg_warning(cpl_func, "Exposure times differ by %e %%",
508 100 * (max_exptime - min_exptime) / min_exptime);
509 }
510
511 /* compute correct exposure time */
512 *mean_exptime=0.5 * (max_exptime + min_exptime);
513 return preproc_images;
514}
515
516
517cpl_image *
518irplib_mdark_process_chip(const cpl_imagelist *raw_images,
519 cpl_propertylist **raw_headers, const cpl_image *master_bias,
520 cpl_propertylist *mdark_header, const cpl_parameterlist *parameters,
521 const char* recipe_id, cpl_table* qclog, const int do_qc,
522 const char* STACK_METHOD, const double STACK_KLOW, const double STACK_KHIGH,
523 const int STACK_NITER,
524 const int pr_num_x, const int pr_num_y,
525 const int pr_box_sx, const int pr_box_sy) {
526 cpl_image *master_dark = NULL; /* Result */
527 cpl_image *current_dark = NULL;
528 cpl_imagelist *preproc_images = NULL;
529 double mean_exptime = 0;
530
531 /* First process each input image and store the results in a
532 new image list */
533 preproc_images = irplib_mkmaster_dark_fill_imagelist(raw_images, raw_headers,
534 master_bias, &mean_exptime);
535 if (do_qc) {
536 /* Here we should compute QC but a a better way to log it is TBD */
537 irplib_mkmaster_dark_qc(raw_images, preproc_images, parameters, pr_num_x,
538 pr_num_y, pr_box_sx, pr_box_sy, recipe_id, qclog);
539
540 }
541 /* Get median stack of input darks */
542 if (strcmp(STACK_METHOD, "MEDIAN") == 0) {
543 cpl_msg_info(cpl_func, "Calculating stack median");
544 master_dark = cpl_imagelist_collapse_median_create(preproc_images);
545 } else {
546 cpl_msg_info(cpl_func, "Calculating stack mean");
547 master_dark = irplib_imagelist_ksigma_stack(preproc_images, STACK_KLOW,
548 STACK_KHIGH, STACK_NITER);
549
550 }
551 irplib_head_set_exptime(mdark_header, mean_exptime );
552
553 cpl_image_delete(current_dark);
554 cpl_imagelist_delete(preproc_images);
555 if (cpl_error_get_code() != CPL_ERROR_NONE) {
556 cpl_image_delete(master_dark);
557 master_dark = NULL;
558 }
559
560 return master_dark;
561}
562
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.