00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef HAVE_CONFIG_H
00023 #include <config.h>
00024 #endif
00025
00026
00027
00028
00029 #include <cpl.h>
00030 #include <string.h>
00031
00032 #include "muse_image.h"
00033
00034 #include "muse_quadrants.h"
00035 #include "muse_quality.h"
00036 #include "muse_pfits.h"
00037 #include "muse_utils.h"
00038 #include "muse_wcs.h"
00039
00040
00047
00048
00051
00064
00065 muse_image *
00066 muse_image_new(void)
00067 {
00068
00069 muse_image *image = (muse_image *)cpl_calloc(1, sizeof(muse_image));
00070 return image;
00071 }
00072
00073
00083
00084 void
00085 muse_image_delete(muse_image *aImage)
00086 {
00087
00088 if (!aImage) {
00089 return;
00090 }
00091
00092
00093
00094 cpl_image_delete(aImage->data);
00095 aImage->data = NULL;
00096 cpl_image_delete(aImage->dq);
00097 aImage->dq = NULL;
00098 cpl_image_delete(aImage->stat);
00099 aImage->stat = NULL;
00100
00101
00102 cpl_propertylist_delete(aImage->header);
00103 aImage->header = NULL;
00104 cpl_free(aImage);
00105 }
00106
00107
00115
00116 static muse_image *
00117 muse_image_load_internal(const char *aFilename, unsigned char aIFU,
00118 const char *aID)
00119 {
00120 muse_image *image = muse_image_new();
00121
00122
00123
00124 image->header = cpl_propertylist_load(aFilename, 0);
00125 if (!image->header) {
00126 cpl_error_set_message(aID, cpl_error_get_code(), "Loading primary FITS "
00127 "header of \"%s\" did not succeed", aFilename);
00128 muse_image_delete(image);
00129 return NULL;
00130 }
00131
00132
00133 char extname[KEYWORD_LENGTH];
00134 if (aIFU) {
00135
00136 snprintf(extname, KEYWORD_LENGTH, "CHAN%02hhu", aIFU);
00137 cpl_propertylist_update_string(image->header, "EXTNAME", extname);
00138
00139 snprintf(extname, KEYWORD_LENGTH, "CHAN%02hhu.%s", aIFU, EXTNAME_DATA);
00140 } else {
00141 snprintf(extname, KEYWORD_LENGTH, "%s", EXTNAME_DATA);
00142 }
00143 int extension = cpl_fits_find_extension(aFilename, extname);
00144 image->data = cpl_image_load(aFilename, CPL_TYPE_FLOAT, 0, extension);
00145 if (!image->data) {
00146 cpl_error_set_message(aID, MUSE_ERROR_READ_DATA, "Could not load extension "
00147 "%s from \"%s\"", extname, aFilename);
00148 muse_image_delete(image);
00149 return NULL;
00150 }
00151
00152 cpl_propertylist *hdata = cpl_propertylist_load(aFilename, extension);
00153 if (cpl_propertylist_has(hdata, "BUNIT")) {
00154 cpl_propertylist_append_string(image->header, "BUNIT",
00155 muse_pfits_get_bunit(hdata));
00156 cpl_propertylist_set_comment(image->header, "BUNIT",
00157 cpl_propertylist_get_comment(hdata, "BUNIT"));
00158 } else {
00159 cpl_msg_warning(aID, "No BUNIT given in extension %d [%s] of \"%s\"!",
00160 extension, extname, aFilename);
00161 }
00162
00163
00164 if (aIFU) {
00165 cpl_propertylist_erase_regexp(hdata, "^ESO ", 1);
00166 cpl_propertylist_append(image->header, hdata);
00167 }
00168 cpl_propertylist_delete(hdata);
00169
00170 if (aIFU) {
00171 snprintf(extname, KEYWORD_LENGTH, "CHAN%02hhu.%s", aIFU, EXTNAME_DQ);
00172 } else {
00173 snprintf(extname, KEYWORD_LENGTH, "%s", EXTNAME_DQ);
00174 }
00175 extension = cpl_fits_find_extension(aFilename, extname);
00176 image->dq = cpl_image_load(aFilename, CPL_TYPE_INT, 0, extension);
00177 if (!image->dq) {
00178 cpl_error_set_message(aID, MUSE_ERROR_READ_DQ, "Could not load extension "
00179 "%s from \"%s\"", extname, aFilename);
00180 muse_image_delete(image);
00181 return NULL;
00182 }
00183
00184 if (aIFU) {
00185 snprintf(extname, KEYWORD_LENGTH, "CHAN%02hhu.%s", aIFU, EXTNAME_STAT);
00186 } else {
00187 snprintf(extname, KEYWORD_LENGTH, "%s", EXTNAME_STAT);
00188 }
00189 extension = cpl_fits_find_extension(aFilename, extname);
00190 image->stat = cpl_image_load(aFilename, CPL_TYPE_FLOAT, 0, extension);
00191 if (!image->stat) {
00192 cpl_error_set_message(aID, MUSE_ERROR_READ_STAT, "Could not load extension "
00193 "%s from \"%s\"", extname, aFilename);
00194 muse_image_delete(image);
00195 return NULL;
00196 }
00197
00198 return image;
00199 }
00200
00201
00226
00227 muse_image *
00228 muse_image_load(const char *aFilename)
00229 {
00230 return muse_image_load_internal(aFilename, 0, __func__);
00231 }
00232
00233
00260
00261 muse_image *
00262 muse_image_load_from_extensions(const char *aFilename, unsigned char aIFU)
00263 {
00264 return muse_image_load_internal(aFilename, aIFU, __func__);
00265 }
00266
00267
00290
00291 muse_image *
00292 muse_image_load_from_raw(const char *aFilename, int aExtension)
00293 {
00294 muse_image *mImage = muse_image_new();
00295
00296 cpl_errorstate prestate = cpl_errorstate_get();
00297
00298
00299 mImage->data = cpl_image_load(aFilename, CPL_TYPE_FLOAT, 0, aExtension);
00300 char *channel = NULL;
00301 if (!mImage->data) {
00302 muse_image_delete(mImage);
00303
00304 cpl_propertylist *header = cpl_propertylist_load(aFilename, aExtension);
00305 if (!header) {
00306 cpl_msg_error(__func__, "Image \"%s\" (extension %d) could not be read: %s",
00307 aFilename, aExtension, cpl_error_get_message());
00308 return NULL;
00309 }
00310
00311
00312 cpl_boolean live = muse_pfits_get_chip_live(header);
00313 channel = cpl_strdup(muse_pfits_get_extname(header));
00314 cpl_propertylist_delete(header);
00315 if (live) {
00316 cpl_msg_error(__func__, "Image \"%s[%s]\" (extension %d) could not be read "
00317 "although chip is alive: %s", aFilename, channel, aExtension,
00318 cpl_error_get_message());
00319 cpl_free(channel);
00320 return NULL;
00321 }
00322 cpl_msg_warning(__func__, "Image \"%s[%s]\" (extension %d) could not be read,"
00323 " but chip is dead: %s", aFilename, channel, aExtension,
00324 cpl_error_get_message());
00325 cpl_errorstate_set(prestate);
00326 cpl_error_set_message(__func__, MUSE_ERROR_CHIP_NOT_LIVE, "Image \"%s[%s]\" "
00327 "(extension %d) is dead", aFilename, channel,
00328 aExtension);
00329 cpl_free(channel);
00330 return NULL;
00331 }
00332
00333
00334
00335 mImage->dq = cpl_image_new(cpl_image_get_size_x(mImage->data),
00336 cpl_image_get_size_y(mImage->data),
00337 CPL_TYPE_INT);
00338
00339
00340
00341 mImage->stat = cpl_image_new(cpl_image_get_size_x(mImage->data),
00342 cpl_image_get_size_y(mImage->data),
00343 CPL_TYPE_FLOAT);
00344
00345
00346 mImage->header = cpl_propertylist_load(aFilename, 0);
00347 if (aExtension > 0) {
00348 cpl_propertylist *extHeader = cpl_propertylist_load(aFilename, aExtension);
00349
00350 cpl_propertylist_copy_property_regexp(mImage->header, extHeader,
00351 "^XTENSION$|"
00352 "^CHECKSUM$|"
00353 "^DATASUM$", 1);
00354 cpl_propertylist_delete(extHeader);
00355 }
00356 prestate = cpl_errorstate_get();
00357 channel = cpl_strdup(muse_pfits_get_extname(mImage->header));
00358 if (!cpl_errorstate_is_equal(prestate)) {
00359 cpl_errorstate_set(prestate);
00360 }
00361
00362 cpl_propertylist_update_string(mImage->header, "BUNIT", "adu");
00363 cpl_propertylist_set_comment(mImage->header, "BUNIT",
00364 "DATA is in analog-to-digital units");
00365 cpl_msg_info(__func__, "loaded \"%s[%s]\" (extension %d)", aFilename,
00366 channel ? channel : "0", aExtension);
00367 cpl_free(channel);
00368
00369 return mImage;
00370 }
00371
00372
00403
00404 cpl_error_code
00405 muse_image_save(muse_image *aImage, const char *aFilename)
00406 {
00407 cpl_ensure_code(aImage && aImage->data && aFilename, CPL_ERROR_NULL_INPUT);
00408 cpl_ensure_code(cpl_propertylist_has(aImage->header, "BUNIT"),
00409 CPL_ERROR_INCOMPATIBLE_INPUT);
00410
00411
00412
00413 cpl_propertylist *header = cpl_propertylist_duplicate(aImage->header);
00414 cpl_propertylist_erase(header, "BUNIT");
00415
00416 cpl_propertylist_erase_regexp(header, MUSE_WCS_KEYS, 0);
00417
00418
00419
00420 cpl_error_code error = cpl_propertylist_save(header, aFilename, CPL_IO_CREATE);
00421 cpl_propertylist_delete(header);
00422 if (error != CPL_ERROR_NONE) {
00423 cpl_msg_error(__func__, "Could not save header: %s",
00424 cpl_error_get_message());
00425 return error;
00426 }
00427
00428
00429
00430 cpl_propertylist *extheader = cpl_propertylist_new();
00431
00432
00433 cpl_propertylist_copy_property_regexp(extheader, aImage->header,
00434 MUSE_WCS_KEYS, 0);
00435
00436 cpl_propertylist_append_string(extheader, "EXTNAME", EXTNAME_DATA);
00437 cpl_propertylist_set_comment(extheader, "EXTNAME", EXTNAME_DATA_COMMENT);
00438 const char *unit = muse_pfits_get_bunit(aImage->header),
00439 *ucomment = cpl_propertylist_get_comment(aImage->header, "BUNIT");
00440 cpl_propertylist_append_string(extheader, "BUNIT", unit);
00441 cpl_propertylist_set_comment(extheader, "BUNIT", ucomment);
00442 muse_utils_set_hduclass(extheader, "DATA", EXTNAME_DATA,
00443 aImage->dq ? EXTNAME_DQ : NULL,
00444 aImage->stat ? EXTNAME_STAT : NULL);
00445 error = cpl_image_save(aImage->data, aFilename, CPL_TYPE_FLOAT,
00446 extheader, CPL_IO_EXTEND);
00447 if (error != CPL_ERROR_NONE) {
00448 cpl_msg_error(__func__, "Could not append data image: %s",
00449 cpl_error_get_message());
00450 cpl_propertylist_delete(extheader);
00451 return error;
00452 }
00453
00454 if (aImage->dq) {
00455 cpl_propertylist_set_string(extheader, "EXTNAME", EXTNAME_DQ);
00456 cpl_propertylist_set_comment(extheader, "EXTNAME", EXTNAME_DQ_COMMENT);
00457 cpl_propertylist_erase(extheader, "BUNIT");
00458 muse_utils_set_hduclass(extheader, "QUALITY", EXTNAME_DATA, EXTNAME_DQ,
00459 aImage->stat ? EXTNAME_STAT : NULL);
00460 error = cpl_image_save(aImage->dq, aFilename, CPL_TYPE_INT,
00461 extheader, CPL_IO_EXTEND);
00462 if (error != CPL_ERROR_NONE) {
00463 cpl_msg_error(__func__, "Could not append dq image: %s",
00464 cpl_error_get_message());
00465 cpl_propertylist_delete(extheader);
00466 return error;
00467 }
00468 }
00469
00470 if (aImage->stat) {
00471 cpl_propertylist_set_string(extheader, "EXTNAME", EXTNAME_STAT);
00472 cpl_propertylist_set_comment(extheader, "EXTNAME", EXTNAME_STAT_COMMENT);
00473 char *ustat = cpl_sprintf("(%s)**2", unit);
00474 cpl_propertylist_append_string(extheader, "BUNIT", ustat);
00475 cpl_free(ustat);
00476 muse_utils_set_hduclass(extheader, "ERROR", EXTNAME_DATA,
00477 aImage->dq ? EXTNAME_DQ : NULL, EXTNAME_STAT);
00478 error = cpl_image_save(aImage->stat, aFilename, CPL_TYPE_FLOAT,
00479 extheader, CPL_IO_EXTEND);
00480 if (error != CPL_ERROR_NONE) {
00481 cpl_msg_error(__func__, "Could not append stat image: %s",
00482 cpl_error_get_message());
00483 cpl_propertylist_delete(extheader);
00484 return error;
00485 }
00486 }
00487 cpl_propertylist_delete(extheader);
00488
00489 return CPL_ERROR_NONE;
00490 }
00491
00492
00508
00509 muse_image *
00510 muse_image_duplicate(const muse_image *aImage)
00511 {
00512 cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, NULL);
00513
00514 muse_image *image = muse_image_new();
00515 image->data = cpl_image_duplicate(aImage->data);
00516 image->dq = cpl_image_duplicate(aImage->dq);
00517 image->stat = cpl_image_duplicate(aImage->stat);
00518 image->header = cpl_propertylist_duplicate(aImage->header);
00519 if (!image->data || !image->dq || !image->stat || !image->header) {
00520 muse_image_delete(image);
00521 return NULL;
00522 }
00523 return image;
00524 }
00525
00526
00542
00543 static int
00544 muse_image_dq_merge(cpl_image *aDQ1, cpl_image *aDQ2)
00545 {
00546 cpl_ensure(aDQ1, CPL_ERROR_NULL_INPUT, -1);
00547 cpl_ensure(aDQ2, CPL_ERROR_NULL_INPUT, -2);
00548
00549
00550 int *dq1 = cpl_image_get_data_int(aDQ1);
00551
00552 const int *dq2 = cpl_image_get_data_int_const(aDQ2);
00553 if (!dq1 || !dq2) {
00554 return cpl_error_get_code();
00555 }
00556
00557 int i,
00558 nx = cpl_image_get_size_x(aDQ1),
00559 ny = cpl_image_get_size_y(aDQ1);
00560 for (i = 0; i < nx; i++) {
00561 int j;
00562 for (j = 0; j < ny; j++) {
00563
00564
00565 if (dq2[i + j*nx]) {
00566 dq1[i + j*nx] |= dq2[i + j*nx];
00567 }
00568 }
00569 }
00570
00571 return 0;
00572 }
00573
00574
00591
00592 int
00593 muse_image_subtract(muse_image *aImage, muse_image *aSubtract)
00594 {
00595 cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, -1);
00596 cpl_ensure(aSubtract, CPL_ERROR_NULL_INPUT, -2);
00597
00598 cpl_error_code rc = cpl_image_subtract(aImage->data, aSubtract->data);
00599 if (rc != CPL_ERROR_NONE) {
00600 cpl_msg_error(__func__, "failure while subtracting data extension");
00601 return rc;
00602 }
00603
00604 rc = cpl_image_add(aImage->stat, aSubtract->stat);
00605 if (rc != CPL_ERROR_NONE) {
00606 cpl_msg_error(__func__, "failure for stat extension");
00607 return rc;
00608 }
00609
00610 rc = muse_image_dq_merge(aImage->dq, aSubtract->dq);
00611 if (rc) {
00612 cpl_msg_error(__func__, "failure for dq extension");
00613 return rc;
00614 }
00615
00616 return 0;
00617 }
00618
00619
00637
00638 int
00639 muse_image_divide(muse_image *aImage, muse_image *aDivisor)
00640 {
00641 cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, -1);
00642 cpl_ensure(aDivisor, CPL_ERROR_NULL_INPUT, -2);
00643
00644
00645
00646
00647
00648 cpl_image *term2 = cpl_image_power_create(aImage->data, 2);
00649
00650 cpl_error_code rc = cpl_image_divide(aImage->data, aDivisor->data);
00651 if (rc != CPL_ERROR_NONE) {
00652 cpl_msg_error(__func__, "failure while dividing data extension");
00653 cpl_image_delete(term2);
00654 return rc;
00655 }
00656
00657 cpl_image *divsq = cpl_image_power_create(aDivisor->data, 2);
00658 rc = cpl_image_multiply(term2, aDivisor->stat);
00659
00660
00661 if (rc != CPL_ERROR_NONE) {
00662 cpl_msg_error(__func__, "failure while accessing stat extension of divisor");
00663 cpl_image_delete(term2);
00664 cpl_image_delete(divsq);
00665 return rc;
00666 }
00667 cpl_image_divide(term2, divsq);
00668 rc = cpl_image_add(aImage->stat, term2);
00669 if (rc != CPL_ERROR_NONE) {
00670 cpl_msg_error(__func__, "failure while accessing stat extension of image");
00671 cpl_image_delete(term2);
00672 cpl_image_delete(divsq);
00673 return rc;
00674 }
00675 cpl_image_delete(term2);
00676 cpl_image_divide(aImage->stat, divsq);
00677 cpl_image_delete(divsq);
00678
00679 rc = muse_image_dq_merge(aImage->dq, aDivisor->dq);
00680 if (rc) {
00681 cpl_msg_error(__func__, "failure for dq extension");
00682 return rc;
00683 }
00684 return 0;
00685 }
00686
00687
00701
00702 int
00703 muse_image_scale(muse_image *aImage, double aScale)
00704 {
00705 cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, -1);
00706
00707
00708 cpl_error_code rc = cpl_image_multiply_scalar(aImage->data, aScale);
00709 if (rc != CPL_ERROR_NONE) {
00710 cpl_msg_error(__func__, "failure while scaling data extension");
00711 return rc;
00712 }
00713
00714
00715 rc = cpl_image_multiply_scalar(aImage->stat, aScale*aScale);
00716 if (rc != CPL_ERROR_NONE) {
00717 cpl_msg_error(__func__, "failure while scaling stat extension");
00718 return rc;
00719 }
00720
00721 return 0;
00722 }
00723
00724
00745
00746 int
00747 muse_image_variance_create(muse_image *aImage, muse_image *aBias)
00748 {
00749 cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, -1);
00750 cpl_ensure(aBias, CPL_ERROR_NULL_INPUT, -2);
00751 int nx = cpl_image_get_size_x(aImage->stat),
00752 ny = cpl_image_get_size_y(aImage->stat),
00753 nxbias = cpl_image_get_size_x(aBias->stat),
00754 nybias = cpl_image_get_size_y(aBias->stat);
00755 cpl_ensure(nx == nxbias && ny == nybias, CPL_ERROR_INCOMPATIBLE_INPUT, -3);
00756
00757
00758
00759
00760 cpl_image_delete(aImage->stat);
00761 aImage->stat = cpl_image_subtract_create(aImage->data, aBias->data);
00762 float *pixstat = cpl_image_get_data_float(aImage->stat);
00763
00764
00765
00766 unsigned char n;
00767 for (n = 1; n <= 4; n++) {
00768 double gain = muse_pfits_get_gain(aImage->header, n);
00769 cpl_size *window = muse_quadrants_get_window(aImage, n);
00770
00771 int i;
00772 for (i = window[0] - 1; i < window[1]; i++) {
00773 int j;
00774 for (j = window[2] - 1; j < window[3]; j++) {
00775 pixstat[i + j*nx] /= gain;
00776
00777
00778 if (pixstat[i + j*nx] <= 0.0) {
00779
00780 pixstat[i + j*nx] = FLT_MIN;
00781 }
00782 }
00783 }
00784 cpl_free(window);
00785 }
00786
00787 return 0;
00788 }
00789
00790
00809
00810 cpl_error_code
00811 muse_image_adu_to_count(muse_image *aImage)
00812 {
00813 cpl_ensure_code(aImage && aImage->header, CPL_ERROR_NULL_INPUT);
00814 cpl_ensure_code(cpl_propertylist_has(aImage->header, "BUNIT") &&
00815 !strncmp(muse_pfits_get_bunit(aImage->header), "adu", 4),
00816 CPL_ERROR_INCOMPATIBLE_INPUT);
00817 int nx = cpl_image_get_size_x(aImage->data);
00818 float *data = cpl_image_get_data_float(aImage->data),
00819 *stat = cpl_image_get_data_float(aImage->stat);
00820 cpl_ensure_code(data && stat, CPL_ERROR_ILLEGAL_INPUT);
00821
00822 unsigned char n;
00823 for (n = 1; n <= 4; n++) {
00824 double gain = muse_pfits_get_gain(aImage->header, n);
00825 cpl_size *w = muse_quadrants_get_window(aImage, n);
00826 #if 0
00827 cpl_msg_debug(__func__, "looping %"CPL_SIZE_FORMAT"...%"CPL_SIZE_FORMAT
00828 " %"CPL_SIZE_FORMAT"...%"CPL_SIZE_FORMAT"",
00829 w[0], w[1], w[2], w[3]);
00830 #endif
00831
00832 int i;
00833 for (i = w[0] - 1; i < w[1]; i++) {
00834 int j;
00835 for (j = w[2] - 1; j < w[3]; j++) {
00836 data[i + j*nx] *= gain;
00837 stat[i + j*nx] *= gain*gain;
00838 }
00839 }
00840 cpl_free(w);
00841 }
00842 cpl_propertylist_update_string(aImage->header, "BUNIT", "count");
00843 cpl_propertylist_set_comment(aImage->header, "BUNIT", "DATA is in electrons");
00844 return CPL_ERROR_NONE;
00845 }
00846
00847
00861
00862 cpl_error_code
00863 muse_image_reject_from_dq(muse_image *aImage)
00864 {
00865 cpl_ensure_code(aImage && aImage->data && aImage->dq, CPL_ERROR_NULL_INPUT);
00866 int nx = cpl_image_get_size_x(aImage->data),
00867 ny = cpl_image_get_size_y(aImage->data);
00868 const int *dq = cpl_image_get_data_int_const(aImage->dq);
00869 int i, j;
00870 for (i = 0; i < nx; i++) {
00871 for (j = 0; j < ny; j++) {
00872 if (!dq[i + j*nx]) {
00873 continue;
00874 }
00875 cpl_image_reject(aImage->data, i+1, j+1);
00876 if (aImage->stat) {
00877 cpl_image_reject(aImage->stat, i+1, j+1);
00878 }
00879 }
00880 }
00881
00882 return CPL_ERROR_NONE;
00883 }
00884
00885
00902
00903 cpl_error_code
00904 muse_image_dq_to_nan(muse_image *aImage)
00905 {
00906 cpl_ensure_code(aImage && aImage->data && aImage->dq, CPL_ERROR_NULL_INPUT);
00907
00908
00909 int *pdq = cpl_image_get_data_int(aImage->dq);
00910 float *pdata = cpl_image_get_data_float(aImage->data),
00911 *pstat = NULL;
00912
00913 if (aImage->stat) {
00914 pstat = cpl_image_get_data_float(aImage->stat);
00915 }
00916 int i, nx = cpl_image_get_size_x(aImage->data),
00917 ny = cpl_image_get_size_y(aImage->data);
00918 for (i = 0; i < nx; i++) {
00919 int j;
00920 for (j = 0; j < ny; j++) {
00921 if (pdq[i + j*nx] == EURO3D_GOODPIXEL) {
00922 continue;
00923 }
00924
00925 pdata[i + j*nx] = NAN;
00926 if (pstat) {
00927 pstat[i + j*nx] = NAN;
00928 }
00929 }
00930 }
00931
00932
00933 cpl_image_delete(aImage->dq);
00934 aImage->dq = NULL;
00935
00936 return CPL_ERROR_NONE;
00937 }
00938