38 #include <cpl_image.h>
39 #include <cpl_vector.h>
40 #include <cpl_matrix.h>
42 #include <cpl_parameterlist.h>
55 #include "gimessages.h"
57 #include "gilocalize.h"
74 static const cxchar* _task =
"giraffe_localize_spectra";
83 GILOCALIZE_HALF_WIDTH,
87 typedef enum GiLocalizeMethod GiLocalizeMethod;
94 enum GiThresholdMethod
96 GILOCALIZE_THRESHOLD_GLOBAL,
97 GILOCALIZE_THRESHOLD_LOCAL,
98 GILOCALIZE_THRESHOLD_ROW
101 typedef enum GiThresholdMethod GiThresholdMethod;
138 _giraffe_validate_pixel(cxint *pixels, cxint xsize, cxint ysize,
139 cxint xpos, cxint ypos, cxint xwidth, cxint ywidth,
144 cxint xstart = xpos - xwidth;
145 cxint ystart = ypos - ywidth;
146 cxint xend = xpos + xwidth;
147 cxint yend = ypos + ywidth;
157 xstart = CX_MAX(0, xstart);
158 ystart = CX_MAX(0, ystart);
160 xend = CX_MIN(xsize - 1, xend);
161 yend = CX_MIN(ysize - 1, yend);
163 xwidth = CX_MAX(xwidth,1 );
164 ywidth = CX_MAX(ywidth,1 );
172 for (i = ystart; i <= yend; i++) {
191 for (j = xstart; j <= xend; j++) {
192 if (pixels[row + j]) {
196 if (_count >= count) {
235 inline static cpl_matrix*
236 _giraffe_fit_border(cpl_matrix* mborder, cpl_matrix* mbase,
237 cpl_matrix* mxok, cxint nspectra, cxdouble sigma,
238 cxint niter, cxdouble mfrac, cpl_matrix* mcoeff)
241 const cxchar*
const fctid =
"_giraffe_fit_border";
243 register cxint x = 0;
244 register cxint naccept = 0;
245 register cxint ntotal = 0;
246 register cxint iteration = 0;
247 register cxint nx = cpl_matrix_get_ncol(mbase);
248 register cxint yorder = cpl_matrix_get_nrow(mbase);
249 register cxint nxok = cpl_matrix_get_nrow(mxok);
251 register cxdouble ratio = 1.0;
253 cpl_matrix* mtmp = NULL;
254 cpl_matrix* yraw = NULL;
255 cpl_matrix* ydiff = NULL;
256 cpl_matrix* mfit = NULL;
257 cpl_matrix* coeffs = NULL;
262 cpl_error_set(fctid, CPL_ERROR_INCOMPATIBLE_INPUT);
264 GIDEBUG(
gi_warning(
"%s: not enough points mxok[%d] for %d order fit",
265 fctid, nxok, yorder));
275 yraw = cpl_matrix_new(1, nxok);
276 ydiff = cpl_matrix_new(nxok, 1);
278 mtmp = cpl_matrix_duplicate(mxok);
284 for (x = 0; x < nxok; x++) {
285 cxdouble data = cpl_matrix_get(mborder, x, nspectra);
286 cpl_matrix_set(yraw, 0, x, data);
297 while (naccept > 0 && iteration < niter && ratio > mfrac) {
299 register cxint k = 0;
300 register cxint l = 0;
302 register cxdouble ysigma = 0.;
304 cpl_matrix* rawbase = giraffe_chebyshev_base1d(0., nx, yorder, mtmp);
305 cx_assert(rawbase != NULL);
307 if (coeffs != NULL) {
308 cpl_matrix_delete(coeffs);
312 if (coeffs == NULL) {
313 gi_warning(
"%s: error in giraffe_matrix_leastsq(), spectrum %d",
318 cpl_matrix_delete(rawbase);
322 cpl_matrix_delete(mfit);
325 mfit = cpl_matrix_product_create(coeffs, mbase);
327 for (x = 0; x < cpl_matrix_get_nrow(ydiff); x++) {
329 cxint xok = (cxint) cpl_matrix_get(mtmp, x, 0);
332 cpl_matrix_get(yraw, 0, x) - cpl_matrix_get(mfit, 0, xok);
335 cpl_matrix_set(ydiff, x , 0, diff);
347 for (l = 0; l < cpl_matrix_get_nrow(ydiff); l++) {
349 if (fabs(cpl_matrix_get(ydiff, l, 0)) <= ysigma) {
351 cxint xok = cpl_matrix_get(mtmp, l, 0);
352 cxdouble data = cpl_matrix_get(yraw, 0, l);
354 cpl_matrix_set(mtmp, k, 0, xok);
355 cpl_matrix_set(yraw, 0, k, data);
377 ratio = (cxdouble) naccept / (cxdouble) ntotal;
379 GIDEBUG(
gi_message(
"Iteration %d: Sigma %f, accepted bins: %d, "
380 "rejected %d\n", iteration, ysigma, naccept,
387 cpl_matrix_resize(mtmp, 0,
388 naccept - cpl_matrix_get_nrow(mtmp), 0, 0);
389 cpl_matrix_resize(yraw, 0,
390 0, 0, naccept - cpl_matrix_get_ncol(yraw));
391 cpl_matrix_resize(ydiff, 0,
392 naccept - cpl_matrix_get_nrow(ydiff), 0, 0);
397 if (coeffs != NULL) {
400 for (l = 0; l < cpl_matrix_get_nrow(mcoeff); l++) {
401 cpl_matrix_set(mcoeff, l, 0, cpl_matrix_get(coeffs, 0, l));
410 cpl_matrix_delete(coeffs);
411 cpl_matrix_delete(ydiff);
412 cpl_matrix_delete(yraw);
413 cpl_matrix_delete(mtmp);
420 inline static cpl_image*
421 _giraffe_filter_gauss1d(
const cpl_image* image, cxint radius, cxdouble width)
424 cxdouble w2 = width * width;
428 cpl_matrix* kernel = cpl_matrix_new(1, 2 * radius + 1);
430 cpl_image* fimage = NULL;
433 if (kernel == NULL) {
437 for (i = -radius; i <= radius; ++i) {
439 cxdouble y = exp(-x2 / (2. * w2));
441 cpl_matrix_set(kernel, 0, i + radius, y);
445 fimage = cpl_image_new(cpl_image_get_size_x(image),
446 cpl_image_get_size_y(image),
447 cpl_image_get_type(image));
449 if (fimage == NULL) {
450 cpl_matrix_delete(kernel);
454 cpl_image_filter(fimage, image, kernel, CPL_FILTER_LINEAR,
456 cpl_matrix_delete(kernel);
463 inline static cpl_image*
464 _giraffe_filter_sobel(
const cpl_image* image, cxbool vertical)
466 cpl_matrix* kernel = cpl_matrix_new(3, 3);
468 cpl_image* fimage = NULL;
471 if (kernel == NULL) {
478 cpl_matrix_set(kernel, 0, 0, -1);
479 cpl_matrix_set(kernel, 1, 0, -2);
480 cpl_matrix_set(kernel, 2, 0, -1);
482 cpl_matrix_set(kernel, 0, 2, 1);
483 cpl_matrix_set(kernel, 1, 2, 2);
484 cpl_matrix_set(kernel, 2, 2, 1);
486 cpl_matrix_set(kernel, 0, 0, 0);
487 cpl_matrix_set(kernel, 1, 0, -0.5);
488 cpl_matrix_set(kernel, 2, 0, 0);
490 cpl_matrix_set(kernel, 0, 2, 0);
491 cpl_matrix_set(kernel, 1, 2, 0.5);
492 cpl_matrix_set(kernel, 2, 2, 0);
497 cpl_matrix_set(kernel, 0, 0, 1);
498 cpl_matrix_set(kernel, 0, 1, 2);
499 cpl_matrix_set(kernel, 0, 2, 1);
501 cpl_matrix_set(kernel, 2, 0, -1);
502 cpl_matrix_set(kernel, 2, 1, -2);
503 cpl_matrix_set(kernel, 2, 2, -1);
507 fimage = cpl_image_new(cpl_image_get_size_x(image),
508 cpl_image_get_size_y(image),
509 cpl_image_get_type(image));
511 if (fimage == NULL) {
512 cpl_matrix_delete(kernel);
516 cpl_image_filter(fimage, image, kernel, CPL_FILTER_LINEAR,
518 cpl_matrix_delete(kernel);
526 _giraffe_build_edge_mask(cpl_image* raw, cpl_image* bpixel, cxint nspectra,
527 cxdouble noise, GiMaskParameters* config,
528 cxint* ndetect, cpl_matrix* mxok, cpl_matrix* myup,
532 const cxint margin = 5;
540 cxint nrows = cpl_image_get_size_y(raw);
541 cxint ncols = cpl_image_get_size_x(raw);
545 cxdouble* buffer = NULL;
547 cpl_mask* kernel = NULL;
549 cpl_image* fraw = NULL;
550 cpl_image* sraw = NULL;
551 cpl_image* vertical1 = NULL;
552 cpl_image* vertical2 = NULL;
553 cpl_image* center = NULL;
566 kernel = cpl_mask_new(1, 15);
568 if (kernel != NULL) {
570 cpl_mask_not(kernel);
572 fraw = cpl_image_new(ncols, nrows, cpl_image_get_type(raw));
575 cpl_mask_delete(kernel);
581 cpl_image_filter_mask(fraw, raw, kernel, CPL_FILTER_MEDIAN,
586 cpl_mask_delete(kernel);
590 sraw = _giraffe_filter_gauss1d(fraw, 6, 1.);
594 cpl_image_delete(fraw);
601 vertical1 = _giraffe_filter_sobel(sraw, TRUE);
602 vertical2 = _giraffe_filter_sobel(vertical1, TRUE);
604 cpl_image_save(sraw,
"master_flat_smooth.fits", -32, 0, CPL_IO_DEFAULT);
605 cpl_image_save(vertical1,
"vertical.fits", -32, 0, CPL_IO_DEFAULT);
606 cpl_image_save(vertical2,
"vertical2.fits", -32, 0, CPL_IO_DEFAULT);
613 center = cpl_image_new(ncols, nrows, CPL_TYPE_INT);
615 flags = cx_calloc(ncols,
sizeof(cxint));
616 buffer = cx_calloc(ncols,
sizeof(cxdouble));
618 if ((center == NULL) || (flags ==NULL) || (buffer == NULL)) {
626 cpl_image_delete(center);
629 cpl_image_delete(vertical2);
632 cpl_image_delete(vertical1);
635 cpl_image_delete(sraw);
638 cpl_image_delete(fraw);
646 for (m = 0; m < nrows; ++m) {
648 register cxint irow = m * ncols;
649 register cxint n = 0;
654 cxint* _center = cpl_image_get_data_int(center) + irow;
656 const cxdouble* _vt1 = cpl_image_get_data_double_const(vertical1) +
658 const cxdouble* _vt2 = cpl_image_get_data_double_const(vertical2) +
660 const cxdouble* _fraw = cpl_image_get_data_double_const(fraw) +
664 memset(buffer, 0, ncols *
sizeof(cxdouble));
665 memset(flags, 0, ncols *
sizeof(cxint));
668 for (n = 0; n < ncols; ++n) {
678 if ((n - 1 >= 0) && (_vt2[n - 1] > 0.)) {
679 buffer[n - 1] = _vt1[n - 1];
681 if ((n + 1 < ncols) && (_vt2[n + 1] > 0.)) {
682 buffer[n + 1] = _vt1[n + 1];
688 while (iteration < ncols) {
692 cxdouble dx = 3. * 2. * noise;
695 for (n = 0; n < ncols; ++n) {
697 if (!flags[n] && (buffer[n] > dx)) {
707 register cxint k = 0;
714 cxdouble signal = 0.;
720 while ((k >= 0) && (buffer[k] > 0.)) {
727 while ((k < ncols) && (buffer[k] > 0.)) {
733 while ((k < ncols) && (buffer[k] < 0.)) {
738 width = end - start + 1;
746 signal = (_fraw[pos] > 0.) ? _fraw[pos] : 0.;
747 sigma = sqrt((noise * noise + signal) / config->xbin);
749 if ((signal / sigma > 10.) && (width > 1)) {
751 start = (start == pos) ? start - 1 : start;
752 end = (end == pos) ? end + 1 : end;
755 _center[start] += -1;
766 for (n = 0; n < ncols; ++n) {
768 if (_center[n] == 1) {
774 if (scount >= smax) {
790 cx_print(
"scount: %d (%d) at %d\n", smax, nspectra, mmax);
798 const cxint limit = 0.85 * nrows;
803 const cxdouble hwf = sqrt(2. * log(2.));
805 cxint* xtrace = cx_calloc(nrows,
sizeof(cxint));
806 cxint* ytrace = cx_calloc(nrows,
sizeof(cxint));
808 cpl_image* mask = cpl_image_new(ncols, nrows, CPL_TYPE_INT);
810 for (m = 0; m < ncols; ++m) {
812 const cxint* _center = cpl_image_get_data_int(center);
813 const cxint* _reference = _center + mmax * ncols;
815 cxbool out_of_bounds = FALSE;
820 if (_reference[m] == 1) {
822 register cxint j = mmax;
823 register cxint pos = m;
828 xtrace[connected] = pos;
829 ytrace[connected] = j;
835 register cxint k = 0;
836 register cxint l = j * ncols;
837 register cxint kmin = (pos - 1 >= 0) ? pos - 1 : 0;
838 register cxint kmax = (pos + 1 < ncols) ? pos + 1 : ncols - 1;
840 for (k = kmin; k <= kmax; ++k) {
842 if (_center[l + k] == 1) {
844 if ((pos <= margin) || (pos >= ncols - margin)) {
845 out_of_bounds = TRUE;
849 xtrace[connected] = k;
850 ytrace[connected] = j;
867 register cxint k = 0;
868 register cxint l = j * ncols;
869 register cxint kmin = (pos - 1 >= 0) ? pos - 1 : 0;
870 register cxint kmax = (pos + 1 < ncols) ? pos + 1 : ncols - 1;
872 for (k = kmin; k <= kmax; ++k) {
874 if (_center[l + k] == 1) {
876 if ((pos <= margin) || (pos >= ncols - margin)) {
877 out_of_bounds = TRUE;
881 xtrace[connected] = k;
882 ytrace[connected] = j;
894 if ((connected < limit) || (out_of_bounds == TRUE)) {
896 memset(xtrace, 0, nrows *
sizeof(cxint));
897 memset(ytrace, 0, nrows *
sizeof(cxint));
899 if (out_of_bounds == TRUE) {
900 cx_print(
"discarded candidate %d, going out of detector "
901 "boundaries.\n", itrace);
905 cx_print(
"discarded candidate %d, not enough connected "
906 "centers (%d, required: %d)\n", itrace, connected,
913 cxint* _mask = cpl_image_get_data_int(mask);
915 for (j = 0; j < connected; ++j) {
917 register cxint x = xtrace[j];
918 register cxint y = ytrace[j] * ncols;
919 register cxint ix = x;
923 while ((_center[y + ix] != -1) && (ix > 0)) {
929 while ((_center[y + ix] != -2) && (ix < ncols - 1)) {
944 cx_print(
"scount: %d (expected: %d)\n", ispectra, nspectra);
952 for (m = 0; m < nrows; ++m) {
954 register cxint j = 0;
955 register cxint ns = 0;
957 const cxint* _mask = cpl_image_get_data_int(mask) + m * ncols;
958 const cxint* _center = cpl_image_get_data_int(center) + m * ncols;
961 for (j = 0; j < ncols; ++j) {
965 register cxint x = j;
966 register cxint ix = x;
969 while ((_center[ix] != -1) && (ix > 0)) {
972 cpl_matrix_set(mylo, naccepted, ns, x - hwf * fabs(x - ix));
975 while ((_center[ix] != -2) && (ix < ncols - 1)) {
978 cpl_matrix_set(myup, naccepted, ns, x + hwf * fabs(ix - x));
985 if (ns == ispectra) {
986 cpl_matrix_set(mxok, naccepted, 0, m);
995 cpl_image_save(center,
"center.fits", -32, 0, CPL_IO_DEFAULT);
996 cpl_image_save(mask,
"mask.fits", -32, 0, CPL_IO_DEFAULT);
998 cpl_image_delete(mask);
999 cpl_image_delete(center);
1000 cpl_image_delete(vertical2);
1001 cpl_image_delete(vertical1);
1002 cpl_image_delete(sraw);
1003 cpl_image_delete(fraw);
1044 _giraffe_build_raw_mask(cpl_image *raw, cpl_image *bpixel, cxint nspectra,
1045 cxdouble noise, GiMaskParameters *config,
1046 cxint *ndetect, cpl_matrix *mxok, cpl_matrix *myup,
1050 register cxint x = 0;
1051 register cxint y = 0;
1052 register cxint xretry = 0;
1053 register cxint xok = 0;
1058 cxint *yabove = NULL;
1059 cxint *ybelow = NULL;
1060 cxint *good_pixels = NULL;
1061 cxint ywidth = config->ywidth > 1 ? config->ywidth : 2;
1062 cxint ckwidth = config->ckdata.width;
1063 cxint ckheight = config->ckdata.height;
1064 cxint ckcount = config->ckdata.count;
1067 cxdouble* pixels = NULL;
1069 cpl_mask* med = NULL;
1071 cpl_image* img = raw;
1076 med = cpl_mask_new(1, 15);
1082 img = cpl_image_new(cpl_image_get_size_x(raw),
1083 cpl_image_get_size_y(raw),
1084 cpl_image_get_type(raw));
1086 cpl_image_filter_mask(img, raw, med, CPL_FILTER_MEDIAN,
1091 cpl_mask_delete(med);
1096 GIDEBUG(
gi_message(
"noise = %g start = %d tries = %d xbin = %d "
1097 "ywidth = %d", noise, config->start, config->retry,
1098 config->xbin, ywidth));
1100 pixels = cpl_image_get_data_double(img);
1102 nrows = cpl_image_get_size_y(img);
1103 ncols = cpl_image_get_size_x(img);
1106 if (config->xbin > 1) {
1110 cxdouble* _pixels = NULL;
1113 nrows = (cxint) ceil(nrows / config->xbin);
1114 config->start = (cxint) ceil(config->start / config->xbin);
1116 _pixels = cx_calloc(ncols * nrows,
sizeof(cxdouble));
1118 for (y = 0; y < ncols; ++y) {
1120 for (x = 0; x < nrows; ++x) {
1122 register cxint xx = 0;
1123 register cxint zx = x * ncols;
1124 register cxint xr = x * config->xbin;
1125 register cxint zr = xr * ncols;
1128 _pixels[zx + y] = 0.;
1130 for (xx = 0; xx < config->xbin && xr < nx; ++xx) {
1131 _pixels[zx + y] += pixels[zr + y];
1134 _pixels[zx + y] /= config->xbin;
1144 good_pixels = cx_calloc(nrows * ncols,
sizeof(cxint));
1146 switch (config->method) {
1148 case GILOCALIZE_THRESHOLD_LOCAL:
1151 cxint ywidth2 = ywidth / 2;
1152 cxint sz = 2 * ywidth2 + 1;
1154 cpl_vector* ymins = cpl_vector_new(sz);
1163 for (x = 0; x < nrows; x++) {
1165 cpl_vector_fill(ymins, 0.);
1167 for (y = 0; y < ncols; y++) {
1169 register cxint k = 0;
1170 register cxint kk = 0;
1172 cxdouble value = 0.;
1174 cxdouble threshold = 0.;
1177 for (kk = 0, k = -ywidth2; k <= ywidth2; k++) {
1179 register cxint ky = y + k;
1181 if (ky < 0 || ky >= ncols) {
1185 cpl_vector_set(ymins, kk, pixels[x * ncols + ky]);
1193 if (config->threshold > 0.) {
1195 const cxint count = 2;
1210 for (i = 0; i < count; i++) {
1211 bkg += fabs(cpl_vector_get(ymins, i));
1213 bkg /= (cxdouble)count;
1215 threshold = sqrt((2. * noise * noise +
1216 fabs(pixels[x * ncols + y]) + bkg / count) / config->xbin);
1222 register cxdouble mean = 0.;
1225 for (i = 0; i < kk; i++) {
1226 mean += cpl_vector_get(ymins, i);
1232 bkg = (cpl_vector_get(ymins, 0) +
1233 cpl_vector_get(ymins, 1)) / 2.0;
1234 threshold = mean - bkg;
1243 value = pixels[x * ncols + y] - bkg;
1249 if (value > fabs(config->threshold) * threshold) {
1250 good_pixels[x * ncols + y] = 1;
1255 cpl_vector_delete(ymins);
1262 case GILOCALIZE_THRESHOLD_ROW:
1265 cpl_image* snr = cpl_image_abs_create(raw);
1267 cxint sx = cpl_image_get_size_x(snr);
1270 cpl_image_power(snr, 0.5);
1272 for (x = 0; x < nrows; ++x) {
1274 const cxdouble* _snr = cpl_image_get_data_double_const(snr);
1276 cxdouble avsnr = giraffe_array_median(_snr + x * sx, sx);
1279 for (y = 0; y < ncols; ++y) {
1281 if (pixels[x * ncols + y] <= 0.) {
1285 if (_snr[x * ncols + y] > avsnr * fabs(config->threshold)) {
1286 good_pixels[x * ncols + y] = 1;
1293 cpl_image_delete(snr);
1303 cxdouble threshold = 0.;
1310 if (config->threshold > 0.) {
1311 threshold = config->threshold * noise;
1315 cxdouble mean = cpl_image_get_mean(raw);
1317 threshold = -config->threshold * mean *
1318 (nspectra * config->wavg / ncols);
1322 for (x = 0; x < nrows; x++) {
1324 for (y = 0; y < ncols; y++) {
1326 if (pixels[x * ncols + y] > threshold) {
1327 good_pixels[x * ncols + y] = 1;
1340 GIDEBUG(cxint *data = cx_calloc(nrows * ncols,
sizeof(cxint));
1341 memcpy(data, good_pixels, nrows * ncols *
sizeof(cxint));
1342 cpl_image *gp = cpl_image_wrap_int(ncols, nrows, data);
1343 cpl_image_save(gp,
"locmask.fits", 32, NULL, CPL_IO_DEFAULT);
1344 cpl_image_unwrap(gp);
1352 yabove = cx_calloc(nspectra + 1,
sizeof(cxint));
1353 ybelow = cx_calloc(nspectra + 1,
sizeof(cxint));
1365 for (x = config->start; (x >= 0) && (xretry <= config->retry); x--) {
1367 register cxint zx = x * ncols;
1368 register cxint nborders = 0;
1369 register cxint nbelow = 0;
1370 register cxint nabove = 0;
1371 register cxint in_spectrum = 0;
1374 for (y = 1; y < ny; y++) {
1376 register cxint tmp = 2 * good_pixels[zx + y];
1382 nborders = CX_MAX(CX_MAX(nborders, nbelow), nabove);
1384 if (nborders > nspectra) {
1394 if (good_pixels[zx + y + 1]) {
1401 if ((tmp - good_pixels[zx + y - 1]) == 2) {
1415 ybelow[nbelow++] = y;
1424 if (good_pixels[zx + y - 1]) {
1431 if ((tmp - good_pixels[zx + y + 1]) == 2) {
1445 yabove[nabove++] = y;
1457 !good_pixels[zx + y - 1] && !good_pixels[zx + y + 1]) {
1459 if (_giraffe_validate_pixel(good_pixels, ncols, nrows, y, x,
1460 ckwidth, ckheight, ckcount)) {
1462 yabove[nabove++] = y;
1463 ybelow[nbelow++] = y;
1476 *ndetect = nborders;
1478 if (!in_spectrum && (nbelow == nspectra) && (nbelow == nabove)) {
1487 for (y = 0; y < nspectra; y++) {
1488 cpl_matrix_set(mylo, xok, y, (cxdouble) ybelow[y]);
1489 cpl_matrix_set(myup, xok, y, (cxdouble) yabove[y]);
1490 cpl_matrix_set(mxok, xok, 0, (config->xbin > 1) ?
1491 (cxdouble) (x + 0.5) * config->xbin :
1497 else if (xretry++ < config->retry) {
1527 for (x = config->start + 1; (x < nrows) &&
1528 (xretry <= config->retry); x++) {
1530 register cxint zx = x * ncols;
1531 register cxint nborders = 0;
1532 register cxint nbelow = 0;
1533 register cxint nabove = 0;
1534 register cxint in_spectrum = 0;
1537 for (y = 1; y < ny; y++) {
1539 register cxint tmp = 2 * good_pixels[zx + y];
1541 nborders = CX_MAX(CX_MAX(nborders, nbelow), nabove);
1543 if (nborders > nspectra) {
1547 if (good_pixels[zx + y + 1]) {
1548 if ((tmp - good_pixels[zx + y - 1]) == 2) {
1550 ybelow[nbelow++] = y;
1556 if (good_pixels[zx + y - 1]) {
1557 if ((tmp - good_pixels[zx + y + 1]) == 2) {
1559 yabove[nabove++] = y;
1568 !good_pixels[zx + y - 1] && !good_pixels[zx + y + 1]) {
1570 if (_giraffe_validate_pixel(good_pixels, ncols, nrows, y, x,
1571 ckwidth, ckheight, ckcount)) {
1573 yabove[nabove++] = y;
1574 ybelow[nbelow++] = y;
1587 *ndetect = nborders;
1589 if (!in_spectrum && (nbelow == nspectra) && (nbelow == nabove)) {
1591 for (y = 0; y < nspectra; y++) {
1592 cpl_matrix_set(mylo, xok, y, (cxdouble) ybelow[y]);
1593 cpl_matrix_set(myup, xok, y, (cxdouble) yabove[y]);
1594 cpl_matrix_set(mxok, xok, 0, (config->xbin > 1) ?
1595 (cxdouble) (x + 0.5) * config->xbin :
1601 else if (xretry++ < config->retry) {
1612 cx_free(good_pixels);
1614 if (pixels != cpl_image_get_data_double(img)) {
1620 cpl_image_delete(img);
1625 if (*ndetect < nspectra) {
1628 else if (*ndetect > nspectra) {
1636 *ndetect = nspectra;
1670 _giraffe_fit_raw_mask(cpl_matrix *mxok, cpl_matrix *myup, cpl_matrix *mylo,
1671 cpl_table *fibers, GiMaskParameters *config,
1672 GiMaskPosition *position)
1675 register cxint nn, x, nspectra;
1676 register cxint nx = cpl_matrix_get_nrow(position->my);
1677 register cxint ns = cpl_table_get_nrow(fibers);
1685 mxraw = cpl_matrix_new(nx, 1);
1686 mcoeff = cpl_matrix_new(config->ydeg + 1, 1);
1693 for (x = 0; x < nx; x++) {
1694 cpl_matrix_set(mxraw, x, 0, x);
1701 base = giraffe_chebyshev_base1d(0., nx, config->ydeg + 1, mxraw);
1702 cpl_matrix_delete(mxraw);
1705 for (nn = 0; nn < ns; nn++) {
1706 cpl_matrix *ylofit = NULL;
1707 cpl_matrix *yupfit = NULL;
1720 ylofit = _giraffe_fit_border(mylo, base, mxok, nspectra,
1721 config->sigma, config->niter,
1722 config->mfrac, mcoeff);
1723 if (ylofit == NULL) {
1724 cpl_msg_warning(_task,
"Could not compute low border for "
1731 yupfit = _giraffe_fit_border(myup, base, mxok, nspectra,
1732 config->sigma, config->niter,
1733 config->mfrac, mcoeff);
1734 if (yupfit == NULL) {
1735 cpl_msg_warning(_task,
"Could not compute up border for "
1747 for (x = 0; x < nx; x++) {
1749 cpl_matrix_set(position->my, x, nn, 0.5 *
1750 (cpl_matrix_get(yupfit, x, 0) +
1751 cpl_matrix_get(ylofit, x, 0)));
1753 cpl_matrix_set(position->my, x, nn, 0.5 *
1754 (cpl_matrix_get(yupfit, x, 0) -
1755 cpl_matrix_get(ylofit, x, 0)) + config->ewid);
1758 cpl_matrix_delete(ylofit);
1759 cpl_matrix_delete(yupfit);
1764 cpl_msg_info(_task,
"%03d spectrum positions fitted", nspectra);
1766 cpl_matrix_delete(base);
1767 cpl_matrix_delete(mcoeff);
1769 if (nspectra == 0) {
1770 cpl_msg_warning(_task,
"could not fit any spectra, check number "
1771 "of good wavelength bins");
1815 _giraffe_fit_raw_centroid(cpl_image* mz, cpl_matrix* mxok, cpl_matrix* myup,
1816 cpl_matrix* mylo, cpl_table* fibers,
1817 GiMaskParameters* config, GiMaskPosition* position,
1818 GiMaskPosition* coeffs)
1821 const cxchar*
const fctid =
"_giraffe_fit_raw_centroid";
1823 register cxint nn = 0;
1824 register cxint x = 0;
1825 register cxint y = 0;
1826 register cxint nspectra = 0;
1827 register cxint nx = cpl_image_get_size_y(mz);
1828 register cxint ny = cpl_image_get_size_x(mz);
1829 register cxint ns = cpl_table_get_nrow(fibers);
1831 cxint yorder = config->ydeg + 1;
1832 cxint worder = config->wdeg + 1;
1834 cpl_matrix* mxraw = NULL;
1835 cpl_matrix* base = NULL;
1836 cpl_matrix* mycenter = NULL;
1837 cpl_matrix* mywidth = NULL;
1838 cpl_matrix* mx = NULL;
1839 cpl_matrix* my = NULL;
1840 cpl_matrix* mw = NULL;
1841 cpl_matrix* chebcoeff = NULL;
1842 cpl_matrix* mfitlocw = NULL;
1843 cpl_matrix* ycenfit = NULL;
1844 cpl_matrix* ycencoeff = NULL;
1848 if (cpl_matrix_get_nrow(position->my) != nx ||
1849 cpl_matrix_get_ncol(position->my) != ns) {
1850 gi_error(
"%s: invalid size for position->my[%" CPL_SIZE_FORMAT
",%"
1851 CPL_SIZE_FORMAT
"], expected [%d,%d]", fctid,
1852 cpl_matrix_get_nrow(position->my),
1853 cpl_matrix_get_ncol(position->my), nx, ns);
1857 if (cpl_matrix_get_nrow(position->mw) != nx ||
1858 cpl_matrix_get_ncol(position->mw) != ns) {
1859 gi_error(
"%s: invalid size for position->mw[%" CPL_SIZE_FORMAT
",%"
1860 CPL_SIZE_FORMAT
"], expected [%d,%d]", fctid,
1861 cpl_matrix_get_nrow(position->my),
1862 cpl_matrix_get_ncol(position->my), nx, ns);
1871 mxraw = cpl_matrix_new(nx, 1);
1873 for (x = 0; x < nx; x++) {
1874 cpl_matrix_set(mxraw, x, 0, x);
1882 base = giraffe_chebyshev_base1d(0., nx, yorder, mxraw);
1883 cpl_matrix_delete(mxraw);
1885 mycenter = cpl_matrix_new(cpl_matrix_get_nrow(mxok), ns);
1886 mywidth = cpl_matrix_new(1, cpl_matrix_get_nrow(mxok) * ns);
1888 ycencoeff = cpl_matrix_new(yorder, 1);
1890 for (nn = 0; nn < ns; nn++) {
1907 cxdouble* pixels = cpl_image_get_data_double(mz);
1909 for (x = 0; x < cpl_matrix_get_nrow(mxok); x++) {
1911 register cxint zx = (cxint) cpl_matrix_get(mxok, x, 0);
1913 register cxdouble zz = 0.;
1914 register cxdouble yy = 0.;
1916 cxdouble lower = cpl_matrix_get(mylo, x, nspectra);
1917 cxdouble upper = cpl_matrix_get(myup, x, nspectra);
1920 for (y = (cxint) lower; y <= (cxint) upper; y++) {
1921 yy += pixels[zx * ny + y] * y;
1922 zz += pixels[zx * ny + y];
1925 cpl_matrix_set(mycenter, x, nspectra, yy / zz);
1926 cpl_matrix_set(mywidth, 0, x * ns + nspectra, config->ewid +
1927 (upper - lower) / 2.0);
1935 cpl_matrix_fill(ycencoeff, 0.);
1936 ycenfit = _giraffe_fit_border(mycenter, base, mxok, nspectra,
1937 config->sigma, config->niter,
1938 config->mfrac, ycencoeff);
1939 if (ycenfit == NULL) {
1940 cpl_msg_warning(_task,
"Could not fit centroid for spectrum %d",
1950 for (x = 0; x < yorder; x++) {
1951 cpl_matrix_set(coeffs->my, x, nn,
1952 cpl_matrix_get(ycencoeff, x, 0));
1960 for (x = 0; x < nx; x++) {
1961 cpl_matrix_set(position->my, x, nn,
1962 cpl_matrix_get(ycenfit, 0, x));
1965 cpl_matrix_delete(ycenfit);
1971 cpl_image_save(lycenter,
"lycenter.fits", -32, NULL,
1973 cpl_image_delete(lycenter);
1976 cpl_image_save(lycenter,
"lycenterfit.fits", -32, NULL,
1978 cpl_image_delete(lycenter);
1981 cpl_image_save(lyxok,
"lyxok.fits", -32, NULL,
1983 cpl_image_delete(lyxok));
1986 cpl_msg_info(_task,
"%03d spectrum positions fitted", nspectra);
1988 cpl_matrix_delete(base);
1989 cpl_matrix_delete(mycenter);
1990 cpl_matrix_delete(ycencoeff);
1992 if (nspectra == 0) {
1993 cpl_msg_warning(_task,
"Could not fit any spectra, check number of "
1994 "good wavelength bins");
1996 cpl_matrix_delete(mywidth);
2004 cpl_msg_info(_task,
"2D fit (order %dx%d) of mask width", worder,
2011 mx = cpl_matrix_new(cpl_matrix_get_nrow(mxok) * nspectra, 1);
2012 my = cpl_matrix_new(cpl_matrix_get_nrow(mxok) * nspectra, 1);
2013 mw = cpl_matrix_new(1, cpl_matrix_get_nrow(mxok) * nspectra);
2015 for (y = 0, nn = 0; nn < nspectra; nn++) {
2027 for (x = 0; x < cpl_matrix_get_nrow(mxok); x++) {
2029 register cxint zx = (cxint) cpl_matrix_get(mxok, x, 0);
2030 register cxint lx = x * nspectra + y;
2033 cpl_matrix_set(mx, lx, 0, cpl_matrix_get(mxok, x, 0));
2034 cpl_matrix_set(my, lx, 0, cpl_matrix_get(position->my, zx, nn));
2035 cpl_matrix_set(mw, 0, lx, cpl_matrix_get(mywidth, 0, x * ns + y));
2040 base = giraffe_chebyshev_base2d(0., 0., nx, ny, worder, worder, mx, my);
2042 cpl_matrix_delete(my);
2043 cpl_matrix_delete(mx);
2046 cpl_matrix_delete(base);
2047 cpl_matrix_delete(mw);
2049 cpl_matrix_delete(mywidth);
2051 if (chebcoeff == NULL) {
2052 gi_warning(
"%s: error in giraffe_matrix_leastsq() for width 2D fit",
2061 for (nn = 0; nn < cpl_matrix_get_ncol(chebcoeff); nn++) {
2062 cpl_matrix_set(coeffs->mw, 0, nn, cpl_matrix_get(chebcoeff, 0, nn));
2069 mx = cpl_matrix_new(nx * nspectra, 1);
2070 my = cpl_matrix_new(nx * nspectra, 1);
2072 for (y = 0, nn = 0; nn < nspectra; nn++) {
2084 for (x = 0; x < nx; x++) {
2086 register cxint lx = x * nspectra + y;
2088 cpl_matrix_set(mx, lx, 0, x);
2089 cpl_matrix_set(my, lx, 0, cpl_matrix_get(position->my, x, nn));
2095 cpl_matrix_set_size(chebcoeff, worder, worder);
2097 mfitlocw = giraffe_chebyshev_fit2d(0., 0., nx, ny, chebcoeff, mx, my);
2098 cpl_matrix_delete(chebcoeff);
2100 cpl_matrix_delete(my);
2101 cpl_matrix_delete(mx);
2103 for (y = 0, nn = 0; nn < nspectra; nn++) {
2115 for (x = 0; x < nx; x++) {
2117 register cxint lx = x * nspectra + y;
2119 cpl_matrix_set(position->mw, x, nn,
2120 cpl_matrix_get(mfitlocw, lx, 0));
2126 cpl_matrix_delete(mfitlocw);
2159 _giraffe_localize_spectra(cpl_image *mzraw, cpl_image *bpixel,
2160 cpl_table *fibers, GiLocalizeMethod method,
2161 cxbool normalize, cxdouble noise,
2162 GiMaskParameters *config, GiMaskPosition *position,
2163 GiMaskPosition *coeffs)
2168 cxint ndetect, nspectra;
2171 cxdouble uplost = 0.;
2172 cxdouble lolost = 0.;
2173 cxdouble avglost = 0.;
2174 cxdouble avgmask = 0.;
2175 cxdouble sigmask = 0.;
2176 cxdouble sigmean = 0.;
2177 cxdouble avgborders = 0.;
2186 cpl_image *mz = NULL;
2187 cpl_image *mznorm = NULL;
2191 nx = cpl_image_get_size_y(mzraw);
2192 ny = cpl_image_get_size_x(mzraw);
2193 _mzraw = cpl_image_get_data_double(mzraw);
2196 if (normalize == TRUE) {
2198 cxdouble zxmax = 0.0;
2199 cxdouble *_mzx = NULL;
2200 cxdouble *_mznorm = NULL;
2202 cpl_image *mzx = NULL;
2205 cpl_msg_info(_task,
"Using normalized spectra for localization");
2214 mznorm = cpl_image_new(ny, nx, CPL_TYPE_DOUBLE);
2215 _mznorm = cpl_image_get_data_double(mznorm);
2217 mzx = cpl_image_new(1, nx, CPL_TYPE_DOUBLE);
2218 _mzx = cpl_image_get_data_double(mzx);
2225 for (x = 0 ; x < nx; x++) {
2226 for (y = 0 ; y < ny; y++) {
2227 _mzx[x] += _mzraw[x * ny + y];
2234 if (_mzx[x] > zxmax) {
2239 GIDEBUG(cpl_image_save(mzx,
"mzx.fits", -32, NULL, CPL_IO_DEFAULT));
2241 for (x = 0 ; x < nx; x++) {
2243 register cxdouble zxnorm = zxmax / _mzx[x];
2245 for (y = 0 ; y < ny; y++) {
2246 _mznorm[x * ny + y] = _mzraw[x * ny + y] * zxnorm;
2251 cpl_image_delete(mzx);
2260 cpl_msg_info(_task,
"Using raw spectra for localization");
2269 nspectra = cpl_table_get_nrow(fibers);
2271 mxok = cpl_matrix_new(nx, 1);
2272 myup = cpl_matrix_new(nx, nspectra);
2273 mylo = cpl_matrix_new(nx, nspectra);
2280 config->xbin = (config->xbin > 1) ? 2 * (config->xbin / 2) : 1;
2282 GIDEBUG(cpl_image_save(mz,
"mz.fits", -32, NULL, CPL_IO_DEFAULT));
2289 cpl_msg_info(_task,
"Generating mask (%d spectra expected) ...",
2295 nxok = _giraffe_build_edge_mask(mz, bpixel, nspectra, noise, config,
2296 &ndetect, mxok, myup, mylo);
2301 nxok = _giraffe_build_raw_mask(mz, bpixel, nspectra, noise, config,
2302 &ndetect, mxok, myup, mylo);
2306 cpl_matrix_delete(mxok);
2307 cpl_matrix_delete(myup);
2308 cpl_matrix_delete(mylo);
2312 cpl_msg_warning(_task,
"Invalid number of spectra detected: "
2313 "%d != %d", ndetect, nspectra);
2317 cpl_msg_warning(_task,
"No abcissa with good number "
2322 cpl_msg_warning(_task,
"Error while searching for spectra");
2330 cpl_msg_info(_task,
"%d spectra detected in %d wavelength bins",
2339 cpl_matrix_resize(mxok, 0, nxok - cpl_matrix_get_nrow(mxok), 0, 0);
2340 cpl_matrix_resize(myup, 0, nxok - cpl_matrix_get_nrow(myup), 0, 0);
2341 cpl_matrix_resize(mylo, 0, nxok - cpl_matrix_get_nrow(mylo), 0, 0);
2343 GIDEBUG(
gi_message(
"%s: mxok[0-%d]=[%g-%g]", __func__,
2344 cpl_matrix_get_nrow(mxok) - 1,
2345 cpl_matrix_get_min(mxok),
2346 cpl_matrix_get_max(mxok)));
2349 cpl_msg_info(_task,
"Computing spectrum positions and widths in "
2350 "pixel range [%g,%g]", cpl_matrix_get_min(mxok),
2351 cpl_matrix_get_max(mxok));
2353 if (cpl_matrix_get_nrow(mxok) <= config->ydeg) {
2354 cpl_msg_info(_task,
"Not enough data points %" CPL_SIZE_FORMAT
2355 " for %d order fit", cpl_matrix_get_nrow(mxok),
2362 case GILOCALIZE_HALF_WIDTH:
2363 cpl_msg_info(_task,
"Using half-width for localization");
2364 _giraffe_fit_raw_mask(mxok, myup, mylo, fibers, config,
2368 case GILOCALIZE_BARYCENTER:
2370 cpl_msg_info(_task,
"Using barycenter for localization");
2371 _giraffe_fit_raw_centroid(mz, mxok, myup, mylo, fibers, config,
2376 if (normalize == 1) {
2377 cpl_image_delete(mznorm);
2390 mwid = cpl_matrix_new(nxok, nspectra);
2392 for (n = 0, nn = 0; nn < cpl_table_get_nrow(fibers); nn++) {
2394 for (x = 0; x < nxok; x++) {
2395 register cxint lx = (cxint) cpl_matrix_get(mxok, x, 0);
2397 cxdouble lower = cpl_matrix_get(mylo, x, n);
2398 cxdouble upper = cpl_matrix_get(myup, x, n);
2399 cxdouble width = cpl_matrix_get(position->mw, lx, nn);
2401 uplost += cpl_matrix_get(position->my, lx, nn) + width - upper;
2402 lolost += cpl_matrix_get(position->my, lx, nn) - width - lower;
2404 avgborders += upper - lower;
2407 cpl_matrix_set(mwid, x, n, 2. * width);
2412 sigmean = cpl_matrix_get_mean(mwid);
2414 avglost = (lolost + uplost) / (nspectra * nxok);
2415 avgmask = 2.0 * avgmask / nspectra;
2417 cpl_msg_info(_task,
"Mask was computed using %d of %d wavelength bins",
2419 cpl_msg_info(_task,
"Average # of pixels per spectra: %.4g",
2421 cpl_msg_info(_task,
"Average # of in-borders pixels per spectra: %.4g",
2422 avgborders / nspectra);
2423 cpl_msg_info(_task,
"Average lost pixels per spectra: %.4g",
2425 cpl_msg_info(_task,
"Average lost pixels at upper border: %.4g",
2426 uplost / (nspectra * nxok));
2427 cpl_msg_info(_task,
"Average lost pixels at lower border: %.4g",
2428 lolost / (nspectra * nxok));
2429 cpl_msg_info(_task,
"Average spectrum width: %.4g +/- %.4g, "
2430 "(min, max) = (%.4g, %.4g)", sigmean, sigmask,
2431 cpl_matrix_get_min(mwid), cpl_matrix_get_max(mwid));
2433 cpl_matrix_delete(mwid);
2435 cpl_matrix_delete(mylo);
2436 cpl_matrix_delete(myup);
2437 cpl_matrix_delete(mxok);
2445 _giraffe_finalize_fibers(cpl_table *fibers, cpl_matrix *locy, GiImage *mlocy,
2446 cxdouble maxoffset, cxdouble* maxshift)
2458 cxdouble max_shift = 0.;
2459 cxdouble *positions = NULL;
2461 cpl_image *_mlocy = NULL;
2464 if (fibers == NULL || locy == NULL || mlocy == NULL) {
2468 if (cpl_table_has_column(fibers,
"RINDEX") == FALSE) {
2472 nx = cpl_matrix_get_ncol(locy);
2473 ny = cpl_matrix_get_nrow(locy);
2475 nfibers = cpl_table_get_nrow(fibers);
2478 _nx = cpl_image_get_size_x(_mlocy);
2479 _ny = cpl_image_get_size_y(_mlocy);
2485 if (nfibers > _nx) {
2489 cpl_table_select_all(fibers);
2496 irow = (_ny - 1) / 2;
2497 positions = (cxdouble *)cpl_image_get_data(_mlocy) + irow * _nx;
2508 for (i = 0; i < nfibers; i++) {
2512 cxint pos = cpl_table_get_int(fibers,
"RINDEX", i, NULL) - 1;
2514 cxdouble yc = cpl_matrix_get(locy, irow, j);
2515 cxdouble shift = fabs(yc - positions[pos]);
2517 if (shift <= maxoffset) {
2518 cpl_table_unselect_row(fibers, i);
2522 max_shift = CX_MAX(max_shift, shift);
2528 cpl_table_erase_selected(fibers);
2530 if (maxshift != NULL) {
2531 *maxshift = max_shift;
2569 GiTable *fibers, GiLocalization *master,
2570 GiImage *badpixels, GiLocalizeConfig *config)
2573 const cxchar *fctid =
"giraffe_localize_spectra";
2585 cxdouble conad = 0.;
2586 cxdouble bias_ron = 0.;
2587 cxdouble mask_sigma = 0.;
2591 cpl_propertylist *properties;
2595 cpl_image *_result = NULL;
2599 cpl_table *_fibers = NULL;
2600 cpl_table *fiber_setup = NULL;
2603 GiLocalizeMethod method;
2605 GiInstrumentMode mode;
2607 GiMaskParameters mask_config;
2609 GiMaskPosition mask_position;
2610 GiMaskPosition mask_coeffs;
2618 if (result == NULL || image == NULL || fibers == NULL || config == NULL) {
2619 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
2623 if (badpixels != NULL) {
2624 cpl_msg_debug(fctid,
"Bad pixel correction is not available. Bad "
2625 "pixel map will be ignored.");
2630 if (_fibers == NULL) {
2631 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
2635 fiber_setup = _fibers;
2645 nfibers = cpl_table_get_nrow(_fibers);
2647 cpl_msg_info(fctid,
"Setting number of fibers (%s) to %d",
2648 GIALIAS_NFIBERS, nfibers);
2650 cpl_propertylist_update_int(properties, GIALIAS_NFIBERS, nfibers);
2651 cpl_propertylist_set_comment(properties, GIALIAS_NFIBERS,
2652 "Number of fibres");
2655 giraffe_error_push();
2659 if (cpl_error_get_code() != CPL_ERROR_NONE) {
2663 giraffe_error_pop();
2670 if (config->ron > 0.) {
2671 cpl_msg_info(fctid,
"Setting bias sigma value (%s) to %.5g",
2672 GIALIAS_BIASSIGMA, config->ron);
2673 cpl_propertylist_update_double(properties, GIALIAS_BIASSIGMA,
2678 cpl_msg_info(fctid,
"Bias sigma value: %.3g e-", bias_ron);
2681 if (cpl_propertylist_has(properties, GIALIAS_DATANCOM)) {
2682 nframes = cpl_propertylist_get_int(properties, GIALIAS_DATANCOM);
2686 if (config->noise > 0.) {
2687 cpl_msg_info(fctid,
"Noise multiplier: %.3g",
2691 cpl_msg_info(fctid,
"Threshold multiplier: %.3g",
2692 fabs(config->noise));
2700 nrows = cpl_image_get_size_y(_image);
2702 if (config->start < 0) {
2703 config->start = nrows / 2;
2713 if (config->ywidth < 1) {
2715 cpl_msg_info(fctid,
"Configuring equilizing filter width from "
2720 config->ywidth = 16;
2732 cpl_msg_error(fctid,
"Invalid instrument mode!");
2738 if (!cpl_propertylist_has(properties, GIALIAS_SLITNAME)) {
2739 cpl_msg_error(fctid,
"Property (%s) not found in raw image",
2744 const cxchar *slit =
2745 cpl_propertylist_get_string(properties, GIALIAS_SLITNAME);
2747 cpl_msg_info(fctid,
"Setting equilizing filter to %d [pxl] "
2748 "for slit configuration `%s'", config->ywidth,
2761 mwidth = GISPECTRUM_MWIDTH_MEDUSA;
2770 mwidth = GISPECTRUM_MWIDTH_IFU;
2779 mwidth = GISPECTRUM_MWIDTH_IFU;
2788 cpl_msg_error(fctid,
"Invalid instrument mode!");
2798 if (config->centroid == TRUE) {
2799 method = GILOCALIZE_BARYCENTER;
2802 method = GILOCALIZE_HALF_WIDTH;
2811 mask_config.ywidth = config->ywidth;
2812 mask_config.method = config->threshold;
2813 mask_config.threshold = config->noise;
2814 mask_config.ydeg = config->yorder;
2815 mask_config.wdeg = config->worder;
2816 mask_config.ewid = config->ewidth;
2817 mask_config.wavg = mwidth;
2818 mask_config.ckdata.width = ckwidth;
2819 mask_config.ckdata.height = ckheight;
2820 mask_config.ckdata.count = ckcount;
2821 mask_config.sigma = config->sigma;
2822 mask_config.niter = config->iterations;
2823 mask_config.mfrac = config->fraction;
2824 mask_config.start = config->start;
2825 mask_config.retry = config->retries;
2826 mask_config.xbin = config->binsize;
2836 if (config->noise > 0.) {
2837 mask_config.threshold *= sqrt(nframes * conad);
2851 if (config->full != TRUE) {
2853 cpl_msg_info(fctid,
"Computing spectrum localization using SIWC "
2856 if (!master || !master->locy || !master->locy) {
2857 cpl_msg_error(fctid,
"Required full master localization is "
2868 cpl_table_unselect_all(_fibers);
2869 cpl_table_or_selected_int(_fibers,
"RP", CPL_EQUAL_TO, -1);
2871 fiber_setup = cpl_table_extract_selected(_fibers);
2872 nfibers = cpl_table_get_nrow(fiber_setup);
2882 mask_position.type = GIMASK_FITTED_DATA;
2883 mask_position.my = cpl_matrix_new(nrows, nfibers);
2884 mask_position.mw = cpl_matrix_new(nrows, nfibers);
2886 mask_coeffs.type = GIMASK_FIT_COEFFS;
2887 mask_coeffs.my = cpl_matrix_new(mask_config.ydeg + 1, nfibers);
2888 mask_coeffs.mw = cpl_matrix_new(1, (mask_config.wdeg + 1) *
2889 (mask_config.wdeg + 1));
2897 _image = cpl_image_multiply_scalar_create(_image, nframes * conad);
2899 mask_sigma = sqrt(nframes) * bias_ron;
2906 status = _giraffe_localize_spectra(_image, _bpixel, fiber_setup,
2907 method, config->normalize,
2909 &mask_config, &mask_position,
2912 cpl_image_delete(_image);
2916 result->locy = NULL;
2917 result->locw = NULL;
2918 result->locc = NULL;
2921 cpl_matrix_delete(mask_position.my);
2922 cpl_matrix_delete(mask_position.mw);
2924 cpl_matrix_delete(mask_coeffs.my);
2925 cpl_matrix_delete(mask_coeffs.mw);
2927 if (config->full != TRUE) {
2928 cpl_table_delete(fiber_setup);
2931 cpl_msg_error(fctid,
"Spectrum localization computation failed!");
2941 if (config->full != TRUE) {
2948 cpl_table_delete(fiber_setup);
2953 if (master != NULL && master->locy != NULL) {
2955 cxint nf = cpl_table_get_nrow(_fibers);
2957 cxdouble maxoffset = 0.5 * mask_config.wavg;
2958 cxdouble maxshift = 0.;
2961 cpl_msg_info(fctid,
"Comparing detected and expected fiber "
2964 status = _giraffe_finalize_fibers(_fibers, mask_position.my,
2965 master->locy, maxoffset,
2973 cxint _nf = cpl_image_get_size_x(mlocy);
2975 cpl_msg_error(fctid,
"More fibers (%d) than expected "
2976 "(%d) were found!", nf, _nf);
2980 result->locy = NULL;
2981 result->locw = NULL;
2982 result->locc = NULL;
2985 cpl_matrix_delete(mask_position.my);
2986 cpl_matrix_delete(mask_position.mw);
2988 cpl_matrix_delete(mask_coeffs.my);
2989 cpl_matrix_delete(mask_coeffs.mw);
2991 if (config->full != TRUE) {
2992 cpl_table_delete(fiber_setup);
2995 cpl_msg_error(fctid,
"Comparison of fiber positions "
3001 cx_assert(cpl_table_get_nrow(_fibers) <= nf);
3003 cpl_msg_info(fctid,
"%" CPL_SIZE_FORMAT
" of %d expected fibers "
3004 "were detected.", cpl_table_get_nrow(_fibers), nf);
3006 if (cpl_table_get_nrow(_fibers) < nf) {
3007 cpl_msg_debug(fctid,
"Maximum offset from the expected "
3008 "position is %.2f, maximum allowed offset is %.2f",
3009 maxshift, maxoffset);
3010 cpl_msg_warning(fctid,
"%" CPL_SIZE_FORMAT
" fibers are "
3011 "missing!", nf - cpl_table_get_nrow(_fibers));
3028 cpl_matrix_get_ncol(mask_position.my),
3029 cpl_matrix_get_nrow(mask_position.my));
3032 cpl_matrix_delete(mask_position.my);
3039 cpl_propertylist_set_int(properties, GIALIAS_NAXIS1,
3040 cpl_image_get_size_x(_result));
3041 cpl_propertylist_set_int(properties, GIALIAS_NAXIS2,
3042 cpl_image_get_size_y(_result));
3043 cpl_propertylist_set_int(properties, GIALIAS_BITPIX, -32);
3044 cpl_propertylist_set_double(properties, GIALIAS_BZERO, 0.);
3045 cpl_propertylist_set_double(properties, GIALIAS_BSCALE, 1.);
3047 cpl_propertylist_append_int(properties, GIALIAS_LOCNX,
3048 cpl_image_get_size_y(_result));
3049 cpl_propertylist_append_int(properties, GIALIAS_LOCNS,
3050 cpl_image_get_size_x(_result));
3052 if (config->centroid) {
3053 cpl_propertylist_append_string(properties, GIALIAS_LMETHOD,
3057 cpl_propertylist_append_string(properties, GIALIAS_LMETHOD,
3061 if (config->normalize) {
3062 cpl_propertylist_append_int(properties, GIALIAS_LNORMALIZE,
3066 cpl_propertylist_append_int(properties, GIALIAS_LNORMALIZE,
3070 cpl_propertylist_append_bool(properties, GIALIAS_LFULLLOC, config->full);
3071 cpl_propertylist_append_int(properties, GIALIAS_LOCYDEG, config->yorder);
3072 cpl_propertylist_append_int(properties, GIALIAS_LOCWDEG, config->worder);
3073 cpl_propertylist_append_double(properties, GIALIAS_LEXTRAWID,
3075 cpl_propertylist_append_double(properties, GIALIAS_LNOISEMULT,
3078 cpl_propertylist_append_double(properties, GIALIAS_LCLIPSIGMA,
3080 cpl_propertylist_append_int(properties, GIALIAS_LCLIPNITER,
3081 config->iterations);
3082 cpl_propertylist_append_double(properties, GIALIAS_LCLIPMFRAC,
3086 if (cpl_propertylist_has(properties, GIALIAS_GIRFTYPE)) {
3087 cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE,
"LOCY");
3090 cpl_propertylist_append_string(properties, GIALIAS_GIRFTYPE,
"LOCY");
3092 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
"GIRAFFE "
3093 "localization centroid");
3100 cpl_matrix_get_ncol(mask_position.mw),
3101 cpl_matrix_get_nrow(mask_position.mw));
3104 cpl_matrix_delete(mask_position.mw);
3111 cpl_propertylist_set_int(properties, GIALIAS_NAXIS1,
3112 cpl_image_get_size_x(_result));
3113 cpl_propertylist_set_int(properties, GIALIAS_NAXIS2,
3114 cpl_image_get_size_y(_result));
3116 if (cpl_propertylist_has(properties, GIALIAS_GIRFTYPE)) {
3117 cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE,
3121 cpl_propertylist_append_string(properties, GIALIAS_GIRFTYPE,
3124 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
"GIRAFFE "
3125 "localization half-width");
3130 locc = cpl_table_new(cpl_matrix_get_ncol(mask_coeffs.my));
3132 cpl_table_new_column(locc,
"BUTTON", CPL_TYPE_INT);
3133 for (i = 0; i < cpl_table_get_nrow(locc); i++) {
3134 cpl_table_set_int(locc,
"BUTTON", i, i);
3137 for (i = 0; i < cpl_matrix_get_nrow(mask_coeffs.my); i++) {
3138 cxchar *label = NULL;
3140 cx_asprintf(&label,
"YC%d", i);
3141 cpl_table_new_column(locc, label, CPL_TYPE_DOUBLE);
3147 cpl_table_delete(locc);
3149 _my = cpl_matrix_transpose_create(mask_coeffs.my);
3151 cpl_matrix_delete(_my);
3152 cpl_matrix_delete(mask_coeffs.my);
3159 pname = cx_string_new();
3161 for (i = 0; i < cpl_matrix_get_ncol(mask_coeffs.mw); i++) {
3162 cx_string_sprintf(pname,
"%s%d", GIALIAS_LOCWIDCOEF, i);
3163 cpl_propertylist_append_double(properties, cx_string_get(pname),
3164 cpl_matrix_get(mask_coeffs.mw, 0, i));
3167 cx_string_delete(pname);
3168 cpl_matrix_delete(mask_coeffs.mw);
3170 cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
3172 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
"GIRAFFE "
3173 "localization fit coefficients");
3202 GiLocalizeConfig *config = NULL;
3209 config = cx_calloc(1,
sizeof *config);
3216 config->full = TRUE;
3217 config->centroid = TRUE;
3218 config->threshold = GILOCALIZE_THRESHOLD_LOCAL;
3221 p = cpl_parameterlist_find(list,
"giraffe.localization.mode");
3222 s = cpl_parameter_get_string(p);
3223 if (strcmp(s,
"siwc") == 0) {
3224 config->full = FALSE;
3227 p = cpl_parameterlist_find(list,
"giraffe.localization.start");
3228 config->start = cpl_parameter_get_int(p);
3230 p = cpl_parameterlist_find(list,
"giraffe.localization.retries");
3231 config->retries = cpl_parameter_get_int(p);
3233 p = cpl_parameterlist_find(list,
"giraffe.localization.binsize");
3234 config->binsize = cpl_parameter_get_int(p);
3236 p = cpl_parameterlist_find(list,
"giraffe.localization.ewidth");
3237 config->ewidth = cpl_parameter_get_double(p);
3239 p = cpl_parameterlist_find(list,
"giraffe.localization.ywidth");
3240 config->ywidth = cpl_parameter_get_int(p);
3242 p = cpl_parameterlist_find(list,
"giraffe.localization.center");
3243 s = cpl_parameter_get_string(p);
3244 if (!strcmp(s,
"hwidth")) {
3245 config->centroid = FALSE;
3248 p = cpl_parameterlist_find(list,
"giraffe.localization.normalize");
3249 config->normalize = cpl_parameter_get_bool(p);
3251 p = cpl_parameterlist_find(list,
"giraffe.localization.threshold");
3252 s = cpl_parameter_get_string(p);
3254 if (strncmp(s,
"global", 6) == 0) {
3255 config->threshold = GILOCALIZE_THRESHOLD_GLOBAL;
3257 else if (strncmp(s,
"row", 3) == 0) {
3258 config->threshold = GILOCALIZE_THRESHOLD_ROW;
3261 config->threshold = GILOCALIZE_THRESHOLD_LOCAL;
3264 p = cpl_parameterlist_find(list,
"giraffe.localization.noise");
3265 config->noise = cpl_parameter_get_double(p);
3267 p = cpl_parameterlist_find(list,
"giraffe.localization.ron");
3268 config->ron = cpl_parameter_get_double(p);
3270 p = cpl_parameterlist_find(list,
"giraffe.localization.yorder");
3271 config->yorder = cpl_parameter_get_int(p);
3273 p = cpl_parameterlist_find(list,
"giraffe.localization.worder");
3274 config->worder = cpl_parameter_get_int(p);
3276 p = cpl_parameterlist_find(list,
"giraffe.localization.sigma");
3277 config->sigma = cpl_parameter_get_double(p);
3279 p = cpl_parameterlist_find(list,
"giraffe.localization.iterations");
3280 config->iterations = cpl_parameter_get_int(p);
3282 p = cpl_parameterlist_find(list,
"giraffe.localization.fraction");
3283 config->fraction = cpl_parameter_get_double(p);
3337 p = cpl_parameter_new_enum(
"giraffe.localization.mode",
3339 "Localization mode: Use all spectra "
3340 "or the 5 SIWC spectra",
3341 "giraffe.localization",
3342 "all", 2,
"all",
"siwc");
3343 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-mode");
3344 cpl_parameterlist_append(list, p);
3347 p = cpl_parameter_new_value(
"giraffe.localization.start",
3350 "giraffe.localization",
3352 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-start");
3353 cpl_parameterlist_append(list, p);
3356 p = cpl_parameter_new_value(
"giraffe.localization.retries",
3358 "Initial localization detection "
3360 "giraffe.localization",
3362 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-retries");
3363 cpl_parameterlist_append(list, p);
3366 p = cpl_parameter_new_value(
"giraffe.localization.binsize",
3368 "Initial localization detection "
3370 "giraffe.localization",
3372 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-binsize");
3373 cpl_parameterlist_append(list, p);
3376 p = cpl_parameter_new_value(
"giraffe.localization.ewidth",
3378 "Localization detection extra width.",
3379 "giraffe.localization",
3381 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-ewidth");
3382 cpl_parameterlist_append(list, p);
3385 p = cpl_parameter_new_value(
"giraffe.localization.ywidth",
3387 "Full width [pxl] of the equilizing "
3388 "filter (distance between two "
3389 "adjacent fibers).",
3390 "giraffe.localization",
3392 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-ywidth");
3393 cpl_parameterlist_append(list, p);
3396 p = cpl_parameter_new_enum(
"giraffe.localization.center",
3398 "Method used for mask center "
3400 "giraffe.localization",
3401 "centroid", 2,
"centroid",
3403 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-center");
3404 cpl_parameterlist_append(list, p);
3407 p = cpl_parameter_new_value(
"giraffe.localization.normalize",
3409 "Enable spectrum normalization along "
3410 "the dispersion axis.",
3411 "giraffe.localization",
3413 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-norm");
3414 cpl_parameterlist_append(list, p);
3417 p = cpl_parameter_new_value(
"giraffe.localization.noise",
3419 "Threshold multiplier.",
3420 "giraffe.localization",
3422 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-noise");
3423 cpl_parameterlist_append(list, p);
3426 p = cpl_parameter_new_enum(
"giraffe.localization.threshold",
3428 "Selects thresholding algorithm: local, "
3430 "giraffe.localization",
3431 "local", 3,
"local",
"row",
"global");
3432 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-threshold");
3433 cpl_parameterlist_append(list, p);
3436 p = cpl_parameter_new_value(
"giraffe.localization.ron",
3438 "New bias sigma (RON) value for dark "
3440 "giraffe.localization",
3442 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-ron");
3443 cpl_parameterlist_append(list, p);
3446 p = cpl_parameter_new_value(
"giraffe.localization.yorder",
3448 "Order of Chebyshev polynomial fit.",
3449 "giraffe.localization",
3451 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-yorder");
3452 cpl_parameterlist_append(list, p);
3455 p = cpl_parameter_new_value(
"giraffe.localization.worder",
3457 "Order of Chebyshev 2D polynomial fit.",
3458 "giraffe.localization",
3460 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-worder");
3461 cpl_parameterlist_append(list, p);
3464 p = cpl_parameter_new_value(
"giraffe.localization.sigma",
3466 "Localization clipping: sigma threshold "
3468 "giraffe.localization",
3470 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-sigma");
3471 cpl_parameterlist_append(list, p);
3474 p = cpl_parameter_new_value(
"giraffe.localization.iterations",
3476 "Localization clipping: number of "
3478 "giraffe.localization",
3480 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-niter");
3481 cpl_parameterlist_append(list, p);
3484 p = cpl_parameter_new_range(
"giraffe.localization.fraction",
3486 "Localization clipping: minimum fraction "
3487 "of points accepted/total.",
3488 "giraffe.localization",
3490 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sloc-mfrac");
3491 cpl_parameterlist_append(list, p);
void gi_warning(const cxchar *format,...)
Log a warning.
GiInstrumentMode giraffe_get_mode(cpl_propertylist *properties)
Determines the instrument mode from a property list.
cxdouble giraffe_matrix_sigma_mean(const cpl_matrix *matrix, cxdouble mean)
Compute sigma of matrix elements, with a given mean value.
cpl_table * giraffe_table_get(const GiTable *self)
Get the table data from a Giraffe table.
GiLocalizeConfig * giraffe_localize_config_create(cpl_parameterlist *list)
Creates a setup structure for the spectrum localization.
void gi_error(const cxchar *format,...)
Log an error message.
void gi_message(const cxchar *format,...)
Log a normal message.
cxdouble giraffe_propertylist_get_conad(const cpl_propertylist *properties)
Retrieve the ADU to electrons conversion factor from the given properties.
GiImage * giraffe_image_create(cpl_type type, cxint nx, cxint ny)
Creates an image container of a given type.
cxint giraffe_table_copy_matrix(GiTable *table, const cxchar *name, cpl_matrix *matrix)
Copies matrix elements into a table.
void giraffe_localize_config_destroy(GiLocalizeConfig *config)
Destroys a spectrum localization setup structure.
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
cpl_matrix * giraffe_matrix_leastsq(const cpl_matrix *mA, const cpl_matrix *mB)
Computes the solution of an equation using a pseudo-inverse.
cxint giraffe_localize_spectra(GiLocalization *result, GiImage *image, GiTable *fibers, GiLocalization *master, GiImage *badpixels, GiLocalizeConfig *config)
Finds the location of spectra in a Giraffe observation.
cxint giraffe_array_sort(cxdouble *array, cxsize size)
Sorts an array in ascending order.
cxdouble giraffe_propertylist_get_ron(const cpl_propertylist *properties)
Retrieve the read-out noise from the given properties.
cxint giraffe_image_set_properties(GiImage *self, cpl_propertylist *properties)
Attaches a property list to an image.
cxint giraffe_image_copy_matrix(GiImage *self, cpl_matrix *matrix)
Copies matrix elements into an image.
cpl_propertylist * giraffe_table_get_properties(const GiTable *self)
Gets the table properties.
void giraffe_localize_config_add(cpl_parameterlist *list)
Adds parameters for the spectrum localization.
GiTable * giraffe_table_create(cpl_table *table, cpl_propertylist *properties)
Creates a Giraffe table from a table and a property list.
cpl_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
cpl_image * giraffe_matrix_create_image(const cpl_matrix *matrix)
Converts a matrix into an image.