GIRAFFE Pipeline Reference Manual

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

This file is part of the GIRAFFE Pipeline Reference Manual 2.12.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Mon Mar 24 2014 11:43:53 by doxygen 1.8.2 written by Dimitri van Heesch, © 1997-2004