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 }
00657
00658 cpl_msg_debug(fctid, "Procedure End" );
00659
00660 return giimage_out;
00661
00662 }
00663
00679 GiStackingConfig *
00680 giraffe_stacking_config_create(cpl_parameterlist *list)
00681 {
00682
00683 const cxchar *fctid = "giraffe_stacking_config_create";
00684
00685
00686 cxchar *method = NULL;
00687
00688 cpl_parameter *p = NULL;
00689
00690 GiStackingConfig *config = NULL;
00691
00692
00693 if (list == NULL) {
00694 return NULL;
00695 }
00696
00697 config = cx_calloc(1, sizeof *config);
00698
00699
00700
00701
00702
00703
00704 config->stackmethod = GISTACKING_METHOD_UNDEFINED;
00705 config->min_nr_frames = 0;
00706
00707
00708
00709
00710
00711
00712 p = cpl_parameterlist_find(list, "giraffe.stacking.method");
00713 method = cx_strdup(cpl_parameter_get_string(p));
00714
00715 p = cpl_parameterlist_find(list, "giraffe.stacking.ksigma.low");
00716 config->ksigmalow = cpl_parameter_get_double(p);
00717
00718 p = cpl_parameterlist_find(list, "giraffe.stacking.ksigma.high");
00719 config->ksigmahigh = cpl_parameter_get_double(p);
00720
00721 p = cpl_parameterlist_find(list, "giraffe.stacking.minmax.minimum");
00722 config->rejectmin = cpl_parameter_get_int(p);
00723
00724 p = cpl_parameterlist_find(list, "giraffe.stacking.minmax.maximum");
00725 config->rejectmax = cpl_parameter_get_int(p);
00726
00727
00728
00729
00730
00731
00732 if (strcmp(method, "average") == 0) {
00733 config->stackmethod = GISTACKING_METHOD_AVERAGE;
00734 }
00735
00736 if (strcmp(method, "median") == 0) {
00737 config->stackmethod = GISTACKING_METHOD_MEDIAN;
00738 }
00739
00740 if (strcmp(method, "minmax") == 0) {
00741 config->stackmethod = GISTACKING_METHOD_MINMAX;
00742 }
00743
00744 if (strcmp(method, "ksigma") == 0) {
00745 config->stackmethod = GISTACKING_METHOD_KSIGMA;
00746 }
00747
00748 cx_free(method);
00749
00750 switch (config->stackmethod) {
00751 case GISTACKING_METHOD_AVERAGE:
00752 config->min_nr_frames = MIN_IMAGES_AVERAGE;
00753 break;
00754
00755 case GISTACKING_METHOD_MEDIAN:
00756 config->min_nr_frames = MIN_IMAGES_MEDIAN;
00757 break;
00758
00759 case GISTACKING_METHOD_MINMAX:
00760 config->min_nr_frames = MIN_IMAGES_MINMAX;
00761 break;
00762
00763 case GISTACKING_METHOD_KSIGMA:
00764 config->min_nr_frames = MIN_IMAGES_KSIGMA;
00765 break;
00766
00767 case GISTACKING_METHOD_UNDEFINED:
00768 default:
00769 giraffe_stacking_config_destroy(config);
00770 config = NULL;
00771
00772 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
00773
00774 break;
00775 }
00776
00777
00778 return config;
00779
00780 }
00781
00782
00795 void
00796 giraffe_stacking_config_destroy(GiStackingConfig *config)
00797 {
00798
00799 if (config != NULL) {
00800 cx_free(config);
00801 }
00802
00803 return;
00804 }
00805
00806
00818 void
00819 giraffe_stacking_config_add(cpl_parameterlist *list)
00820 {
00821
00822 cpl_parameter *p;
00823
00824 if (list == NULL) {
00825 return;
00826 }
00827
00828 p = cpl_parameter_new_enum("giraffe.stacking.method",
00829 CPL_TYPE_STRING,
00830 "Stacking method: average, median, minmax or "
00831 "ksigma",
00832 "giraffe.stacking",
00833 "average", 4, "average", "median",
00834 "minmax", "ksigma");
00835
00836 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-method");
00837 cpl_parameterlist_append(list, p);
00838
00839 p = cpl_parameter_new_value("giraffe.stacking.ksigma.low",
00840 CPL_TYPE_DOUBLE,
00841 "Lower threshold multiplier for method "
00842 "ksigma",
00843 "giraffe.stacking.ksigma",
00844 5.0);
00845 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-ksigmalow");
00846 cpl_parameterlist_append(list, p);
00847
00848 p = cpl_parameter_new_value("giraffe.stacking.ksigma.high",
00849 CPL_TYPE_DOUBLE,
00850 "Upper threshold multiplier for method "
00851 "ksigma",
00852 "giraffe.stacking.ksigma",
00853 5.0);
00854 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-ksigmahigh");
00855 cpl_parameterlist_append(list, p);
00856
00857 p = cpl_parameter_new_value("giraffe.stacking.minmax.minimum",
00858 CPL_TYPE_INT,
00859 "Minimum rejection level for method minmax",
00860 "giraffe.stacking.minmax",
00861 1);
00862 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-minreject");
00863 cpl_parameterlist_append(list, p);
00864
00865 p = cpl_parameter_new_value("giraffe.stacking.minmax.maximum",
00866 CPL_TYPE_INT,
00867 "Maximum rejection level for method minmax",
00868 "giraffe.stacking.minmax",
00869 1);
00870 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stack-maxreject");
00871 cpl_parameterlist_append(list, p);
00872
00873 return;
00874
00875 }