GIRAFFE Pipeline Reference Manual

gistacking.c
1/*
2 * This file is part of the GIRAFFE Pipeline
3 * Copyright (C) 2002-2019 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
24#include <math.h>
25
26#include <cxmemory.h>
27#include <cxmessages.h>
28#include <cxstrutils.h>
29#include <cxstring.h>
30
31#include <cpl_msg.h>
32#include <cpl_parameterlist.h>
33#include <cpl_vector.h>
34
35#include "gifiberutils.h"
36#include "gifibers.h"
37#include "gistacking.h"
38#include "giimage.h"
39#include "gimath.h"
40
41
56/*
57 * Minimum number of images required for the different stacking methods.
58 */
59
60enum {
61 MIN_IMAGES_AVERAGE = 2,
62 MIN_IMAGES_MEDIAN = 3,
63 MIN_IMAGES_MINMAX = 3,
64 MIN_IMAGES_KSIGMA = 2
65};
66
67
68inline static cxint
69_image_array_count(GiImage **img_array)
70{
71 cxint count = 0;
72
73 if (img_array == NULL) {
74 return 0;
75 }
76
77 while (img_array[count] != NULL) {
78 count++;
79 }
80
81 return count;
82
83}
84
85inline static cxbool
86_image_array_same_size(GiImage **img_array)
87{
88
89 cxint num_images = 0,
90 nrow,
91 ncol,
92 i;
93
94 num_images = _image_array_count(img_array);
95
96 if (num_images <= 0) {
97 return FALSE;
98 }
99
100 ncol = cpl_image_get_size_x(giraffe_image_get(img_array[0]));
101 nrow = cpl_image_get_size_y(giraffe_image_get(img_array[0]));
102
103 for (i=1; i<num_images; i++) {
104 if ((cpl_image_get_size_x(giraffe_image_get(img_array[i]))!=ncol) ||
105 (cpl_image_get_size_y(giraffe_image_get(img_array[i]))!=nrow)) {
106 return FALSE;
107 }
108 }
109
110 return TRUE;
111
112}
113
128GiImage*
129giraffe_stacking_average(GiImage **img_array, const GiStackingConfig *config)
130{
131
132 const cxchar *fctid = "giraffe_stacking_average";
133
134 GiImage *result = NULL;
135
136 cxint num_images = 0,
137 ncol = 0,
138 nrow = 0,
139 i = 0;
140 /*cxint e_code = 0;*/
141
142 cxlong npix = 0L;
143
144 cxdouble *pdresult = NULL,
145 inverse = 0.0;
146
147
148 /* Not used here! */
149 (void) config;
150
151 num_images = _image_array_count(img_array);
152
153 if (num_images<=0) {
154 cpl_msg_error(fctid, "Empty array of images, aborting..." );
155 return NULL;
156 }
157
158 if (_image_array_same_size(img_array)==FALSE) {
159 cpl_msg_error(fctid, "Input Images are not the same size, "
160 "aborting..." );
161 return NULL;
162 }
163
164 ncol = cpl_image_get_size_x(giraffe_image_get(img_array[0]));
165 nrow = cpl_image_get_size_y(giraffe_image_get(img_array[0]));
166 npix = ncol * nrow;
167
168 result = giraffe_image_create(CPL_TYPE_DOUBLE, ncol, nrow);
169 pdresult = cpl_image_get_data_double(giraffe_image_get(result));
170
171 for (i = 0; i < npix; i++) {
172 pdresult[i] = 0.0;
173 }
174
175 for (i = 0; i < num_images; i++) {
176
177 /*e_code =*/ cpl_image_add(giraffe_image_get(result),
178 giraffe_image_get(img_array[i]));
179
180 }
181
182 inverse = 1.0 / num_images;
183
184 /*e_code =*/ cpl_image_multiply_scalar(giraffe_image_get(result), inverse);
185
186 return result;
187
188}
189
204GiImage*
205giraffe_stacking_median(GiImage **img_array, const GiStackingConfig *config)
206{
207
208 const cxchar *fctid = "giraffe_stacking_median";
209
210 cxint num_images = 0;
211 cxint ncol = 0;
212 cxint nrow = 0;
213 cxint i = 0;
214
215 cxlong npix = 0L;
216 cxlong j = 0L;
217
218 cxdouble *pdresult = NULL;
219 cxdouble **pdimgs = NULL;
220
221 cpl_vector *zvalue = NULL;
222
223 GiImage *result = NULL;
224
225
226 /* Not used here! */
227 (void) config;
228
229 num_images = _image_array_count(img_array);
230
231 if (num_images <= 0) {
232 cpl_msg_error(fctid, "Empty array of images, aborting..." );
233 return NULL;
234 }
235
236 if (num_images < MIN_IMAGES_MEDIAN) {
237 cpl_msg_error(fctid, "Not enough Images in array to perform median "
238 "stacking, aborting...");
239 return NULL;
240 }
241
242 if (_image_array_same_size(img_array) == FALSE) {
243 cpl_msg_error(fctid, "Input Images are not the same size, "
244 "aborting...");
245 return NULL;
246 }
247
248 ncol = cpl_image_get_size_x(giraffe_image_get(img_array[0]));
249 nrow = cpl_image_get_size_y(giraffe_image_get(img_array[0]));
250 npix = ncol * nrow;
251
252 result = giraffe_image_create(CPL_TYPE_DOUBLE, ncol, nrow);
253 pdresult = cpl_image_get_data_double(giraffe_image_get(result));
254
255 pdimgs = cx_calloc(num_images, sizeof(cxdouble*));
256
257 zvalue = cpl_vector_new(num_images);
258
259 for (i = 0; i < num_images; i++) {
260 pdimgs[i] = cpl_image_get_data_double(giraffe_image_get(img_array[i]));
261 }
262
263 for (j = 0; j < npix; j++) {
264 for (i = 0; i < num_images; i++) {
265 cpl_vector_set(zvalue, i, (pdimgs[i])[j]);
266 }
267 pdresult[j] = cpl_vector_get_median(zvalue);
268 }
269
270 cpl_vector_delete(zvalue);
271 zvalue = NULL;
272
273 cx_free(pdimgs);
274 pdimgs = NULL;
275
276 return result;
277
278}
279
305GiImage*
306giraffe_stacking_minmax(GiImage **img_array, const GiStackingConfig *config)
307{
308
309 const cxchar *fctid = "giraffe_stacking_minmax";
310
311 cxint i = 0;
312 cxint n = 0;
313 cxint ncol = 0;
314 cxint nrow = 0;
315 cxint minn = 0;
316 cxint maxn = 0;
317 cxint num_images = 0;
318
319 cxlong j = 0L;
320 cxlong npix = 0L;
321
322 cxdouble daverage = 0.;
323 cxdouble dinvdeltan = 0.;
324 cxdouble *pdresult = NULL;
325 cxdouble **pdimgs = NULL;
326
327 cpl_vector *zvalue = NULL;
328
329 GiImage *result = NULL;
330
331
332 num_images = _image_array_count(img_array);
333
334 if (num_images <= 0) {
335 cpl_msg_error(fctid, "Empty array of images, aborting...");
336 return NULL;
337 }
338
339 if (num_images < MIN_IMAGES_MINMAX) {
340 cpl_msg_error(fctid, "Not enough Images in array to perform minmax "
341 "stacking, aborting...");
342 return NULL;
343 }
344
345 if (_image_array_same_size(img_array) == FALSE) {
346 cpl_msg_error(fctid, "Input Images are not the same size, "
347 "aborting...");
348 return NULL;
349 }
350
351 if ((config->rejectmin + config->rejectmax) >= num_images) {
352 cpl_msg_error(fctid, "Max %d Input Images can be rejected, "
353 "aborting...", num_images - 1);
354 return NULL;
355 }
356
357 if ((config->rejectmin == 0) || (config->rejectmax == 0)) {
358 cpl_msg_error(fctid, "At least one value should be rejected [%d,%d],"
359 " aborting...", config->rejectmin,
360 config->rejectmax);
361 return NULL;
362 }
363
364 ncol = cpl_image_get_size_x(giraffe_image_get(img_array[0]));
365 nrow = cpl_image_get_size_y(giraffe_image_get(img_array[0]));
366 npix = ncol * nrow;
367
368 result = giraffe_image_create(CPL_TYPE_DOUBLE, ncol, nrow);
369 pdresult = cpl_image_get_data_double(giraffe_image_get(result));
370
371 minn = config->rejectmin;
372 maxn = num_images - config->rejectmax;
373
374 dinvdeltan = 1. / (maxn - minn);
375
376 pdimgs = (cxdouble**) cx_calloc(num_images, sizeof(cxdouble*));
377
378 zvalue = cpl_vector_new(num_images);
379
380 for (i = 0; i < num_images; i++) {
381 pdimgs[i] = cpl_image_get_data_double(giraffe_image_get(img_array[i]));
382 }
383
384 for (j = 0; j < npix; j++) {
385 for (i = 0; i < num_images; i++) {
386 cpl_vector_set(zvalue, i, (pdimgs[i])[j]);
387 }
388
389 cpl_vector_sort(zvalue, 1);
390
391 daverage = 0.;
392
393 for (n = minn; n < maxn; n++) {
394 daverage += cpl_vector_get(zvalue, n);
395 }
396
397 pdresult[j] = daverage * dinvdeltan;
398 }
399
400 cpl_vector_delete(zvalue);
401 zvalue = NULL;
402
403 cx_free(pdimgs);
404 pdimgs = NULL;
405
406 return result;
407
408}
409
432GiImage*
433giraffe_stacking_ksigma(GiImage **img_array, const GiStackingConfig *config)
434{
435
436 const cxchar *fctid = "giraffe_stacking_ksigma";
437
438 cxint i = 0;
439 cxint n = 0;
440 cxint ncol = 0;
441 cxint nrow = 0;
442 cxint num_images = 0;
443
444 cxlong j = 0L;
445 cxlong npix = 0L;
446 cxlong goodpix = 0L;
447
448 cxdouble *pdresult = NULL;
449 cxdouble **pdimgs = NULL;
450
451 cpl_vector *zvalue = NULL;
452
453 GiImage *result = NULL;
454
455
456 num_images = _image_array_count(img_array);
457
458 if (num_images <= 0) {
459 cpl_msg_error(fctid, "Empty array of images, aborting...");
460 return NULL;
461 }
462
463 if (num_images < MIN_IMAGES_KSIGMA) {
464 cpl_msg_error(fctid, "Not enough Images in array to perform "
465 "kappa-sigma stacking, aborting...");
466 return NULL;
467 }
468
469 if (_image_array_same_size(img_array) == FALSE) {
470 cpl_msg_error(fctid, "Input Images are not the same size, "
471 "aborting...");
472 return NULL;
473 }
474
475 ncol = cpl_image_get_size_x(giraffe_image_get(img_array[0]));
476 nrow = cpl_image_get_size_y(giraffe_image_get(img_array[0]));
477 npix = ncol * nrow;
478
479 result = giraffe_image_create(CPL_TYPE_DOUBLE, ncol, nrow);
480 pdresult = cpl_image_get_data_double(giraffe_image_get(result));
481
482 pdimgs = (cxdouble**) cx_calloc(num_images, sizeof(cxdouble*));
483
484 zvalue = cpl_vector_new(num_images);
485
486 for (i = 0; i < num_images; i++) {
487 pdimgs[i] = cpl_image_get_data_double(giraffe_image_get(img_array[i]));
488 }
489
490 for (j = 0; j < npix; j++) {
491
492 cxdouble median = 0.;
493 cxdouble sigma = 0.;
494 cxdouble sum = 0.;
495 cxdouble low_median = 0.;
496 cxdouble high_median = 0.;
497
498
499 for (i = 0; i < num_images; i++) {
500 cpl_vector_set(zvalue, i, (pdimgs[i])[j]);
501 }
502
503 median = cpl_vector_get_median(zvalue);
504
505 for (n = 0; n < num_images; n++) {
506 sigma += fabs(cpl_vector_get(zvalue, n) - median);
507 }
508
509 sigma /= num_images;
510
511 low_median = median - ( sigma * config->ksigmalow );
512 high_median = median + ( sigma * config->ksigmahigh );
513
514 sum = 0.;
515
516 goodpix = num_images;
517
518 for (n = 0; n < num_images; n++) {
519
520 cxdouble _zvalue = cpl_vector_get(zvalue, n);
521
522 if ((_zvalue < low_median) || (_zvalue > high_median)) {
523 --goodpix;
524 }
525 else {
526 sum += _zvalue;
527 }
528
529 }
530
531 pdresult[j] = sum / goodpix;
532 }
533
534 cpl_vector_delete(zvalue);
535 zvalue = NULL;
536
537 cx_free(pdimgs);
538 pdimgs = NULL;
539
540 return result;
541
542}
543
570GiImage*
572 const GiStackingConfig *config)
573{
574
575 const cxchar *fctid = "giraffe_stacking_stack_images";
576
577 GiImage *giimage_out;
578 cxint num_images = 0;
579
580 cpl_msg_debug(fctid, "Procedure Start" );
581
582 if (config == NULL) {
583 return NULL;
584 }
585
586 if (img_array == NULL) {
587 return NULL;
588 }
589
590 num_images = _image_array_count(img_array);
591
592 switch (config->stackmethod) {
593
594 case GISTACKING_METHOD_AVERAGE :
595
596 cpl_msg_info(fctid, "Combination method is Average");
597 cpl_msg_info(fctid, "Averaging %d images\n", num_images);
598
599 giimage_out = giraffe_stacking_average(img_array, config);
600
601 break;
602
603 case GISTACKING_METHOD_MEDIAN :
604
605 cpl_msg_info(fctid, "Combination method is Median");
606 cpl_msg_info(fctid, "Finding median of %d images", num_images);
607
608 giimage_out = giraffe_stacking_median(img_array, config);
609
610 break;
611
612 case GISTACKING_METHOD_MINMAX :
613
614 cpl_msg_info(fctid, "Combination method is MinMax Rejection");
615 cpl_msg_info(
616 fctid,
617 "Rejecting lower %d and upper %d pixel values out of possible %d",
618 (cxint) (floor(num_images * config->rejectmin / 100.0)) + 1,
619 (cxint) (floor(num_images * config->rejectmax / 100.0)) + 1,
620 num_images
621 );
622
623 giimage_out = giraffe_stacking_minmax(img_array, config);
624
625 break;
626
627 case GISTACKING_METHOD_KSIGMA :
628
629 cpl_msg_info(fctid, "Combination method is K-Sigma Clipping");
630 cpl_msg_info(
631 fctid,
632 "K Low = %3.1f sigma, K High = %3.1f sigma",
633 config->ksigmalow,
634 config->ksigmahigh
635 );
636
637 giimage_out = giraffe_stacking_ksigma(img_array, config);
638
639 break;
640
641 case GISTACKING_METHOD_UNDEFINED :
642 default :
643
644
645 cpl_msg_error(fctid, "Invalid stacking method, aborting...");
646
647 giimage_out = NULL;
648 break;
649 }
650
651 cpl_msg_debug(fctid, "Procedure End" );
652
653 return giimage_out;
654
655}
656
672GiStackingConfig *
673giraffe_stacking_config_create(cpl_parameterlist *list)
674{
675
676 const cxchar *fctid = "giraffe_stacking_config_create";
677
678
679 cxchar *method = NULL;
680
681 cpl_parameter *p = NULL;
682
683 GiStackingConfig *config = NULL;
684
685
686 if (list == NULL) {
687 return NULL;
688 }
689
690 config = cx_calloc(1, sizeof *config);
691
692
693 /*
694 * Some defaults
695 */
696
697 config->stackmethod = GISTACKING_METHOD_UNDEFINED;
698 config->min_nr_frames = 0;
699
700
701 /*
702 * Retrieve parameter values...
703 */
704
705 p = cpl_parameterlist_find(list, "giraffe.stacking.method");
706 method = cx_strdup(cpl_parameter_get_string(p));
707
708 p = cpl_parameterlist_find(list, "giraffe.stacking.ksigma.low");
709 config->ksigmalow = cpl_parameter_get_double(p);
710
711 p = cpl_parameterlist_find(list, "giraffe.stacking.ksigma.high");
712 config->ksigmahigh = cpl_parameter_get_double(p);
713
714 p = cpl_parameterlist_find(list, "giraffe.stacking.minmax.minimum");
715 config->rejectmin = cpl_parameter_get_int(p);
716
717 p = cpl_parameterlist_find(list, "giraffe.stacking.minmax.maximum");
718 config->rejectmax = cpl_parameter_get_int(p);
719
720
721 /*
722 * Select method.
723 */
724
725 if (strcmp(method, "average") == 0) {
726 config->stackmethod = GISTACKING_METHOD_AVERAGE;
727 }
728
729 if (strcmp(method, "median") == 0) {
730 config->stackmethod = GISTACKING_METHOD_MEDIAN;
731 }
732
733 if (strcmp(method, "minmax") == 0) {
734 config->stackmethod = GISTACKING_METHOD_MINMAX;
735 }
736
737 if (strcmp(method, "ksigma") == 0) {
738 config->stackmethod = GISTACKING_METHOD_KSIGMA;
739 }
740
741 cx_free(method);
742
743 switch (config->stackmethod) {
744 case GISTACKING_METHOD_AVERAGE:
745 config->min_nr_frames = MIN_IMAGES_AVERAGE;
746 break;
747
748 case GISTACKING_METHOD_MEDIAN:
749 config->min_nr_frames = MIN_IMAGES_MEDIAN;
750 break;
751
752 case GISTACKING_METHOD_MINMAX:
753 config->min_nr_frames = MIN_IMAGES_MINMAX;
754 break;
755
756 case GISTACKING_METHOD_KSIGMA:
757 config->min_nr_frames = MIN_IMAGES_KSIGMA;
758 break;
759
760 case GISTACKING_METHOD_UNDEFINED:
761 default:
763 config = NULL;
764
765 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
766
767 break;
768 }
769
770
771 return config;
772
773}
774
775
788void
789giraffe_stacking_config_destroy(GiStackingConfig *config)
790{
791
792 if (config != NULL) {
793 cx_free(config);
794 }
795
796 return;
797}
798
799
811void
812giraffe_stacking_config_add(cpl_parameterlist *list)
813{
814
815 cpl_parameter *p;
816
817 if (list == NULL) {
818 return;
819 }
820
821 p = cpl_parameter_new_enum("giraffe.stacking.method",
822 CPL_TYPE_STRING,
823 "Stacking method: average, median, minmax or "
824 "ksigma",
825 "giraffe.stacking",
826 "average", 4, "average", "median",
827 "minmax", "ksigma");
828
829 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-method");
830 cpl_parameterlist_append(list, p);
831
832 p = cpl_parameter_new_value("giraffe.stacking.ksigma.low",
833 CPL_TYPE_DOUBLE,
834 "Lower threshold multiplier for method "
835 "ksigma",
836 "giraffe.stacking.ksigma",
837 5.0);
838 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-ksigmalow");
839 cpl_parameterlist_append(list, p);
840
841 p = cpl_parameter_new_value("giraffe.stacking.ksigma.high",
842 CPL_TYPE_DOUBLE,
843 "Upper threshold multiplier for method "
844 "ksigma",
845 "giraffe.stacking.ksigma",
846 5.0);
847 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-ksigmahigh");
848 cpl_parameterlist_append(list, p);
849
850 p = cpl_parameter_new_value("giraffe.stacking.minmax.minimum",
851 CPL_TYPE_INT,
852 "Minimum rejection level for method minmax",
853 "giraffe.stacking.minmax",
854 1);
855 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-minreject");
856 cpl_parameterlist_append(list, p);
857
858 p = cpl_parameter_new_value("giraffe.stacking.minmax.maximum",
859 CPL_TYPE_INT,
860 "Maximum rejection level for method minmax",
861 "giraffe.stacking.minmax",
862 1);
863 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-maxreject");
864 cpl_parameterlist_append(list, p);
865
866 return;
867
868}
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
Definition: giimage.c:218
GiImage * giraffe_image_create(cpl_type type, cxint nx, cxint ny)
Creates an image container of a given type.
Definition: giimage.c:95
GiImage * giraffe_stacking_ksigma(GiImage **img_array, const GiStackingConfig *config)
Stack a list of images using Kappa Sigma Clipping and return the resulting image.
Definition: gistacking.c:433
void giraffe_stacking_config_add(cpl_parameterlist *list)
Adds parameters for the stacking of images.
Definition: gistacking.c:812
GiImage * giraffe_stacking_average(GiImage **img_array, const GiStackingConfig *config)
Stack a list of images using averaging and return the resulting image.
Definition: gistacking.c:129
void giraffe_stacking_config_destroy(GiStackingConfig *config)
Destroys a setup structure for the stacking of images.
Definition: gistacking.c:789
GiImage * giraffe_stacking_minmax(GiImage **img_array, const GiStackingConfig *config)
Stack a list of images using minmax rejection and return the resulting image.
Definition: gistacking.c:306
GiStackingConfig * giraffe_stacking_config_create(cpl_parameterlist *list)
Creates a setup structure for the stacking of images.
Definition: gistacking.c:673
GiImage * giraffe_stacking_median(GiImage **img_array, const GiStackingConfig *config)
Stack a list of images using median and return the resulting image.
Definition: gistacking.c:205
GiImage * giraffe_stacking_stack_images(GiImage **img_array, const GiStackingConfig *config)
Stack a list of images using one of four different kinds of stacking and return the resulting image.
Definition: gistacking.c:571

This file is part of the GIRAFFE Pipeline Reference Manual 2.16.14.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Wed Jan 15 2025 22:16:53 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2004