MUSE Pipeline Reference Manual  0.18.1
muse_image.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set sw=2 sts=2 et cin: */
3 /*
4  * This file is part of the MUSE Instrument Pipeline
5  * Copyright (C) 2005-2014 European Southern Observatory
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 /*----------------------------------------------------------------------------*
27  * Includes *
28  *----------------------------------------------------------------------------*/
29 #include <cpl.h>
30 #include <string.h>
31 
32 #include "muse_image.h"
33 
34 #include "muse_quadrants.h"
35 #include "muse_pfits.h"
36 #include "muse_utils.h"
37 #include "muse_wcs.h"
38 
39 /*----------------------------------------------------------------------------*/
46 /*----------------------------------------------------------------------------*/
47 
50 /*---------------------------------------------------------------------------*/
63 /*---------------------------------------------------------------------------*/
64 muse_image *
66 {
67  /* calloc automatically NULLs out the four components of the structure */
68  muse_image *image = (muse_image *)cpl_calloc(1, sizeof(muse_image));
69  return image;
70 } /* muse_image_new() */
71 
72 /*---------------------------------------------------------------------------*/
82 /*---------------------------------------------------------------------------*/
83 void
85 {
86  /* if image does not exists at all, we don't need to do anything */
87  if (!aImage) {
88  return;
89  }
90 
91  /* checks for the existence of the sub-images *
92  * are done in the CPL functions */
93  cpl_image_delete(aImage->data);
94  aImage->data = NULL;
95  cpl_image_delete(aImage->dq);
96  aImage->dq = NULL;
97  cpl_image_delete(aImage->stat);
98  aImage->stat = NULL;
99 
100  /* delete the FITS header, too */
101  cpl_propertylist_delete(aImage->header);
102  aImage->header = NULL;
103  cpl_free(aImage);
104 } /* muse_image_delete() */
105 
106 /*---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------*/
115 static muse_image *
116 muse_image_load_internal(const char *aFilename, unsigned char aIFU, const char *aID)
117 {
118  muse_image *image = muse_image_new();
119 
120  /* Load the primary FITS header first. This is not critical, but *
121  * a good first test to see, if the file is really there. */
122  image->header = cpl_propertylist_load(aFilename, 0);
123  if (!image->header) {
124  cpl_error_set_message(aID, cpl_error_get_code(), "Loading primary FITS "
125  "header of \"%s\" did not succeed", aFilename);
126  muse_image_delete(image);
127  return NULL;
128  }
129 
130  /* now load the image data from the there extensions */
131  char extname[KEYWORD_LENGTH];
132  if (aIFU) {
133  snprintf(extname, KEYWORD_LENGTH, "CHAN%02hhu.%s", aIFU, EXTNAME_DATA);
134  } else {
135  snprintf(extname, KEYWORD_LENGTH, "%s", EXTNAME_DATA);
136  }
137  int extension = cpl_fits_find_extension(aFilename, extname);
138  image->data = cpl_image_load(aFilename, CPL_TYPE_FLOAT, 0, extension);
139  if (!image->data) {
140  cpl_error_set_message(aID, MUSE_ERROR_READ_DATA, "Could not load extension "
141  "%s from \"%s\"", extname, aFilename);
142  muse_image_delete(image);
143  return NULL;
144  }
145  /* get BUNIT back from the header of this data extension */
146  cpl_propertylist *hdata = cpl_propertylist_load(aFilename, extension);
147  if (cpl_propertylist_has(hdata, "BUNIT")) { /* backward compatibility */
148  cpl_propertylist_append_string(image->header, "BUNIT",
149  cpl_propertylist_get_string(hdata, "BUNIT"));
150  cpl_propertylist_set_comment(image->header, "BUNIT",
151  cpl_propertylist_get_comment(hdata, "BUNIT"));
152  } else {
153  cpl_msg_warning(aID, "No BUNIT given in extension %d [%s] of \"%s\"!",
154  extension, extname, aFilename);
155  }
156  /* When reading from extensions, we also need to merge in all *
157  * HIERARCH keywords from the data extension. */
158  if (aIFU) {
159  cpl_propertylist_erase_regexp(hdata, "^ESO ", 1);
160  cpl_propertylist_append(image->header, hdata);
161  }
162  cpl_propertylist_delete(hdata);
163 
164  if (aIFU) {
165  snprintf(extname, KEYWORD_LENGTH, "CHAN%02hhu.%s", aIFU, EXTNAME_DQ);
166  } else {
167  snprintf(extname, KEYWORD_LENGTH, "%s", EXTNAME_DQ);
168  }
169  extension = cpl_fits_find_extension(aFilename, extname);
170  image->dq = cpl_image_load(aFilename, CPL_TYPE_INT, 0, extension);
171  if (!image->dq) {
172  cpl_error_set_message(aID, MUSE_ERROR_READ_DQ, "Could not load extension "
173  "%s from \"%s\"", extname, aFilename);
174  muse_image_delete(image);
175  return NULL;
176  }
177 
178  if (aIFU) {
179  snprintf(extname, KEYWORD_LENGTH, "CHAN%02hhu.%s", aIFU, EXTNAME_STAT);
180  } else {
181  snprintf(extname, KEYWORD_LENGTH, "%s", EXTNAME_STAT);
182  }
183  extension = cpl_fits_find_extension(aFilename, extname);
184  image->stat = cpl_image_load(aFilename, CPL_TYPE_FLOAT, 0, extension);
185  if (!image->stat) {
186  cpl_error_set_message(aID, MUSE_ERROR_READ_STAT, "Could not load extension "
187  "%s from \"%s\"", extname, aFilename);
188  muse_image_delete(image);
189  return NULL;
190  }
191 
192  return image;
193 } /* muse_image_load_internal() */
194 
195 /*---------------------------------------------------------------------------*/
220 /*---------------------------------------------------------------------------*/
221 muse_image *
222 muse_image_load(const char *aFilename)
223 {
224  return muse_image_load_internal(aFilename, 0, __func__);
225 } /* muse_image_load() */
226 
227 /*---------------------------------------------------------------------------*/
254 /*---------------------------------------------------------------------------*/
255 muse_image *
256 muse_image_load_from_extensions(const char *aFilename, unsigned char aIFU)
257 {
258  return muse_image_load_internal(aFilename, aIFU, __func__);
259 } /* muse_image_load_from_extensions() */
260 
261 /*---------------------------------------------------------------------------*/
284 /*---------------------------------------------------------------------------*/
285 muse_image *
286 muse_image_load_from_raw(const char *aFilename, int aExtension)
287 {
288  muse_image *mImage = muse_image_new();
289 
290  cpl_errorstate prestate = cpl_errorstate_get();
291  /* Raw images are always integer. *
292  * The cast to float happens implicitely on loading */
293  mImage->data = cpl_image_load(aFilename, CPL_TYPE_FLOAT, 0, aExtension);
294  char *channel = NULL;
295  if (!mImage->data) {
296  muse_image_delete(mImage);
297 
298  cpl_propertylist *header = cpl_propertylist_load(aFilename, aExtension);
299  if (!header) {
300  cpl_msg_error(__func__, "Image \"%s\" (extension %d) could not be read: %s",
301  aFilename, aExtension, cpl_error_get_message());
302  return NULL;
303  }
304  /* check if the header contains DET.CHIP.LIVE=F; if so, *
305  * set a special error to not fail the whole recipe */
306  cpl_boolean live = muse_pfits_get_chip_live(header);
307  channel = cpl_strdup(muse_pfits_get_extname(header));
308  cpl_propertylist_delete(header);
309  if (live) { /* something is wrong with the file! */
310  cpl_msg_error(__func__, "Image \"%s[%s]\" (extension %d) could not be read "
311  "although chip is alive: %s", aFilename, channel, aExtension,
312  cpl_error_get_message());
313  cpl_free(channel);
314  return NULL;
315  }
316  cpl_msg_warning(__func__, "Image \"%s[%s]\" (extension %d) could not be read,"
317  " but chip is dead: %s", aFilename, channel, aExtension,
318  cpl_error_get_message());
319  cpl_errorstate_set(prestate);
320  cpl_error_set_message(__func__, MUSE_ERROR_CHIP_NOT_LIVE, "Image \"%s[%s]\" "
321  "(extension %d) is dead", aFilename, channel,
322  aExtension);
323  cpl_free(channel);
324  return NULL;
325  } /* if data not loaded */
326 
327  /* Create an empty DQ extension, signifying a CCD without flaws. *
328  * As a first guess this should be adequate. */
329  mImage->dq = cpl_image_new(cpl_image_get_size_x(mImage->data),
330  cpl_image_get_size_y(mImage->data),
331  CPL_TYPE_INT); /* is initialized to 0 */
332 
333  /* create STAT extension filled with zeros; this must be replaced later *
334  * by the caller of this function */
335  mImage->stat = cpl_image_new(cpl_image_get_size_x(mImage->data),
336  cpl_image_get_size_y(mImage->data),
337  CPL_TYPE_FLOAT); /* is initialized to 0 */
338 
339  /* load and merge primary and extension header */
340  mImage->header = cpl_propertylist_load(aFilename, 0);
341  if (aExtension > 0) {
342  cpl_propertylist *extHeader = cpl_propertylist_load(aFilename, aExtension);
343  /* leave EXTNAME in place but remove other stuff related to extensions: */
344  cpl_propertylist_copy_property_regexp(mImage->header, extHeader,
345  "^XTENSION$|"
346  "^CHECKSUM$|"
347  "^DATASUM$", 1);
348  cpl_propertylist_delete(extHeader);
349  }
350  prestate = cpl_errorstate_get();
351  channel = cpl_strdup(muse_pfits_get_extname(mImage->header));
352  if (!cpl_errorstate_is_equal(prestate)) { /* ignore missing EXTNAME */
353  cpl_errorstate_set(prestate);
354  }
355  /* make sure that the unit is correct */
356  cpl_propertylist_update_string(mImage->header, "BUNIT", "adu");
357  cpl_propertylist_set_comment(mImage->header, "BUNIT",
358  "DATA is in analog-to-digital units");
359  cpl_msg_info(__func__, "loaded \"%s[%s]\" (extension %d)", aFilename,
360  channel ? channel : "0", aExtension);
361  cpl_free(channel);
362 
363  return mImage;
364 } /* muse_image_load_from_raw() */
365 
366 /*----------------------------------------------------------------------------*/
394 /*----------------------------------------------------------------------------*/
395 cpl_error_code
396 muse_image_save(muse_image *aImage, const char *aFilename)
397 {
398  cpl_ensure_code(aImage && aFilename, CPL_ERROR_NULL_INPUT);
399  cpl_ensure_code(cpl_propertylist_has(aImage->header, "BUNIT"),
400  CPL_ERROR_INCOMPATIBLE_INPUT);
401 
402  /* BUNIT should only be saved in the image extension(s), *
403  * so save a header without it */
404  cpl_propertylist *header = cpl_propertylist_duplicate(aImage->header);
405  cpl_propertylist_erase(header, "BUNIT");
406 
407  /* Save the FITS header first, as the primary header of the file. *
408  * The extensions will contain only minimal image headers. */
409  cpl_error_code error = cpl_propertylist_save(header, aFilename, CPL_IO_CREATE);
410  cpl_propertylist_delete(header);
411  if (error != CPL_ERROR_NONE) {
412  cpl_msg_error(__func__, "Could not save header: %s",
413  cpl_error_get_message());
414  return error;
415  }
416 
417  /* minimal header information for the extensions to add *
418  * extension name information */
419  cpl_propertylist *extheader = cpl_propertylist_new();
420 
421  /* copy WCS information to minimal extension header */
422  cpl_propertylist_copy_property_regexp(extheader, aImage->header,
423  MUSE_WCS_KEYS, 0);
424 
425  cpl_propertylist_append_string(extheader, "EXTNAME", EXTNAME_DATA);
426  cpl_propertylist_set_comment(extheader, "EXTNAME", EXTNAME_DATA_COMMENT);
427  const char *unit = cpl_propertylist_get_string(aImage->header, "BUNIT"),
428  *ucomment = cpl_propertylist_get_comment(aImage->header, "BUNIT");
429  cpl_propertylist_append_string(extheader, "BUNIT", unit);
430  cpl_propertylist_set_comment(extheader, "BUNIT", ucomment);
431  muse_utils_set_hduclass(extheader, "DATA",
432  EXTNAME_DATA, EXTNAME_DQ, EXTNAME_STAT);
433  error = cpl_image_save(aImage->data, aFilename, CPL_TYPE_FLOAT,
434  extheader, CPL_IO_EXTEND);
435  if (error != CPL_ERROR_NONE) {
436  cpl_msg_error(__func__, "Could not append data image: %s",
437  cpl_error_get_message());
438  cpl_propertylist_delete(extheader);
439  return error;
440  }
441 
442  cpl_propertylist_set_string(extheader, "EXTNAME", EXTNAME_DQ);
443  cpl_propertylist_set_comment(extheader, "EXTNAME", EXTNAME_DQ_COMMENT);
444  cpl_propertylist_erase(extheader, "BUNIT"); /* no unit for data quality */
445  muse_utils_set_hduclass(extheader, "QUALITY",
446  EXTNAME_DATA, EXTNAME_DQ, EXTNAME_STAT);
447  error = cpl_image_save(aImage->dq, aFilename, CPL_TYPE_INT,
448  extheader, CPL_IO_EXTEND);
449  if (error != CPL_ERROR_NONE) {
450  cpl_msg_error(__func__, "Could not append dq image: %s",
451  cpl_error_get_message());
452  cpl_propertylist_delete(extheader);
453  return error;
454  }
455 
456  cpl_propertylist_set_string(extheader, "EXTNAME", EXTNAME_STAT);
457  cpl_propertylist_set_comment(extheader, "EXTNAME", EXTNAME_STAT_COMMENT);
458  char *ustat = cpl_sprintf("%s^2", unit); /* variance in squared units */
459  cpl_propertylist_append_string(extheader, "BUNIT", ustat);
460  cpl_free(ustat);
461  muse_utils_set_hduclass(extheader, "ERROR",
462  EXTNAME_DATA, EXTNAME_DQ, EXTNAME_STAT);
463  error = cpl_image_save(aImage->stat, aFilename, CPL_TYPE_FLOAT,
464  extheader, CPL_IO_EXTEND);
465  if (error != CPL_ERROR_NONE) {
466  cpl_msg_error(__func__, "Could not append stat image: %s",
467  cpl_error_get_message());
468  cpl_propertylist_delete(extheader);
469  return error;
470  }
471  cpl_propertylist_delete(extheader);
472 
473  return CPL_ERROR_NONE;
474 } /* muse_image_save() */
475 
476 /*----------------------------------------------------------------------------*/
492 /*----------------------------------------------------------------------------*/
493 muse_image *
495 {
496  cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, NULL);
497 
498  muse_image *image = muse_image_new();
499  image->data = cpl_image_duplicate(aImage->data);
500  image->dq = cpl_image_duplicate(aImage->dq);
501  image->stat = cpl_image_duplicate(aImage->stat);
502  image->header = cpl_propertylist_duplicate(aImage->header);
503  if (!image->data || !image->dq || !image->stat || !image->header) {
504  muse_image_delete(image);
505  return NULL;
506  }
507  return image;
508 } /* muse_image_duplicate() */
509 
510 /*---------------------------------------------------------------------------*/
526 /*---------------------------------------------------------------------------*/
527 static int
528 muse_image_dq_merge(cpl_image *aDQ1, cpl_image *aDQ2)
529 {
530  cpl_ensure(aDQ1, CPL_ERROR_NULL_INPUT, -1);
531  cpl_ensure(aDQ2, CPL_ERROR_NULL_INPUT, -2);
532 
533  /* get the output dq image buffer as normal int */
534  int *dq1 = cpl_image_get_data_int(aDQ1);
535  /* get the subtract dq image buffer as const because we don't want to change it */
536  const int *dq2 = cpl_image_get_data_int_const(aDQ2);
537  if (!dq1 || !dq2) {
538  return cpl_error_get_code();
539  }
540 
541  int i,
542  nx = cpl_image_get_size_x(aDQ1),
543  ny = cpl_image_get_size_y(aDQ1);
544  for (i = 0; i < nx; i++) {
545  int j;
546  for (j = 0; j < ny; j++) {
547  /* If the second pixel is bad somehow, merge it with the dq flag *
548  * of the first image. The output pixel gets a combined dq status. */
549  if (dq2[i + j*nx]) {
550  dq1[i + j*nx] |= dq2[i + j*nx];
551  }
552  } /* for j */
553  } /* for i */
554 
555  return 0;
556 } /* muse_image_dq_merge() */
557 
558 /*---------------------------------------------------------------------------*/
575 /*---------------------------------------------------------------------------*/
576 int
578 {
579  cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, -1);
580  cpl_ensure(aSubtract, CPL_ERROR_NULL_INPUT, -2);
581 
582  cpl_error_code rc = cpl_image_subtract(aImage->data, aSubtract->data);
583  if (rc != CPL_ERROR_NONE) {
584  cpl_msg_error(__func__, "failure while subtracting data extension");
585  return rc;
586  }
587 
588  rc = cpl_image_add(aImage->stat, aSubtract->stat);
589  if (rc != CPL_ERROR_NONE) {
590  cpl_msg_error(__func__, "failure for stat extension");
591  return rc;
592  }
593 
594  rc = muse_image_dq_merge(aImage->dq, aSubtract->dq);
595  if (rc) {
596  cpl_msg_error(__func__, "failure for dq extension");
597  return rc;
598  }
599 
600  return 0;
601 } /* muse_image_subtract() */
602 
603 /*---------------------------------------------------------------------------*/
621 /*---------------------------------------------------------------------------*/
622 int
624 {
625  cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, -1);
626  cpl_ensure(aDivisor, CPL_ERROR_NULL_INPUT, -2);
627 
628  /* Gaussian error propagation for a division:
629  * variance_out = (variance_in + in^2 * variance_divisor / divisor^2 ) / divisor^2
630  * ^------------- term2 -------------^
631  */
632  cpl_image *term2 = cpl_image_power_create(aImage->data, 2);
633 
634  cpl_error_code rc = cpl_image_divide(aImage->data, aDivisor->data);
635  if (rc != CPL_ERROR_NONE) {
636  cpl_msg_error(__func__, "failure while dividing data extension");
637  cpl_image_delete(term2);
638  return rc;
639  }
640 
641  cpl_image *divsq = cpl_image_power_create(aDivisor->data, 2);
642  rc = cpl_image_multiply(term2, aDivisor->stat);
643 
644  /* first access to stat, better check error */
645  if (rc != CPL_ERROR_NONE) {
646  cpl_msg_error(__func__, "failure while accessing stat extension of divisor");
647  cpl_image_delete(term2);
648  cpl_image_delete(divsq);
649  return rc;
650  }
651  cpl_image_divide(term2, divsq);
652  rc = cpl_image_add(aImage->stat, term2);
653  if (rc != CPL_ERROR_NONE) {
654  cpl_msg_error(__func__, "failure while accessing stat extension of image");
655  cpl_image_delete(term2);
656  cpl_image_delete(divsq);
657  return rc;
658  }
659  cpl_image_delete(term2);
660  cpl_image_divide(aImage->stat, divsq);
661  cpl_image_delete(divsq);
662 
663  rc = muse_image_dq_merge(aImage->dq, aDivisor->dq);
664  if (rc) {
665  cpl_msg_error(__func__, "failure for dq extension");
666  return rc;
667  }
668  return 0;
669 } /* muse_image_divide() */
670 
671 /*---------------------------------------------------------------------------*/
685 /*---------------------------------------------------------------------------*/
686 int
687 muse_image_scale(muse_image *aImage, double aScale)
688 {
689  cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, -1);
690 
691  /* scale the data extension */
692  cpl_error_code rc = cpl_image_multiply_scalar(aImage->data, aScale);
693  if (rc != CPL_ERROR_NONE) {
694  cpl_msg_error(__func__, "failure while scaling data extension");
695  return rc;
696  }
697 
698  /* scale the stat extension (squared as this is the variance) */
699  rc = cpl_image_multiply_scalar(aImage->stat, aScale*aScale);
700  if (rc != CPL_ERROR_NONE) {
701  cpl_msg_error(__func__, "failure while scaling stat extension");
702  return rc;
703  }
704 
705  return 0;
706 } /* muse_image_scale() */
707 
708 /*---------------------------------------------------------------------------*/
729 /*---------------------------------------------------------------------------*/
730 int
732 {
733  cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, -1);
734  cpl_ensure(aBias, CPL_ERROR_NULL_INPUT, -2);
735  int nx = cpl_image_get_size_x(aImage->stat),
736  ny = cpl_image_get_size_y(aImage->stat),
737  nxbias = cpl_image_get_size_x(aBias->stat),
738  nybias = cpl_image_get_size_y(aBias->stat);
739  cpl_ensure(nx == nxbias && ny == nybias, CPL_ERROR_INCOMPATIBLE_INPUT, -3);
740 
741  /* the easiest is, to remove the existing stat extension and *
742  * create a new image in its place (otherwise one would need *
743  * to check that it is still zero everywhere */
744  cpl_image_delete(aImage->stat);
745  aImage->stat = cpl_image_subtract_create(aImage->data, aBias->data);
746  float *pixstat = cpl_image_get_data_float(aImage->stat);
747 
748  /* now loop through all quadrants and their pixels and divide *
749  * by the gain value */
750  unsigned char n;
751  for (n = 1; n <= 4; n++) {
752  double gain = muse_pfits_get_gain(aImage->header, n); /* in count/adu */
753  cpl_size *window = muse_quadrants_get_window(aImage, n);
754 
755  int i;
756  for (i = window[0] - 1; i < window[1]; i++) {
757  int j;
758  for (j = window[2] - 1; j < window[3]; j++) {
759  pixstat[i + j*nx] /= gain;
760  /* if the photon variance turns out to be too low, we have to reset *
761  * it, because variance cannot take a negative or zero value */
762  if (pixstat[i + j*nx] <= 0.0) {
763  /* set it to the smallest value possible for 32bit float data */
764  pixstat[i + j*nx] = FLT_MIN;
765  }
766  } /* for j (y pixels) */
767  } /* for i (x pixels) */
768  cpl_free(window);
769  } /* for n (quadrants) */
770 
771  return 0;
772 } /* muse_image_variance_create() */
773 
774 /*---------------------------------------------------------------------------*/
793 /*---------------------------------------------------------------------------*/
794 cpl_error_code
796 {
797  cpl_ensure_code(aImage && aImage->header, CPL_ERROR_NULL_INPUT);
798  cpl_ensure_code(cpl_propertylist_has(aImage->header, "BUNIT") &&
799  !strncmp(cpl_propertylist_get_string(aImage->header, "BUNIT"),
800  "adu", 4),
801  CPL_ERROR_INCOMPATIBLE_INPUT);
802  int nx = cpl_image_get_size_x(aImage->data);
803  float *data = cpl_image_get_data_float(aImage->data),
804  *stat = cpl_image_get_data_float(aImage->stat);
805  cpl_ensure_code(data && stat, CPL_ERROR_ILLEGAL_INPUT);
806 
807  unsigned char n;
808  for (n = 1; n <= 4; n++) {
809  double gain = muse_pfits_get_gain(aImage->header, n); /* gain in count/adu */
810  cpl_size *w = muse_quadrants_get_window(aImage, n);
811 #if 0
812  cpl_msg_debug(__func__, "looping %"CPL_SIZE_FORMAT"...%"CPL_SIZE_FORMAT
813  " %"CPL_SIZE_FORMAT"...%"CPL_SIZE_FORMAT"",
814  w[0], w[1], w[2], w[3]);
815 #endif
816  /* loop through this window and multiply counts by gain to get count */
817  int i;
818  for (i = w[0] - 1; i < w[1]; i++) {
819  int j;
820  for (j = w[2] - 1; j < w[3]; j++) {
821  data[i + j*nx] *= gain;
822  stat[i + j*nx] *= gain*gain;
823  } /* for j (window y pixels) */
824  } /* for i (window x pixels) */
825  cpl_free(w);
826  } /* for n (quadrants) */
827  cpl_propertylist_update_string(aImage->header, "BUNIT", "count");
828  cpl_propertylist_set_comment(aImage->header, "BUNIT", "DATA is in electrons");
829  return CPL_ERROR_NONE;
830 } /* muse_image_adu_to_count() */
831 
832 /*---------------------------------------------------------------------------*/
846 /*---------------------------------------------------------------------------*/
847 cpl_error_code
849 {
850  cpl_ensure_code(aImage && aImage->data && aImage->dq, CPL_ERROR_NULL_INPUT);
851  int nx = cpl_image_get_size_x(aImage->data),
852  ny = cpl_image_get_size_y(aImage->data);
853  const int *dq = cpl_image_get_data_int_const(aImage->dq);
854  int i, j;
855  for (i = 0; i < nx; i++) {
856  for (j = 0; j < ny; j++) {
857  if (!dq[i + j*nx]) { /* dq == 0 means bad */
858  continue;
859  }
860  cpl_image_reject(aImage->data, i+1, j+1);
861  if (aImage->stat) {
862  cpl_image_reject(aImage->stat, i+1, j+1);
863  }
864  } /* for j (columns) */
865  } /* for i (rows) */
866 
867  return CPL_ERROR_NONE;
868 } /* muse_image_reject_from_dq() */
869 
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
Definition: muse_image.c:84
cpl_boolean muse_pfits_get_chip_live(const cpl_propertylist *aHeaders)
find out if the CCD was active (live)
Definition: muse_pfits.c:423
int muse_image_divide(muse_image *aImage, muse_image *aDivisor)
Divide a muse_image by another with correct treatment of bad pixels and variance. ...
Definition: muse_image.c:623
const char * muse_pfits_get_extname(const cpl_propertylist *aHeaders)
find out the extension name
Definition: muse_pfits.c:188
cpl_size * muse_quadrants_get_window(const muse_image *aImage, unsigned char aQuadrant)
Determine the data window of a given quadrant on the CCD.
int muse_image_scale(muse_image *aImage, double aScale)
Scale a muse_image with correct treatment of variance.
Definition: muse_image.c:687
double muse_pfits_get_gain(const cpl_propertylist *aHeaders, unsigned char aQuadrant)
find the detector gain (in units of count/adu)
Definition: muse_pfits.c:470
cpl_image * data
the data extension
Definition: muse_image.h:47
muse_image * muse_image_load_from_raw(const char *aFilename, int aExtension)
Load raw image into the data extension of a MUSE image.
Definition: muse_image.c:286
static muse_image * muse_image_load_internal(const char *aFilename, unsigned char aIFU, const char *aID)
Load the three extensions and the FITS headers of a MUSE image.
Definition: muse_image.c:116
muse_image * muse_image_duplicate(const muse_image *aImage)
Duplicate the three image extensions and the FITS headers of a MUSE image.
Definition: muse_image.c:494
cpl_image * stat
the statistics extension
Definition: muse_image.h:65
int muse_image_subtract(muse_image *aImage, muse_image *aSubtract)
Subtract a muse_image from another with correct treatment of bad pixels and variance.
Definition: muse_image.c:577
Structure definition of MUSE three extension FITS file.
Definition: muse_image.h:41
cpl_propertylist * header
the FITS header
Definition: muse_image.h:73
cpl_error_code muse_utils_set_hduclass(cpl_propertylist *aHeader, const char *aClass2, const char *aExtData, const char *aExtDQ, const char *aExtStat)
Set HDU headers for the ESO FITS data format.
Definition: muse_utils.c:2181
int muse_image_variance_create(muse_image *aImage, muse_image *aBias)
Create the photon noise-based variance in the stat extension.
Definition: muse_image.c:731
cpl_image * dq
the data quality extension
Definition: muse_image.h:57
cpl_error_code muse_image_save(muse_image *aImage, const char *aFilename)
Save the three image extensions and the FITS headers of a MUSE image to a file.
Definition: muse_image.c:396
muse_image * muse_image_load(const char *aFilename)
Load the three extensions and the FITS headers of a MUSE image from a file.
Definition: muse_image.c:222
cpl_error_code muse_image_reject_from_dq(muse_image *aImage)
Reject pixels of a muse_image depending on its DQ data.
Definition: muse_image.c:848
muse_image * muse_image_new(void)
Allocate memory for a new muse_image object.
Definition: muse_image.c:65
cpl_error_code muse_image_adu_to_count(muse_image *aImage)
Convert the data units from raw adu to count (= electron) units.
Definition: muse_image.c:795
muse_image * muse_image_load_from_extensions(const char *aFilename, unsigned char aIFU)
Load the three extensions and the FITS headers of a MUSE image from extensions of a merged file...
Definition: muse_image.c:256