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