32 #include "muse_quadrants.h"
33 #include "muse_instrument.h"
35 #include "muse_artifacts.h"
37 #include "muse_pfits.h"
38 #include "muse_utils.h"
82 cpl_ensure_code(aImage && aImage->
data && aImage->
header, CPL_ERROR_NULL_INPUT);
85 CPL_ERROR_BAD_FILE_FORMAT);
90 for (n = 1; n <= 4; n++) {
92 cpl_ensure_code(w, CPL_ERROR_ILLEGAL_INPUT);
95 int nx = cpl_image_get_size_x(aImage->
data);
97 enum { REJ_NONE, REJ_DCR, REJ_FIT } reject = REJ_NONE;
99 if (!strncmp(aRejection,
"dcr", 3)) {
101 }
else if (!strncmp(aRejection,
"fit", 3)) {
103 }
else if (strncmp(aRejection,
"none", 5)) {
104 return cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT,
105 "Unknown rejection type \"%s\"", aRejection);
115 unsigned long dcrbox1 = 128, dcrbox2 = 32, dcrnpass = 3;
116 float dcrthres = 2.5,
118 if (reject == REJ_DCR) {
119 char *rest = strchr(aRejection,
':');
120 if (strlen(aRejection) > 4 && rest) {
121 dcrbox1 = strtoul(++rest, &rest, 10);
122 if (strlen(rest) > 0) {
123 dcrbox2 = strtoul(++rest, &rest, 10);
124 if (strlen(rest) > 0) {
125 dcrnpass = strtoul(++rest, &rest, 10);
126 if (strlen(rest) > 0) {
127 dcrthres = strtof(++rest, NULL);
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);
142 cpl_msg_debug(__func__,
"Using DCR cosmic ray rejection for overscan "
143 "statistics (%lux%lu, %lu, %f)", dcrbox1, dcrbox2, dcrnpass,
146 }
else if (reject == REJ_FIT) {
147 char *rest = strchr(aRejection,
':');
148 if (strlen(aRejection) > 4 && rest) {
149 sigma = strtof(++rest, NULL);
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);
158 cpl_msg_debug(__func__,
"Using constant fit for overscan statistics (0, "
163 const float *data = cpl_image_get_data_float_const(aImage->
data);
164 const int *dq = cpl_image_get_data_int_const(aImage->
dq);
167 for (n = 1; n <= 4; n++) {
170 int nh1 = w[1] - w[0] + 1,
171 nh2 = w[3] - w[2] + 1,
173 nv1 = w[5] - w[4] + 1,
174 nv2 = w[7] - w[6] + 1,
176 ntot = nhori + nvert,
179 if (reject == REJ_DCR && dcrnpass > 0 && dcrbox1 > 0 && dcrbox2 > 0) {
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]);
187 nhcr =
muse_cosmics_dcr(image, CPL_MIN(dcrbox1, nh1), CPL_MIN(dcrbox2, nh2),
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]);
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]);
199 nvcr =
muse_cosmics_dcr(image, CPL_MIN(dcrbox2, nv1), CPL_MIN(dcrbox1, nv2),
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]);
208 cpl_vector *hori = cpl_vector_new(nhori),
209 *vert = cpl_vector_new(nvert),
210 *tot = cpl_vector_new(ntot);
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++) {
218 cpl_vector_set(tot, ihori + ivert, data[i + j*nx]);
219 cpl_vector_set(hori, ihori++, data[i + j*nx]);
222 for (i = w[4] - 1; i < w[5]; i++) {
223 for (j = w[6] - 1; j < w[7]; j++) {
227 cpl_vector_set(tot, ihori + ivert, data[i + j*nx]);
228 cpl_vector_set(vert, ivert++, data[i + j*nx]);
231 cpl_vector_set_size(hori, ihori);
232 cpl_vector_set_size(vert, ivert);
233 cpl_vector_set_size(tot, ihori + ivert);
237 if (reject == REJ_FIT) {
240 cpl_matrix *pos = cpl_matrix_new(1, ihori + ivert);
241 cpl_vector *val = cpl_vector_duplicate(tot);
244 0, sigma, &mse, NULL);
245 nrej = ihori + ivert - cpl_vector_get_size(val);
247 mean = cpl_polynomial_get_coeff(fit, &pows);
249 cpl_polynomial_delete(fit);
250 cpl_matrix_delete(pos);
251 cpl_vector_delete(val);
254 mean = cpl_vector_get_mean(tot);
255 stdev = cpl_vector_get_stdev(tot);
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);
266 double lo = 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);
272 if (vmean < lo || vmean > hi) {
273 cpl_msg_warning(__func__,
"Vertical overscan differs from total "
274 "(%.3f outside %.3f+/-%.3f)", vmean, mean, stdev);
277 char *keyword = cpl_sprintf(MUSE_HDR_OVSC_MEAN, n);
278 cpl_propertylist_append_float(aImage->
header, keyword, mean);
280 keyword = cpl_sprintf(MUSE_HDR_OVSC_STDEV, n);
281 cpl_propertylist_append_float(aImage->
header, keyword, stdev);
284 cpl_vector_delete(hori);
285 cpl_vector_delete(vert);
286 cpl_vector_delete(tot);
290 return CPL_ERROR_NONE;
310 cpl_ensure(aImage && aImage->
header && aRefImage && aRefImage->
header,
311 CPL_ERROR_NULL_INPUT, CPL_FALSE);
315 for (n = 1; n <= 4; n++) {
317 char *keywordmean = cpl_sprintf(MUSE_HDR_OVSC_MEAN, n),
318 *keywordstdev = cpl_sprintf(MUSE_HDR_OVSC_STDEV, n);
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;
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,
338 cpl_free(keywordmean);
339 cpl_free(keywordstdev);
363 cpl_ensure_code(aImage && aImage->
header && aRefImage && aRefImage->
header,
364 CPL_ERROR_NULL_INPUT);
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);
375 cpl_msg_debug(__func__,
"ref=%f+/-%f, image=%f+/-%f", refmean, refstdev,
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);
385 cpl_image_copy(aImage->
data, data, w[0], w[2]);
386 cpl_image_delete(data);
389 cpl_image *stat = cpl_image_extract(aImage->
stat, w[0], w[2], w[1], w[3]);
393 cpl_msg_debug(__func__,
"variance: %f", (refstdev*refstdev + stdev*stdev) / gain);
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);
400 cpl_propertylist_update_float(aImage->
header, keywordmean, refmean);
403 cpl_free(keywordmean);
404 cpl_free(keywordstdev);
407 return CPL_ERROR_NONE;
460 unsigned char aOrder,
double aSigma,
461 const double aFRMS,
double aFChiSq)
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);
468 CPL_ERROR_BAD_FILE_FORMAT);
471 int nx = cpl_image_get_size_x(aImage->
data),
480 cpl_ensure_code(outnx > 0 && outny > 0 && overx > 0 && overy > 0 &&
481 prex > 0 && prey > 0, CPL_ERROR_INCOMPATIBLE_INPUT);
488 for (n = 1; n <= 4; n++) {
490 cpl_ensure_code(w, CPL_ERROR_ILLEGAL_INPUT);
494 cpl_boolean debug = CPL_FALSE;
495 if (getenv(
"MUSE_DEBUG_QUADRANTS")) {
496 debug = atoi(getenv(
"MUSE_DEBUG_QUADRANTS")) > 0;
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++) {
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);
508 for (i = w[4] - 1; i < w[5]; i++) {
509 for (j = w[6] - 1; j < w[7]; j++) {
513 cpl_matrix_set(pos, 0, ivert, j + 1);
514 cpl_vector_set(val, ivert++, data[i + j*nx]);
517 cpl_matrix_set_size(pos, 1, ivert);
518 cpl_vector_set_size(val, ivert);
522 cpl_matrix *pos2 = cpl_matrix_duplicate(pos);
523 cpl_vector *val2 = cpl_vector_duplicate(val);
524 double rms1, rms2, chisq1, chisq2;
526 aSigma, &rms1, &chisq1),
529 cpl_matrix_delete(pos2);
530 cpl_vector_delete(val2);
532 unsigned char norder;
533 for (norder = 1; norder <= aOrder; norder++) {
534 pos2 = cpl_matrix_duplicate(pos);
535 val2 = cpl_vector_duplicate(val);
537 norder, aSigma, &rms2,
540 cpl_matrix_delete(pos2);
541 cpl_vector_delete(val2);
543 double frms = rms1 / rms2,
544 fchisq = chisq1 / chisq2;
546 cpl_msg_debug(__func__,
"%2hhu: %f / %f, %f / %f, p(%"CPL_SIZE_FORMAT
547 ")=%f .. p(%"CPL_SIZE_FORMAT
")=%f", norder, rms2, chisq2,
549 w[6], cpl_polynomial_eval_1d(fit, w[6], NULL),
550 w[7], cpl_polynomial_eval_1d(fit, w[7], NULL));
552 if (norder == aOrder || (frms < aFRMS && fchisq < aFChiSq)) {
556 cpl_polynomial_delete(fit2);
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);
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));
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);
583 cpl_msg_debug(__func__,
"quad %1hhu fill region [%d:%d,%d:%d]", n,
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;
596 cpl_polynomial_delete(fit);
598 cpl_polynomial_delete(fit0);
602 return CPL_ERROR_NONE;
640 unsigned char aQuadrant,
641 unsigned int aIgnore)
643 cpl_ensure(aImage && aImage->
data && aImage->
header, CPL_ERROR_NULL_INPUT,
645 cpl_ensure(aQuadrant >= 1 && aQuadrant <= 4, CPL_ERROR_ILLEGAL_INPUT, NULL);
647 cpl_errorstate state = cpl_errorstate_get();
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);
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);
672 cpl_size *over = cpl_calloc(8,
sizeof(cpl_size));
675 over[1] = prex + outnx;
676 over[4] = prex + outnx + 1 + aIgnore;
677 over[5] = prex + outnx + overx;
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;
685 over[2] = prey + outny + 1 + aIgnore;
686 over[3] = prey + outny + overy;
688 over[7] = prey + outny + overy;
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;
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]);
728 cpl_ensure(aImage && aImage->
data && aImage->
header, CPL_ERROR_NULL_INPUT,
730 cpl_boolean debug = CPL_FALSE;
731 if (getenv(
"MUSE_DEBUG_QUADRANTS")) {
732 debug = atoi(getenv(
"MUSE_DEBUG_QUADRANTS")) > 0;
736 int xout = 0, yout = 0;
738 int nx[4], ny[4], portx[4], porty[4];
745 for (n = 1; n <= 4; n++) {
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);
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);
769 if (portx[n-1] == 1) {
773 if (porty[n-1] == 1) {
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);
788 cpl_msg_debug(__func__,
"output size %dx%d", xout, yout);
790 cpl_ensure(xout > 0 && yout > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
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 "
797 cpl_error_set(__func__, CPL_ERROR_INCOMPATIBLE_INPUT);
804 trimmed->
data = cpl_image_new(xout, yout, CPL_TYPE_FLOAT);
807 trimmed->
dq = cpl_image_new(xout, yout, CPL_TYPE_INT);
810 trimmed->
stat = cpl_image_new(xout, yout, CPL_TYPE_FLOAT);
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",
822 for (n = 1; n <= 4; n++) {
828 int x1 = 0, x2 = 0, y1 = 0, y2= 0,
829 xtarget = 0, ytarget = 0;
832 if (portx[n-1] == 1) {
834 cpl_msg_debug(__func__,
"left quadrant (OUT%d)", n);
837 x2 = x_prescan + nx[0];
839 }
else if (portx[n-1] == kMuseOutputXRight) {
841 cpl_msg_debug(__func__,
"right quadrant (OUT%d)", n);
843 x1 = x_size - x_prescan - nx[0] + 1;
844 x2 = x_size - x_prescan;
849 if (porty[n-1] == 1) {
851 cpl_msg_debug(__func__,
"bottom quadrant (OUT%d)", n);
854 y2 = y_prescan + ny[0];
856 }
else if (porty[n-1] == kMuseOutputYTop) {
858 cpl_msg_debug(__func__,
"top quadrant (OUT%d)", n);
860 y1 = y_size - y_prescan - ny[0] + 1;
861 y2 = y_size - y_prescan;
866 cpl_image *image = cpl_image_extract(aImage->
data, x1, y1, x2, y2);
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),
874 cpl_image_copy(trimmed->
data, image, xtarget, ytarget);
875 cpl_image_delete(image);
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);
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);
913 cpl_ensure_code(aX || aY, CPL_ERROR_NULL_INPUT);
917 *aX += kMusePreOverscanSize;
918 if (*aX > kMuseOutputXRight/2) {
919 *aX += 2 * kMusePreOverscanSize;
923 *aY += kMusePreOverscanSize;
924 if (*aY > kMuseOutputYTop/2) {
925 *aY += 2 * kMusePreOverscanSize;
928 return CPL_ERROR_NONE;
931 return CPL_ERROR_NONE;
959 cpl_ensure(aHeader, CPL_ERROR_NULL_INPUT, CPL_FALSE);
961 int portx[4], porty[4], nx[4], ny[4],
962 prex[4], prey[4], overx[4], overy[4];
968 for (n = 1; n <= 4; n++) {
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]);
984 cpl_ensure(portx[0] < portx[1], CPL_ERROR_ILLEGAL_INPUT, CPL_FALSE);
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);
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);
994 for (n = 1; n < 4; n++) {
995 cpl_ensure(nx[0] == nx[n] && ny[0] == ny[n], CPL_ERROR_INCOMPATIBLE_INPUT,
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);
1027 cpl_ensure(aImage && aImage->
data && aImage->
header, CPL_ERROR_NULL_INPUT,
1029 cpl_ensure(aQuadrant >= 1 && aQuadrant <= 4, CPL_ERROR_ILLEGAL_INPUT, NULL);
1031 cpl_boolean debug = CPL_FALSE;
1032 if (getenv(
"MUSE_DEBUG_QUADRANTS")) {
1033 debug = atoi(getenv(
"MUSE_DEBUG_QUADRANTS")) > 0;
1040 nx[0] = cpl_image_get_size_x(aImage->
data);
1041 ny[0] = cpl_image_get_size_y(aImage->
data);
1043 for (n = 1; n <= 4; n++) {
1048 cpl_size *window = (cpl_size *)cpl_calloc(
sizeof(cpl_size), 4);
1049 switch (aQuadrant) {
1057 window[0] = nx[1] + 1;
1058 window[1] = nx[1] + nx[2];
1063 window[0] = nx[3] + 1;
1064 window[1] = nx[3] + nx[4];
1065 window[2] = ny[2] + 1;
1066 window[3] = ny[2] + ny[4];
1071 window[2] = ny[1] + 1;
1072 window[3] = ny[1] + ny[3];
1078 if ((nx[1] + nx[2]) == nx[0] && (ny[1] + ny[3]) == ny[0]) {
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]);
1089 int overx[5], overy[5],
1091 for (n = 1; n <= 4; n++) {
1098 int addx = 0, addy = 0;
1099 switch (aQuadrant) {
1105 addx = prex[1] + overx[1] + overx[2];
1109 addx = prex[3] + overx[3] + overx[4];
1110 addy = prey[1] + overy[1] + overy[3];
1114 addy = prey[2] + overy[2] + overy[4];
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]);
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
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
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
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)
cpl_image * data
the data extension
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
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
cpl_image * stat
the statistics extension
Structure definition of MUSE three extension FITS file.
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
cpl_image * dq
the data quality extension
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
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
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
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.
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
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.
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
muse_image * muse_image_new(void)
Allocate memory for a new muse_image object.
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
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.