GIRAFFE Pipeline Reference Manual

gistacking.c

00001 /* $Id: gistacking.c,v 1.15 2011/12/23 13:40:23 rpalsa Exp $
00002  *
00003  * This file is part of the GIRAFFE Pipeline
00004  * Copyright (C) 2002-2006 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 /*
00022  * $Author: rpalsa $
00023  * $Date: 2011/12/23 13:40:23 $
00024  * $Revision: 1.15 $
00025  * $Name: giraffe-2_10 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #  include <config.h>
00030 #endif
00031 
00032 #include <math.h>
00033 
00034 #include <cxmemory.h>
00035 #include <cxmessages.h>
00036 #include <cxstrutils.h>
00037 #include <cxstring.h>
00038 
00039 #include <cpl_msg.h>
00040 #include <cpl_parameterlist.h>
00041 #include <cpl_vector.h>
00042 
00043 #include "gifiberutils.h"
00044 #include "gifibers.h"
00045 #include "gistacking.h"
00046 #include "giimage.h"
00047 #include "gimath.h"
00048 
00049 
00064 /*
00065  * Minimum number of images required for the different stacking methods.
00066  */
00067 
00068 enum {
00069     MIN_IMAGES_AVERAGE = 2,
00070     MIN_IMAGES_MEDIAN = 3,
00071     MIN_IMAGES_MINMAX = 3,
00072     MIN_IMAGES_KSIGMA = 2
00073 };
00074 
00075 
00076 inline static cxint
00077 _image_array_count(GiImage **img_array)
00078 {
00079     cxint count = 0;
00080 
00081     if (img_array == NULL) {
00082         return 0;
00083     }
00084 
00085     while (img_array[count] != NULL) {
00086         count++;
00087     }
00088 
00089     return count;
00090 
00091 }
00092 
00093 inline static cxbool
00094 _image_array_same_size(GiImage **img_array)
00095 {
00096 
00097     cxint num_images = 0,
00098           nrow,
00099           ncol,
00100           i;
00101 
00102     num_images = _image_array_count(img_array);
00103 
00104     if (num_images <= 0) {
00105         return FALSE;
00106     }
00107 
00108     ncol = cpl_image_get_size_x(giraffe_image_get(img_array[0]));
00109     nrow = cpl_image_get_size_y(giraffe_image_get(img_array[0]));
00110 
00111     for (i=1; i<num_images; i++) {
00112         if ((cpl_image_get_size_x(giraffe_image_get(img_array[i]))!=ncol) ||
00113             (cpl_image_get_size_y(giraffe_image_get(img_array[i]))!=nrow)) {
00114             return FALSE;
00115         }
00116     }
00117 
00118     return TRUE;
00119 
00120 }
00121 
00136 GiImage*
00137 giraffe_stacking_average(GiImage **img_array, const GiStackingConfig *config)
00138 {
00139 
00140     const cxchar *fctid = "giraffe_stacking_average";
00141 
00142     GiImage  *result     = NULL;
00143 
00144     cxint     num_images = 0,
00145               ncol       = 0,
00146               nrow       = 0,
00147               i          = 0;
00148     cxint     e_code     = 0;
00149 
00150     cxlong    npix       = 0L;
00151 
00152     cxdouble *pdresult   = NULL,
00153               inverse    = 0.0;
00154 
00155 
00156     /* Not used here! */
00157     config = NULL;
00158 
00159     num_images = _image_array_count(img_array);
00160 
00161     if (num_images<=0) {
00162         cpl_msg_error(fctid, "Empty array of images, aborting..." );
00163         return NULL;
00164     }
00165 
00166     if (_image_array_same_size(img_array)==FALSE) {
00167         cpl_msg_error(fctid, "Input Images are not the same size, "
00168                              "aborting..." );
00169         return NULL;
00170     }
00171 
00172     ncol = cpl_image_get_size_x(giraffe_image_get(img_array[0]));
00173     nrow = cpl_image_get_size_y(giraffe_image_get(img_array[0]));
00174     npix = ncol * nrow;
00175 
00176     result = giraffe_image_create(CPL_TYPE_DOUBLE, ncol, nrow);
00177     pdresult = cpl_image_get_data_double(giraffe_image_get(result));
00178 
00179     for (i = 0; i < npix; i++) {
00180         pdresult[i] = 0.0;
00181     }
00182 
00183     for (i = 0; i < num_images; i++) {
00184 
00185         e_code = cpl_image_add(giraffe_image_get(result),
00186                                giraffe_image_get(img_array[i]));
00187 
00188     }
00189 
00190     inverse = 1.0 / num_images;
00191 
00192     e_code = cpl_image_multiply_scalar(giraffe_image_get(result), inverse);
00193 
00194     return result;
00195 
00196 }
00197 
00212 GiImage*
00213 giraffe_stacking_median(GiImage **img_array, const GiStackingConfig *config)
00214 {
00215 
00216     const cxchar *fctid = "giraffe_stacking_median";
00217 
00218     cxint num_images = 0;
00219     cxint ncol = 0;
00220     cxint nrow = 0;
00221     cxint i = 0;
00222 
00223     cxlong npix = 0L;
00224     cxlong j = 0L;
00225 
00226     cxdouble *pdresult = NULL;
00227     cxdouble **pdimgs = NULL;
00228 
00229     cpl_vector *zvalue = NULL;
00230 
00231     GiImage  *result = NULL;
00232 
00233 
00234     /* Not used here! */
00235     config = NULL;
00236 
00237     num_images = _image_array_count(img_array);
00238 
00239     if (num_images <= 0) {
00240         cpl_msg_error(fctid, "Empty array of images, aborting..." );
00241         return NULL;
00242     }
00243 
00244     if (num_images < MIN_IMAGES_MEDIAN) {
00245         cpl_msg_error(fctid, "Not enough Images in array to perform median "
00246                              "stacking, aborting...");
00247         return NULL;
00248     }
00249 
00250     if (_image_array_same_size(img_array) == FALSE) {
00251         cpl_msg_error(fctid, "Input Images are not the same size, "
00252                              "aborting...");
00253         return NULL;
00254     }
00255 
00256     ncol = cpl_image_get_size_x(giraffe_image_get(img_array[0]));
00257     nrow = cpl_image_get_size_y(giraffe_image_get(img_array[0]));
00258     npix = ncol * nrow;
00259 
00260     result = giraffe_image_create(CPL_TYPE_DOUBLE, ncol, nrow);
00261     pdresult = cpl_image_get_data_double(giraffe_image_get(result));
00262 
00263     pdimgs = cx_calloc(num_images, sizeof(cxdouble*));
00264 
00265     zvalue = cpl_vector_new(num_images);
00266 
00267     for (i = 0; i < num_images; i++) {
00268         pdimgs[i] = cpl_image_get_data_double(giraffe_image_get(img_array[i]));
00269     }
00270 
00271     for (j = 0; j < npix; j++) {
00272         for (i = 0; i < num_images; i++) {
00273             cpl_vector_set(zvalue, i, (pdimgs[i])[j]);
00274         }
00275         pdresult[j] = cpl_vector_get_median(zvalue);
00276     }
00277 
00278     cpl_vector_delete(zvalue);
00279     zvalue = NULL;
00280 
00281     cx_free(pdimgs);
00282     pdimgs = NULL;
00283 
00284     return result;
00285 
00286 }
00287 
00313 GiImage*
00314 giraffe_stacking_minmax(GiImage **img_array, const GiStackingConfig *config)
00315 {
00316 
00317     const cxchar *fctid = "giraffe_stacking_minmax";
00318 
00319     cxint i = 0;
00320     cxint n = 0;
00321     cxint ncol = 0;
00322     cxint nrow = 0;
00323     cxint minn = 0;
00324     cxint maxn = 0;
00325     cxint num_images = 0;
00326 
00327     cxlong j = 0L;
00328     cxlong npix = 0L;
00329 
00330     cxdouble daverage = 0.;
00331     cxdouble dinvdeltan = 0.;
00332     cxdouble *pdresult = NULL;
00333     cxdouble **pdimgs = NULL;
00334 
00335     cpl_vector *zvalue = NULL;
00336 
00337     GiImage *result = NULL;
00338 
00339 
00340     num_images = _image_array_count(img_array);
00341 
00342     if (num_images <= 0) {
00343         cpl_msg_error(fctid, "Empty array of images, aborting...");
00344         return NULL;
00345     }
00346 
00347     if (num_images < MIN_IMAGES_MINMAX) {
00348         cpl_msg_error(fctid, "Not enough Images in array to perform minmax "
00349                              "stacking, aborting...");
00350         return NULL;
00351     }
00352 
00353     if (_image_array_same_size(img_array) == FALSE) {
00354         cpl_msg_error(fctid, "Input Images are not the same size, "
00355                              "aborting...");
00356         return NULL;
00357     }
00358 
00359     if ((config->rejectmin + config->rejectmax) >= num_images) {
00360         cpl_msg_error(fctid, "Max %d Input Images can be rejected, "
00361                              "aborting...", num_images - 1);
00362         return NULL;
00363     }
00364 
00365     if ((config->rejectmin == 0) || (config->rejectmax == 0)) {
00366         cpl_msg_error(fctid, "At least one value should be rejected [%d,%d],"
00367                              " aborting...", config->rejectmin,
00368                              config->rejectmax);
00369         return NULL;
00370     }
00371 
00372     ncol = cpl_image_get_size_x(giraffe_image_get(img_array[0]));
00373     nrow = cpl_image_get_size_y(giraffe_image_get(img_array[0]));
00374     npix = ncol * nrow;
00375 
00376     result = giraffe_image_create(CPL_TYPE_DOUBLE, ncol, nrow);
00377     pdresult = cpl_image_get_data_double(giraffe_image_get(result));
00378 
00379     minn = config->rejectmin;
00380     maxn = num_images - config->rejectmax;
00381 
00382     dinvdeltan = 1. / (maxn - minn);
00383 
00384     pdimgs = (cxdouble**) cx_calloc(num_images, sizeof(cxdouble*));
00385 
00386     zvalue = cpl_vector_new(num_images);
00387 
00388     for (i = 0; i < num_images; i++) {
00389         pdimgs[i] = cpl_image_get_data_double(giraffe_image_get(img_array[i]));
00390     }
00391 
00392     for (j = 0; j < npix; j++) {
00393         for (i = 0; i < num_images; i++) {
00394             cpl_vector_set(zvalue, i, (pdimgs[i])[j]);
00395         }
00396 
00397         cpl_vector_sort(zvalue, 1);
00398 
00399         daverage = 0.;
00400 
00401         for (n = minn; n < maxn; n++) {
00402             daverage += cpl_vector_get(zvalue, n);
00403         }
00404 
00405         pdresult[j] = daverage * dinvdeltan;
00406     }
00407 
00408     cpl_vector_delete(zvalue);
00409     zvalue = NULL;
00410 
00411     cx_free(pdimgs);
00412     pdimgs = NULL;
00413 
00414     return result;
00415 
00416 }
00417 
00440 GiImage*
00441 giraffe_stacking_ksigma(GiImage **img_array, const GiStackingConfig *config)
00442 {
00443 
00444     const cxchar *fctid = "giraffe_stacking_ksigma";
00445 
00446     cxint i = 0;
00447     cxint n = 0;
00448     cxint ncol = 0;
00449     cxint nrow = 0;
00450     cxint num_images = 0;
00451 
00452     cxlong j = 0L;
00453     cxlong npix = 0L;
00454     cxlong goodpix = 0L;
00455 
00456     cxdouble *pdresult = NULL;
00457     cxdouble **pdimgs = NULL;
00458 
00459     cpl_vector *zvalue = NULL;
00460 
00461     GiImage *result = NULL;
00462 
00463 
00464     num_images = _image_array_count(img_array);
00465 
00466     if (num_images <= 0) {
00467         cpl_msg_error(fctid, "Empty array of images, aborting...");
00468         return NULL;
00469     }
00470 
00471     if (num_images < MIN_IMAGES_KSIGMA) {
00472         cpl_msg_error(fctid, "Not enough Images in array to perform "
00473                              "kappa-sigma stacking, aborting...");
00474         return NULL;
00475     }
00476 
00477     if (_image_array_same_size(img_array) == FALSE) {
00478         cpl_msg_error(fctid, "Input Images are not the same size, "
00479                              "aborting...");
00480         return NULL;
00481     }
00482 
00483     ncol = cpl_image_get_size_x(giraffe_image_get(img_array[0]));
00484     nrow = cpl_image_get_size_y(giraffe_image_get(img_array[0]));
00485     npix = ncol * nrow;
00486 
00487     result = giraffe_image_create(CPL_TYPE_DOUBLE, ncol, nrow);
00488     pdresult = cpl_image_get_data_double(giraffe_image_get(result));
00489 
00490     pdimgs = (cxdouble**) cx_calloc(num_images, sizeof(cxdouble*));
00491 
00492     zvalue = cpl_vector_new(num_images);
00493 
00494     for (i = 0; i < num_images; i++) {
00495         pdimgs[i] = cpl_image_get_data_double(giraffe_image_get(img_array[i]));
00496     }
00497 
00498     for (j = 0; j < npix; j++) {
00499 
00500         cxdouble median = 0.;
00501         cxdouble sigma = 0.;
00502         cxdouble sum = 0.;
00503         cxdouble low_median = 0.;
00504         cxdouble high_median = 0.;
00505 
00506 
00507         for (i = 0; i < num_images; i++) {
00508             cpl_vector_set(zvalue, i, (pdimgs[i])[j]);
00509         }
00510 
00511         median = cpl_vector_get_median(zvalue);
00512 
00513         for (n = 0; n < num_images; n++) {
00514             sigma += fabs(cpl_vector_get(zvalue, n) - median);
00515         }
00516 
00517         sigma /= num_images;
00518 
00519         low_median  = median - ( sigma * config->ksigmalow );
00520         high_median = median + ( sigma * config->ksigmahigh );
00521 
00522         sum = 0.;
00523 
00524         goodpix = num_images;
00525 
00526         for (n = 0; n < num_images; n++) {
00527 
00528             cxdouble _zvalue = cpl_vector_get(zvalue, n);
00529 
00530             if ((_zvalue  < low_median) || (_zvalue > high_median)) {
00531                 --goodpix;
00532             }
00533             else {
00534                 sum += _zvalue;
00535             }
00536 
00537         }
00538 
00539         pdresult[j] = sum / goodpix;
00540     }
00541 
00542     cpl_vector_delete(zvalue);
00543     zvalue = NULL;
00544 
00545     cx_free(pdimgs);
00546     pdimgs = NULL;
00547 
00548     return result;
00549 
00550 }
00551 
00578 GiImage*
00579 giraffe_stacking_stack_images(GiImage **img_array,
00580                               const GiStackingConfig *config)
00581 {
00582 
00583     const cxchar *fctid = "giraffe_stacking_stack_images";
00584 
00585     GiImage *giimage_out;
00586     cxint    num_images = 0;
00587 
00588     cpl_msg_debug(fctid, "Procedure Start" );
00589 
00590     if (config == NULL) {
00591         return NULL;
00592     }
00593 
00594     if (img_array == NULL) {
00595         return NULL;
00596     }
00597 
00598     num_images = _image_array_count(img_array);
00599 
00600     switch (config->stackmethod) {
00601 
00602     case GISTACKING_METHOD_AVERAGE :
00603 
00604         cpl_msg_info(fctid, "Combination method is Average");
00605         cpl_msg_info(fctid, "Averaging %d images\n", num_images);
00606 
00607         giimage_out = giraffe_stacking_average(img_array, config);
00608 
00609         break;
00610 
00611     case GISTACKING_METHOD_MEDIAN :
00612 
00613         cpl_msg_info(fctid, "Combination method is Median");
00614         cpl_msg_info(fctid, "Finding median of %d images", num_images);
00615 
00616         giimage_out = giraffe_stacking_median(img_array, config);
00617 
00618         break;
00619 
00620     case GISTACKING_METHOD_MINMAX :
00621 
00622         cpl_msg_info(fctid, "Combination method is MinMax Rejection");
00623         cpl_msg_info(
00624             fctid,
00625             "Rejecting lower %d and upper %d pixel values out of possible %d",
00626             (cxint) (floor(num_images * config->rejectmin / 100.0)) + 1,
00627             (cxint) (floor(num_images * config->rejectmax / 100.0)) + 1,
00628             num_images
00629         );
00630 
00631         giimage_out = giraffe_stacking_minmax(img_array, config);
00632 
00633         break;
00634 
00635     case GISTACKING_METHOD_KSIGMA :
00636 
00637         cpl_msg_info(fctid, "Combination method is K-Sigma Clipping");
00638         cpl_msg_info(
00639             fctid,
00640             "K Low = %3.1f sigma, K High = %3.1f sigma",
00641             config->ksigmalow,
00642             config->ksigmahigh
00643         );
00644 
00645         giimage_out = giraffe_stacking_ksigma(img_array, config);
00646 
00647         break;
00648 
00649     case GISTACKING_METHOD_UNDEFINED :
00650     default :
00651 
00652 
00653         cpl_msg_error(fctid, "Invalid stacking method, aborting...");
00654 
00655         giimage_out = NULL;
00656         break;
00657     }
00658 
00659     cpl_msg_debug(fctid, "Procedure End" );
00660 
00661     return giimage_out;
00662 
00663 }
00664 
00680 GiStackingConfig *
00681 giraffe_stacking_config_create(cpl_parameterlist *list)
00682 {
00683 
00684     const cxchar *fctid = "giraffe_stacking_config_create";
00685 
00686 
00687     cxchar *method = NULL;
00688 
00689     cpl_parameter *p = NULL;
00690 
00691     GiStackingConfig *config = NULL;
00692 
00693 
00694     if (list == NULL) {
00695         return NULL;
00696     }
00697 
00698     config = cx_calloc(1, sizeof *config);
00699 
00700 
00701     /*
00702      * Some defaults
00703      */
00704 
00705     config->stackmethod   = GISTACKING_METHOD_UNDEFINED;
00706     config->min_nr_frames = 0;
00707 
00708 
00709     /*
00710      *  Retrieve parameter values...
00711      */
00712 
00713     p = cpl_parameterlist_find(list, "giraffe.stacking.method");
00714     method = cx_strdup(cpl_parameter_get_string(p));
00715 
00716     p = cpl_parameterlist_find(list, "giraffe.stacking.ksigma.low");
00717     config->ksigmalow = cpl_parameter_get_double(p);
00718 
00719     p = cpl_parameterlist_find(list, "giraffe.stacking.ksigma.high");
00720     config->ksigmahigh = cpl_parameter_get_double(p);
00721 
00722     p = cpl_parameterlist_find(list, "giraffe.stacking.minmax.minimum");
00723     config->rejectmin = cpl_parameter_get_int(p);
00724 
00725     p = cpl_parameterlist_find(list, "giraffe.stacking.minmax.maximum");
00726     config->rejectmax = cpl_parameter_get_int(p);
00727 
00728 
00729     /*
00730      * Select method.
00731      */
00732 
00733     if (strcmp(method, "average") == 0) {
00734         config->stackmethod = GISTACKING_METHOD_AVERAGE;
00735     }
00736 
00737     if (strcmp(method, "median") == 0) {
00738         config->stackmethod = GISTACKING_METHOD_MEDIAN;
00739     }
00740 
00741     if (strcmp(method, "minmax") == 0) {
00742         config->stackmethod = GISTACKING_METHOD_MINMAX;
00743     }
00744 
00745     if (strcmp(method, "ksigma") == 0) {
00746         config->stackmethod = GISTACKING_METHOD_KSIGMA;
00747     }
00748 
00749     cx_free(method);
00750 
00751     switch (config->stackmethod) {
00752     case GISTACKING_METHOD_AVERAGE:
00753         config->min_nr_frames = MIN_IMAGES_AVERAGE;
00754         break;
00755 
00756     case GISTACKING_METHOD_MEDIAN:
00757         config->min_nr_frames = MIN_IMAGES_MEDIAN;
00758         break;
00759 
00760     case GISTACKING_METHOD_MINMAX:
00761         config->min_nr_frames = MIN_IMAGES_MINMAX;
00762         break;
00763 
00764     case GISTACKING_METHOD_KSIGMA:
00765         config->min_nr_frames = MIN_IMAGES_KSIGMA;
00766         break;
00767 
00768     case GISTACKING_METHOD_UNDEFINED:
00769     default:
00770         giraffe_stacking_config_destroy(config);
00771         config = NULL;
00772 
00773         cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
00774 
00775         break;
00776     }
00777 
00778 
00779     return config;
00780 
00781 }
00782 
00783 
00796 void
00797 giraffe_stacking_config_destroy(GiStackingConfig *config)
00798 {
00799 
00800     if (config != NULL) {
00801         cx_free(config);
00802     }
00803 
00804     return;
00805 }
00806 
00807 
00819 void
00820 giraffe_stacking_config_add(cpl_parameterlist *list)
00821 {
00822 
00823     cpl_parameter *p;
00824 
00825     if (list == NULL) {
00826         return;
00827     }
00828 
00829     p = cpl_parameter_new_enum("giraffe.stacking.method",
00830                                CPL_TYPE_STRING,
00831                                "Stacking method: average, median, minmax or "
00832                                "ksigma",
00833                                "giraffe.stacking",
00834                                "average", 4, "average", "median",
00835                                "minmax", "ksigma");
00836 
00837     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-method");
00838     cpl_parameterlist_append(list, p);
00839 
00840     p = cpl_parameter_new_value("giraffe.stacking.ksigma.low",
00841                                 CPL_TYPE_DOUBLE,
00842                                 "Lower threshold multiplier for method "
00843                                 "ksigma",
00844                                 "giraffe.stacking.ksigma",
00845                                 5.0);
00846     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-ksigmalow");
00847     cpl_parameterlist_append(list, p);
00848 
00849     p = cpl_parameter_new_value("giraffe.stacking.ksigma.high",
00850                                 CPL_TYPE_DOUBLE,
00851                                 "Upper threshold multiplier for method "
00852                                 "ksigma",
00853                                 "giraffe.stacking.ksigma",
00854                                 5.0);
00855     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-ksigmahigh");
00856     cpl_parameterlist_append(list, p);
00857 
00858     p = cpl_parameter_new_value("giraffe.stacking.minmax.minimum",
00859                                 CPL_TYPE_INT,
00860                                 "Minimum rejection level for method minmax",
00861                                 "giraffe.stacking.minmax",
00862                                 1);
00863     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-minreject");
00864     cpl_parameterlist_append(list, p);
00865 
00866     p = cpl_parameter_new_value("giraffe.stacking.minmax.maximum",
00867                                 CPL_TYPE_INT,
00868                                 "Maximum rejection level for method minmax",
00869                                 "giraffe.stacking.minmax",
00870                                 1);
00871     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-maxreject");
00872     cpl_parameterlist_append(list, p);
00873 
00874     return;
00875 
00876 }

This file is part of the GIRAFFE Pipeline Reference Manual 2.10.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Thu Mar 7 14:11:02 2013 by doxygen 1.4.7 written by Dimitri van Heesch, © 1997-2004