37 #include "muse_combine.h" 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" 50 const char *kCombinationStrings[] = {
75 #define MUSE_COMBINE_DATA_DELETE \ 80 #define MUSE_COMBINE_DATA_NEW \ 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); \ 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); \ 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); \ 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(); \ 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);\ 113 if (!cpl_errorstate_is_equal(state)) { \ 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"); \ 155 cpl_ensure(aImages, CPL_ERROR_NULL_INPUT, NULL);
158 MUSE_COMBINE_DATA_NEW
162 for (i = 0; i < nx; i++) {
164 for (j = 0; j < ny; j++) {
165 unsigned int ngood = 0, outdq = EURO3D_GOODPIXEL;
166 double sumdata = 0., sumstat = 0.;
169 for (k = 0; k < n; k++) {
170 if (indq[k][i + j*nx] != EURO3D_GOODPIXEL) {
176 sumdata += indata[k][i + j*nx];
177 sumstat += instat[k][i + j*nx];
183 unsigned int kbest = 0;
184 for (k = 0; k < n; k++) {
185 if (indq[k][i + j*nx] < outdq) {
187 outdq = indq[k][i + j*nx];
190 sumdata = indata[kbest][i + j*nx];
191 sumstat = instat[kbest][i + j*nx];
197 pixdata[i + j*nx] = sumdata * n / ngood;
198 pixdq[i + j*nx] = outdq;
200 pixstat[i + j*nx] = sumstat * n * n / ngood / ngood;
204 MUSE_COMBINE_DATA_DELETE
236 cpl_ensure(aImages, CPL_ERROR_NULL_INPUT, NULL);
239 MUSE_COMBINE_DATA_NEW
243 for (i = 0; i < nx; i++) {
245 for (j = 0; j < ny; j++) {
246 unsigned int ngood = 0, outdq = EURO3D_GOODPIXEL;
247 double sumdata = 0., sumstat = 0.;
250 for (k = 0; k < n; k++) {
251 if (indq[k][i + j*nx] != EURO3D_GOODPIXEL) {
257 sumdata += indata[k][i + j*nx];
258 sumstat += instat[k][i + j*nx];
264 unsigned int kbest = 0;
265 for (k = 0; k < n; k++) {
266 if (indq[k][i + j*nx] < outdq) {
268 outdq = indq[k][i + j*nx];
271 sumdata = indata[kbest][i + j*nx];
272 sumstat = instat[kbest][i + j*nx];
277 pixdata[i + j*nx] = sumdata / ngood;
278 pixdq[i + j*nx] = outdq;
281 pixstat[i + j*nx] = sumstat / ngood / ngood;
285 MUSE_COMBINE_DATA_DELETE
318 cpl_ensure(aImages, CPL_ERROR_NULL_INPUT, NULL);
321 MUSE_COMBINE_DATA_NEW
325 for (i = 0; i < nx; i++) {
327 for (j = 0; j < ny; j++) {
328 unsigned int ngood = 0;
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) {
337 cpl_matrix_set(values, ngood, 0, indata[k][i + j*nx]);
338 cpl_matrix_set(values, ngood, 1, instat[k][i + j*nx]);
343 cpl_matrix_set_size(values, ngood, 2);
344 cpl_matrix_sort_rows(values, 1);
349 pixdata[i + j*nx] = cpl_matrix_get(values, ngood/2, 0);
351 pixstat[i + j*nx] = cpl_matrix_get(values, ngood/2, 1);
354 pixdata[i + j*nx] = 0.5 * (cpl_matrix_get(values, ngood/2, 0)
355 + cpl_matrix_get(values, ngood/2-1, 0));
357 pixstat[i + j*nx] = cpl_matrix_get(values, ngood/2, 1)
358 + cpl_matrix_get(values, ngood/2-1, 1);
360 pixdq[i + j*nx] = EURO3D_GOODPIXEL;
364 unsigned int outdq = 1 << 31,
366 for (k = 0; k < n; k++) {
367 if (indq[k][i + j*nx] < outdq) {
369 outdq = indq[k][i + j*nx];
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];
378 cpl_matrix_delete(values);
382 MUSE_COMBINE_DATA_DELETE
429 cpl_ensure(aImages, CPL_ERROR_NULL_INPUT, NULL);
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);
441 MUSE_COMBINE_DATA_NEW
445 for (i = 0; i < nx; i++) {
447 for (j = 0; j < ny; j++) {
448 unsigned int ngood = 0;
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) {
457 cpl_matrix_set(values, ngood, 0, indata[k][i + j*nx]);
458 cpl_matrix_set(values, ngood, 1, instat[k][i + j*nx]);
462 int npix = ngood - aMax - aMin;
464 unsigned int outdq = EURO3D_GOODPIXEL;
465 if (npix > 0 && npix < aKeep) {
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];
478 cpl_matrix_set_size(values, ngood, 2);
479 cpl_matrix_sort_rows(values, 1);
483 cpl_matrix_erase_rows(values, ngood - aMin, aMin);
486 cpl_matrix_erase_rows(values, 0, aMax);
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);
495 pixdata[i + j*nx] = sumdata / npix;
496 pixstat[i + j*nx] = sumstat / npix / npix;
497 pixdq[i + j*nx] = outdq;
501 unsigned int outdq = 1 << 31,
503 for (k = 0; k < n; k++) {
504 if (indq[k][i + j*nx] < outdq) {
506 outdq = indq[k][i + j*nx];
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];
514 cpl_matrix_delete(values);
518 MUSE_COMBINE_DATA_DELETE
559 cpl_ensure(aImages, CPL_ERROR_NULL_INPUT, NULL);
563 cpl_msg_error(__func__,
"Sigma clipping requires at least 3 images!");
564 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
567 MUSE_COMBINE_DATA_NEW
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));
577 for (i = 0; i < nx; i++) {
579 for (j = 0; j < ny; j++) {
580 unsigned int ngood = 0;
584 for (k = 0; k < n; k++) {
585 if (indq[k][i + j*nx] != EURO3D_GOODPIXEL) {
588 pdata[ngood] = indata[k][i + j*nx];
589 pstat[ngood] = instat[k][i + j*nx];
590 pdtmp[ngood] = pdata[ngood];
596 cpl_vector *vtmp = cpl_vector_wrap(ngood, pdtmp);
598 lo = median - aLow * mdev,
599 hi = median + aHigh * mdev;
600 cpl_vector_unwrap(vtmp);
605 unsigned int ntest = ngood;
607 for (k = 0; k < ntest; k++) {
608 if (pdata[k] >= lo && pdata[k] <= hi) {
613 for (k = 0; k < ngood; k++) {
619 double sumdata = 0., sumstat = 0.;
620 for (k = 0; k < ngood; k++) {
621 sumdata += pdata[idx[k]];
622 sumstat += pstat[idx[k]];
624 pixdata[i + j*nx] = sumdata / ngood;
625 pixstat[i + j*nx] = sumstat / ngood / ngood;
626 pixdq[i + j*nx] = EURO3D_GOODPIXEL;
630 unsigned int outdq = 1 << 31,
632 for (k = 0; k < n; k++) {
633 if (indq[k][i + j*nx] < outdq) {
635 outdq = indq[k][i + j*nx];
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];
649 MUSE_COMBINE_DATA_DELETE
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;
678 cpl_parameter *param;
681 const char *method = param ? cpl_parameter_get_string(param) :
"median";
683 for (i = 0; i < MUSE_COMBINE_UNKNOWN; i++) {
684 if (!strcmp(kCombinationStrings[i], method)) {
690 cpars->nLow = param ? cpl_parameter_get_int(param) : 1;
692 cpars->nHigh = param ? cpl_parameter_get_int(param) : 1;
694 cpars->nKeep = param ? cpl_parameter_get_int(param) : 1;
697 cpars->lSigma = param ? cpl_parameter_get_double(param) : 3.0;
699 cpars->hSigma = param ? cpl_parameter_get_double(param) : 3.0;
702 cpars->scale = param ? cpl_parameter_get_bool(param) : FALSE;
744 cpl_msg_error(__func__,
"Image list missing!");
745 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT);
749 cpl_msg_error(__func__,
"Parameters missing!");
750 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT);
755 cpl_msg_debug(__func__,
"Only one image in list, duplicate instead of combine...");
764 switch (aCPars->combine) {
765 case MUSE_COMBINE_SUM:
766 cpl_msg_info(__func__,
"Combination method: sum (without rejection)");
770 case MUSE_COMBINE_AVERAGE:
771 cpl_msg_info(__func__,
"Combination method: average (without rejection)");
775 case MUSE_COMBINE_MEDIAN:
776 cpl_msg_info(__func__,
"Combination method: median (without rejection)");
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);
787 case MUSE_COMBINE_SIGCLIP:
788 cpl_msg_info(__func__,
"Combination method: average with sigma clipping " 789 "(%f/%f)", aCPars->lSigma, aCPars->hSigma);
791 aCPars->lSigma, aCPars->hSigma);
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);
805 cpl_propertylist_copy_property_regexp(masterimage->
header,
807 MUSE_HDR_TMP_REGEXP, 1);
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.
muse_image * muse_image_duplicate(const muse_image *aImage)
Duplicate the three image extensions and the FITS headers of a MUSE image.
muse_image * muse_combine_median_create(muse_imagelist *aImages)
Median combine a list of input images.
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.
Structure definition of MUSE three extension FITS file.
cpl_propertylist * header
the FITS header
muse_image * muse_combine_average_create(muse_imagelist *aImages)
Average a list of input images.
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.
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.
muse_combinepar * muse_combinepar_new(cpl_parameterlist *aParameters, const char *aPrefix)
Create a new set of combination parameters.
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.