00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
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
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
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
00703
00704
00705 config->stackmethod = GISTACKING_METHOD_UNDEFINED;
00706 config->min_nr_frames = 0;
00707
00708
00709
00710
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
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 }