MUSE Pipeline Reference Manual  1.0.2
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_quality.h"
36 #include "muse_pfits.h"
37 #include "muse_utils.h"
38 #include "muse_wcs.h"
39 
40 /*----------------------------------------------------------------------------*/
47 /*----------------------------------------------------------------------------*/
48 
51 /*---------------------------------------------------------------------------*/
64 /*---------------------------------------------------------------------------*/
65 muse_image *
67 {
68  /* calloc automatically NULLs out the four components of the structure */
69  muse_image *image = (muse_image *)cpl_calloc(1, sizeof(muse_image));
70  return image;
71 } /* muse_image_new() */
72 
73 /*---------------------------------------------------------------------------*/
83 /*---------------------------------------------------------------------------*/
84 void
86 {
87  /* if image does not exists at all, we don't need to do anything */
88  if (!aImage) {
89  return;
90  }
91 
92  /* checks for the existence of the sub-images *
93  * are done in the CPL functions */
94  cpl_image_delete(aImage->data);
95  aImage->data = NULL;
96  cpl_image_delete(aImage->dq);
97  aImage->dq = NULL;
98  cpl_image_delete(aImage->stat);
99  aImage->stat = NULL;
100 
101  /* delete the FITS header, too */
102  cpl_propertylist_delete(aImage->header);
103  aImage->header = NULL;
104  cpl_free(aImage);
105 } /* muse_image_delete() */
106 
107 /*---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------*/
116 static muse_image *
117 muse_image_load_internal(const char *aFilename, unsigned char aIFU, const char *aID)
118 {
119  muse_image *image = muse_image_new();
120 
121  /* Load the primary FITS header first. This is not critical, but *
122  * a good first test to see, if the file is really there. */
123  image->header = cpl_propertylist_load(aFilename, 0);
124  if (!image->header) {
125  cpl_error_set_message(aID, cpl_error_get_code(), "Loading primary FITS "
126  "header of \"%s\" did not succeed", aFilename);
127  muse_image_delete(image);
128  return NULL;
129  }
130 
131  /* now load the image data from the there extensions */
132  char extname[KEYWORD_LENGTH];
133  if (aIFU) {
134  snprintf(extname, KEYWORD_LENGTH, "CHAN%02hhu.%s", aIFU, EXTNAME_DATA);
135  } else {
136  snprintf(extname, KEYWORD_LENGTH, "%s", EXTNAME_DATA);
137  }
138  int extension = cpl_fits_find_extension(aFilename, extname);
139  image->data = cpl_image_load(aFilename, CPL_TYPE_FLOAT, 0, extension);
140  if (!image->data) {
141  cpl_error_set_message(aID, MUSE_ERROR_READ_DATA, "Could not load extension "
142  "%s from \"%s\"", extname, aFilename);
143  muse_image_delete(image);
144  return NULL;
145  }
146  /* get BUNIT back from the header of this data extension */
147  cpl_propertylist *hdata = cpl_propertylist_load(aFilename, extension);
148  if (cpl_propertylist_has(hdata, "BUNIT")) { /* backward compatibility */
149  cpl_propertylist_append_string(image->header, "BUNIT",
150  cpl_propertylist_get_string(hdata, "BUNIT"));
151  cpl_propertylist_set_comment(image->header, "BUNIT",
152  cpl_propertylist_get_comment(hdata, "BUNIT"));
153  } else {
154  cpl_msg_warning(aID, "No BUNIT given in extension %d [%s] of \"%s\"!",
155  extension, extname, aFilename);
156  }
157  /* When reading from extensions, we also need to merge in all *
158  * HIERARCH keywords from the data extension. */
159  if (aIFU) {
160  cpl_propertylist_erase_regexp(hdata, "^ESO ", 1);
161  cpl_propertylist_append(image->header, hdata);
162  }
163  cpl_propertylist_delete(hdata);
164 
165  if (aIFU) {
166  snprintf(extname, KEYWORD_LENGTH, "CHAN%02hhu.%s", aIFU, EXTNAME_DQ);
167  } else {
168  snprintf(extname, KEYWORD_LENGTH, "%s", EXTNAME_DQ);
169  }
170  extension = cpl_fits_find_extension(aFilename, extname);
171  image->dq = cpl_image_load(aFilename, CPL_TYPE_INT, 0, extension);
172  if (!image->dq) {
173  cpl_error_set_message(aID, MUSE_ERROR_READ_DQ, "Could not load extension "
174  "%s from \"%s\"", extname, aFilename);
175  muse_image_delete(image);
176  return NULL;
177  }
178 
179  if (aIFU) {
180  snprintf(extname, KEYWORD_LENGTH, "CHAN%02hhu.%s", aIFU, EXTNAME_STAT);
181  } else {
182  snprintf(extname, KEYWORD_LENGTH, "%s", EXTNAME_STAT);
183  }
184  extension = cpl_fits_find_extension(aFilename, extname);
185  image->stat = cpl_image_load(aFilename, CPL_TYPE_FLOAT, 0, extension);
186  if (!image->stat) {
187  cpl_error_set_message(aID, MUSE_ERROR_READ_STAT, "Could not load extension "
188  "%s from \"%s\"", extname, aFilename);
189  muse_image_delete(image);
190  return NULL;
191  }
192 
193  return image;
194 } /* muse_image_load_internal() */
195 
196 /*---------------------------------------------------------------------------*/
221 /*---------------------------------------------------------------------------*/
222 muse_image *
223 muse_image_load(const char *aFilename)
224 {
225  return muse_image_load_internal(aFilename, 0, __func__);
226 } /* muse_image_load() */
227 
228 /*---------------------------------------------------------------------------*/
255 /*---------------------------------------------------------------------------*/
256 muse_image *
257 muse_image_load_from_extensions(const char *aFilename, unsigned char aIFU)
258 {
259  return muse_image_load_internal(aFilename, aIFU, __func__);
260 } /* muse_image_load_from_extensions() */
261 
262 /*---------------------------------------------------------------------------*/
285 /*---------------------------------------------------------------------------*/
286 muse_image *
287 muse_image_load_from_raw(const char *aFilename, int aExtension)
288 {
289  muse_image *mImage = muse_image_new();
290 
291  cpl_errorstate prestate = cpl_errorstate_get();
292  /* Raw images are always integer. *
293  * The cast to float happens implicitely on loading */
294  mImage->data = cpl_image_load(aFilename, CPL_TYPE_FLOAT, 0, aExtension);
295  char *channel = NULL;
296  if (!mImage->data) {
297  muse_image_delete(mImage);
298 
299  cpl_propertylist *header = cpl_propertylist_load(aFilename, aExtension);
300  if (!header) {
301  cpl_msg_error(__func__, "Image \"%s\" (extension %d) could not be read: %s",
302  aFilename, aExtension, cpl_error_get_message());
303  return NULL;
304  }
305  /* check if the header contains DET.CHIP.LIVE=F; if so, *
306  * set a special error to not fail the whole recipe */
307  cpl_boolean live = muse_pfits_get_chip_live(header);
308  channel = cpl_strdup(muse_pfits_get_extname(header));
309  cpl_propertylist_delete(header);
310  if (live) { /* something is wrong with the file! */
311  cpl_msg_error(__func__, "Image \"%s[%s]\" (extension %d) could not be read "
312  "although chip is alive: %s", aFilename, channel, aExtension,
313  cpl_error_get_message());
314  cpl_free(channel);
315  return NULL;
316  }
317  cpl_msg_warning(__func__, "Image \"%s[%s]\" (extension %d) could not be read,"
318  " but chip is dead: %s", aFilename, channel, aExtension,
319  cpl_error_get_message());
320  cpl_errorstate_set(prestate);
321  cpl_error_set_message(__func__, MUSE_ERROR_CHIP_NOT_LIVE, "Image \"%s[%s]\" "
322  "(extension %d) is dead", aFilename, channel,
323  aExtension);
324  cpl_free(channel);
325  return NULL;
326  } /* if data not loaded */
327 
328  /* Create an empty DQ extension, signifying a CCD without flaws. *
329  * As a first guess this should be adequate. */
330  mImage->dq = cpl_image_new(cpl_image_get_size_x(mImage->data),
331  cpl_image_get_size_y(mImage->data),
332  CPL_TYPE_INT); /* is initialized to 0 */
333 
334  /* create STAT extension filled with zeros; this must be replaced later *
335  * by the caller of this function */
336  mImage->stat = cpl_image_new(cpl_image_get_size_x(mImage->data),
337  cpl_image_get_size_y(mImage->data),
338  CPL_TYPE_FLOAT); /* is initialized to 0 */
339 
340  /* load and merge primary and extension header */
341  mImage->header = cpl_propertylist_load(aFilename, 0);
342  if (aExtension > 0) {
343  cpl_propertylist *extHeader = cpl_propertylist_load(aFilename, aExtension);
344  /* leave EXTNAME in place but remove other stuff related to extensions: */
345  cpl_propertylist_copy_property_regexp(mImage->header, extHeader,
346  "^XTENSION$|"
347  "^CHECKSUM$|"
348  "^DATASUM$", 1);
349  cpl_propertylist_delete(extHeader);
350  }
351  prestate = cpl_errorstate_get();
352  channel = cpl_strdup(muse_pfits_get_extname(mImage->header));
353  if (!cpl_errorstate_is_equal(prestate)) { /* ignore missing EXTNAME */
354  cpl_errorstate_set(prestate);
355  }
356  /* make sure that the unit is correct */
357  cpl_propertylist_update_string(mImage->header, "BUNIT", "adu");
358  cpl_propertylist_set_comment(mImage->header, "BUNIT",
359  "DATA is in analog-to-digital units");
360  cpl_msg_info(__func__, "loaded \"%s[%s]\" (extension %d)", aFilename,
361  channel ? channel : "0", aExtension);
362  cpl_free(channel);
363 
364  return mImage;
365 } /* muse_image_load_from_raw() */
366 
367 /*----------------------------------------------------------------------------*/
397 /*----------------------------------------------------------------------------*/
398 cpl_error_code
399 muse_image_save(muse_image *aImage, const char *aFilename)
400 {
401  cpl_ensure_code(aImage && aImage->data && aFilename, CPL_ERROR_NULL_INPUT);
402  cpl_ensure_code(cpl_propertylist_has(aImage->header, "BUNIT"),
403  CPL_ERROR_INCOMPATIBLE_INPUT);
404 
405  /* BUNIT should only be saved in the image extension(s), *
406  * so save a header without it */
407  cpl_propertylist *header = cpl_propertylist_duplicate(aImage->header);
408  cpl_propertylist_erase(header, "BUNIT");
409 
410  /* Save the FITS header first, as the primary header of the file. *
411  * The extensions will contain only minimal image headers. */
412  cpl_error_code error = cpl_propertylist_save(header, aFilename, CPL_IO_CREATE);
413  cpl_propertylist_delete(header);
414  if (error != CPL_ERROR_NONE) {
415  cpl_msg_error(__func__, "Could not save header: %s",
416  cpl_error_get_message());
417  return error;
418  }
419 
420  /* minimal header information for the extensions to add *
421  * extension name information */
422  cpl_propertylist *extheader = cpl_propertylist_new();
423 
424  /* copy WCS information to minimal extension header */
425  cpl_propertylist_copy_property_regexp(extheader, aImage->header,
426  MUSE_WCS_KEYS, 0);
427 
428  cpl_propertylist_append_string(extheader, "EXTNAME", EXTNAME_DATA);
429  cpl_propertylist_set_comment(extheader, "EXTNAME", EXTNAME_DATA_COMMENT);
430  const char *unit = cpl_propertylist_get_string(aImage->header, "BUNIT"),
431  *ucomment = cpl_propertylist_get_comment(aImage->header, "BUNIT");
432  cpl_propertylist_append_string(extheader, "BUNIT", unit);
433  cpl_propertylist_set_comment(extheader, "BUNIT", ucomment);
434  muse_utils_set_hduclass(extheader, "DATA", EXTNAME_DATA,
435  aImage->dq ? EXTNAME_DQ : NULL,
436  aImage->stat ? EXTNAME_STAT : NULL);
437  error = cpl_image_save(aImage->data, aFilename, CPL_TYPE_FLOAT,
438  extheader, CPL_IO_EXTEND);
439  if (error != CPL_ERROR_NONE) {
440  cpl_msg_error(__func__, "Could not append data image: %s",
441  cpl_error_get_message());
442  cpl_propertylist_delete(extheader);
443  return error;
444  } /* if error */
445 
446  if (aImage->dq) {
447  cpl_propertylist_set_string(extheader, "EXTNAME", EXTNAME_DQ);
448  cpl_propertylist_set_comment(extheader, "EXTNAME", EXTNAME_DQ_COMMENT);
449  cpl_propertylist_erase(extheader, "BUNIT"); /* no unit for data quality */
450  muse_utils_set_hduclass(extheader, "QUALITY", EXTNAME_DATA, EXTNAME_DQ,
451  aImage->stat ? EXTNAME_STAT : NULL);
452  error = cpl_image_save(aImage->dq, aFilename, CPL_TYPE_INT,
453  extheader, CPL_IO_EXTEND);
454  if (error != CPL_ERROR_NONE) {
455  cpl_msg_error(__func__, "Could not append dq image: %s",
456  cpl_error_get_message());
457  cpl_propertylist_delete(extheader);
458  return error;
459  } /* if error */
460  } /* if stat */
461 
462  if (aImage->stat) {
463  cpl_propertylist_set_string(extheader, "EXTNAME", EXTNAME_STAT);
464  cpl_propertylist_set_comment(extheader, "EXTNAME", EXTNAME_STAT_COMMENT);
465  char *ustat = cpl_sprintf("(%s)**2", unit); /* variance in squared units */
466  cpl_propertylist_append_string(extheader, "BUNIT", ustat);
467  cpl_free(ustat);
468  muse_utils_set_hduclass(extheader, "ERROR", EXTNAME_DATA,
469  aImage->dq ? EXTNAME_DQ : NULL, EXTNAME_STAT);
470  error = cpl_image_save(aImage->stat, aFilename, CPL_TYPE_FLOAT,
471  extheader, CPL_IO_EXTEND);
472  if (error != CPL_ERROR_NONE) {
473  cpl_msg_error(__func__, "Could not append stat image: %s",
474  cpl_error_get_message());
475  cpl_propertylist_delete(extheader);
476  return error;
477  } /* if error */
478  } /* if stat */
479  cpl_propertylist_delete(extheader);
480 
481  return CPL_ERROR_NONE;
482 } /* muse_image_save() */
483 
484 /*----------------------------------------------------------------------------*/
500 /*----------------------------------------------------------------------------*/
501 muse_image *
503 {
504  cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, NULL);
505 
506  muse_image *image = muse_image_new();
507  image->data = cpl_image_duplicate(aImage->data);
508  image->dq = cpl_image_duplicate(aImage->dq);
509  image->stat = cpl_image_duplicate(aImage->stat);
510  image->header = cpl_propertylist_duplicate(aImage->header);
511  if (!image->data || !image->dq || !image->stat || !image->header) {
512  muse_image_delete(image);
513  return NULL;
514  }
515  return image;
516 } /* muse_image_duplicate() */
517 
518 /*---------------------------------------------------------------------------*/
534 /*---------------------------------------------------------------------------*/
535 static int
536 muse_image_dq_merge(cpl_image *aDQ1, cpl_image *aDQ2)
537 {
538  cpl_ensure(aDQ1, CPL_ERROR_NULL_INPUT, -1);
539  cpl_ensure(aDQ2, CPL_ERROR_NULL_INPUT, -2);
540 
541  /* get the output dq image buffer as normal int */
542  int *dq1 = cpl_image_get_data_int(aDQ1);
543  /* get the subtract dq image buffer as const because we don't want to change it */
544  const int *dq2 = cpl_image_get_data_int_const(aDQ2);
545  if (!dq1 || !dq2) {
546  return cpl_error_get_code();
547  }
548 
549  int i,
550  nx = cpl_image_get_size_x(aDQ1),
551  ny = cpl_image_get_size_y(aDQ1);
552  for (i = 0; i < nx; i++) {
553  int j;
554  for (j = 0; j < ny; j++) {
555  /* If the second pixel is bad somehow, merge it with the dq flag *
556  * of the first image. The output pixel gets a combined dq status. */
557  if (dq2[i + j*nx]) {
558  dq1[i + j*nx] |= dq2[i + j*nx];
559  }
560  } /* for j */
561  } /* for i */
562 
563  return 0;
564 } /* muse_image_dq_merge() */
565 
566 /*---------------------------------------------------------------------------*/
583 /*---------------------------------------------------------------------------*/
584 int
586 {
587  cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, -1);
588  cpl_ensure(aSubtract, CPL_ERROR_NULL_INPUT, -2);
589 
590  cpl_error_code rc = cpl_image_subtract(aImage->data, aSubtract->data);
591  if (rc != CPL_ERROR_NONE) {
592  cpl_msg_error(__func__, "failure while subtracting data extension");
593  return rc;
594  }
595 
596  rc = cpl_image_add(aImage->stat, aSubtract->stat);
597  if (rc != CPL_ERROR_NONE) {
598  cpl_msg_error(__func__, "failure for stat extension");
599  return rc;
600  }
601 
602  rc = muse_image_dq_merge(aImage->dq, aSubtract->dq);
603  if (rc) {
604  cpl_msg_error(__func__, "failure for dq extension");
605  return rc;
606  }
607 
608  return 0;
609 } /* muse_image_subtract() */
610 
611 /*---------------------------------------------------------------------------*/
629 /*---------------------------------------------------------------------------*/
630 int
632 {
633  cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, -1);
634  cpl_ensure(aDivisor, CPL_ERROR_NULL_INPUT, -2);
635 
636  /* Gaussian error propagation for a division:
637  * variance_out = (variance_in + in^2 * variance_divisor / divisor^2 ) / divisor^2
638  * ^------------- term2 -------------^
639  */
640  cpl_image *term2 = cpl_image_power_create(aImage->data, 2);
641 
642  cpl_error_code rc = cpl_image_divide(aImage->data, aDivisor->data);
643  if (rc != CPL_ERROR_NONE) {
644  cpl_msg_error(__func__, "failure while dividing data extension");
645  cpl_image_delete(term2);
646  return rc;
647  }
648 
649  cpl_image *divsq = cpl_image_power_create(aDivisor->data, 2);
650  rc = cpl_image_multiply(term2, aDivisor->stat);
651 
652  /* first access to stat, better check error */
653  if (rc != CPL_ERROR_NONE) {
654  cpl_msg_error(__func__, "failure while accessing stat extension of divisor");
655  cpl_image_delete(term2);
656  cpl_image_delete(divsq);
657  return rc;
658  }
659  cpl_image_divide(term2, divsq);
660  rc = cpl_image_add(aImage->stat, term2);
661  if (rc != CPL_ERROR_NONE) {
662  cpl_msg_error(__func__, "failure while accessing stat extension of image");
663  cpl_image_delete(term2);
664  cpl_image_delete(divsq);
665  return rc;
666  }
667  cpl_image_delete(term2);
668  cpl_image_divide(aImage->stat, divsq);
669  cpl_image_delete(divsq);
670 
671  rc = muse_image_dq_merge(aImage->dq, aDivisor->dq);
672  if (rc) {
673  cpl_msg_error(__func__, "failure for dq extension");
674  return rc;
675  }
676  return 0;
677 } /* muse_image_divide() */
678 
679 /*---------------------------------------------------------------------------*/
693 /*---------------------------------------------------------------------------*/
694 int
695 muse_image_scale(muse_image *aImage, double aScale)
696 {
697  cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, -1);
698 
699  /* scale the data extension */
700  cpl_error_code rc = cpl_image_multiply_scalar(aImage->data, aScale);
701  if (rc != CPL_ERROR_NONE) {
702  cpl_msg_error(__func__, "failure while scaling data extension");
703  return rc;
704  }
705 
706  /* scale the stat extension (squared as this is the variance) */
707  rc = cpl_image_multiply_scalar(aImage->stat, aScale*aScale);
708  if (rc != CPL_ERROR_NONE) {
709  cpl_msg_error(__func__, "failure while scaling stat extension");
710  return rc;
711  }
712 
713  return 0;
714 } /* muse_image_scale() */
715 
716 /*---------------------------------------------------------------------------*/
737 /*---------------------------------------------------------------------------*/
738 int
740 {
741  cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, -1);
742  cpl_ensure(aBias, CPL_ERROR_NULL_INPUT, -2);
743  int nx = cpl_image_get_size_x(aImage->stat),
744  ny = cpl_image_get_size_y(aImage->stat),
745  nxbias = cpl_image_get_size_x(aBias->stat),
746  nybias = cpl_image_get_size_y(aBias->stat);
747  cpl_ensure(nx == nxbias && ny == nybias, CPL_ERROR_INCOMPATIBLE_INPUT, -3);
748 
749  /* the easiest is, to remove the existing stat extension and *
750  * create a new image in its place (otherwise one would need *
751  * to check that it is still zero everywhere */
752  cpl_image_delete(aImage->stat);
753  aImage->stat = cpl_image_subtract_create(aImage->data, aBias->data);
754  float *pixstat = cpl_image_get_data_float(aImage->stat);
755 
756  /* now loop through all quadrants and their pixels and divide *
757  * by the gain value */
758  unsigned char n;
759  for (n = 1; n <= 4; n++) {
760  double gain = muse_pfits_get_gain(aImage->header, n); /* in count/adu */
761  cpl_size *window = muse_quadrants_get_window(aImage, n);
762 
763  int i;
764  for (i = window[0] - 1; i < window[1]; i++) {
765  int j;
766  for (j = window[2] - 1; j < window[3]; j++) {
767  pixstat[i + j*nx] /= gain;
768  /* if the photon variance turns out to be too low, we have to reset *
769  * it, because variance cannot take a negative or zero value */
770  if (pixstat[i + j*nx] <= 0.0) {
771  /* set it to the smallest value possible for 32bit float data */
772  pixstat[i + j*nx] = FLT_MIN;
773  }
774  } /* for j (y pixels) */
775  } /* for i (x pixels) */
776  cpl_free(window);
777  } /* for n (quadrants) */
778 
779  return 0;
780 } /* muse_image_variance_create() */
781 
782 /*---------------------------------------------------------------------------*/
801 /*---------------------------------------------------------------------------*/
802 cpl_error_code
804 {
805  cpl_ensure_code(aImage && aImage->header, CPL_ERROR_NULL_INPUT);
806  cpl_ensure_code(cpl_propertylist_has(aImage->header, "BUNIT") &&
807  !strncmp(cpl_propertylist_get_string(aImage->header, "BUNIT"),
808  "adu", 4),
809  CPL_ERROR_INCOMPATIBLE_INPUT);
810  int nx = cpl_image_get_size_x(aImage->data);
811  float *data = cpl_image_get_data_float(aImage->data),
812  *stat = cpl_image_get_data_float(aImage->stat);
813  cpl_ensure_code(data && stat, CPL_ERROR_ILLEGAL_INPUT);
814 
815  unsigned char n;
816  for (n = 1; n <= 4; n++) {
817  double gain = muse_pfits_get_gain(aImage->header, n); /* gain in count/adu */
818  cpl_size *w = muse_quadrants_get_window(aImage, n);
819 #if 0
820  cpl_msg_debug(__func__, "looping %"CPL_SIZE_FORMAT"...%"CPL_SIZE_FORMAT
821  " %"CPL_SIZE_FORMAT"...%"CPL_SIZE_FORMAT"",
822  w[0], w[1], w[2], w[3]);
823 #endif
824  /* loop through this window and multiply counts by gain to get count */
825  int i;
826  for (i = w[0] - 1; i < w[1]; i++) {
827  int j;
828  for (j = w[2] - 1; j < w[3]; j++) {
829  data[i + j*nx] *= gain;
830  stat[i + j*nx] *= gain*gain;
831  } /* for j (window y pixels) */
832  } /* for i (window x pixels) */
833  cpl_free(w);
834  } /* for n (quadrants) */
835  cpl_propertylist_update_string(aImage->header, "BUNIT", "count");
836  cpl_propertylist_set_comment(aImage->header, "BUNIT", "DATA is in electrons");
837  return CPL_ERROR_NONE;
838 } /* muse_image_adu_to_count() */
839 
840 /*---------------------------------------------------------------------------*/
854 /*---------------------------------------------------------------------------*/
855 cpl_error_code
857 {
858  cpl_ensure_code(aImage && aImage->data && aImage->dq, CPL_ERROR_NULL_INPUT);
859  int nx = cpl_image_get_size_x(aImage->data),
860  ny = cpl_image_get_size_y(aImage->data);
861  const int *dq = cpl_image_get_data_int_const(aImage->dq);
862  int i, j;
863  for (i = 0; i < nx; i++) {
864  for (j = 0; j < ny; j++) {
865  if (!dq[i + j*nx]) { /* dq == 0 means bad */
866  continue;
867  }
868  cpl_image_reject(aImage->data, i+1, j+1);
869  if (aImage->stat) {
870  cpl_image_reject(aImage->stat, i+1, j+1);
871  }
872  } /* for j (columns) */
873  } /* for i (rows) */
874 
875  return CPL_ERROR_NONE;
876 } /* muse_image_reject_from_dq() */
877 
878 /*---------------------------------------------------------------------------*/
895 /*---------------------------------------------------------------------------*/
896 cpl_error_code
898 {
899  cpl_ensure_code(aImage && aImage->data && aImage->dq, CPL_ERROR_NULL_INPUT);
900 
901  /* get pointers to the 2 mandatory components */
902  int *pdq = cpl_image_get_data_int(aImage->dq);
903  float *pdata = cpl_image_get_data_float(aImage->data),
904  *pstat = NULL;
905  /* get the pointers to optional stat component as well, if possible */
906  if (aImage->stat) {
907  pstat = cpl_image_get_data_float(aImage->stat);
908  }
909  int i, nx = cpl_image_get_size_x(aImage->data),
910  ny = cpl_image_get_size_y(aImage->data);
911  for (i = 0; i < nx; i++) {
912  int j;
913  for (j = 0; j < ny; j++) {
914  if (pdq[i + j*nx] == EURO3D_GOODPIXEL) {
915  continue; /* nothing to do for good pixels */
916  }
917  /* set bad pixels of any type to not-a-number in both extensions */
918  pdata[i + j*nx] = NAN; /* supposed to be quiet NaN */
919  if (pstat) {
920  pstat[i + j*nx] = NAN;
921  }
922  } /* for j (y direction) */
923  } /* for i (x direction) */
924 
925  /* deallocate DQ and set it to NULL to be able to check for it */
926  cpl_image_delete(aImage->dq);
927  aImage->dq = NULL;
928 
929  return CPL_ERROR_NONE;
930 } /* muse_image_dq_to_nan() */
931 
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
Definition: muse_image.c:85
cpl_boolean muse_pfits_get_chip_live(const cpl_propertylist *aHeaders)
find out if the CCD was active (live)
Definition: muse_pfits.c:492
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:631
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:695
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:539
cpl_image * data
the data extension
Definition: muse_image.h:46
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:287
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:117
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:502
cpl_image * stat
the statistics extension
Definition: muse_image.h:64
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:585
Structure definition of MUSE three extension FITS file.
Definition: muse_image.h:40
cpl_propertylist * header
the FITS header
Definition: muse_image.h:72
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:2530
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:739
cpl_image * dq
the data quality extension
Definition: muse_image.h:56
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:399
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:223
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:856
muse_image * muse_image_new(void)
Allocate memory for a new muse_image object.
Definition: muse_image.c:66
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:803
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:257
cpl_error_code muse_image_dq_to_nan(muse_image *aImage)
Convert pixels flagged in the DQ extension to NANs in DATA (and STAT, if present).
Definition: muse_image.c:897