29 #include "visir_recipe.h"
31 #include "visir_spc_distortion.h"
32 #include "visir_utils.h"
33 #include "irplib_framelist.h"
47 #define RECIPE_STRING "visir_util_detect_shift"
49 #define VISIR_UTIL_DETECT_SHIFT_PROCATG "BEAM_DETECTED"
50 #define VISIR_UTIL_DETECT_SHIFT_TEMPLATE_PROCATG "CORRELATION_TEMPLATE"
54 #define SQR(a) ((a)*(a))
61 VISIR_SHIFT_XCORRELATE,
70 VISIR_PLANE_UNDEFINED = 4,
73 static const char * type2string[] = {
"Aoff",
"Bon",
"Aon",
"Boff",
"full"};
78 cpl_propertylist * plist;
79 visir_plane_type type;
106 cpl_error_code visir_util_detect_shift_one(cpl_frameset *,
107 irplib_framelist * ,
int,
108 const cpl_parameterlist *,
113 static double t_loading = 0.;
114 static double t_loading_blocked = 0.;
115 static double t_handling_blocked_in = 0.;
116 static double t_handling = 0.;
117 static double t_handling_blocked_out = 0.;
118 static double t_writing = 0.;
119 static double t_writing_blocked = 0.;
121 static size_t nbytes_load = 0;
122 static size_t nbytes_load_eff = 0;
123 static size_t nbytes_save = 0;
125 static int is_aqu_data = -1;
128 #define cpl_plugin_get_info visir_util_detect_shift_get_info
130 cpl_recipe_define(visir_util_detect_shift, VISIR_BINARY_VERSION,
131 "Find beam positions and reject bad images",
132 "Julian Tayor", PACKAGE_BUGREPORT,
"2012",
133 "Detects beams in a background subtracted multi-beam image,"
134 " determines the shifts between different images and their "
135 "correlation. Images can be rejected if their correlation "
137 "The files listed in the Set Of Frames (sof-file) "
139 "VISIR-chopnod-corrected-file.fits "
141 "\nbad-pixel-mask.fits " VISIR_CALIB_STATIC_MASK
142 "\nThe output consists of single beam images of the size "
143 "of the throw. The shifts will be written int CRPIX[12].");
163 cpl_image_delete(pl->img);
164 cpl_propertylist_delete(pl->plist);
172 if (a->seqnb < b->seqnb)
174 if (a->seqnb > b->seqnb)
179 static void planelist_delete(cx_list * l)
182 cx_list_destroy(l, (cx_free_func)&visir_plane_delete);
185 static inline cpl_image *
186 window_extract(
const cpl_image * img,
187 const cpl_size x,
const cpl_size y,
const cpl_size window)
189 const cpl_size nx = cpl_image_get_size_x(img);
190 const cpl_size ny = cpl_image_get_size_y(img);
191 if (x > nx || y > ny || window <= 0)
193 return cpl_image_extract(img,
194 CX_MAX(1, x - window / 2),
195 CX_MAX(1, y - window / 2),
196 CX_MIN(nx, x + window / 2),
197 CX_MIN(ny, y + window / 2));
202 window_extract_p(
visir_plane * pl,
const cpl_image * img,
203 const double x,
const double y,
const cpl_size window)
205 pl->img = window_extract(img, x, y, window);
206 pl->x = x - CX_MAX(1, (cpl_size)x - window / 2) + 1;
207 pl->y = y - CX_MAX(1, (cpl_size)y - window / 2) + 1;
217 static void cut_aqu_illuminated(cpl_image ** img)
219 assert(is_aqu_data >= 0);
224 cpl_size llx = cpl_image_get_size_x(*img) == 1024 ? 22 : 1;
225 cpl_size lly = cpl_image_get_size_y(*img) == 1024 ? 92 : 1;
226 cpl_size urx = cpl_image_get_size_x(*img) == 1024 ?
227 878 : cpl_image_get_size_x(*img);
228 cpl_size ury = cpl_image_get_size_y(*img) == 1024 ?
229 948 : cpl_image_get_size_y(*img);
231 cpl_image * tmp = cpl_image_extract(*img, llx, lly, urx, ury);
232 cpl_image_delete(*img);
236 static inline cpl_boolean
239 return pl->correlation < limits->min_cor ||
240 hypot(pl->xshift, pl->yshift) > limits->max_shift ||
241 (limits->max_mad > 0 && pl->mad > limits->max_mad);
254 static cpl_error_code
255 visir_util_detect_shift_fill_parameterlist(cpl_parameterlist *
self)
257 const char * context = PACKAGE
"." RECIPE_STRING;
260 cpl_ensure_code(
self, CPL_ERROR_NULL_INPUT);
265 err = irplib_parameterlist_set_string(
self, PACKAGE, RECIPE_STRING,
266 "template", VISIR_STR_PAR_EMPTY, NULL,
267 context,
"Correlation template used "
268 "to detect shifts and reject bad "
269 "images.\n If none given an "
270 "averaged image is used");
271 cpl_ensure_code(!err, err);
274 err = irplib_parameterlist_set_double(
self, PACKAGE, RECIPE_STRING,
275 "min-correlation", 0.5, NULL, context,
276 "Minimal correlation to the template "
277 "required to be accepted");
278 cpl_ensure_code(!err, err);
281 err = irplib_parameterlist_set_double(
self, PACKAGE, RECIPE_STRING,
282 "max-shift", 10., NULL, context,
283 "Maximal allowed object shift for an "
284 "image to be accepted");
285 cpl_ensure_code(!err, err);
288 err = irplib_parameterlist_set_double(
self, PACKAGE, RECIPE_STRING,
289 "max-mad", 0., NULL, context,
290 "Maximal allowed median absolute "
291 "deviation for an image to be "
292 "accepted. <= 0 equals no limit");
293 cpl_ensure_code(!err, err);
296 err = irplib_parameterlist_set_int(
self, PACKAGE, RECIPE_STRING,
297 "naverage", 1, NULL, context,
298 "Number of planes to average before "
299 "attempting to detect the shifts.");
300 cpl_ensure_code(!err, err);
303 err = irplib_parameterlist_set_string(
self, PACKAGE, RECIPE_STRING,
304 "method",
"xcorrelate", NULL, context,
305 "Method to determine beam shifts.\n"
306 " xcorrelate: use the cross "
307 "correlation shift.\n"
308 " brightest: use the position of "
309 "the brightest pixel");
310 cpl_ensure_code(!err, err);
313 err = irplib_parameterlist_set_bool(
self, PACKAGE, RECIPE_STRING,
314 "no-shift", CPL_FALSE, NULL, context,
315 "Sets whether to apply the "
316 "determined shifts in following "
317 "recipes. Set to TRUE of shifts "
318 "appear too large.");
319 cpl_ensure_code(!err, err);
322 err = irplib_parameterlist_set_bool(
self, PACKAGE, RECIPE_STRING,
323 "no-reject", CPL_TRUE, NULL, context,
324 "If true images with bad "
325 "statistics will not be rejected "
326 "and no shift correction is done");
327 cpl_ensure_code(!err, err);
330 err = irplib_parameterlist_set_string(
self, PACKAGE, RECIPE_STRING,
331 "beampos", VISIR_STR_PAR_EMPTY,
333 "Define the positions of the beams. "
334 "These positions are cut by the "
335 "window to extract the single "
336 "beam images.\n Format: "
337 "sign:x,y,window;sign:x,y,window;... "
338 "\n where sign is \"pos\" or \"neg\" "
339 "depending on whether the beam is "
340 "positive or negative.\n "
341 "The window is optional and defines "
342 "the size of the cut image around "
343 "the beam. The default window is "
344 "the chop throw.\n E.g.: "
345 "pos:50,60;neg:50,160;\n By default "
346 "autodetection is attempted.\n");
347 cpl_ensure_code(!err, err);
350 irplib_parameterlist_set_double(
self, PACKAGE, RECIPE_STRING,
"eccmax",
352 "The maximum eccentricity allowed in the combination "
353 "of the three (in parallel nod/chopping) or four (in "
354 "perpendicular nod/chopping) beams. In parallel mode, "
355 "three perfectly aligned points spaced with the "
356 "chopnod throw will have eccentricity 0, while in "
357 "perpedicular mode a square with the chopnod throw as "
358 "the side length will have eccentricity 0"
360 cpl_ensure_code(!err, err);
362 return CPL_ERROR_NONE;
374 static int visir_util_detect_shift(cpl_frameset * framelist,
375 const cpl_parameterlist * parlist)
377 irplib_framelist * allframes = NULL;
378 irplib_framelist * rawframes = NULL;
380 cpl_mask * bpm = NULL;
384 omp_set_num_threads(visir_get_num_threads(CPL_FALSE));
389 cpl_fits_set_mode(CPL_FITS_START_CACHING);
393 skip_if(allframes == NULL);
397 skip_if (rawframes == NULL);
401 if (cpl_frameset_find_const(framelist, VISIR_CALIB_STATIC_MASK)) {
402 irplib_framelist * bpmframes =
405 const cpl_frame * bpmframe =
407 const char * bpmname = cpl_frame_get_filename(bpmframe);
409 cpl_image_load(bpmname, CPL_TYPE_UNSPECIFIED, 0, 0);
410 cpl_error_code errori;
412 bpm = cpl_mask_threshold_image_create(bpmimg, 0.1, DBL_MAX);
413 cpl_image_delete(bpmimg);
415 errori = cpl_error_set_where(cpl_func);
416 error_if(errori, errori,
"Could not load bad pixel map");
417 cpl_msg_info(cpl_func,
"Loaded bad pixel map");
420 error_if(1, CPL_ERROR_ILLEGAL_INPUT,
421 "Unexpected number of bad pixel maps");
425 for (cpl_size i = 0; i < n; i++) {
426 skip_if(visir_util_detect_shift_one(framelist, rawframes, i,
427 parlist, bpm, &
template));
428 cpl_fits_set_mode(CPL_FITS_RESTART_CACHING);
435 cpl_mask_delete(bpm);
436 visir_plane_delete(
template);
438 return cpl_error_get_code();
457 parallel_load(
const char * filename, cpl_size iext, cpl_size lim,
458 cpl_image * imgbuf[], cpl_size nimgbuf)
460 assert(nimgbuf % 2 == 0);
461 for (cpl_size i = 0; i < nimgbuf; i+=2) {
462 OMP3_PRAGMA(omp task firstprivate(i)
if (iext + i < lim))
464 cpl_errorstate prestate = cpl_errorstate_get();
465 if (iext + i < lim) {
466 imgbuf[i] = cpl_image_load(filename, CPL_TYPE_FLOAT, 0,
469 if (iext + i + 1 < lim) {
470 imgbuf[i + 1] = cpl_image_load(filename, CPL_TYPE_FLOAT, 0,
473 cpl_errorstate_set(prestate);
476 OMP3_PRAGMA(omp taskwait)
481 load_range(
const cpl_frame *frame, cpl_size * start, cpl_size nplanes,
482 const cpl_size naverage, cpl_mask * bpm)
484 const cpl_size next = cpl_frame_get_nextensions(frame);
486 const char * filename = cpl_frame_get_filename(frame);
488 cpl_propertylist * plist = NULL;
492 cpl_image * imgbuf[20] = {NULL};
493 size_t nimgbuf =
sizeof(imgbuf) /
sizeof(imgbuf[0]);
495 nplanes = CX_MAX(nplanes, naverage);
497 cpl_ensure(naverage > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
498 cpl_imagelist * av = cpl_imagelist_new();
500 for (iext = *start; iext < 1 + next; iext++) {
501 cpl_errorstate prestate = cpl_errorstate_get();
504 cpl_propertylist_delete(plist);
506 plist = cpl_propertylist_load(filename, iext);
508 cpl_msg_info(cpl_func,
"No propertylist in extension %d",
510 cpl_errorstate_set(prestate);
518 if (imgbuf[0] == NULL) {
519 parallel_load(filename, iext, next + 1, imgbuf, nimgbuf);
523 cpl_image * img = imgbuf[0];
524 memmove(imgbuf, imgbuf + 1,
sizeof(imgbuf) -
sizeof(imgbuf[0]));
525 imgbuf[nimgbuf - 1] = NULL;
528 cpl_msg_debug(cpl_func,
"No image-data in extension %d",
530 cpl_propertylist_delete(plist);
532 cpl_errorstate_set(prestate);
536 nbytes = visir_get_nbytes_plist(plist);
540 if (iext == *start + 1) {
541 visir_readahead(filename, iext * nbytes, nplanes * nbytes);
544 nbytes_load += nbytes;
546 nbytes_load_eff += cpl_image_get_size_x(img) *
547 cpl_image_get_size_y(img) * 4;
548 cpl_imagelist_set(av, img, cpl_imagelist_get_size(av));
550 if (cpl_imagelist_get_size(av) == naverage) {
551 cpl_image * avimg = naverage > 1 ? cpl_imagelist_collapse_create(av)
552 : cpl_imagelist_unset(av, 0);
554 cpl_image_reject_from_mask(avimg, bpm);
556 visir_interpolate_rejected(avimg, &pbpm, &ndata);
559 cut_aqu_illuminated(&avimg);
560 visir_imglist_append(range, avimg, plist);
563 cpl_imagelist_delete(av);
564 av = cpl_imagelist_new();
567 if (visir_imglist_get_size(range) == nplanes/naverage)
571 if (cpl_imagelist_get_size(av) != 0) {
572 cpl_image * avimg = cpl_imagelist_collapse_create(av);
574 cpl_image_reject_from_mask(avimg, bpm);
576 visir_interpolate_rejected(avimg, &pbpm, &ndata);
578 cut_aqu_illuminated(&avimg);
579 visir_imglist_append(range, avimg, plist);
583 cpl_imagelist_delete(av);
588 if (visir_imglist_get_size(range) > 1) {
591 cpl_propertylist * plist = visir_imglist_get_data(range, 1);
592 size_t nbytes = visir_get_nbytes_plist(plist);
593 visir_drop_cache(filename, 0, nbytes * (*start));
613 parse_beampos_cmd(
const char * bpstr)
615 char *str, *token, *istr = cpl_strdup(bpstr);
616 cx_list * bpl = cx_list_new();
618 for (str = istr; ; str = NULL) {
623 token = strtok(str,
";");
628 bi->type = cx_list_size(bpl);
629 cx_list_push_back(bpl, bi);
632 if (strncmp(token,
"pos", 3) == 0)
634 else if (strncmp(token,
"neg", 3) == 0)
637 error_if(1, CPL_ERROR_ILLEGAL_INPUT,
638 "Invalid beam sign: %s", bpstr);
640 ret = sscanf(token+4,
"%lf,%lf,%lf", &bi->x, &bi->y, &w);
641 if ((ret != 2 && ret != 3) || bi->x < 0 || bi->y < 0 || w < 0)
642 error_if(1, CPL_ERROR_ILLEGAL_INPUT,
643 "Invalid beam position: %s", bpstr);
646 bi->window = ceil(w);
651 error_if(cx_list_size(bpl) < 1, CPL_ERROR_ILLEGAL_INPUT,
652 "Invalid beam position: %s", bpstr);
655 int npos = 0, nneg = 0;
665 if (nneg == 2 && npos == 1)
676 get_beam_positions(cpl_image * average,
const cpl_parameterlist * parlist,
677 cpl_propertylist * plist)
679 cpl_errorstate cleanstate = cpl_errorstate_get();
680 cpl_propertylist * qclist = cpl_propertylist_new();
681 cpl_image * inverse = cpl_image_duplicate(average);
683 const cpl_boolean chop_on =
684 cpl_propertylist_get_bool(plist, VISIR_PFITS_BOOL_CHOP_STATUS);
685 cx_list * beamposl = cx_list_new();
690 cpl_image_multiply_scalar(inverse, -1);
692 visir_chopnod_mode mode =
693 visir_img_find_beam(qclist, average, inverse,
694 plist, parlist, RECIPE_STRING,
696 if (cpl_error_get_code() != CPL_ERROR_NONE) {
697 irplib_error_recover(cleanstate,
"Could not detect objects,"
698 " using full image. Photometry "
699 "will not work without object positions.");
701 const cpl_size nx = cpl_image_get_size_x(average);
702 const cpl_size ny = cpl_image_get_size_y(average);
705 bi->window = CX_MAX(nx, ny);
708 bi->type = VISIR_PLANE_UNDEFINED;
709 cx_list_push_back(beamposl, bi);
713 if (mode == VISIR_CHOPNOD_PERPENDICULAR)
715 else if (mode == VISIR_CHOPNOD_PARALLEL)
718 error_if(1, CPL_ERROR_UNSUPPORTED_MODE,
"Unsupported chop mode");
720 if (chop_on == CPL_FALSE)
723 for (
int i = 0; i < n; i++) {
728 if (n == 4 || n == 2) {
729 bi->sign = i < n / 2 ? 1 : -1;
735 bi->sign = i < 1 ? 1 : -1;
736 bi->weight = i < 1 ? 2. : 1.;
739 cx_list_push_back(beamposl, bi);
744 cpl_image_delete(inverse);
745 cpl_propertylist_delete(qclist);
751 cut_image(
const cpl_image * img,
const cpl_propertylist * plist,
752 const cx_list * beampos, cpl_size window)
754 cx_list * l = cx_list_new();
756 FOR_EACH_T(
const beam_info * bi, beampos) {
757 const cpl_size win = bi->window > 0 ? bi->window : window;
763 cpl_propertylist_duplicate(plist) : cpl_propertylist_new();
765 window_extract_p(pl, img, bi->x, bi->y, win);
766 skip_if(pl->img == NULL);
771 cpl_image_multiply_scalar(pl->img, bi->sign);
773 cx_list_push_back(l, pl);
786 cpl_errorstate prestate = cpl_errorstate_get();
788 cpl_stats_new_from_image(pl->img, CPL_STATS_MAD |
789 CPL_STATS_MEDIAN | CPL_STATS_MAXPOS |
790 CPL_STATS_MAX | CPL_STATS_MIN |
792 pl->stdev = cpl_stats_get_stdev(stat);
793 pl->median = cpl_stats_get_median(stat);
794 pl->mad = cpl_stats_get_mad(stat);
795 pl->max = cpl_stats_get_max(stat);
796 pl->min = cpl_stats_get_min(stat);
797 mx = cpl_stats_get_max_x(stat);
798 my = cpl_stats_get_max_y(stat);
799 if (cpl_image_get_fwhm(pl->img, mx, my,
800 &pl->fwhmx, &pl->fwhmy) != CPL_ERROR_NONE) {
803 cpl_msg_warning(cpl_func,
"Could not determine fwhm.");
804 cpl_errorstate_set(prestate);
807 cpl_stats_delete(stat);
813 const cx_list * beampos,
814 const visir_shift_method method,
817 const cpl_size n = visir_imglist_get_size(chunk);
818 cpl_propertylist * mplist = visir_imglist_get_mplist(chunk);
820 cx_list * res = cx_list_new();
824 for (
size_t i = 0; i < MAX_BEAMS; i++) {
825 fft_cache[i] = visir_new_fftx_cache();
828 cx_list * beams = cut_image(visir_imglist_get_img(chunk, 0),
829 NULL, beampos, pthrow);
831 for (cpl_size j = 0, m = cx_list_size(beams); j < m; j++) {
833 visir_fftxcorrelate(template->img, pl->img, CPL_TRUE,
834 NULL, NULL, NULL, fft_cache[j]);
835 visir_plane_delete(pl);
837 cx_list_delete(beams);
846 for (cpl_size i = 0; i < n; i++)
847 OMP3_PRAGMA(omp task firstprivate(i))
849 cx_list * beams = cut_image(visir_imglist_get_img(chunk, i),
850 visir_imglist_get_data(chunk, i),
853 for (cpl_size j = 0, m = cx_list_size(beams); j < m; j++) {
854 double xshift = 0, yshift = 0, max_cor = 1;
857 if (limits->min_cor > 0 || method == VISIR_SHIFT_XCORRELATE) {
859 visir_fftxcorrelate(template->img, pl->img, CPL_TRUE,
860 &xshift, &yshift, &max_cor, fft_cache[j]);
861 xshift =
template->x + xshift;
862 yshift =
template->y + yshift;
865 if (method == VISIR_SHIFT_BRIGHTEST) {
866 cpl_size ixshift, iyshift;
868 cpl_image_get_maxpos(pl->img, &ixshift, &iyshift);
869 visir_get_subpixel_maxpos(pl->img, ixshift, iyshift,
871 xshift = ixshift + xsub;
872 yshift = iyshift + ysub;
875 cpl_msg_debug(cpl_func,
"%4s: correlation %5.3f shift %5.2f %5.2f",
876 type2string[pl->type], max_cor, xshift, yshift);
879 pl->xshift = xshift - pl->x;
880 pl->yshift = yshift - pl->y;
881 pl->correlation = max_cor;
883 pl->crval1 =
template->crval1;
884 pl->crval2 =
template->crval2;
886 generate_statistics(pl);
887 OMP_PRAGMA(omp critical(chunk_lock))
888 cx_list_push_back(res, pl);
891 cx_list_delete(beams);
893 OMP3_PRAGMA(omp taskwait)
898 cx_list_sort(res, (cx_compare_func)pl_compare_seqnb);
903 for (
size_t i = 0; i <
sizeof(fft_cache)/
sizeof(fft_cache[0]); i++)
904 visir_delete_fftx_cache(fft_cache[i]);
910 improve_template(
const cx_list *imgs,
const stats_limits * limits)
912 cpl_imagelist * l = cpl_imagelist_new();
914 cx_list_iterator it = cx_list_begin(imgs);
915 const cx_list_iterator end = cx_list_end(imgs);
919 skip_if(cx_list_empty(imgs));
923 cpl_image * img = cpl_image_duplicate(pl->img);
924 nx = nx == 0 ? cpl_image_get_size_x(img) : nx;
925 ny = ny == 0 ? cpl_image_get_size_y(img) : ny;
929 if (cpl_image_get_size_x(img) != nx ||
930 cpl_image_get_size_y(img) != ny) {
931 it = cx_list_next(imgs, it);
936 if (is_image_bad(pl, limits) == CPL_FALSE)
937 cpl_image_shift(img, -visir_round_to_int(pl->xshift),
938 -visir_round_to_int(pl->yshift));
940 cpl_imagelist_set(l, img, cpl_imagelist_get_size(l));
942 it = cx_list_next(imgs, it);
948 cpl_image * tmp = visir_parallel_median_collapse(l);
949 visir_plane * firstpl = cx_list_get(imgs, cx_list_begin(imgs));
950 template->x = firstpl->x;
951 template->y = firstpl->y;
952 window_extract_p(
template, tmp, firstpl->x, firstpl->y,
953 cpl_image_get_size_x(tmp) / 2);
954 cpl_image_delete(tmp);
958 cpl_imagelist_delete(l);
963 static cpl_error_code
964 save_images(cx_list * imgs,
const cpl_propertylist * mplist,
965 const cpl_parameterlist * parlist,
const int iframe,
968 const cpl_boolean noshift =
969 irplib_parameterlist_get_bool(parlist, PACKAGE,
970 RECIPE_STRING,
"no-shift");
971 const cpl_boolean noreject =
972 irplib_parameterlist_get_bool(parlist, PACKAGE,
973 RECIPE_STRING,
"no-reject");
975 irplib_parameterlist_get_int(parlist, PACKAGE,
976 RECIPE_STRING,
"naverage");
978 for (cpl_size j = 0, n = cx_list_size(imgs); j < n; j++) {
982 cpl_boolean bad = is_image_bad(pl, limits);
983 cpl_type save_type = CPL_TYPE_FLOAT;
985 if (noreject == CPL_FALSE && bad) {
986 visir_plane_delete(pl);
990 if (pl->max <= CX_MAXSHORT && pl->min >= CX_MINSHORT &&
991 naverage == 1 && cpl_propertylist_get_int(pl->plist,
"BITPIX") > 0)
992 save_type = CPL_TYPE_SHORT;
994 cpl_propertylist_copy_property_regexp(pl->plist, mplist,
"^("
995 IRPLIB_PFITS_WCS_REGEXP
")$",
999 if (noshift || (noreject && bad)) {
1000 cpl_propertylist_append_double(pl->plist,
"CRPIX1", pl->x);
1001 cpl_propertylist_append_double(pl->plist,
"CRPIX2", pl->y);
1003 cpl_propertylist_append_double(pl->plist,
"CRPIX1",
1004 pl->x + pl->xshift);
1005 cpl_propertylist_append_double(pl->plist,
"CRPIX2",
1006 pl->y + pl->yshift);
1008 cpl_propertylist_append_double(pl->plist,
"CRVAL1", pl->crval1);
1009 cpl_propertylist_append_double(pl->plist,
"CRVAL2", pl->crval2);
1011 cpl_propertylist_append_double(pl->plist,
"ESO QC CORR",
1014 cpl_propertylist_append_double(pl->plist,
"ESO QC MEDIAN",
1016 cpl_propertylist_append_double(pl->plist,
"ESO QC MAD",
1018 cpl_propertylist_append_double(pl->plist,
"ESO QC STDEV",
1020 cpl_propertylist_append_double(pl->plist,
"ESO QC FWHMX",
1022 cpl_propertylist_append_double(pl->plist,
"ESO QC FWHMY",
1025 sprintf(buffer, RECIPE_STRING
"_%03d_%s"CPL_DFS_FITS,
1026 iframe+1, type2string[pl->type]);
1028 cpl_image_save(pl->img, buffer, save_type,
1029 pl->plist, CPL_IO_EXTEND);
1030 nbytes_save += cpl_image_get_size_x(pl->img) *
1031 cpl_image_get_size_y(pl->img) * cpl_type_get_sizeof(save_type);
1033 visir_plane_delete(pl);
1039 return cpl_error_get_code();
1044 static cpl_error_code
1045 read_data(visir_queue * readq, cpl_propertylist * mplist,
1046 cpl_frame * frame,
const cpl_size chunksize,
1047 const cpl_size naverage, cpl_mask * bpm, cpl_size * cur)
1051 double t = cpl_test_get_walltime(), t2;
1052 range = load_range(frame, cur, chunksize,
1056 if (visir_imglist_get_size(range) == 0) {
1057 visir_imglist_delete(range, (visir_free)cpl_propertylist_delete);
1061 visir_imglist_set_mplist(range, mplist);
1062 t2 = cpl_test_get_walltime();
1063 t_loading += t2 - t;
1064 skip_if(visir_queue_put(readq, range));
1065 t_loading_blocked += cpl_test_get_walltime() - t2;
1066 }
while (visir_imglist_get_size(range) != 0);
1068 cpl_msg_info(cpl_func,
1069 "Loading thread done, %.3g MB/s (%.3g MB/s uncompressed)",
1070 (nbytes_load / 1024. / 1024.) / t_loading,
1071 (nbytes_load_eff / 1024. / 1024.) / t_loading);
1075 visir_queue_put(readq, NULL);
1077 cpl_error_code err = cpl_error_get_code();
1078 if (err != CPL_ERROR_NONE)
1079 visir_queue_set_error(readq, err);
1084 static cpl_error_code
1085 handle_data(visir_queue * readq, visir_queue * writeq,
1087 cx_list * beampos,
const visir_shift_method method,
1092 double t = cpl_test_get_walltime(), t2;
1093 range = visir_queue_pop(readq);
1094 t2 = cpl_test_get_walltime();
1095 t_handling_blocked_in += t2 - t;
1098 cx_list * res = handle_chunk(range,
template, beampos,
1101 visir_imglist_delete(range, (visir_free)cpl_propertylist_delete);
1103 t = cpl_test_get_walltime();
1104 t_handling += t - t2;
1105 skip_if(visir_queue_put(writeq, res));
1106 t_handling_blocked_out += cpl_test_get_walltime() - t;
1107 }
while(range != NULL);
1111 visir_queue_put(writeq, NULL);
1113 cpl_error_code err = cpl_error_get_code();
1114 if (err != CPL_ERROR_NONE) {
1115 visir_queue_set_error(writeq, err);
1116 visir_queue_set_error(readq, err);
1123 static cpl_error_code
1124 write_data(visir_queue * writeq, cpl_propertylist * mplist,
1125 const cpl_parameterlist * parlist,
1127 const cpl_size chunksize,
const cpl_size next)
1129 cx_list * res = NULL;
1132 double t = cpl_test_get_walltime(), t2;
1133 res = visir_queue_pop(writeq);
1134 t2 = cpl_test_get_walltime();
1135 t_writing_blocked += t2 - t;
1139 save_images(res, mplist, parlist, iframe, limits);
1140 planelist_delete(res);
1141 t_writing += cpl_test_get_walltime() - t2;
1143 cpl_msg_info(cpl_func,
"done: %d/%d",
1144 (
int)CX_MIN((count * chunksize), next + 1),
1147 }
while(res != NULL);
1149 cpl_msg_info(cpl_func,
"Writing thread done, %.3g MB /s",
1150 (nbytes_save / 1024. / 1024.) / t_writing);
1154 cpl_error_code err = cpl_error_get_code();
1155 if (err != CPL_ERROR_NONE)
1156 visir_queue_set_error(writeq, err);
1173 cpl_error_code visir_util_detect_shift_one(cpl_frameset * framelist,
1174 irplib_framelist * rawframes,
1176 const cpl_parameterlist * parlist,
1180 cpl_frameset * products = cpl_frameset_new();
1182 cpl_image * av = NULL;
1183 cpl_boolean bfirst = CPL_FALSE;
1184 cx_list * res = NULL;
1186 const char * filename = cpl_frame_get_filename(frame);
1187 const char * fn_template =
1188 irplib_parameterlist_get_string(parlist, PACKAGE,
1189 RECIPE_STRING,
"template");
1190 const int naverage =
1191 irplib_parameterlist_get_int(parlist, PACKAGE,
1192 RECIPE_STRING,
"naverage");
1194 const cpl_size chunksize = 200 * naverage;
1195 cpl_frame_set_group(frame, CPL_FRAME_GROUP_RAW);
1199 cpl_propertylist * mplist = cpl_propertylist_load(filename, 0);
1201 visir_data_type datatype;
1202 visir_get_data_type(frame, mplist, &datatype, &next);
1203 is_aqu_data = visir_data_is_aqu(datatype);
1207 visir_imglist_set_mplist(range, mplist);
1209 const char * sbeampos =
1210 irplib_parameterlist_get_string(parlist, PACKAGE,
1211 RECIPE_STRING,
"beampos");
1212 cx_list * beampos = NULL;
1214 skip_if(range == NULL);
1216 if (cpl_frameset_find(framelist,
"MEAN")) {
1217 cpl_frame * fn = cpl_frameset_find(framelist,
"MEAN");
1218 av = cpl_image_load(cpl_frame_get_filename(fn),
1219 CPL_TYPE_FLOAT, 0,0);
1220 cut_aqu_illuminated(&av);
1224 cpl_image * ibpm = cpl_image_new_from_mask(bpm);
1225 cut_aqu_illuminated(&ibpm);
1226 cpl_mask * nbpm = cpl_mask_threshold_image_create(ibpm, 0.1, DBL_MAX);
1228 cpl_image_reject_from_mask(av, nbpm);
1230 cpl_image_delete(ibpm);
1231 cpl_mask_delete(nbpm);
1233 skip_if(visir_interpolate_rejected(av, NULL, NULL));
1237 const cpl_imagelist * tmpl = visir_imglist_get_imglist(range);
1238 av = visir_parallel_median_collapse(tmpl);
1242 if (!visir_str_par_is_empty(sbeampos))
1243 beampos = parse_beampos_cmd(sbeampos);
1245 beampos = get_beam_positions(av, parlist, mplist);
1249 error_if(cx_list_size(beampos) > MAX_BEAMS, CPL_ERROR_ILLEGAL_INPUT,
1250 "Too many beams, maximum supported: %d", MAX_BEAMS);
1251 error_if(ptemplate == NULL, CPL_ERROR_NULL_INPUT,
"Bug: ptemplate == NULL");
1255 if ((!visir_str_par_is_empty(sbeampos) ||
1256 cpl_frameset_find(framelist,
"MEAN")) &&
1257 cpl_propertylist_has(mplist, VISIR_DRS_CUMOFFSETXA)) {
1258 double dxa = cpl_propertylist_get_double(mplist, VISIR_DRS_CUMOFFSETXA);
1259 double dya = cpl_propertylist_get_double(mplist, VISIR_DRS_CUMOFFSETYA);
1260 double dxb = cpl_propertylist_get_double(mplist, VISIR_DRS_CUMOFFSETXB);
1261 double dyb = cpl_propertylist_get_double(mplist, VISIR_DRS_CUMOFFSETYB);
1263 if (bi->type == VISIR_PLANE_AOFF || bi->type == VISIR_PLANE_AON) {
1267 else if (bi->type == VISIR_PLANE_BOFF || bi->type == VISIR_PLANE_BON) {
1274 FOR_EACH_T(
const beam_info * bi, beampos) {
1275 double window = bi->window > 0 ? bi->window : pthrow;
1276 cpl_msg_info(cpl_func,
"Beam position: x %5.1f, y %5.1f, window %4.0f,"
1277 " sign %2d", bi->x, bi->y, window, bi->sign);
1282 irplib_parameterlist_get_double(parlist, PACKAGE,
1283 RECIPE_STRING,
"min-correlation");
1285 irplib_parameterlist_get_double(parlist, PACKAGE,
1286 RECIPE_STRING,
"max-shift");
1288 irplib_parameterlist_get_double(parlist, PACKAGE,
1289 RECIPE_STRING,
"max-mad");
1291 const char * smethod =
1292 irplib_parameterlist_get_string(parlist, PACKAGE,
1293 RECIPE_STRING,
"method");
1294 visir_shift_method method = VISIR_SHIFT_XCORRELATE;
1296 if (strncmp(smethod,
"xcorrelate",
sizeof(
"xcorrelate")) == 0)
1297 method = VISIR_SHIFT_XCORRELATE;
1298 else if (strncmp(smethod,
"brightest",
sizeof(
"brightest")) == 0)
1299 method = VISIR_SHIFT_BRIGHTEST;
1301 cpl_msg_warning(cpl_func,
"Unknown method %s. Using xcorrelate",
1306 if (*ptemplate != NULL)
1307 template = *ptemplate;
1308 else if (!visir_str_par_is_empty(fn_template)) {
1309 cpl_msg_info(cpl_func,
"Loading %s as template", fn_template);
1310 template = visir_plane_new();
1311 template->plist = cpl_propertylist_load(fn_template, 0);
1312 template->img = cpl_image_load(fn_template, CPL_TYPE_UNSPECIFIED, 0, 0);
1313 skip_if(template->img == NULL || template->plist == NULL);
1314 if (cpl_propertylist_has(template->plist,
"CRPIX1") &&
1315 cpl_propertylist_has(template->plist,
"CRPIX2") &&
1316 cpl_propertylist_has(template->plist,
"CRVAL1") &&
1317 cpl_propertylist_has(template->plist,
"CRVAL2")) {
1318 template->x = cpl_propertylist_get_double(template->plist,
"CRPIX1");
1319 template->y = cpl_propertylist_get_double(template->plist,
"CRPIX2");
1320 template->crval1 = cpl_propertylist_get_double(template->plist,
"CRVAL1");
1321 template->crval2 = cpl_propertylist_get_double(template->plist,
"CRVAL2");
1324 error_if(1, CPL_ERROR_ILLEGAL_INPUT,
1325 "Input template must have WCS coordinates");
1328 *ptemplate =
template;
1332 template = visir_plane_new();
1333 cpl_msg_info(cpl_func,
"Using average as template");
1334 const cpl_boolean noshift =
1335 irplib_parameterlist_get_bool(parlist, PACKAGE,
1336 RECIPE_STRING,
"no-shift");
1337 beam_info * bi = cx_list_get(beampos, cx_list_begin(beampos));
1339 const cpl_size window = bi->window > 0 ?
1340 bi->window * 2 / 3. : pthrow * 2 / 3.;
1341 window_extract_p(
template, av, bi->x, bi->y, window);
1342 cpl_image_multiply_scalar(template->img, bi->sign);
1345 (limits.min_cor > 0 || method == VISIR_SHIFT_XCORRELATE)) {
1349 lim.max_shift = 5000;
1351 OMP_PRAGMA(omp parallel)
1352 OMP_PRAGMA(omp single)
1353 res = handle_chunk(range,
template, beampos, method, &lim);
1354 visir_plane_delete(
template);
1355 template = improve_template(res, &limits);
1357 planelist_delete(res);
1360 template->plist = cpl_propertylist_new();
1361 cpl_propertylist_append_double(template->plist,
"CRPIX1", template->x);
1362 cpl_propertylist_append_double(template->plist,
"CRPIX2", template->y);
1363 *ptemplate =
template;
1366 cpl_wcs * wcs = cpl_wcs_new_from_propertylist(mplist);
1367 cpl_matrix * from = cpl_matrix_new(1, 2);
1368 cpl_matrix * to = NULL;
1369 cpl_matrix_set(from, 0, 0, bi->x);
1370 cpl_matrix_set(from, 0, 1, bi->y);
1371 cpl_array * status = NULL;
1372 skip_if(cpl_wcs_convert(wcs, from, &to, &status, CPL_WCS_PHYS2WORLD));
1373 template->crval1 = cpl_matrix_get(to, 0, 0);
1374 template->crval2 = cpl_matrix_get(to, 0, 1);
1375 cpl_matrix_delete(from);
1376 cpl_matrix_delete(to);
1377 cpl_array_delete(status);
1385 cpl_frame * frm = cpl_frameset_find(framelist, VISIR_CALIB_STATIC_MASK);
1386 cpl_image * ibpm = cpl_image_new_from_mask(bpm);
1387 cut_aqu_illuminated(&ibpm);
1388 cx_list * cbpml = cut_image(ibpm, NULL, beampos, pthrow);
1389 cpl_frameset * usedframes = cpl_frameset_new();
1390 cpl_frameset_insert(usedframes, cpl_frame_duplicate(frm));
1392 FOR_EACH(it, cbpml) {
1394 cpl_image * img = ((
visir_plane*)cx_list_get(cbpml, it))->img;
1396 sprintf(buffer, RECIPE_STRING
"_bpm_%03d_%s"CPL_DFS_FITS,
1397 iframe+1, type2string[i++]);
1399 usedframes, img, CPL_BPP_8_UNSIGNED,
1402 NULL, NULL, visir_pipe_id,
1405 planelist_delete(cbpml);
1406 cpl_image_delete(ibpm);
1407 cpl_frameset_delete(usedframes);
1414 cpl_frameset * usedframes = cpl_frameset_new();
1415 sprintf(buffer, RECIPE_STRING
"_template_%03d"CPL_DFS_FITS,
1418 cpl_frameset_insert(usedframes, cpl_frame_duplicate(frame));
1420 usedframes, template->img, CPL_TYPE_FLOAT,
1422 VISIR_UTIL_DETECT_SHIFT_TEMPLATE_PROCATG,
1423 template->plist, NULL, visir_pipe_id,
1425 cpl_frameset_delete(usedframes);
1428 FOR_EACH_T(
const beam_info * bi, beampos) {
1430 cpl_frameset * usedframes = cpl_frameset_new();
1431 cpl_propertylist * _mplist = cpl_propertylist_new();
1432 cpl_propertylist_copy_property_regexp(_mplist, mplist,
".*", 0);
1434 if (bi->type != VISIR_PLANE_UNDEFINED)
1435 sprintf(buffer,
"%01d", bi->type);
1437 sprintf(buffer,
"UNDEFINED");
1438 cpl_propertylist_append_string(_mplist,
"ESO QC BEAMID", buffer);
1439 cpl_propertylist_append_float(_mplist,
"ESO DRS IMGWGT", bi->weight);
1440 cpl_propertylist_append_double(_mplist,
"ESO QC BEAMX", bi->x);
1441 cpl_propertylist_append_double(_mplist,
"ESO QC BEAMY", bi->y);
1443 sprintf(buffer, RECIPE_STRING
"_%03d_%s"CPL_DFS_FITS,
1444 iframe+1, type2string[bi->type]);
1446 cpl_frameset_insert(usedframes, cpl_frame_duplicate(frame));
1448 usedframes, RECIPE_STRING,
1449 VISIR_UTIL_DETECT_SHIFT_PROCATG,
1450 _mplist, NULL, visir_pipe_id, buffer);
1451 cpl_frameset_delete(usedframes);
1452 cpl_propertylist_delete(_mplist);
1456 cpl_msg_info(cpl_func,
"Working on frame %d", iframe);
1460 cpl_error_code serr, werr, lerr;
1461 serr = werr = lerr = CPL_ERROR_NONE;
1462 visir_queue * readq = visir_queue_init(3);
1463 visir_queue * writeq = visir_queue_init(3);
1464 visir_queue_put(readq, range);
1478 int nthreads = CX_MAX(visir_get_num_threads(CPL_FALSE) + 2, 3);
1479 #pragma omp parallel num_threads(nthreads)
1481 #pragma omp single nowait
1482 lerr = read_data(readq, mplist, frame, chunksize, naverage, bpm, &cur);
1483 #pragma omp single nowait
1484 serr = handle_data(readq, writeq,
template, beampos, method, &limits);
1485 #pragma omp single nowait
1486 werr = write_data(writeq, mplist, parlist, iframe, &limits,
1489 visir_queue_delete(readq);
1490 visir_queue_delete(writeq);
1492 error_if(serr, serr,
"Failed to save data");
1493 error_if(werr, werr,
"Failed to handle data");
1494 error_if(lerr, lerr,
"Failed to load data");
1496 cpl_msg_info(cpl_func,
"Time spent loading data: %3.3gs",
1498 cpl_msg_info(cpl_func,
"Time loading thread was blocked on output: %3.3gs",
1499 t_loading_blocked < 1e-3 ? 0. : t_loading_blocked);
1500 cpl_msg_info(cpl_func,
"Time working thread was blocked on input: %3.3gs",
1501 t_handling_blocked_in < 1e-3 ? 0. : t_handling_blocked_in);
1502 cpl_msg_info(cpl_func,
"Time working on data: %3.3gs",
1504 cpl_msg_info(cpl_func,
"Time working thread was blocked on output: %3.3gs",
1505 t_handling_blocked_out < 1e-3 ? 0. : t_handling_blocked_out);
1506 cpl_msg_info(cpl_func,
"Time saving thread was blocked on input: %3.3gs",
1507 t_writing_blocked < 1e-3 ? 0. : t_writing_blocked);
1508 cpl_msg_info(cpl_func,
"Time spent saving data: %3.3gs",
1513 res = handle_chunk(range,
template, beampos,
1517 cpl_msg_info(cpl_func,
"done: %d/%d",
1518 (
int)cur - 1, (
int)next + 1);
1519 visir_imglist_delete(range,
1520 (visir_free)cpl_propertylist_delete);
1523 range = load_range(frame, &cur, chunksize,
1526 visir_imglist_set_mplist(range, mplist);
1528 save_images(res, mplist, parlist, iframe, &limits);
1529 planelist_delete(res);
1532 }
while (visir_imglist_get_size(range) != 0);
1536 FOR_EACH_FRAMESET_C(frm, products) {
1537 if (cpl_frame_get_nextensions(frm) > 0 ||
1538 strcmp(cpl_frame_get_tag(frm),
1539 VISIR_UTIL_DETECT_SHIFT_TEMPLATE_PROCATG) == 0 ||
1540 strcmp(cpl_frame_get_tag(frm),
1541 VISIR_CALIB_BPM) == 0 ||
1542 cpl_frame_get_group(frm) != CPL_FRAME_GROUP_PRODUCT) {
1543 cpl_frameset_insert(framelist, cpl_frame_duplicate(frm));
1548 planelist_delete(res);
1549 cpl_image_delete(av);
1550 cx_list_destroy(beampos, (visir_free)cpl_free);
1551 visir_imglist_delete(range, (visir_free)cpl_propertylist_delete);
1552 cpl_propertylist_delete(mplist);
1553 cpl_frameset_delete(products);
1555 return cpl_error_get_code();
double visir_pfits_get_chop_pthrow(const cpl_propertylist *self)
The chopping throw in pixels.
cpl_error_code irplib_dfs_save_propertylist(cpl_frameset *allframes, const cpl_parameterlist *parlist, const cpl_frameset *usedframes, const char *recipe, const char *procat, const cpl_propertylist *applist, const char *remregexp, const char *pipe_id, const char *filename)
Save a propertylist as a DFS-compliant pipeline product.
irplib_framelist * irplib_framelist_extract_regexp(const irplib_framelist *self, const char *regexp, cpl_boolean invert)
Extract the frames with the given tag from a framelist.
cpl_error_code irplib_dfs_save_image(cpl_frameset *allframes, const cpl_parameterlist *parlist, const cpl_frameset *usedframes, const cpl_image *image, cpl_type_bpp bpp, const char *recipe, const char *procat, const cpl_propertylist *applist, const char *remregexp, const char *pipe_id, const char *filename)
Save an image as a DFS-compliant pipeline product.
cpl_frame * irplib_framelist_get(irplib_framelist *self, int pos)
Get the specified frame from the framelist.
irplib_framelist * irplib_framelist_extract(const irplib_framelist *self, const char *tag)
Extract the frames with the given tag from a framelist.
int visir_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
const cpl_frame * irplib_framelist_get_const(const irplib_framelist *self, int pos)
Get the specified frame from the framelist.
void irplib_framelist_delete(irplib_framelist *self)
Deallocate an irplib_framelist with its frames and properties.
irplib_framelist * irplib_framelist_cast(const cpl_frameset *frameset)
Create an irplib_framelist from a cpl_framelist.
int irplib_framelist_get_size(const irplib_framelist *self)
Get the size of a framelist.