MUSE Pipeline Reference Manual  2.1.1
muse_combine.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set sw=2 sts=2 et cin: */
3 /*
4  * This file is part of the MUSE Instrument Pipeline
5  * Copyright (C) 2005-2013 European Southern Observatory
6  * (C) 2002-2004 European Southern Observatory
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  */
22 
23 /*
24  * $Original Author: jag $
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 
31 /*----------------------------------------------------------------------------*
32  * Includes *
33  *----------------------------------------------------------------------------*/
34 #include <string.h>
35 #include <cpl.h>
36 
37 #include "muse_combine.h"
38 
39 #include "muse_basicproc.h"
40 #include "muse_cplwrappers.h"
41 #include "muse_pfits.h"
42 #include "muse_quality.h"
43 #include "muse_utils.h"
44 
45 /*----------------------------------------------------------------------------*
46  * Global variables *
47  *----------------------------------------------------------------------------*/
48 /* strings of combination methods; *
49  * keep in sync with combinationMethods in muse_combine.h! */
50 const char *kCombinationStrings[] = {
51  "sum",
52  "average",
53  "median",
54  "minmax",
55  "sigclip",
56  "none", /* for muse_scibasic */
57  "unknown"
58 };
59 
60 /*----------------------------------------------------------------------------*/
71 /*----------------------------------------------------------------------------*/
72 
75 #define MUSE_COMBINE_DATA_DELETE \
76  cpl_free(indata); \
77  cpl_free(indq); \
78  cpl_free(instat);
79 
80 #define MUSE_COMBINE_DATA_NEW \
81  /* image dimensions, derive them from the first image in the input list */ \
82  int nx = cpl_image_get_size_x(muse_imagelist_get(aImages, 0)->data), \
83  ny = cpl_image_get_size_y(muse_imagelist_get(aImages, 0)->data); \
84  \
85  /* create the output image and its three components */ \
86  muse_image *combined = muse_image_new(); \
87  combined->data = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); \
88  combined->dq = cpl_image_new(nx, ny, CPL_TYPE_INT); \
89  combined->stat = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); \
90  combined->header = cpl_propertylist_new(); \
91  if (!combined || !combined->data || !combined->dq || !combined->stat) { \
92  cpl_msg_error(__func__, "Could not allocate all parts of output image"); \
93  muse_image_delete(combined); /* remove whatever is there */ \
94  return NULL; \
95  } \
96  \
97  /* use array access method for speed */ \
98  float *pixdata = cpl_image_get_data_float(combined->data), \
99  *pixstat = cpl_image_get_data_float(combined->stat); \
100  unsigned int *pixdq = (unsigned int *)cpl_image_get_data_int(combined->dq); \
101  \
102  /* get pixel arrays of all input images, too */ \
103  float **indata = (float **)cpl_malloc(n * sizeof(float *)), \
104  **instat = (float **)cpl_malloc(n * sizeof(float *)); \
105  unsigned int **indq = (unsigned int **)cpl_malloc(n * sizeof(unsigned int *));\
106  cpl_errorstate state = cpl_errorstate_get(); \
107  unsigned int k; \
108  for (k = 0; k < n; k++) { \
109  indata[k] = cpl_image_get_data_float(muse_imagelist_get(aImages, k)->data);\
110  indq[k] = (unsigned int *)cpl_image_get_data_int(muse_imagelist_get(aImages, k)->dq);\
111  instat[k] = cpl_image_get_data_float(muse_imagelist_get(aImages, k)->stat);\
112  } \
113  if (!cpl_errorstate_is_equal(state)) { \
114  /* access to at least one image component failed, */ \
115  /* indexing it would cause a segfault! */ \
116  cpl_errorstate_set(state); \
117  muse_image_delete(combined); \
118  MUSE_COMBINE_DATA_DELETE \
119  cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT, \
120  "An image component in the input list was missing"); \
121  return NULL; \
122  }
123 
124 /*----------------------------------------------------------------------------*/
151 /*----------------------------------------------------------------------------*/
152 muse_image *
154 {
155  cpl_ensure(aImages, CPL_ERROR_NULL_INPUT, NULL);
156 
157  unsigned int n = muse_imagelist_get_size(aImages); /* number of images */
158  MUSE_COMBINE_DATA_NEW
159 
160  /* loop over all pixels using the FITS convention, i.e. [1:ncol,1:nrow] */
161  int i;
162  for (i = 0; i < nx; i++) {
163  int j;
164  for (j = 0; j < ny; j++) {
165  unsigned int ngood = 0, outdq = EURO3D_GOODPIXEL;
166  double sumdata = 0., sumstat = 0.;
167 
168  /* loop through all images in the list */
169  for (k = 0; k < n; k++) {
170  if (indq[k][i + j*nx] != EURO3D_GOODPIXEL) {
171  /* bad pixel, don't use its value or variance */
172  continue;
173  }
174 
175  ngood++;
176  sumdata += indata[k][i + j*nx];
177  sumstat += instat[k][i + j*nx];
178  }
179  if (!ngood) {
180  /* if no good pixels were found before, pick the one with the least *
181  * severe flaw and propagate just that value and variance */
182  outdq = 1 << 31; /* start with worst possible value */
183  unsigned int kbest = 0;
184  for (k = 0; k < n; k++) {
185  if (indq[k][i + j*nx] < outdq) {
186  kbest = k;
187  outdq = indq[k][i + j*nx];
188  }
189  }
190  sumdata = indata[kbest][i + j*nx];
191  sumstat = instat[kbest][i + j*nx];
192  /* pretend that there was one good pixel for the extrapolation */
193  ngood = 1;
194  } /* if !ngood */
195 
196  /* simple sum, scaled by the number of total to good pixels */
197  pixdata[i + j*nx] = sumdata * n / ngood;
198  pixdq[i + j*nx] = outdq;
199  /* sigma^2 = N^2/Ngood^2 * (sigma1^2 + sigma2^2 + ... + sigmaN^2) */
200  pixstat[i + j*nx] = sumstat * n * n / ngood / ngood;
201  } /* for j (columns) */
202  } /* for i (rows) */
203 
204  MUSE_COMBINE_DATA_DELETE
205 
206  return combined;
207 } /* muse_combine_sum_create() */
208 
209 /*----------------------------------------------------------------------------*/
232 /*----------------------------------------------------------------------------*/
233 muse_image *
235 {
236  cpl_ensure(aImages, CPL_ERROR_NULL_INPUT, NULL);
237 
238  unsigned int n = muse_imagelist_get_size(aImages); /* number of images */
239  MUSE_COMBINE_DATA_NEW
240 
241  /* loop over all pixels using the FITS convention, i.e. [1:ncol,1:nrow] */
242  int i;
243  for (i = 0; i < nx; i++) {
244  int j;
245  for (j = 0; j < ny; j++) {
246  unsigned int ngood = 0, outdq = EURO3D_GOODPIXEL;
247  double sumdata = 0., sumstat = 0.;
248 
249  /* loop through all images in the list */
250  for (k = 0; k < n; k++) {
251  if (indq[k][i + j*nx] != EURO3D_GOODPIXEL) {
252  /* bad pixel, don't use its value or variance */
253  continue;
254  }
255 
256  ngood++;
257  sumdata += indata[k][i + j*nx];
258  sumstat += instat[k][i + j*nx];
259  }
260  if (!ngood) {
261  /* if no good pixels were found before, pick the one with the least *
262  * severe flaw and propagate just that value and variance */
263  outdq = 1 << 31; /* start with worst possible value */
264  unsigned int kbest = 0;
265  for (k = 0; k < n; k++) {
266  if (indq[k][i + j*nx] < outdq) {
267  kbest = k;
268  outdq = indq[k][i + j*nx];
269  }
270  }
271  sumdata = indata[kbest][i + j*nx];
272  sumstat = instat[kbest][i + j*nx];
273  ngood = 1;
274  }
275 
276  /* simple average */
277  pixdata[i + j*nx] = sumdata / ngood;
278  pixdq[i + j*nx] = outdq;
279  /* sigma^2 = 1/N^2 * (sigma1^2 + sigma2^2 + ... + sigmaN^2) *
280  * or = mean(sigma1^2...sigmaN^2) / N */
281  pixstat[i + j*nx] = sumstat / ngood / ngood;
282  } /* for j (columns) */
283  } /* for i (rows) */
284 
285  MUSE_COMBINE_DATA_DELETE
286 
287  return combined;
288 } /* muse_combine_average_create() */
289 
290 /*----------------------------------------------------------------------------*/
314 /*----------------------------------------------------------------------------*/
315 muse_image *
317 {
318  cpl_ensure(aImages, CPL_ERROR_NULL_INPUT, NULL);
319 
320  unsigned int n = muse_imagelist_get_size(aImages); /* number of images */
321  MUSE_COMBINE_DATA_NEW
322 
323  /* loop over all pixels using the FITS convention, i.e. [1:ncol,1:nrow] */
324  int i;
325  for (i = 0; i < nx; i++) {
326  int j;
327  for (j = 0; j < ny; j++) {
328  unsigned int ngood = 0;
329 
330  /* record data, dq, and stat in the columns of a matrix, *
331  * if dq != EURO3D_GOODPIXEL */
332  cpl_matrix *values = cpl_matrix_new(n, 2);
333  for (k = 0; k < n; k++) {
334  if (indq[k][i + j*nx] != EURO3D_GOODPIXEL) {
335  continue;
336  }
337  cpl_matrix_set(values, ngood, 0, indata[k][i + j*nx]);
338  cpl_matrix_set(values, ngood, 1, instat[k][i + j*nx]);
339  ngood++;
340  }
341 
342  if (ngood) {
343  cpl_matrix_set_size(values, ngood, 2); /* cut off the unused rows */
344  cpl_matrix_sort_rows(values, 1); /* sort by decreasing data values */
345 
346  /* take the middle value, if the middle is an integer */
347  if (ngood & 1) {
348  /* odd number of values, directly take the middle one */
349  pixdata[i + j*nx] = cpl_matrix_get(values, ngood/2, 0);
350  /* sigma^2 = sigma(median_value)^2 */
351  pixstat[i + j*nx] = cpl_matrix_get(values, ngood/2, 1);
352  } else {
353  /* even number, take the average of the two middle ones */
354  pixdata[i + j*nx] = 0.5 * (cpl_matrix_get(values, ngood/2, 0)
355  + cpl_matrix_get(values, ngood/2-1, 0));
356  /* sigma^2 = sigma(median_value1)^2+sigma(median_value2)^2 */
357  pixstat[i + j*nx] = cpl_matrix_get(values, ngood/2, 1)
358  + cpl_matrix_get(values, ngood/2-1, 1);
359  }
360  pixdq[i + j*nx] = EURO3D_GOODPIXEL;
361  } else {
362  /* if no good pixels were found before, pick the one with the least *
363  * severe flaw and propagate just that value and variance */
364  unsigned int outdq = 1 << 31, /* start with worst possible value */
365  kbest = 0;
366  for (k = 0; k < n; k++) {
367  if (indq[k][i + j*nx] < outdq) {
368  kbest = k;
369  outdq = indq[k][i + j*nx];
370  }
371  }
372  pixdata[i + j*nx] = indata[kbest][i + j*nx];
373  pixdq[i + j*nx] = outdq;
374  pixstat[i + j*nx] = instat[kbest][i + j*nx];
375  ngood = 1;
376  }
377 
378  cpl_matrix_delete(values);
379  } /* for j */
380  } /* for i */
381 
382  MUSE_COMBINE_DATA_DELETE
383 
384  return combined;
385 } /* muse_combine_median_create() */
386 
387 /*----------------------------------------------------------------------------*/
425 /*----------------------------------------------------------------------------*/
426 muse_image *
427 muse_combine_minmax_create(muse_imagelist *aImages, int aMin, int aMax, int aKeep)
428 {
429  cpl_ensure(aImages, CPL_ERROR_NULL_INPUT, NULL);
430 
431  unsigned int n = muse_imagelist_get_size(aImages); /* number of images */
432  int nMax = n - aMax;
433  /* check values, unlike IRAF, do not attempt combination if conditions not met */
434  if ((nMax-aMin) < aKeep || nMax <= 0) {
435  cpl_msg_error(__func__, "Not enough images left after minmax rejection: %d "
436  "input images, min=%d, max=%d, keep=%d", n, aMin, aMax, aKeep);
437  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
438  return NULL;
439  }
440 
441  MUSE_COMBINE_DATA_NEW
442 
443  /* loop over all pixels using the FITS convention, i.e. [1:ncol,1:nrow] */
444  int i;
445  for (i = 0; i < nx; i++) {
446  int j;
447  for (j = 0; j < ny; j++) {
448  unsigned int ngood = 0;
449 
450  /* record data, dq, and stat in the columns of a matrix, *
451  * if dq != EURO3D_GOODPIXEL */
452  cpl_matrix *values = cpl_matrix_new(n, 2);
453  for (k = 0; k < n; k++) {
454  if (indq[k][i + j*nx] != EURO3D_GOODPIXEL) {
455  continue;
456  }
457  cpl_matrix_set(values, ngood, 0, indata[k][i + j*nx]);
458  cpl_matrix_set(values, ngood, 1, instat[k][i + j*nx]);
459  ngood++;
460  } /* for k (all input images) */
461 
462  int npix = ngood - aMax - aMin;
463  if (ngood > 0) { /* we found some good pixels */
464  unsigned int outdq = EURO3D_GOODPIXEL;
465  if (npix > 0 && npix < aKeep) {
466  /* add from images with bad pixels until we are above the threshold */
467  for (k = 0; k < n && npix < aKeep; k++) {
468  if (indq[k][i + j*nx] != EURO3D_GOODPIXEL) {
469  cpl_matrix_set(values, ngood, 0, indata[k][i + j*nx]);
470  cpl_matrix_set(values, ngood, 1, instat[k][i + j*nx]);
471  outdq |= indq[k][i + j*nx];
472  ngood++, npix++;
473  } /* if */
474  } /* for k (all input images) */
475  } /* if */
476 
477  /* now we are sure that some pixels will be left are minmax rejection */
478  cpl_matrix_set_size(values, ngood, 2); /* cut off the unused rows */
479  cpl_matrix_sort_rows(values, 1); /* sort by decreasing data values */
480 
481  /* do the rejection */
482  if (aMin > 0) {
483  cpl_matrix_erase_rows(values, ngood - aMin, aMin);
484  }
485  if (aMax > 0) {
486  cpl_matrix_erase_rows(values, 0, aMax);
487  }
488 
489  /* now it's down to a simple average of the remaining pixels */
490  double sumdata = 0., sumstat = 0.;
491  for (k = 0; (int)k < npix; k++) {
492  sumdata += cpl_matrix_get(values, k, 0);
493  sumstat += cpl_matrix_get(values, k, 1);
494  }
495  pixdata[i + j*nx] = sumdata / npix;
496  pixstat[i + j*nx] = sumstat / npix / npix;
497  pixdq[i + j*nx] = outdq;
498  } else {
499  /* if no good pixels were found before, pick the one with the least *
500  * severe flaw and propagate just that value and variance */
501  unsigned int outdq = 1 << 31, /* start with worst possible value */
502  kbest = 0;
503  for (k = 0; k < n; k++) {
504  if (indq[k][i + j*nx] < outdq) {
505  kbest = k;
506  outdq = indq[k][i + j*nx];
507  }
508  }
509  pixdata[i + j*nx] = indata[kbest][i + j*nx];
510  pixdq[i + j*nx] = outdq;
511  pixstat[i + j*nx] = instat[kbest][i + j*nx];
512  }
513 
514  cpl_matrix_delete(values);
515  } /* for j */
516  } /* for i */
517 
518  MUSE_COMBINE_DATA_DELETE
519 
520  return combined;
521 } /* muse_combine_minmax_create() */
522 
523 /*----------------------------------------------------------------------------*/
555 /*----------------------------------------------------------------------------*/
556 muse_image *
557 muse_combine_sigclip_create(muse_imagelist *aImages, double aLow, double aHigh)
558 {
559  cpl_ensure(aImages, CPL_ERROR_NULL_INPUT, NULL);
560 
561  unsigned int n = muse_imagelist_get_size(aImages); /* number of images */
562  if (n < 3) {
563  cpl_msg_error(__func__, "Sigma clipping requires at least 3 images!");
564  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
565  return NULL;
566  }
567  MUSE_COMBINE_DATA_NEW
568 
569  /* allocate buffers for data (twice), variance, and "good" indices */
570  double *pdata = cpl_malloc(n * sizeof(double)),
571  *pdtmp = cpl_malloc(n * sizeof(double)),
572  *pstat = cpl_malloc(n * sizeof(double));
573  unsigned int *idx = cpl_malloc(n * sizeof(unsigned int));
574 
575  /* loop over all pixels using the FITS convention, i.e. [1:ncol,1:nrow] */
576  int i;
577  for (i = 0; i < nx; i++) {
578  int j;
579  for (j = 0; j < ny; j++) {
580  unsigned int ngood = 0;
581 
582  /* record data, dq, and stat in the columns of a matrix, *
583  * if dq != EURO3D_GOODPIXEL */
584  for (k = 0; k < n; k++) {
585  if (indq[k][i + j*nx] != EURO3D_GOODPIXEL) {
586  continue;
587  }
588  pdata[ngood] = indata[k][i + j*nx];
589  pstat[ngood] = instat[k][i + j*nx];
590  pdtmp[ngood] = pdata[ngood]; /* duplicate to allow re-ordering */
591  ngood++;
592  } /* for k (all input images) */
593 
594  if (ngood > 0) { /* we found some good pixels */
595  /* compute the good limits */
596  cpl_vector *vtmp = cpl_vector_wrap(ngood, pdtmp);
597  double median, mdev = muse_cplvector_get_median_dev(vtmp, &median),
598  lo = median - aLow * mdev,
599  hi = median + aHigh * mdev;
600  cpl_vector_unwrap(vtmp);
601 
602  /* if for some reason mdev == 0, skip the rejection */
603  if (hi > lo) {
604  /* find locations of the good values in the buffers */
605  unsigned int ntest = ngood;
606  ngood = 0; /* count good pixels again */
607  for (k = 0; k < ntest; k++) {
608  if (pdata[k] >= lo && pdata[k] <= hi) {
609  idx[ngood++] = k; /* good pixel, record index */
610  } /* if */
611  } /* for k (all good values) */
612  } else { /* invalid limit range, record all indices */
613  for (k = 0; k < ngood; k++) {
614  idx[k] = k;
615  } /* for k (all values) */
616  } /* else: invalid limit range */
617 
618  /* now it's down to a simple average of the remaining pixels */
619  double sumdata = 0., sumstat = 0.;
620  for (k = 0; k < ngood; k++) {
621  sumdata += pdata[idx[k]];
622  sumstat += pstat[idx[k]];
623  } /* for k (all good values within limits) */
624  pixdata[i + j*nx] = sumdata / ngood;
625  pixstat[i + j*nx] = sumstat / ngood / ngood;
626  pixdq[i + j*nx] = EURO3D_GOODPIXEL;
627  } else { /* no good pixels */
628  /* if no good pixels were found before, pick the one with the least *
629  * severe flaw and propagate just that value and variance */
630  unsigned int outdq = 1 << 31, /* start with worst possible value */
631  kbest = 0;
632  for (k = 0; k < n; k++) {
633  if (indq[k][i + j*nx] < outdq) {
634  kbest = k;
635  outdq = indq[k][i + j*nx];
636  } /* if less bad status */
637  } /* for k (all input pixels) */
638  pixdata[i + j*nx] = indata[kbest][i + j*nx];
639  pixdq[i + j*nx] = outdq;
640  pixstat[i + j*nx] = instat[kbest][i + j*nx];
641  } /* else (no good pixels) */
642  } /* for j */
643  } /* for i */
644  cpl_free(pdata);
645  cpl_free(pdtmp);
646  cpl_free(pstat);
647  cpl_free(idx);
648 
649  MUSE_COMBINE_DATA_DELETE
650 
651  return combined;
652 } /* muse_combine_sigclip_create() */
653 
654 /*---------------------------------------------------------------------------*/
670 /*---------------------------------------------------------------------------*/
671 muse_combinepar *
672 muse_combinepar_new(cpl_parameterlist *aParameters, const char *aPrefix)
673 {
674  cpl_ensure(aParameters && aPrefix, CPL_ERROR_NULL_INPUT, NULL);
675  muse_combinepar *cpars = cpl_calloc(1, sizeof(muse_combinepar));
676  cpars->combine = MUSE_COMBINE_UNKNOWN;
677 
678  cpl_parameter *param;
679  /* --combine */
680  param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "combine");
681  const char *method = param ? cpl_parameter_get_string(param) : "median";
682  int i;
683  for (i = 0; i < MUSE_COMBINE_UNKNOWN; i++) {
684  if (!strcmp(kCombinationStrings[i], method)) {
685  cpars->combine = i;
686  }
687  }
688  /* Parameters for --combine=minmax */
689  param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "nlow");
690  cpars->nLow = param ? cpl_parameter_get_int(param) : 1;
691  param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "nhigh");
692  cpars->nHigh = param ? cpl_parameter_get_int(param) : 1;
693  param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "nkeep");
694  cpars->nKeep = param ? cpl_parameter_get_int(param) : 1;
695  /* Parameters for --combine=sigclip */
696  param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "lsigma");
697  cpars->lSigma = param ? cpl_parameter_get_double(param) : 3.0;
698  param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "hsigma");
699  cpars->hSigma = param ? cpl_parameter_get_double(param) : 3.0;
700  /* --scale */
701  param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "scale");
702  cpars->scale = param ? cpl_parameter_get_bool(param) : FALSE;
703 
704  return cpars;
705 } /* muse_combinepar_new() */
706 
707 
708 /*---------------------------------------------------------------------------*/
713 /*---------------------------------------------------------------------------*/
714 void
715 muse_combinepar_delete(muse_combinepar *aCPars)
716 {
717  cpl_free(aCPars);
718 }
719 
720 /*---------------------------------------------------------------------------*/
739 /*---------------------------------------------------------------------------*/
740 muse_image *
741 muse_combine_images(muse_combinepar *aCPars, muse_imagelist *aImages)
742 {
743  if (!aImages) {
744  cpl_msg_error(__func__, "Image list missing!");
745  cpl_error_set(__func__, CPL_ERROR_NULL_INPUT);
746  return NULL;
747  }
748  if (!aCPars) {
749  cpl_msg_error(__func__, "Parameters missing!");
750  cpl_error_set(__func__, CPL_ERROR_NULL_INPUT);
751  return NULL;
752  }
753 
754  if (muse_imagelist_get_size(aImages) == 1) {
755  cpl_msg_debug(__func__, "Only one image in list, duplicate instead of combine...");
756  return muse_image_duplicate(muse_imagelist_get(aImages, 0));
757  }
758 
759  if (aCPars->scale) {
761  }
762 
763  muse_image *masterimage = NULL;
764  switch (aCPars->combine) {
765  case MUSE_COMBINE_SUM:
766  cpl_msg_info(__func__, "Combination method: sum (without rejection)");
767  masterimage = muse_combine_sum_create(aImages);
768  break;
769 
770  case MUSE_COMBINE_AVERAGE:
771  cpl_msg_info(__func__, "Combination method: average (without rejection)");
772  masterimage = muse_combine_average_create(aImages);
773  break;
774 
775  case MUSE_COMBINE_MEDIAN:
776  cpl_msg_info(__func__, "Combination method: median (without rejection)");
777  masterimage = muse_combine_median_create(aImages);
778  break;
779 
780  case MUSE_COMBINE_MINMAX:
781  cpl_msg_info(__func__, "Combination method: average with minmax rejection "
782  "(%d/%d/%d)", aCPars->nLow, aCPars->nHigh, aCPars->nKeep);
783  masterimage = muse_combine_minmax_create(aImages, aCPars->nLow, aCPars->nHigh,
784  aCPars->nKeep);
785  break;
786 
787  case MUSE_COMBINE_SIGCLIP:
788  cpl_msg_info(__func__, "Combination method: average with sigma clipping "
789  "(%f/%f)", aCPars->lSigma, aCPars->hSigma);
790  masterimage = muse_combine_sigclip_create(aImages,
791  aCPars->lSigma, aCPars->hSigma);
792  break;
793 
794  default:
795  cpl_msg_error(__func__, "Unknown combination method: %s (%d)",
796  kCombinationStrings[aCPars->combine], aCPars->combine);
797  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
798  }
799  if (!masterimage) {
800  return NULL;
801  }
802 
803  /* copy all headers except temporary headers *
804  * (that do not make sense in combined image) */
805  cpl_propertylist_copy_property_regexp(masterimage->header,
806  muse_imagelist_get(aImages, 0)->header,
807  MUSE_HDR_TMP_REGEXP, 1);
808 
809  return masterimage;
810 } /* muse_combine_images() */
811 
Structure definition for a collection of muse_images.
muse_image * muse_combine_minmax_create(muse_imagelist *aImages, int aMin, int aMax, int aKeep)
Average a list of input images with minmax rejection.
Definition: muse_combine.c:427
muse_image * muse_image_duplicate(const muse_image *aImage)
Duplicate the three image extensions and the FITS headers of a MUSE image.
Definition: muse_image.c:510
muse_image * muse_combine_median_create(muse_imagelist *aImages)
Median combine a list of input images.
Definition: muse_combine.c:316
double muse_cplvector_get_median_dev(cpl_vector *aVector, double *aMedian)
Compute the median and average absolute deviation against the median of a vector. ...
muse_image * muse_combine_images(muse_combinepar *aCPars, muse_imagelist *aImages)
Combine several images into one.
Definition: muse_combine.c:741
Structure definition of MUSE three extension FITS file.
Definition: muse_image.h:40
cpl_propertylist * header
the FITS header
Definition: muse_image.h:72
muse_image * muse_combine_average_create(muse_imagelist *aImages)
Average a list of input images.
Definition: muse_combine.c:234
unsigned int muse_imagelist_get_size(muse_imagelist *aList)
Return the number of stored images.
void muse_combinepar_delete(muse_combinepar *aCPars)
Clear the combination parameters.
Definition: muse_combine.c:715
cpl_error_code muse_imagelist_scale_exptime(muse_imagelist *aList)
Scale muse_images to a common exposure time.
muse_image * muse_imagelist_get(muse_imagelist *aList, unsigned int aIdx)
Get the muse_image of given list index.
muse_image * muse_combine_sum_create(muse_imagelist *aImages)
Sum a list of input images.
Definition: muse_combine.c:153
muse_combinepar * muse_combinepar_new(cpl_parameterlist *aParameters, const char *aPrefix)
Create a new set of combination parameters.
Definition: muse_combine.c:672
cpl_parameter * muse_cplparamerterlist_find_prefix(cpl_parameterlist *aParameters, const char *aPrefix, const char *aName)
Return the full recipe parameter belonging to prefix and shortname.
muse_image * muse_combine_sigclip_create(muse_imagelist *aImages, double aLow, double aHigh)
Average a list of input images with sigma clipping rejection.
Definition: muse_combine.c:557