MUSE Pipeline Reference Manual  0.18.5
muse_quadrants.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> /* strncmp() */
31 
32 #include "muse_quadrants.h"
33 #include "muse_instrument.h"
34 
35 #include "muse_artifacts.h"
36 #include "muse_dfs.h"
37 #include "muse_pfits.h"
38 #include "muse_utils.h"
39 
40 /*----------------------------------------------------------------------------*/
47 /*----------------------------------------------------------------------------*/
48 
51 /*---------------------------------------------------------------------------*/
77 /*---------------------------------------------------------------------------*/
78 cpl_error_code
79 muse_quadrants_overscan_stats(muse_image *aImage, const char *aRejection,
80  unsigned int aIgnore)
81 {
82  cpl_ensure_code(aImage && aImage->data && aImage->header, CPL_ERROR_NULL_INPUT);
83  /* ensure that the region sizes are the same for all quadrants */
84  cpl_ensure_code(muse_quadrants_verify(aImage->header),
85  CPL_ERROR_BAD_FILE_FORMAT);
86  /* Check that the overscan windows make sense for all quadrants; *
87  * do this early to not waste time on other computations before. *
88  * This implicitly checks, if the input aIgnore value is usable. */
89  unsigned char n; /* quadrant counter */
90  for (n = 1; n <= 4; n++) {
91  cpl_size *w = muse_quadrants_overscan_get_window(aImage, n, aIgnore);
92  cpl_ensure_code(w, CPL_ERROR_ILLEGAL_INPUT);
93  cpl_free(w);
94  } /* for n (quadrants) */
95  int nx = cpl_image_get_size_x(aImage->data);
96 
97  enum { REJ_NONE, REJ_DCR, REJ_FIT } reject = REJ_NONE;
98  if (aRejection) {
99  if (!strncmp(aRejection, "dcr", 3)) { /* allow parameters after string! */
100  reject = REJ_DCR;
101  } else if (!strncmp(aRejection, "fit", 3)) { /* allow parameters after string! */
102  reject = REJ_FIT;
103  } else if (strncmp(aRejection, "none", 5)) {
104  return cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT,
105  "Unknown rejection type \"%s\"", aRejection);
106  }
107  } /* if aRejection */
108 
109  unsigned int binx = muse_pfits_get_binx(aImage->header),
110  biny = muse_pfits_get_biny(aImage->header),
111  outnx = muse_pfits_get_out_nx(aImage->header, 1) / binx,
112  outny = muse_pfits_get_out_ny(aImage->header, 1) / biny,
113  overx = muse_pfits_get_out_overscan_x(aImage->header, 1) / binx,
114  overy = muse_pfits_get_out_overscan_y(aImage->header, 1) / biny;
115  unsigned long dcrbox1 = 128, dcrbox2 = 32, dcrnpass = 3;
116  float dcrthres = 2.5,
117  sigma = 5.0;
118  if (reject == REJ_DCR) {
119  char *rest = strchr(aRejection, ':');
120  if (strlen(aRejection) > 4 && rest) { /* try to access info after "dcr:" */
121  dcrbox1 = strtoul(++rest, &rest, 10);
122  if (strlen(rest) > 0) {
123  dcrbox2 = strtoul(++rest, &rest, 10); /* ++ to skip over the comma */
124  if (strlen(rest) > 0) {
125  dcrnpass = strtoul(++rest, &rest, 10);
126  if (strlen(rest) > 0) {
127  dcrthres = strtof(++rest, NULL);
128  }
129  }
130  }
131  }
132  /* check that box sizes in both directions stay inside overscan regions */
133  if (dcrbox2 > overx || dcrbox2 > overy ||
134  dcrbox1 > outnx || dcrbox1 > outny ||
135  dcrnpass <= 0 || dcrthres <= 0.) {
136  cpl_msg_warning(__func__, "Detected illegal DCR parameters for overscan "
137  "statistics (%lux%lu, %lu, %f; overscan: %ux%u, output: "
138  "%ux%u), not rejecting anything!", dcrbox1, dcrbox2,
139  dcrnpass, dcrthres, overx, overy, outnx, outny);
140  reject = REJ_NONE;
141  } else {
142  cpl_msg_debug(__func__, "Using DCR cosmic ray rejection for overscan "
143  "statistics (%lux%lu, %lu, %f)", dcrbox1, dcrbox2, dcrnpass,
144  dcrthres);
145  }
146  } else if (reject == REJ_FIT) {
147  char *rest = strchr(aRejection, ':');
148  if (strlen(aRejection) > 4 && rest) { /* try to access info after "fit:" */
149  sigma = strtof(++rest, NULL);
150  }
151  /* check that box sizes in both directions stay inside overscan regions */
152  if (sigma <= 0.) {
153  cpl_msg_warning(__func__, "Detected illegal fit sigma for overscan "
154  "statistics (%f; overscan: %ux%u, output: %ux%u) not "
155  "rejecting anything!", sigma, overx, overy, outnx, outny);
156  reject = REJ_NONE;
157  } else {
158  cpl_msg_debug(__func__, "Using constant fit for overscan statistics (0, "
159  "%f)", sigma);
160  }
161  } /* if REJ_DCR */
162 
163  const float *data = cpl_image_get_data_float_const(aImage->data);
164  const int *dq = cpl_image_get_data_int_const(aImage->dq);
165 
166  /* get data region for each quadrant and compute the size of the output image */
167  for (n = 1; n <= 4; n++) {
168  /* get overscan regions and compute pixel numbers */
169  cpl_size *w = muse_quadrants_overscan_get_window(aImage, n, aIgnore);
170  int nh1 = w[1] - w[0] + 1,
171  nh2 = w[3] - w[2] + 1,
172  nhori = nh1 * nh2,
173  nv1 = w[5] - w[4] + 1,
174  nv2 = w[7] - w[6] + 1,
175  nvert = nv1 * nv2,
176  ntot = nhori + nvert,
177  nhcr = 0, nvcr = 0;
178 
179  if (reject == REJ_DCR && dcrnpass > 0 && dcrbox1 > 0 && dcrbox2 > 0) {
180  /* extract subframes to use for cosmic ray marking, then put them back */
181  /* horizontal part */
182  muse_image *image = muse_image_new();
183  image->data = cpl_image_extract(aImage->data, w[0], w[2], w[1], w[3]);
184  image->dq = cpl_image_extract(aImage->dq, w[0], w[2], w[1], w[3]);
185  image->stat = cpl_image_extract(aImage->stat, w[0], w[2], w[1], w[3]);
186  /* make sure to not cause illegal inputs due to too large boxes */
187  nhcr = muse_cosmics_dcr(image, CPL_MIN(dcrbox1, nh1), CPL_MIN(dcrbox2, nh2),
188  dcrnpass, dcrthres);
189  cpl_image_copy(aImage->data, image->data, w[0], w[2]);
190  cpl_image_copy(aImage->dq, image->dq, w[0], w[2]);
191  cpl_image_copy(aImage->stat, image->stat, w[0], w[2]);
192  muse_image_delete(image);
193  /* vertical part */
194  image = muse_image_new();
195  image->data = cpl_image_extract(aImage->data, w[4], w[6], w[5], w[7]);
196  image->dq = cpl_image_extract(aImage->dq, w[4], w[6], w[5], w[7]);
197  image->stat = cpl_image_extract(aImage->stat, w[4], w[6], w[5], w[7]);
198  /* inverted box size */
199  nvcr = muse_cosmics_dcr(image, CPL_MIN(dcrbox2, nv1), CPL_MIN(dcrbox1, nv2),
200  dcrnpass, dcrthres);
201  cpl_image_copy(aImage->data, image->data, w[4], w[6]);
202  cpl_image_copy(aImage->dq, image->dq, w[4], w[6]);
203  cpl_image_copy(aImage->stat, image->stat, w[4], w[6]);
204  muse_image_delete(image);
205  } /* if REJ_DCR */
206 
207  /* now loop over both regions and fill vectors for the statistics */
208  cpl_vector *hori = cpl_vector_new(nhori),
209  *vert = cpl_vector_new(nvert),
210  *tot = cpl_vector_new(ntot);
211  /* collect all pixels in the horizontal overscan */
212  int i, j, ihori = 0, ivert = 0;
213  for (i = w[0] - 1; i < w[1]; i++) {
214  for (j = w[2] - 1; j < w[3]; j++) {
215  if (dq[i + j*nx]) { /* exclude pixels with bad status */
216  continue;
217  }
218  cpl_vector_set(tot, ihori + ivert, data[i + j*nx]);
219  cpl_vector_set(hori, ihori++, data[i + j*nx]);
220  }
221  }
222  for (i = w[4] - 1; i < w[5]; i++) {
223  for (j = w[6] - 1; j < w[7]; j++) {
224  if (dq[i + j*nx]) {
225  continue;
226  }
227  cpl_vector_set(tot, ihori + ivert, data[i + j*nx]);
228  cpl_vector_set(vert, ivert++, data[i + j*nx]);
229  }
230  }
231  cpl_vector_set_size(hori, ihori);
232  cpl_vector_set_size(vert, ivert);
233  cpl_vector_set_size(tot, ihori + ivert);
234 
235  int nrej = 0;
236  double mean, stdev;
237  if (reject == REJ_FIT) {
238  /* For the iterative fit, we only care about the mean, not *
239  * about the position, so leave the matrix filled with zeros. */
240  cpl_matrix *pos = cpl_matrix_new(1, ihori + ivert);
241  cpl_vector *val = cpl_vector_duplicate(tot);
242  double mse;
243  cpl_polynomial *fit = muse_utils_iterate_fit_polynomial(pos, val, NULL, NULL,
244  0, sigma, &mse, NULL);
245  nrej = ihori + ivert - cpl_vector_get_size(val);
246  cpl_size pows = 0; /* get the zero-order coefficient */
247  mean = cpl_polynomial_get_coeff(fit, &pows);
248  stdev = sqrt(mse);
249  cpl_polynomial_delete(fit);
250  cpl_matrix_delete(pos);
251  cpl_vector_delete(val);
252  } else { /* no fitting */
253  nrej = nhcr + nvcr;
254  mean = cpl_vector_get_mean(tot);
255  stdev = cpl_vector_get_stdev(tot);
256  } /* else */
257 
258  double hmean = cpl_vector_get_mean(hori),
259  vmean = cpl_vector_get_mean(vert),
260  hstdev = cpl_vector_get_stdev(hori),
261  vstdev = cpl_vector_get_stdev(vert);
262  cpl_msg_debug(__func__, "quadrant %1hhu: %.3f+/-%.3f (h=%.1f+/-%.1f; "
263  "v=%.1f+/-%.1f; nrej=%d) [%s]", n, mean, stdev,
264  hmean, hstdev, vmean, vstdev, nrej, aRejection);
265  /* cross check vertical and horizontal against total */
266  double lo = mean - stdev,
267  hi = mean + stdev;
268  if (hmean < lo || hmean > hi) {
269  cpl_msg_warning(__func__, "Horizontal overscan differs from total "
270  "(%.3f outside %.3f+/-%.3f)", hmean, mean, stdev);
271  }
272  if (vmean < lo || vmean > hi) {
273  cpl_msg_warning(__func__, "Vertical overscan differs from total "
274  "(%.3f outside %.3f+/-%.3f)", vmean, mean, stdev);
275  }
276 
277  char *keyword = cpl_sprintf(MUSE_HDR_OVSC_MEAN, n);
278  cpl_propertylist_append_float(aImage->header, keyword, mean);
279  cpl_free(keyword);
280  keyword = cpl_sprintf(MUSE_HDR_OVSC_STDEV, n);
281  cpl_propertylist_append_float(aImage->header, keyword, stdev);
282  cpl_free(keyword);
283 
284  cpl_vector_delete(hori);
285  cpl_vector_delete(vert);
286  cpl_vector_delete(tot);
287  cpl_free(w);
288  } /* for n (quadrants) */
289 
290  return CPL_ERROR_NONE;
291 } /* muse_quadrants_overscan_stats() */
292 
293 /*---------------------------------------------------------------------------*/
305 /*---------------------------------------------------------------------------*/
306 cpl_boolean
308  double aSigma)
309 {
310  cpl_ensure(aImage && aImage->header && aRefImage && aRefImage->header,
311  CPL_ERROR_NULL_INPUT, CPL_FALSE);
312 
313  int rc = CPL_TRUE;
314  unsigned char n; /* quadrant counter */
315  for (n = 1; n <= 4; n++) {
316  /* create correct header keyword names */
317  char *keywordmean = cpl_sprintf(MUSE_HDR_OVSC_MEAN, n),
318  *keywordstdev = cpl_sprintf(MUSE_HDR_OVSC_STDEV, n);
319 
320  /* overscan stats for reference image */
321  float refmean = cpl_propertylist_get_float(aRefImage->header, keywordmean),
322  refstdev = cpl_propertylist_get_float(aRefImage->header, keywordstdev),
323  hilimit = refmean + aSigma * refstdev,
324  lolimit = refmean - aSigma * refstdev;
325 
326  float mean = cpl_propertylist_get_float(aImage->header, keywordmean),
327  stdev = cpl_propertylist_get_float(aImage->header, keywordstdev);
328  if (mean > hilimit || mean < lolimit) {
329  const char *fn = cpl_propertylist_get_string(aImage->header, MUSE_HDR_TMP_FN),
330  *reffn = cpl_propertylist_get_string(aRefImage->header, MUSE_HDR_TMP_FN);
331  cpl_msg_warning(__func__, "Overscan of quadrant %1u of image [%s] "
332  "(%.3f+/-%.3f) differs from reference image [%s] "
333  "(%.3f+/-%.3f)!", n, fn, mean, stdev, reffn, refmean,
334  refstdev);
335  rc = CPL_FALSE;
336  }
337 
338  cpl_free(keywordmean);
339  cpl_free(keywordstdev);
340  } /* for n (quadrants) */
341 
342  return rc;
343 } /* muse_quadrants_overscan_check() */
344 
345 /*---------------------------------------------------------------------------*/
359 /*---------------------------------------------------------------------------*/
360 cpl_error_code
362 {
363  cpl_ensure_code(aImage && aImage->header && aRefImage && aRefImage->header,
364  CPL_ERROR_NULL_INPUT);
365 
366  unsigned char n; /* quadrant counter */
367  for (n = 1; n <= 4; n++) {
368  char *keywordmean = cpl_sprintf(MUSE_HDR_OVSC_MEAN, n),
369  *keywordstdev = cpl_sprintf(MUSE_HDR_OVSC_STDEV, n);
370  float refmean = cpl_propertylist_get_float(aRefImage->header, keywordmean),
371  refstdev = cpl_propertylist_get_float(aRefImage->header, keywordstdev),
372  mean = cpl_propertylist_get_float(aImage->header, keywordmean),
373  stdev = cpl_propertylist_get_float(aImage->header, keywordstdev);
374 #if 0
375  cpl_msg_debug(__func__, "ref=%f+/-%f, image=%f+/-%f", refmean, refstdev,
376  mean, stdev);
377 #endif
378  cpl_size *w = muse_quadrants_get_window(aImage, n);
379 
380  /* subtract difference from this quadrant of aImage->data */
381  /* get the data for this quadrant */
382  cpl_image *data = cpl_image_extract(aImage->data, w[0], w[2], w[1], w[3]);
383  cpl_image_add_scalar(data, refmean - mean);
384  /* copy the data back into the original image */
385  cpl_image_copy(aImage->data, data, w[0], w[2]);
386  cpl_image_delete(data);
387 
388  /* somehow add the stdev to this quadrant of aImage->stat in quadrature */
389  cpl_image *stat = cpl_image_extract(aImage->stat, w[0], w[2], w[1], w[3]);
390  /* use the gain to correct the variances, as in muse_image_variance_create() */
391  double gain = muse_pfits_get_gain(aImage->header, n); /* in count/adu */
392 #if 0
393  cpl_msg_debug(__func__, "variance: %f", (refstdev*refstdev + stdev*stdev) / gain);
394 #endif
395  cpl_image_add_scalar(stat, (refstdev*refstdev + stdev*stdev) / gain);
396  cpl_image_copy(aImage->stat, stat, w[0], w[2]);
397  cpl_image_delete(stat);
398 
399  /* update the overscans */
400  cpl_propertylist_update_float(aImage->header, keywordmean, refmean);
401 
402  cpl_free(w);
403  cpl_free(keywordmean);
404  cpl_free(keywordstdev);
405  } /* for n (quadrants) */
406 
407  return CPL_ERROR_NONE;
408 } /* muse_quadrants_overscan_correct() */
409 
410 /*---------------------------------------------------------------------------*/
457 /*---------------------------------------------------------------------------*/
458 cpl_error_code
460  unsigned char aOrder, double aSigma,
461  const double aFRMS, double aFChiSq)
462 {
463  cpl_ensure_code(aImage && aImage->data && aImage->dq && aImage->header,
464  CPL_ERROR_NULL_INPUT);
465  cpl_ensure_code(aFRMS > 1. && aFChiSq > 1., CPL_ERROR_ILLEGAL_INPUT);
466  /* ensure that the region sizes are the same for all quadrants */
467  cpl_ensure_code(muse_quadrants_verify(aImage->header),
468  CPL_ERROR_BAD_FILE_FORMAT);
469 
470  /* get output sizes for data regions, and pre- and overscans */
471  int nx = cpl_image_get_size_x(aImage->data),
472  binx = muse_pfits_get_binx(aImage->header),
473  biny = muse_pfits_get_biny(aImage->header),
474  outnx = muse_pfits_get_out_nx(aImage->header, 1) / binx,
475  outny = muse_pfits_get_out_ny(aImage->header, 1) / biny,
476  prex = muse_pfits_get_out_prescan_x(aImage->header, 1) / binx,
477  prey = muse_pfits_get_out_prescan_y(aImage->header, 1) / biny,
478  overx = muse_pfits_get_out_overscan_x(aImage->header, 1) / binx,
479  overy = muse_pfits_get_out_overscan_y(aImage->header, 1) / biny;
480  cpl_ensure_code(outnx > 0 && outny > 0 && overx > 0 && overy > 0 &&
481  prex > 0 && prey > 0, CPL_ERROR_INCOMPATIBLE_INPUT);
482 
483  /* Check that the overscan windows make sense for all quadrants; *
484  * do this for all quadrants before everything else, so that we *
485  * don't end up with a partially corrected image! This implicitly *
486  * checks, if the input aIgnore value is usable. */
487  unsigned char n; /* quadrant counter */
488  for (n = 1; n <= 4; n++) {
489  cpl_size *w = muse_quadrants_overscan_get_window(aImage, n, aIgnore);
490  cpl_ensure_code(w, CPL_ERROR_ILLEGAL_INPUT);
491  cpl_free(w);
492  } /* for n (quadrants) */
493 
494  cpl_boolean debug = CPL_FALSE;
495  if (getenv("MUSE_DEBUG_QUADRANTS")) {
496  debug = atoi(getenv("MUSE_DEBUG_QUADRANTS")) > 0;
497  }
498 
499  float *data = cpl_image_get_data_float(aImage->data);
500  const int *dq = cpl_image_get_data_int_const(aImage->dq);
501  for (n = 1; n <= 4; n++) {
502  cpl_size *w = muse_quadrants_overscan_get_window(aImage, n, aIgnore);
503  /* over vertical overscan only, indices 4 - 7 */
504  int nvert = (w[5] - w[4] + 1) * (w[7] - w[6] + 1);
505  cpl_matrix *pos = cpl_matrix_new(1, nvert);
506  cpl_vector *val = cpl_vector_new(nvert);
507  int i, j, ivert = 0;
508  for (i = w[4] - 1; i < w[5]; i++) {
509  for (j = w[6] - 1; j < w[7]; j++) {
510  if (dq[i + j*nx]) { /* exclude pixels with bad status */
511  continue;
512  }
513  cpl_matrix_set(pos, 0, ivert, j + 1);
514  cpl_vector_set(val, ivert++, data[i + j*nx]);
515  } /* for j */
516  } /* for i */
517  cpl_matrix_set_size(pos, 1, ivert);
518  cpl_vector_set_size(val, ivert);
519 
520  /* Fit a constant first, and compute the RMS and Chi^2 of the fit; since *
521  * the iterations remove input data, we have to work on duplicates! */
522  cpl_matrix *pos2 = cpl_matrix_duplicate(pos);
523  cpl_vector *val2 = cpl_vector_duplicate(val);
524  double rms1, rms2, chisq1, chisq2;
525  cpl_polynomial *fit0 = muse_utils_iterate_fit_polynomial(pos2, val2, NULL, NULL, 0,
526  aSigma, &rms1, &chisq1),
527  *fit = fit0;
528  rms1 = sqrt(rms1);
529  cpl_matrix_delete(pos2);
530  cpl_vector_delete(val2);
531  /* now see, how much a higher order improves the fit */
532  unsigned char norder;
533  for (norder = 1; norder <= aOrder; norder++) {
534  pos2 = cpl_matrix_duplicate(pos);
535  val2 = cpl_vector_duplicate(val);
536  cpl_polynomial *fit2 = muse_utils_iterate_fit_polynomial(pos2, val2, NULL, NULL,
537  norder, aSigma, &rms2,
538  &chisq2);
539  rms2 = sqrt(rms2);
540  cpl_matrix_delete(pos2);
541  cpl_vector_delete(val2);
542  /* improvement factors in RMS and Chi^2 */
543  double frms = rms1 / rms2,
544  fchisq = chisq1 / chisq2;
545  if (debug) {
546  cpl_msg_debug(__func__, "%2hhu: %f / %f, %f / %f, p(%"CPL_SIZE_FORMAT
547  ")=%f .. p(%"CPL_SIZE_FORMAT")=%f", norder, rms2, chisq2,
548  frms, fchisq,
549  w[6], cpl_polynomial_eval_1d(fit, w[6], NULL),
550  w[7], cpl_polynomial_eval_1d(fit, w[7], NULL));
551  }
552  if (norder == aOrder || (frms < aFRMS && fchisq < aFChiSq)) {
553  fit = fit2;
554  break;
555  }
556  cpl_polynomial_delete(fit2);
557  rms1 = rms2;
558  chisq1 = chisq2;
559  } /* for norder */
560  cpl_matrix_delete(pos);
561  cpl_vector_delete(val);
562  unsigned char order = cpl_polynomial_get_degree(fit);
563  char *kw = cpl_sprintf(MUSE_HDR_OVSC_PNC, n);
564  cpl_propertylist_append_int(aImage->header, kw, order + 1);
565  cpl_free(kw);
566  for (norder = 0; norder <= order; norder++) {
567  cpl_size pow = norder;
568  kw = cpl_sprintf(MUSE_HDR_OVSC_PY, n, norder);
569  cpl_propertylist_append_double(aImage->header, kw,
570  cpl_polynomial_get_coeff(fit, &pow));
571  cpl_free(kw);
572  } /* for norder */
573 
574  /* Now create a vector containing a sampling from the polynomial, *
575  * and subtract this from every column of the given quadrant window. */
576  int outx = muse_pfits_get_out_output_x(aImage->header, n),
577  outy = muse_pfits_get_out_output_y(aImage->header, n),
578  i1 = outx == 1 ? 1 : prex + outnx + overx + 1,
579  i2 = outx == 1 ? prex + outnx + overx : 2 * (prex + outnx + overx),
580  j1 = outy == 1 ? 1 : prey + outny + overy + 1,
581  j2 = outy == 1 ? prey + outny + overy : 2 * (prey + outny + overy);
582  if (debug) {
583  cpl_msg_debug(__func__, "quad %1hhu fill region [%d:%d,%d:%d]", n,
584  i1, i2, j1, j2);
585  }
586  /* Evaluate the polynomial at every vertical position in the *
587  * quadrant, then subtract it from the whole row in that quadrant. */
588  for (j = j1 - 1; j < j2; j++) {
589  double subval = cpl_polynomial_eval_1d(fit, j + 1, NULL);
590  for (i = i1 - 1; i < i2; i++) {
591  data[i + j*nx] -= subval;
592  } /* for i */
593  } /* for j */
594 
595  if (fit != fit0) {
596  cpl_polynomial_delete(fit);
597  }
598  cpl_polynomial_delete(fit0);
599  cpl_free(w);
600  } /* for n (quadrants) */
601 
602  return CPL_ERROR_NONE;
603 } /* muse_quadrants_overscan_polyfit_vertical() */
604 
605 /*---------------------------------------------------------------------------*/
637 /*---------------------------------------------------------------------------*/
638 cpl_size *
640  unsigned char aQuadrant,
641  unsigned int aIgnore)
642 {
643  cpl_ensure(aImage && aImage->data && aImage->header, CPL_ERROR_NULL_INPUT,
644  NULL);
645  cpl_ensure(aQuadrant >= 1 && aQuadrant <= 4, CPL_ERROR_ILLEGAL_INPUT, NULL);
646  /* get output sizes for data regions, and pre- and overscans */
647  cpl_errorstate state = cpl_errorstate_get();
648  int binx = muse_pfits_get_binx(aImage->header),
649  biny = muse_pfits_get_biny(aImage->header),
650  outnx = muse_pfits_get_out_nx(aImage->header, aQuadrant) / binx,
651  outny = muse_pfits_get_out_ny(aImage->header, aQuadrant) / biny,
652  prex = muse_pfits_get_out_prescan_x(aImage->header, aQuadrant) / binx,
653  prey = muse_pfits_get_out_prescan_y(aImage->header, aQuadrant) / biny,
654  overx = muse_pfits_get_out_overscan_x(aImage->header, aQuadrant) / binx,
655  overy = muse_pfits_get_out_overscan_y(aImage->header, aQuadrant) / biny,
656  portx = muse_pfits_get_out_output_x(aImage->header, aQuadrant),
657  porty = muse_pfits_get_out_output_y(aImage->header, aQuadrant);
658 #if 0
659  cpl_msg_debug(__func__, "%d/%d, out %d/%d, pre %d/%d, over %d/%d, port %d/%d",
660  binx, biny, outnx, outny, prex, prey, overx, overy, portx, porty);
661 #endif
662  cpl_ensure(cpl_errorstate_is_equal(state) &&
663  outnx > 0 && outny > 0 && overx > 0 && overy > 0 &&
664  prex >= 0 && prey >= 0 && binx > 0 && biny > 0 &&
665  (portx == 1 || portx == kMuseOutputXRight) &&
666  (porty == 1 || porty == kMuseOutputYTop),
667  CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
668  cpl_ensure(aIgnore < (unsigned int)overx, CPL_ERROR_ILLEGAL_INPUT, NULL);
669 
670  /* horizontal overscan region: x1, x2, y1, y2 (indices: 0 - 3) *
671  * vertical overscan region: x1, x2, y1, y2 (indices: 4 - 7) */
672  cpl_size *over = cpl_calloc(8, sizeof(cpl_size));
673  if (portx == 1) {
674  over[0] = prex + 1;
675  over[1] = prex + outnx;
676  over[4] = prex + outnx + 1 + aIgnore;
677  over[5] = prex + outnx + overx;
678  } else { /* portx == kMuseOutputXRight */
679  over[0] = prex + outnx + 2*overx + 1;
680  over[1] = prex + 2*outnx + 2*overx;
681  over[4] = prex + outnx + overx + 1;
682  over[5] = prex + outnx + 2*overx - aIgnore;
683  }
684  if (porty == 1) {
685  over[2] = prey + outny + 1 + aIgnore;
686  over[3] = prey + outny + overy;
687  over[6] = prey + 1;
688  over[7] = prey + outny + overy;
689  } else { /* porty == kMuseOutputYTop */
690  over[2] = prey + outny + overy + 1;
691  over[3] = prey + outny + 2*overy - aIgnore;
692  over[6] = prey + outny + overy + 1;
693  over[7] = prey + 2*outny + 2*overy;
694  }
695 
696  if (getenv("MUSE_DEBUG_QUADRANTS") &&
697  atoi(getenv("MUSE_DEBUG_QUADRANTS")) > 0) {
698  cpl_msg_debug(__func__, "Quadrant %hhu overscan regions: "
699  "[%"CPL_SIZE_FORMAT":%"CPL_SIZE_FORMAT
700  ",%"CPL_SIZE_FORMAT":%"CPL_SIZE_FORMAT"] and "
701  "[%"CPL_SIZE_FORMAT":%"CPL_SIZE_FORMAT
702  ",%"CPL_SIZE_FORMAT":%"CPL_SIZE_FORMAT"]", aQuadrant,
703  over[0], over[1], over[2], over[3],
704  over[4], over[5], over[6], over[7]);
705  } /* if debug */
706  return over;
707 } /* muse_quadrants_overscan_get_window() */
708 
709 /*---------------------------------------------------------------------------*/
724 /*---------------------------------------------------------------------------*/
725 muse_image *
727 {
728  cpl_ensure(aImage && aImage->data && aImage->header, CPL_ERROR_NULL_INPUT,
729  NULL);
730  cpl_boolean debug = CPL_FALSE;
731  if (getenv("MUSE_DEBUG_QUADRANTS")) {
732  debug = atoi(getenv("MUSE_DEBUG_QUADRANTS")) > 0;
733  }
734 
735  /* output image size */
736  int xout = 0, yout = 0;
737  /* arrays of input data region sizes, and output port locations */
738  int nx[4], ny[4], portx[4], porty[4];
739  /* binning to take into account */
740  int binx = muse_pfits_get_binx(aImage->header),
741  biny = muse_pfits_get_biny(aImage->header);
742 
743  /* get data region for each quadrant and compute the size of the output image */
744  unsigned char n; /* quadrant counter */
745  for (n = 1; n <= 4; n++) {
746  nx[n-1] = muse_pfits_get_out_nx(aImage->header, n) / binx;
747  ny[n-1] = muse_pfits_get_out_ny(aImage->header, n) / biny;
748  portx[n-1] = muse_pfits_get_out_output_x(aImage->header, n);
749  porty[n-1] = muse_pfits_get_out_output_y(aImage->header, n);
750  /* check values to see if the relevant headers were present, otherwise abort */
751  if (nx[n-1] < 0 || ny[n-1] < 0 || portx[n-1] < 0 || porty[n-1] < 0) {
752  cpl_msg_error(__func__, "FITS headers necessary for trimming are missing "
753  "from quadrant %1d: NX=%d, NY=%d at OUT X=%d/OUT Y=%d", n,
754  nx[n-1], ny[n-1], portx[n-1], porty[n-1]);
755  cpl_error_set(__func__, CPL_ERROR_DATA_NOT_FOUND);
756  return NULL;
757  }
758  /* check values to see if the outputs are valid, otherwise abort */
759  if ((portx[n-1] != 1 && portx[n-1] != kMuseOutputXRight) ||
760  (porty[n-1] != 1 && porty[n-1] != kMuseOutputYTop)) {
761  cpl_msg_error(__func__, "FITS headers necessary for trimming are "
762  "unsupported for quadrant %1d: OUT X=%d/OUT Y=%d", n,
763  portx[n-1], porty[n-1]);
764  cpl_error_set(__func__, CPL_ERROR_INCOMPATIBLE_INPUT);
765  return NULL;
766  }
767 
768  /* use the left two quadrants to count the output height */
769  if (portx[n-1] == 1) {
770  yout += ny[n-1];
771  }
772  /* use the bottom two quadrants to count the output width */
773  if (porty[n-1] == 1) {
774  xout += nx[n-1];
775  }
776  } /* for n (quadrants) */
777 
778  /* now we should have a valid output size */
779  int x_size = cpl_image_get_size_x(aImage->data),
780  y_size = cpl_image_get_size_y(aImage->data);
781  if (xout > x_size || yout > y_size) {
782  cpl_msg_error(__func__, "output size (%dx%d) is larger than input size "
783  "(%dx%d): wrong binning?!", xout, yout, x_size, y_size);
784  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
785  return NULL;
786  }
787  if (debug) {
788  cpl_msg_debug(__func__, "output size %dx%d", xout, yout);
789  }
790  cpl_ensure(xout > 0 && yout > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
791 
792  /* verify that all the data regions have the same size */
793  for (n = 1; n < 4; n++) {
794  if (nx[n] != nx[0] || ny[n] != ny[0]) {
795  cpl_msg_error(__func__, "Data region of quadrant %d is different from "
796  "quadrant 1!", n+1);
797  cpl_error_set(__func__, CPL_ERROR_INCOMPATIBLE_INPUT);
798  return NULL;
799  }
800  }
801 
802  /* create the trimmed output image and its components */
803  muse_image *trimmed = muse_image_new();
804  trimmed->data = cpl_image_new(xout, yout, CPL_TYPE_FLOAT);
805  /* only create the other two components if they exist in the input image */
806  if (aImage->dq) {
807  trimmed->dq = cpl_image_new(xout, yout, CPL_TYPE_INT);
808  }
809  if (aImage->stat) {
810  trimmed->stat = cpl_image_new(xout, yout, CPL_TYPE_FLOAT);
811  }
812 
813  /* copy the input header but erase those that are no longer relevant */
814  trimmed->header = cpl_propertylist_duplicate(aImage->header);
815  cpl_propertylist_erase_regexp(trimmed->header,
816  "^NAXIS|^DATASUM$|^DATAMIN$|^DATAMAX$|^DATAMD5$|"
817  "^ESO DET OUT.*PRSC|^ESO DET OUT.*OVSC",
818  0);
819 
820  /* copy data regions (of all three extensions, if they exist) *
821  * and for all quadrants into the output image */
822  for (n = 1; n <= 4; n++) {
823  /* read properties from input header */
824  int x_prescan = muse_pfits_get_out_prescan_x(aImage->header, n) / binx,
825  y_prescan = muse_pfits_get_out_prescan_y(aImage->header, n) / biny;
826 
827  /* determine the data regions to extract and the target output positions */
828  int x1 = 0, x2 = 0, y1 = 0, y2= 0,
829  xtarget = 0, ytarget = 0;
830 
831  /* quadrant at left or at right */
832  if (portx[n-1] == 1) {
833 #if 0
834  cpl_msg_debug(__func__, "left quadrant (OUT%d)", n);
835 #endif
836  x1 = x_prescan + 1;
837  x2 = x_prescan + nx[0];
838  xtarget = 1;
839  } else if (portx[n-1] == kMuseOutputXRight) {
840 #if 0
841  cpl_msg_debug(__func__, "right quadrant (OUT%d)", n);
842 #endif
843  x1 = x_size - x_prescan - nx[0] + 1;
844  x2 = x_size - x_prescan;
845  xtarget = nx[0] + 1;
846  }
847 
848  /* quadrant at bottom or at top */
849  if (porty[n-1] == 1) {
850 #if 0
851  cpl_msg_debug(__func__, "bottom quadrant (OUT%d)", n);
852 #endif
853  y1 = y_prescan + 1;
854  y2 = y_prescan + ny[0];
855  ytarget = 1;
856  } else if (porty[n-1] == kMuseOutputYTop) {
857 #if 0
858  cpl_msg_debug(__func__, "top quadrant (OUT%d)", n);
859 #endif
860  y1 = y_size - y_prescan - ny[0] + 1;
861  y2 = y_size - y_prescan;
862  ytarget = ny[0] + 1;
863  }
864 
865  /* copy data and maybe extensions */
866  cpl_image *image = cpl_image_extract(aImage->data, x1, y1, x2, y2);
867  if (debug) {
868  cpl_msg_debug(__func__, "port at %d,%d: %d,%d - %d,%d, extracted: "
869  "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT" -> %d,%d",
870  portx[n-1], porty[n-1], x1,y1, x2,y2,
871  cpl_image_get_size_x(image), cpl_image_get_size_y(image),
872  xtarget, ytarget);
873  }
874  cpl_image_copy(trimmed->data, image, xtarget, ytarget);
875  cpl_image_delete(image);
876  if (aImage->dq) {
877  image = cpl_image_extract(aImage->dq, x1, y1, x2, y2);
878  cpl_image_copy(trimmed->dq, image, xtarget, ytarget);
879  cpl_image_delete(image);
880  }
881  if (aImage->stat) {
882  image = cpl_image_extract(aImage->stat, x1, y1, x2, y2);
883  cpl_image_copy(trimmed->stat, image, xtarget, ytarget);
884  cpl_image_delete(image);
885  }
886  } /* for n (quadrants) */
887 
888 #if 0
889  muse_image_save(aImage, "input.fits");
890  muse_image_save(trimmed, "trimmed.fits");
891 #endif
892 
893  return trimmed;
894 } /* muse_quadrants_trim_image() */
895 
896 /*---------------------------------------------------------------------------*/
909 /*---------------------------------------------------------------------------*/
910 cpl_error_code
911 muse_quadrants_coords_to_raw(cpl_propertylist *aHeader, int *aX, int *aY)
912 {
913  cpl_ensure_code(aX || aY, CPL_ERROR_NULL_INPUT);
914  if (!aHeader) {
915  /* assume standard quadrants */
916  if (aX) {
917  *aX += kMusePreOverscanSize; /* add one prescan in any case */
918  if (*aX > kMuseOutputXRight/2) {
919  *aX += 2 * kMusePreOverscanSize; /* add the two overscans, too */
920  }
921  }
922  if (aY) {
923  *aY += kMusePreOverscanSize;
924  if (*aY > kMuseOutputYTop/2) {
925  *aY += 2 * kMusePreOverscanSize;
926  }
927  }
928  return CPL_ERROR_NONE;
929  }
930  /* XXX do futher checks if the header was passed */
931  return CPL_ERROR_NONE;
932 } /* muse_quadrants_coords_to_raw() */
933 
934 /*---------------------------------------------------------------------------*/
955 /*---------------------------------------------------------------------------*/
956 cpl_boolean
957 muse_quadrants_verify(cpl_propertylist *aHeader)
958 {
959  cpl_ensure(aHeader, CPL_ERROR_NULL_INPUT, CPL_FALSE);
960 
961  int portx[4], porty[4], nx[4], ny[4],
962  prex[4], prey[4], overx[4], overy[4];
963 
964  /* get the output position for each quadrant */
965  int binx = muse_pfits_get_binx(aHeader),
966  biny = muse_pfits_get_biny(aHeader);
967  unsigned char n; /* quadrant counter */
968  for (n = 1; n <= 4; n++) {
969  portx[n-1] = muse_pfits_get_out_output_x(aHeader, n);
970  porty[n-1] = muse_pfits_get_out_output_y(aHeader, n);
971  nx[n-1] = muse_pfits_get_out_nx(aHeader, n) / binx;
972  ny[n-1] = muse_pfits_get_out_ny(aHeader, n) / biny;
973  prex[n-1] = muse_pfits_get_out_prescan_x(aHeader, n) / binx;
974  prey[n-1] = muse_pfits_get_out_prescan_y(aHeader, n) / biny;
975  overx[n-1] = muse_pfits_get_out_overscan_x(aHeader, n) / binx;
976  overy[n-1] = muse_pfits_get_out_overscan_y(aHeader, n) / biny;
977 #if 0
978  cpl_msg_debug(__func__, "quadrant %1hhu: port=%d,%d, n=%d,%d, pre=%d,%d, over=%d,%d",
979  n+1, portx[n-1], porty[n-1], nx[n-1], ny[n-1],
980  prex[n-1], prey[n-1], overx[n-1], overy[n-1]);
981 #endif
982  }
983 
984  cpl_ensure(portx[0] < portx[1], CPL_ERROR_ILLEGAL_INPUT, CPL_FALSE);
985  /* XXX don't check the x locations for the INM */
986  if (!cpl_propertylist_has(aHeader, "INMMODEL")) {
987  cpl_ensure(portx[0] < portx[2], CPL_ERROR_ILLEGAL_INPUT, CPL_FALSE);
988  cpl_ensure(portx[0] == portx[3], CPL_ERROR_ILLEGAL_INPUT, CPL_FALSE);
989  }
990  cpl_ensure(porty[0] == porty[1], CPL_ERROR_ILLEGAL_INPUT, CPL_FALSE);
991  cpl_ensure(porty[0] < porty[2], CPL_ERROR_ILLEGAL_INPUT, CPL_FALSE);
992  cpl_ensure(porty[0] < porty[3], CPL_ERROR_ILLEGAL_INPUT, CPL_FALSE);
993 
994  for (n = 1; n < 4; n++) {
995  cpl_ensure(nx[0] == nx[n] && ny[0] == ny[n], CPL_ERROR_INCOMPATIBLE_INPUT,
996  0);
997  cpl_ensure(prex[0] == prex[n] && prey[0] == prey[n],
998  CPL_ERROR_INCOMPATIBLE_INPUT, CPL_FALSE);
999  cpl_ensure(overx[0] == overx[n] && overy[0] == overy[n],
1000  CPL_ERROR_INCOMPATIBLE_INPUT, CPL_FALSE);
1001  }
1002 
1003  return CPL_TRUE;
1004 } /* muse_quadrants_verify() */
1005 
1006 /*---------------------------------------------------------------------------*/
1023 /*---------------------------------------------------------------------------*/
1024 cpl_size *
1025 muse_quadrants_get_window(const muse_image *aImage, unsigned char aQuadrant)
1026 {
1027  cpl_ensure(aImage && aImage->data && aImage->header, CPL_ERROR_NULL_INPUT,
1028  NULL);
1029  cpl_ensure(aQuadrant >= 1 && aQuadrant <= 4, CPL_ERROR_ILLEGAL_INPUT, NULL);
1030 
1031  cpl_boolean debug = CPL_FALSE;
1032  if (getenv("MUSE_DEBUG_QUADRANTS")) {
1033  debug = atoi(getenv("MUSE_DEBUG_QUADRANTS")) > 0;
1034  }
1035 
1036  /* get the total image size and the output size for each quadrant */
1037  int binx = muse_pfits_get_binx(aImage->header),
1038  biny = muse_pfits_get_biny(aImage->header),
1039  nx[5], ny[5]; /* element 0 is the total size, others are the quadrants */
1040  nx[0] = cpl_image_get_size_x(aImage->data);
1041  ny[0] = cpl_image_get_size_y(aImage->data);
1042  unsigned char n; /* quadrant counter */
1043  for (n = 1; n <= 4; n++) {
1044  nx[n] = muse_pfits_get_out_nx(aImage->header, n) / binx;
1045  ny[n] = muse_pfits_get_out_ny(aImage->header, n) / biny;
1046  }
1047 
1048  cpl_size *window = (cpl_size *)cpl_calloc(sizeof(cpl_size), 4);
1049  switch (aQuadrant) {
1050  case 1: /* bottom left */
1051  window[0] = 1;
1052  window[1] = nx[1];
1053  window[2] = 1;
1054  window[3] = ny[1];
1055  break;
1056  case 2: /* bottom right */
1057  window[0] = nx[1] + 1;
1058  window[1] = nx[1] + nx[2];
1059  window[2] = 1;
1060  window[3] = ny[2];
1061  break;
1062  case 3: /* top right */
1063  window[0] = nx[3] + 1; /* XXX switch for INM */
1064  window[1] = nx[3] + nx[4];
1065  window[2] = ny[2] + 1;
1066  window[3] = ny[2] + ny[4];
1067  break;
1068  case 4: /* top left */
1069  window[0] = 1; /* XXX switch for INM */
1070  window[1] = nx[3];
1071  window[2] = ny[1] + 1;
1072  window[3] = ny[1] + ny[3];
1073  break;
1074  }
1075 
1076  /* if the total image size is equal to the added size of the output ports, *
1077  * then the image is trimmed already, and we can return what we have */
1078  if ((nx[1] + nx[2]) == nx[0] && (ny[1] + ny[3]) == ny[0]) {
1079  if (debug) {
1080  cpl_msg_debug(__func__, "quadrant %d, trimmed: %"CPL_SIZE_FORMAT",%"
1081  CPL_SIZE_FORMAT " -> %"CPL_SIZE_FORMAT",%"CPL_SIZE_FORMAT"",
1082  aQuadrant, window[0], window[2], window[1], window[3]);
1083  }
1084  return window;
1085  }
1086 
1087  /* as the image seems to be untrimmed, add the pre- and over-scan sizes *
1088  * of the relevant regions to the positions of the output window */
1089  int overx[5], overy[5], /* element 0 is unused, for consistency with above! */
1090  prex[5], prey[5];
1091  for (n = 1; n <= 4; n++) {
1092  prex[n] = muse_pfits_get_out_prescan_x(aImage->header, n) / binx;
1093  prey[n] = muse_pfits_get_out_prescan_y(aImage->header, n) / biny;
1094  overx[n] = muse_pfits_get_out_overscan_x(aImage->header, n) / binx;
1095  overy[n] = muse_pfits_get_out_overscan_y(aImage->header, n) / biny;
1096  }
1097 
1098  int addx = 0, addy = 0;
1099  switch (aQuadrant) {
1100  case 1: /* bottom left, only add prescans */
1101  addx = prex[1];
1102  addy = prey[1];
1103  break;
1104  case 2: /* bottom right, add prescans, plus twice the horizontal overscan */
1105  addx = prex[1] + overx[1] + overx[2];
1106  addy = prey[2];
1107  break;
1108  case 3: /* top right, add prescans, plus twice the horizontal+vertical overscan */
1109  addx = prex[3] + overx[3] + overx[4]; /* XXX switch for INM */
1110  addy = prey[1] + overy[1] + overy[3];
1111  break;
1112  case 4: /* top left, add prescans, plus twice the vertical overscan */
1113  addx = prex[3]; /* XXX switch for INM */
1114  addy = prey[2] + overy[2] + overy[4];
1115  break;
1116  }
1117  window[0] += addx;
1118  window[1] += addx;
1119  window[2] += addy;
1120  window[3] += addy;
1121 
1122  if (debug) {
1123  cpl_msg_debug(__func__, "quadrant %d, not trimmed: %"CPL_SIZE_FORMAT",%"
1124  CPL_SIZE_FORMAT " -> %"CPL_SIZE_FORMAT",%"CPL_SIZE_FORMAT,
1125  aQuadrant, window[0], window[2], window[1], window[3]);
1126  }
1127 
1128  return window;
1129 } /* muse_quadrants_get_window() */
1130 
cpl_error_code muse_quadrants_overscan_correct(muse_image *aImage, muse_image *aRefImage)
Adapt bias level to reference image using overscan statistics.
int muse_pfits_get_out_overscan_y(const cpl_propertylist *aHeaders, unsigned char aQuadrant)
find out the vertical size of the overscan region of one quadrant
Definition: muse_pfits.c:640
int muse_pfits_get_out_output_y(const cpl_propertylist *aHeaders, unsigned char aQuadrant)
find out the vertical location of the output port of one quadrant
Definition: muse_pfits.c:510
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
Definition: muse_image.c:84
cpl_size * muse_quadrants_get_window(const muse_image *aImage, unsigned char aQuadrant)
Determine the data window of a given quadrant on the CCD.
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
int muse_pfits_get_out_overscan_x(const cpl_propertylist *aHeaders, unsigned char aQuadrant)
find out the horizontal size of the overscan region of one quadrant
Definition: muse_pfits.c:618
int muse_cosmics_dcr(muse_image *aImage, unsigned int aXBox, unsigned int aYBox, unsigned int aPasses, float aThres)
Quickly mark cosmic rays in an image using the DCR algorithm.
int muse_pfits_get_out_output_x(const cpl_propertylist *aHeaders, unsigned char aQuadrant)
find out the horizontal location of the output port of one quadrant
Definition: muse_pfits.c:488
cpl_image * stat
the statistics extension
Definition: muse_image.h:65
Structure definition of MUSE three extension FITS file.
Definition: muse_image.h:41
cpl_error_code muse_quadrants_overscan_polyfit_vertical(muse_image *aImage, unsigned aIgnore, unsigned char aOrder, double aSigma, const double aFRMS, double aFChiSq)
Correct quadrants by polynomial representation of vertical overscan.
cpl_propertylist * header
the FITS header
Definition: muse_image.h:73
cpl_image * dq
the data quality extension
Definition: muse_image.h:57
cpl_boolean muse_quadrants_verify(cpl_propertylist *aHeader)
Verify that quadrant locations and sizes meet the expectations.
int muse_pfits_get_biny(const cpl_propertylist *aHeaders)
find out the binning factor in y direction
Definition: muse_pfits.c:350
cpl_boolean muse_quadrants_overscan_check(muse_image *aImage, muse_image *aRefImage, double aSigma)
Compare overscan statistics of all quadrants to those of reference image.
int muse_pfits_get_out_prescan_y(const cpl_propertylist *aHeaders, unsigned char aQuadrant)
find out the vertical size of the prescan region of one quadrant
Definition: muse_pfits.c:596
int muse_pfits_get_out_nx(const cpl_propertylist *aHeaders, unsigned char aQuadrant)
find out the horizontal size of the data region of one quadrant
Definition: muse_pfits.c:532
cpl_polynomial * muse_utils_iterate_fit_polynomial(cpl_matrix *aPos, cpl_vector *aVal, cpl_vector *aErr, cpl_table *aExtra, const unsigned int aOrder, const double aRSigma, double *aMSE, double *aChiSq)
Iterate a polynomial fit.
Definition: muse_utils.c:1829
cpl_error_code muse_quadrants_overscan_stats(muse_image *aImage, const char *aRejection, unsigned int aIgnore)
Compute overscan statistics of all quadrants and save in FITS header.
int muse_pfits_get_binx(const cpl_propertylist *aHeaders)
find out the binning factor in x direction
Definition: muse_pfits.c:332
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
cpl_error_code muse_quadrants_coords_to_raw(cpl_propertylist *aHeader, int *aX, int *aY)
Convert coordinates of a trimmed image to raw-image coordinates.
int muse_pfits_get_out_prescan_x(const cpl_propertylist *aHeaders, unsigned char aQuadrant)
find out the horizontal size of the prescan region of one quadrant
Definition: muse_pfits.c:574
muse_image * muse_image_new(void)
Allocate memory for a new muse_image object.
Definition: muse_image.c:65
int muse_pfits_get_out_ny(const cpl_propertylist *aHeaders, unsigned char aQuadrant)
find out the vertical size of the data region of one quadrant
Definition: muse_pfits.c:553
muse_image * muse_quadrants_trim_image(muse_image *aImage)
Trim the input image of pre- and over-scan regions of all quadrants.
cpl_size * muse_quadrants_overscan_get_window(const muse_image *aImage, unsigned char aQuadrant, unsigned int aIgnore)
Determine the overscan windows of a given quadrant on the CCD.