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 
60 enum {
61  MIN_IMAGES_AVERAGE = 2,
62  MIN_IMAGES_MEDIAN = 3,
63  MIN_IMAGES_MINMAX = 3,
64  MIN_IMAGES_KSIGMA = 2
65 };
66 
67 
68 inline 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 
85 inline 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 
128 GiImage*
129 giraffe_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 
204 GiImage*
205 giraffe_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 
305 GiImage*
306 giraffe_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 
432 GiImage*
433 giraffe_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 
570 GiImage*
571 giraffe_stacking_stack_images(GiImage **img_array,
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 
672 GiStackingConfig *
673 giraffe_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 
788 void
789 giraffe_stacking_config_destroy(GiStackingConfig *config)
790 {
791 
792  if (config != NULL) {
793  cx_free(config);
794  }
795 
796  return;
797 }
798 
799 
811 void
812 giraffe_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
void giraffe_stacking_config_add(cpl_parameterlist *list)
Adds parameters for the stacking of images.
Definition: gistacking.c:812
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_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
GiStackingConfig * giraffe_stacking_config_create(cpl_parameterlist *list)
Creates a setup structure for the stacking of images.
Definition: gistacking.c:673
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
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
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

This file is part of the GIRAFFE Pipeline Reference Manual 2.16.10.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Thu Dec 15 2022 21:18:51 by doxygen 1.9.1 written by Dimitri van Heesch, © 1997-2004