36 #include "naco_recipe.h"
37 #include "naco_strehl.h"
39 #include "irplib_strehl.h"
40 #include "irplib_calib.h"
49 #define RECIPE_STRING "naco_img_jitter"
53 #define NACO_MIN(A,B) ((A) < (B) ? (A) : (B))
54 #define NACO_MAX(A,B) ((A) > (B) ? (A) : (B))
60 #ifndef NACO_IMG_JITTER_KEEP_SKY_OBJECTS
61 static cpl_error_code naco_img_jitter_reject_objects(cpl_image *,
double,
65 static cpl_error_code naco_img_jitter_find_strehl(
const cpl_imagelist *,
66 const cpl_parameterlist *,
67 const irplib_framelist *);
69 static cpl_image * naco_img_jitter_saa_center(
const cpl_imagelist *,
72 static cpl_image * naco_img_jitter_saa_lucky(
const cpl_imagelist *,
74 const cpl_bivector *,
double);
76 static cpl_image * naco_img_jitter_find_sky_cube(
int,
int,
const cpl_array *,
77 const irplib_framelist *);
79 static cpl_error_code naco_img_jitter_imagelist_wrap_nocube(cpl_imagelist *,
84 static cpl_image * naco_img_jitter_combine_cube(cpl_table *,
const cpl_imagelist *,
85 const cpl_propertylist *,
86 const cpl_parameterlist *,
int);
88 static cpl_error_code naco_img_jitter_check_cube(
const cpl_imagelist *,
91 static cpl_error_code naco_img_jitter_do_cube(cpl_imagelist *, cpl_table *,
94 const irplib_framelist *,
95 const cpl_parameterlist *);
98 cpl_error_code naco_img_jitter_load_objimages(cpl_imagelist *, cpl_array *,
99 const irplib_framelist *,
100 const cpl_parameterlist *);
102 static cpl_image ** naco_img_jitter_reduce(cpl_imagelist *, cpl_table *,
104 const irplib_framelist *,
105 const irplib_framelist *,
106 const cpl_parameterlist *,
112 static cpl_image * naco_img_jitter_find_sky(cpl_propertylist *,
113 const cpl_imagelist *,
114 const cpl_imagelist *);
115 static cpl_image ** naco_img_jitter_saa(cpl_imagelist *,
116 const irplib_framelist *,
117 const cpl_parameterlist *);
118 static cpl_error_code naco_img_jitter_qc(cpl_propertylist *, cpl_propertylist *,
119 const irplib_framelist *,
120 const cpl_image *, cpl_boolean);
121 static cpl_error_code naco_img_jitter_qc_apertures(cpl_propertylist *,
122 const irplib_framelist *,
124 static cpl_error_code naco_img_jitter_save(cpl_frameset *,
125 const cpl_parameterlist *,
126 const cpl_propertylist *,
127 const cpl_propertylist *,
128 const cpl_imagelist *,
133 NACO_RECIPE_DEFINE(naco_img_jitter,
146 RECIPE_STRING
" -- NACO imaging jitter recipe.\n"
147 "The files listed in the Set Of Frames (sof-file) "
149 "NACO-raw-file.fits "NACO_IMG_JITTER_OBJ
" or\n"
150 "NACO-raw-file.fits "NACO_IMG_JITTER_SKY
" or\n"
151 "NACO-raw-file.fits "NACO_IMG_JITTER_OBJ_POL
" or\n"
152 "NACO-raw-file.fits "NACO_IMG_JITTER_SKY_POL
" or\n"
153 "NACO-flat-file.fits "NACO_CALIB_FLAT
" or\n"
154 "NACO-bpm-file.fits "NACO_CALIB_BPM
" or\n"
155 "NACO-dark-file.fits "NACO_CALIB_DARK
"\n");
175 static int naco_img_jitter(cpl_frameset * framelist,
176 const cpl_parameterlist * parlist)
178 cpl_errorstate cleanstate = cpl_errorstate_get();
179 irplib_framelist * allframes = NULL;
180 irplib_framelist * objframes = NULL;
181 irplib_framelist * skyframes = NULL;
182 cpl_propertylist * qclist = cpl_propertylist_new();
183 cpl_propertylist * paflist = cpl_propertylist_new();
184 cpl_imagelist * objimages = cpl_imagelist_new();
185 cpl_image ** combined = NULL;
186 cpl_table * cubetable = cpl_table_new(1);
190 cpl_boolean drop_wcs = CPL_FALSE;
196 allframes = irplib_framelist_cast(framelist);
197 skip_if(allframes == NULL);
199 objframes = irplib_framelist_extract_regexp(allframes,
200 "^(" NACO_IMG_JITTER_OBJ
"|"
201 NACO_IMG_JITTER_OBJ_POL
")$",
203 skip_if(objframes == NULL);
205 skyframes = irplib_framelist_extract_regexp(allframes,
206 "^(" NACO_IMG_JITTER_SKY
"|"
207 NACO_IMG_JITTER_SKY_POL
")$",
209 irplib_framelist_empty(allframes);
210 if (skyframes == NULL) {
211 naco_error_reset(
"The set of frames has no sky frames:");
214 flat = irplib_frameset_find_file(framelist, NACO_CALIB_FLAT);
217 badpix = irplib_frameset_find_file(framelist, NACO_CALIB_BPM);
220 dark = irplib_frameset_find_file(framelist, NACO_CALIB_DARK);
223 skip_if(irplib_framelist_load_propertylist(objframes, 0, 0,
"^("
224 NACO_PFITS_REGEXP_JITTER_FIRST
227 skip_if(irplib_framelist_load_propertylist_all(objframes, 0,
"^("
228 NACO_PFITS_REGEXP_JITTER_ALL
232 cpl_msg_info(cpl_func,
"Apply the data recombination");
233 combined = naco_img_jitter_reduce(objimages, cubetable, qclist, objframes,
234 skyframes, parlist, dark, flat, badpix,
237 skip_if (combined == NULL);
239 irplib_framelist_empty(skyframes);
242 cpl_msg_info(cpl_func,
"Compute QC parameters from the combined image");
243 skip_if (naco_img_jitter_qc(qclist, paflist, objframes, combined[0], drop_wcs));
245 irplib_framelist_empty(objframes);
248 cpl_msg_info(cpl_func,
"Save the products");
251 bug_if (cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,
252 cpl_table_get_ncol(cubetable) > 0 ?
253 NACO_IMG_JITTER_CUBE :
254 NACO_IMG_JITTER_COMB));
256 skip_if (naco_img_jitter_save(framelist, parlist, qclist, paflist,
258 combined[0], combined[1], cubetable));
262 if (combined != NULL) {
263 cpl_image_delete(combined[0]);
264 cpl_image_delete(combined[1]);
267 cpl_imagelist_delete(objimages);
268 irplib_framelist_delete(allframes);
269 irplib_framelist_delete(objframes);
270 irplib_framelist_delete(skyframes);
271 cpl_propertylist_delete(qclist);
272 cpl_propertylist_delete(paflist);
273 cpl_table_delete(cubetable);
275 return cpl_error_get_code();
294 static cpl_image ** naco_img_jitter_reduce(cpl_imagelist * objimages,
295 cpl_table * cubetable,
296 cpl_propertylist * qclist,
297 const irplib_framelist * obj,
298 const irplib_framelist * sky,
299 const cpl_parameterlist * parlist,
303 cpl_boolean * pdid_resize)
305 cpl_errorstate prestate = cpl_errorstate_get();
306 const int nobj = irplib_framelist_get_size(obj);
307 cpl_imagelist * nocubeimgs = NULL;
308 cpl_imagelist * skyimages = NULL;
309 cpl_image * skyimage = NULL;
310 cpl_image ** combined = NULL;
311 cpl_array * iscube = NULL;
312 cpl_boolean has_cube = CPL_FALSE;
314 (parlist, RECIPE_STRING, NACO_PARAM_CUBEMODE);
318 bug_if(pdid_resize == NULL);
319 bug_if(scubemode == NULL);
321 skip_if (irplib_framelist_contains(obj, NACO_PFITS_DOUBLE_CUMOFFSETX,
322 CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
324 skip_if (irplib_framelist_contains(obj, NACO_PFITS_DOUBLE_CUMOFFSETY,
325 CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
328 cpl_msg_info(cpl_func,
"Loading the %d object and %d sky images",
329 irplib_framelist_get_size(obj),
330 sky == NULL ? 0 : irplib_framelist_get_size(sky));
332 iscube = cpl_array_new(nobj, CPL_TYPE_INT);
334 (void)naco_img_jitter_load_objimages(objimages, iscube, obj, parlist);
336 any_if(
"Could not load the %d object images", nobj);
338 cpl_msg_info(cpl_func,
"Loaded %d object images", nobj);
340 skip_if(cpl_imagelist_get_size(objimages) != nobj);
342 skip_if (irplib_flat_dark_bpm_calib(objimages, flat, dark, bpm));
344 cpl_msg_info(cpl_func,
"Sky estimation and correction");
346 if (scubemode[0] ==
'a') {
348 const int mcube = nobj - cpl_array_count_invalid(iscube);
351 cpl_msg_info(cpl_func,
"Collapsing %d cube(s) with no shifting",
353 cpl_array_delete(iscube);
354 iscube = cpl_array_new(nobj, CPL_TYPE_INT);
358 if (cpl_array_has_valid(iscube)) {
361 skip_if(naco_img_jitter_do_cube(objimages, cubetable, qclist,
362 iscube, obj, parlist));
364 #ifdef NACO_IMG_JITTER_DEVELOPMENT
365 skip_if(cpl_imagelist_save(objimages,
"Collapsed.fits", CPL_BPP_IEEE_FLOAT,
366 NULL, CPL_IO_CREATE));
370 if (cpl_array_has_invalid(iscube)) {
372 nocubeimgs = has_cube ? cpl_imagelist_new() : objimages;
374 skip_if(naco_img_jitter_imagelist_wrap_nocube(nocubeimgs, iscube,
376 inocube = cpl_imagelist_get_size(nocubeimgs);
381 skyimages = irplib_imagelist_load_framelist(sky, CPL_TYPE_FLOAT, 0, 0);
382 any_if(
"Could not load sky images");
383 skip_if (irplib_flat_dark_bpm_calib(skyimages, flat, dark, bpm));
386 skyimage = naco_img_jitter_find_sky(qclist, nocubeimgs, skyimages);
387 any_if(
"Could not estimate sky");
389 cpl_imagelist_delete(skyimages);
393 skip_if (cpl_imagelist_subtract_image(nocubeimgs, skyimage));
397 if(naco_img_jitter_find_strehl(objimages, parlist, obj)) {
398 irplib_error_recover(prestate,
"Could not compute Strehl-ratio "
399 "for %d frame(s)", nobj);
403 cpl_msg_info(cpl_func,
"Shift and add");
404 combined = naco_img_jitter_saa(objimages, obj, parlist);
405 skip_if (combined == NULL);
407 *pdid_resize = (cpl_boolean)
408 (cpl_image_get_size_x(combined[0])
409 != cpl_image_get_size_x(cpl_imagelist_get_const(objimages, 0)) ||
410 cpl_image_get_size_y(combined[0])
411 != cpl_image_get_size_y(cpl_imagelist_get_const(objimages, 0)));
416 for (;inocube > 0;) {
417 (void)cpl_imagelist_unset(nocubeimgs, --inocube);
420 if (nocubeimgs != objimages) cpl_imagelist_delete(nocubeimgs);
421 cpl_imagelist_delete(skyimages);
422 cpl_image_delete(skyimage);
423 cpl_array_delete(iscube);
437 static cpl_image * naco_img_jitter_find_sky(cpl_propertylist * qclist,
438 const cpl_imagelist * objs,
439 const cpl_imagelist * skys)
441 cpl_image *
self = NULL;
445 self = cpl_imagelist_collapse_median_create(skys);
446 any_if(
"Could not compute the median of %d sky images",
447 (
int)cpl_imagelist_get_size(skys));
451 self = cpl_imagelist_collapse_median_create(objs);
452 any_if(
"Could not compute the median of %d object images",
453 (
int)cpl_imagelist_get_size(objs));
457 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC BACKGD",
458 cpl_image_get_median(
self)));
459 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC BACKGD STDEV",
460 cpl_image_get_stdev(
self)));
476 static cpl_image ** naco_img_jitter_saa(cpl_imagelist * imlist,
477 const irplib_framelist * objframes,
478 const cpl_parameterlist * parlist)
481 cpl_bivector * offsets_est = NULL;
482 cpl_bivector * objs = NULL;
483 cpl_image ** combined = NULL;
484 cpl_vector * sigmas = NULL;
485 double psigmas[] = {5.0, 2.0, 1.0, 0.5};
486 const char * offsets;
487 const char * objects;
488 #ifdef NACO_USE_ODDEVEN
489 cpl_boolean oddeven_flag;
491 const int nsigmas = (int)(
sizeof(psigmas)/
sizeof(double));
492 const int nfiles = cpl_imagelist_get_size(imlist);
494 int rej_low, rej_high;
495 const char * combine_string;
496 cpl_geom_combine combine_mode;
500 bug_if (irplib_framelist_get_size(objframes) != nfiles);
510 #ifdef NACO_USE_ODDEVEN
519 bug_if (sval == NULL);
521 skip_if_ne(sscanf(sval,
"%d %d %d %d", &sx, &sy, &mx, &my), 4,
522 "number(s) in string parameter (%s): \"%s\"",
523 CPL_XSTRINGIFY(NACO_PARAM_XCORR), sval);
528 bug_if (combine_string == NULL);
530 if (combine_string[0] ==
'u')
531 combine_mode = CPL_GEOM_UNION;
532 else if (combine_string[0] ==
'f')
533 combine_mode = CPL_GEOM_FIRST;
534 else if (combine_string[0] ==
'i')
535 combine_mode = CPL_GEOM_INTERSECT;
541 NACO_PARAM_REJ_HILO);
542 bug_if (sval == NULL);
544 skip_if_ne(sscanf(sval,
"%d %d", &rej_low, &rej_high), 2,
545 "number(s) in string parameter (%s): \"%s\"",
546 CPL_XSTRINGIFY(NACO_PARAM_REJ_HILO), sval);
549 cpl_msg_info(cpl_func,
"Get the offsets estimation");
552 offsets[0] != (
char)0) {
554 offsets_est = cpl_bivector_read(offsets);
555 if (offsets_est == NULL ||
556 cpl_bivector_get_size(offsets_est) != nfiles) {
557 cpl_msg_error(cpl_func,
"Cannot get offsets from %s",
562 double * offsets_est_x;
563 double * offsets_est_y;
564 double offx0 = DBL_MAX;
565 double offy0 = DBL_MAX;
569 offsets_est = cpl_bivector_new(nfiles);
570 offsets_est_x = cpl_bivector_get_x_data(offsets_est);
571 offsets_est_y = cpl_bivector_get_y_data(offsets_est);
572 for (i=0 ; i < nfiles ; i++) {
573 const cpl_propertylist * plist
574 = irplib_framelist_get_propertylist_const(objframes, i);
592 objects[0] != (
char)0) {
593 cpl_msg_info(cpl_func,
"Get the user provided correlation objects");
595 objs = cpl_bivector_read(objects);
597 cpl_msg_error(cpl_func,
"Cannot get objects from %s",
604 sigmas = cpl_vector_wrap(nsigmas, psigmas);
607 cpl_msg_info(cpl_func,
"Recombine the images set");
608 combined = cpl_geom_img_offset_combine(imlist, offsets_est, 1, objs,
609 sigmas, NULL, sx, sy, mx, my,
610 rej_low, rej_high, combine_mode);
612 skip_if (combined == NULL);
616 cpl_bivector_delete(offsets_est);
617 cpl_bivector_delete(objs);
618 cpl_vector_unwrap(sigmas);
634 static cpl_error_code naco_img_jitter_qc(cpl_propertylist * qclist,
635 cpl_propertylist * paflist,
636 const irplib_framelist * objframes,
637 const cpl_image * combined,
638 cpl_boolean drop_wcs)
640 cpl_errorstate cleanstate = cpl_errorstate_get();
641 const cpl_propertylist * reflist
642 = irplib_framelist_get_propertylist_const(objframes, 0);
646 bug_if(combined == NULL);
648 bug_if(cpl_propertylist_copy_property_regexp(paflist, reflist,
"^("
649 NACO_PFITS_REGEXP_JITTER_PAF
652 if (naco_img_jitter_qc_apertures(qclist, objframes, combined)) {
653 naco_error_reset(
"Could not compute all QC parameters");
657 if (cpl_error_get_code()) {
658 naco_error_reset(
"Could not get FITS key:");
660 cpl_propertylist_append_string(qclist,
"ESO QC FILTER OBS", sval);
663 if (cpl_error_get_code()) {
664 naco_error_reset(
"Could not get FITS key:");
666 cpl_propertylist_append_string(qclist,
"ESO QC FILTER NDENS", sval);
669 if (cpl_error_get_code()) {
670 naco_error_reset(
"Could not get FITS key:");
672 cpl_propertylist_append_string(qclist,
"ESO QC FILTER POL", sval);
677 bug_if (cpl_propertylist_append(paflist, qclist));
680 cpl_propertylist * pcopy = cpl_propertylist_new();
681 const cpl_error_code error
682 = cpl_propertylist_copy_property_regexp(pcopy, reflist,
"^("
683 IRPLIB_PFITS_WCS_REGEXP
685 if (!error && cpl_propertylist_get_size(pcopy) > 0) {
686 cpl_msg_warning(cpl_func,
"Combined image will have no WCS "
689 cpl_propertylist_delete(pcopy);
691 bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist,
"^("
692 NACO_PFITS_REGEXP_JITTER_COPY
695 bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist,
"^("
696 IRPLIB_PFITS_WCS_REGEXP
"|"
697 NACO_PFITS_REGEXP_JITTER_COPY
701 if (cpl_propertylist_has(qclist,
"AIRMASS"))
706 return cpl_error_get_code();
718 static cpl_error_code naco_img_jitter_qc_apertures(cpl_propertylist * qclist,
719 const irplib_framelist *
721 const cpl_image * combined)
723 const cpl_propertylist * reflist
724 = irplib_framelist_get_propertylist_const(objframes, 0);
726 cpl_apertures * aperts = NULL;
727 cpl_bivector * fwhms = NULL;
728 cpl_vector * fwhms_sum = NULL;
729 cpl_vector * sigmas = NULL;
732 double * fwhms_sum_data;
735 double psigmas[] = {5.0, 2.0, 1.0, 0.5};
736 const int nsigmas = (int)(
sizeof(psigmas)/
sizeof(double));
742 const double seeing_min_arcsec = 0.1;
743 const double seeing_max_arcsec = 5.0;
744 const double seeing_fwhm_var = 0.2;
746 double iq, fwhm_pix, fwhm_arcsec;
750 cpl_msg_info(cpl_func,
"Detecting apertures using %d sigma-levels "
751 "ranging from %g down to %g", nsigmas, psigmas[0],
755 skip_if( pixscale <= 0.0 );
756 bug_if( seeing_min_arcsec < 0.0);
759 sigmas = cpl_vector_wrap(nsigmas, psigmas);
761 aperts = cpl_apertures_extract(combined, sigmas, &isigma);
762 if (aperts == NULL) {
763 cpl_msg_warning(cpl_func,
"Could not detect any apertures in combined "
770 CPL_DIAG_PRAGMA_PUSH_IGN(-Wdeprecated-declarations);
771 fwhms = cpl_apertures_get_fwhm(combined, aperts);
775 cpl_msg_warning(cpl_func,
"Could not compute any FWHMs of the "
776 "apertures in the combined image");
780 cpl_apertures_delete(aperts);
784 nb_val = cpl_bivector_get_size(fwhms);
785 fwhms_x = cpl_bivector_get_x_data(fwhms);
786 fwhms_y = cpl_bivector_get_y_data(fwhms);
790 for (i=0 ; i < nb_val ; i++) {
791 if (fwhms_x[i] <= 0.0 || fwhms_y[i] <= 0.0)
continue;
792 fwhms_x[nb_good] = fwhms_x[i];
793 fwhms_y[nb_good] = fwhms_y[i];
797 cpl_msg_info(cpl_func,
"Detected %d (%d) apertures at sigma=%g",
798 nb_good, nb_val, psigmas[isigma]);
800 skip_if_lt (nb_good, 1,
"aperture with a FWHM");
804 bug_if(cpl_vector_set_size(cpl_bivector_get_x(fwhms), nb_val));
805 bug_if(cpl_vector_set_size(cpl_bivector_get_y(fwhms), nb_val));
806 fwhms_x = cpl_bivector_get_x_data(fwhms);
807 fwhms_y = cpl_bivector_get_y_data(fwhms);
810 fwhms_sum = cpl_vector_new(nb_good);
811 fwhms_sum_data = cpl_vector_get_data(fwhms_sum);
812 for (i=0; i < nb_good; i++) {
813 fwhms_sum_data[i] = fwhms_x[i] + fwhms_y[i];
816 fwhm_pix = 0.5 * cpl_vector_get_median(fwhms_sum);
818 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC FWHM PIX", fwhm_pix));
820 fwhm_arcsec = fwhm_pix * pixscale;
822 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC FWHM ARCSEC",
829 f_min = seeing_min_arcsec / pixscale;
830 f_max = seeing_max_arcsec / pixscale;
834 for (i=0 ; i < nb_val ; i++) {
835 const double fx = fwhms_x[i];
836 const double fy = fwhms_y[i];
838 if (fx <= f_min || f_max <= fx || fy <= f_min || f_max <= fy)
continue;
839 if (fabs(fx-fy) >= 0.5 * (fx + fy) * seeing_fwhm_var)
continue;
841 fwhms_sum_data[nb_good] = fx + fy;
845 cpl_msg_info(cpl_func,
"%d of the apertures have FWHMs within the range "
846 "%g to %g and eccentricity within %g", nb_good, f_min, f_max,
849 skip_if_lt (nb_good, 1,
"aperture with a good FWHM");
851 bug_if(cpl_vector_set_size(fwhms_sum, nb_good));
854 iq = pixscale * 0.5 * cpl_vector_get_median(fwhms_sum);
856 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC IQ", iq));
860 cpl_vector_delete(fwhms_sum);
861 cpl_bivector_delete(fwhms);
862 cpl_vector_unwrap(sigmas);
863 cpl_apertures_delete(aperts);
865 return cpl_error_get_code();
882 static cpl_error_code naco_img_jitter_save(cpl_frameset * set,
883 const cpl_parameterlist * parlist,
884 const cpl_propertylist * qclist,
885 const cpl_propertylist * paflist,
886 const cpl_imagelist * objimages,
887 const cpl_image * combined,
888 const cpl_image * contrib,
889 const cpl_table * cubetable)
892 const cpl_boolean is_cube = cpl_table_get_ncol(cubetable) > 0
893 ? CPL_TRUE : CPL_FALSE;
894 const char * procatg = is_cube ? NACO_IMG_JITTER_CUBE
895 : NACO_IMG_JITTER_COMB;
896 cpl_propertylist * xtlist = cpl_propertylist_new();
897 const cpl_boolean save_cube =
899 NACO_PARAM_SAVECUBE);
902 bug_if (contrib == NULL);
905 skip_if (irplib_dfs_save_image(set, parlist, set, combined,
906 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
907 procatg, qclist, NULL,
908 naco_pipe_id, RECIPE_STRING CPL_DFS_FITS));
910 bug_if(cpl_propertylist_append_string(xtlist,
"EXTNAME",
911 "Contribution Map"));
912 skip_if (cpl_image_save(contrib, RECIPE_STRING CPL_DFS_FITS,
913 CPL_BPP_16_SIGNED, xtlist, CPL_IO_EXTEND));
917 bug_if(cpl_propertylist_update_string(xtlist,
"EXTNAME",
918 "Plane Properties"));
919 skip_if (cpl_table_save(cubetable, NULL, xtlist,
920 RECIPE_STRING CPL_DFS_FITS, CPL_IO_EXTEND));
924 bug_if(cpl_propertylist_update_string(xtlist,
"EXTNAME",
925 "Corrected object images"));
926 skip_if (cpl_imagelist_save(objimages, RECIPE_STRING CPL_DFS_FITS,
927 CPL_BPP_IEEE_FLOAT, xtlist, CPL_IO_EXTEND));
931 skip_if (cpl_dfs_save_paf(
"NACO", RECIPE_STRING, paflist,
932 RECIPE_STRING CPL_DFS_PAF));
934 bug_if(paflist == NULL);
939 cpl_propertylist_delete(xtlist);
941 return cpl_error_get_code();
959 cpl_error_code naco_img_jitter_load_objimages(cpl_imagelist * objlist,
961 const irplib_framelist *
self,
962 const cpl_parameterlist * parlist)
964 const int nframes = irplib_framelist_get_size(
self);
965 cpl_image * image = NULL;
968 bug_if(objlist == NULL);
969 bug_if(
self == NULL);
970 bug_if(iscube == NULL);
971 bug_if(parlist == NULL);
973 for (i=0; i < nframes; i++, image = NULL) {
974 const char * filename
975 = cpl_frame_get_filename(irplib_framelist_get_const(
self, i));
976 const cpl_propertylist * plist
977 = irplib_framelist_get_propertylist_const(
self, i);
978 const int naxis3 = cpl_propertylist_has(plist,
"NAXIS3") ?
979 cpl_propertylist_get_int(plist,
"NAXIS3") : 1;
984 bug_if(cpl_array_set_int(iscube, i, 1));
992 image = cpl_image_load(filename, CPL_TYPE_FLOAT, naxis3-1, EXT0);
994 any_if(
"Could not load %d-cube-sum from frame %d/%d, file=%s",
995 naxis3-1, i+1, nframes, filename);
998 image = cpl_image_load(filename, CPL_TYPE_FLOAT, 0, EXT0);
1000 any_if(
"Could not load FITS-image from extension %d in frame "
1001 "%d/%d, file=%s", EXT0, i+1, nframes, filename);
1004 bug_if(cpl_imagelist_set(objlist, image, i));
1009 cpl_image_delete(image);
1011 return cpl_error_get_code();
1024 static cpl_error_code naco_img_jitter_check_cube(
const cpl_imagelist *
self,
1025 const cpl_image * sum)
1027 cpl_image * accu = cpl_imagelist_collapse_create(
self);
1030 cpl_image_subtract(accu, sum);
1032 err = cpl_image_get_absflux(accu);
1035 err /= cpl_image_get_size_x(sum) * cpl_image_get_size_y(sum);
1037 cpl_msg_info(cpl_func,
"Average per-pixel error in final sum frame "
1038 "in %d-cube: %g", (
int)cpl_imagelist_get_size(
self), err);
1041 cpl_image_delete(accu);
1043 return cpl_error_get_code();
1060 static cpl_error_code naco_img_jitter_do_cube(cpl_imagelist *
self,
1061 cpl_table * cubetable,
1062 cpl_propertylist * qclist,
1063 const cpl_array * iscube,
1064 const irplib_framelist * obj,
1065 const cpl_parameterlist * parlist)
1068 const int nframes = irplib_framelist_get_size(obj);
1069 cpl_imagelist * onelist = NULL;
1070 cpl_image * sum = NULL;
1071 cpl_image * onesky = NULL;
1074 NACO_PARAM_SKYPLANE);
1075 cpl_vector * skymedians = cpl_vector_new(nframes);
1079 bug_if(
self == NULL);
1080 bug_if(cubetable == NULL);
1081 bug_if(qclist == NULL);
1082 bug_if(obj == NULL);
1083 bug_if(parlist == NULL);
1084 bug_if(nframes != cpl_array_get_size(iscube));
1085 bug_if(nframes != cpl_imagelist_get_size(
self));
1088 for (i=0; i < nframes; i++) {
1091 (void)cpl_array_get_int(iscube, i, &is_invalid);
1094 const char * filename
1095 = cpl_frame_get_filename(irplib_framelist_get_const(obj, i));
1096 const cpl_propertylist * plist
1097 = irplib_framelist_get_propertylist_const(obj, i);
1102 cpl_image_delete(onesky);
1103 onesky = naco_img_jitter_find_sky_cube(i, nskyplane, iscube, obj);
1104 any_if(
"Could not estimate sky for frame %d/%d, file=%s",
1105 i+1, nframes, filename);
1107 skymedian = cpl_image_get_median(onesky);
1108 #ifdef NACO_IMG_JITTER_DEVELOPMENT
1109 if (onelist == NULL) {
1113 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC BACKGD",
1116 cpl_image_save(onesky,
"Sky.fits", CPL_BPP_IEEE_FLOAT, NULL,
1119 cpl_image_save(onesky,
"Sky.fits", CPL_BPP_IEEE_FLOAT, NULL,
1123 cpl_imagelist_delete(onelist);
1124 onelist = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
1126 any_if(
"Could not load cube from frame %d/%d, file=%s",
1127 i+1, nframes, filename);
1129 naxis3 = cpl_imagelist_get_size(onelist);
1131 cpl_msg_info(cpl_func,
"Processing %d-cube from frame %d/%d, "
1132 "file=%s. Median of sky-estimate: %g",
1133 naxis3-1, i+1, nframes, filename, skymedian);
1134 cpl_vector_set(skymedians, nsky++, skymedian);
1138 sum = cpl_imagelist_unset(onelist, naxis3-1);
1140 bug_if(naco_img_jitter_check_cube(onelist, sum));
1142 skip_if(cpl_imagelist_subtract_image(onelist, onesky));
1144 cpl_image_delete(sum);
1145 sum = naco_img_jitter_combine_cube(cubetable, onelist, plist,
1147 any_if(
"Could not combine %d images from frame %d/%d, file=%s",
1148 naxis3-1, i+1, nframes, filename);
1150 bug_if(cpl_imagelist_set(
self, sum, i));
1156 double skystdev, skymean;
1158 bug_if(cpl_vector_set_size(skymedians, nsky));
1160 skymean = cpl_vector_get_mean(skymedians);
1161 skystdev = cpl_vector_get_stdev(skymedians);
1163 cpl_msg_info(cpl_func,
"Mean and stdev of %d medians of sky estimates: "
1164 "%g %g", nsky, skymean, skystdev);
1166 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC SKY STDEV",
1172 cpl_imagelist_delete(onelist);
1173 cpl_image_delete(sum);
1174 cpl_image_delete(onesky);
1175 cpl_vector_delete(skymedians);
1177 return cpl_error_get_code();
1195 cpl_image * naco_img_jitter_combine_cube(cpl_table * cubetable,
1196 const cpl_imagelist * cube,
1197 const cpl_propertylist * plist,
1198 const cpl_parameterlist * parlist,
1202 cpl_errorstate prestate = cpl_errorstate_get();
1203 cpl_image *
self = NULL;
1204 const int ncube = cpl_imagelist_get_size(cube);
1205 cpl_image ** combined = NULL;
1206 cpl_apertures * apert = NULL;
1207 cpl_bivector * offs = cpl_bivector_new(ncube);
1208 cpl_vector * offsx = cpl_bivector_get_x(offs);
1209 cpl_vector * offsy = cpl_bivector_get_y(offs);
1210 cpl_vector * sigmas = NULL;
1211 cpl_vector * vstrehl = cpl_vector_new(ncube);
1212 double psigmas[] = {5.0, 2.0, 1.0, 0.5};
1213 const int nsigmas = (int)(
sizeof(psigmas)/
sizeof(double));
1216 const double rstar = 0.5 * IRPLIB_STREHL_STAR_RADIUS;
1217 const double rbgint = 0.5 * IRPLIB_STREHL_BACKGROUND_R1;
1218 const double rbgext = 0.5 * IRPLIB_STREHL_BACKGROUND_R2;
1222 NACO_PARAM_LUCK_STR);
1224 double lam = DBL_MAX;
1225 double dlam = DBL_MAX;
1226 cpl_size isigma = 0;
1227 const int ncubetable = cpl_table_get_nrow(cubetable);
1232 skip_if(rbgext <= rbgint);
1233 skip_if(pixscale <= 0.0);
1236 "Frame has no info for filter %s", filter);
1238 cpl_msg_debug(cpl_func,
"Frame %d has pixelscale [Arcsecond/pixel]=%g, "
1239 "Central wavelength [micron]=%g, Filter bandwidth "
1240 "[micron]=%g", 1+idx, pixscale, lam, dlam);
1241 cpl_msg_debug(cpl_func,
"Frame %d assumes Rstar [pixel]=%g, Rint "
1242 "[pixel]=%g, Rext [pixel]=%g", 1+idx, rstar/pixscale,
1243 rbgint/pixscale, rbgext/pixscale);
1245 if (cpl_table_get_ncol(cubetable) == 0) {
1246 cpl_table_new_column(cubetable,
"Frame", CPL_TYPE_INT);
1247 cpl_table_new_column(cubetable,
"Plane", CPL_TYPE_INT);
1248 cpl_table_new_column(cubetable,
"XCentroid", CPL_TYPE_DOUBLE);
1249 cpl_table_new_column(cubetable,
"YCentroid", CPL_TYPE_DOUBLE);
1250 cpl_table_set_column_unit(cubetable,
"XCentroid",
"pixel");
1251 cpl_table_set_column_unit(cubetable,
"YCentroid",
"pixel");
1252 cpl_table_new_column(cubetable,
"Strehl", CPL_TYPE_DOUBLE);
1253 cpl_table_new_column(cubetable,
"Strehl_Error", CPL_TYPE_DOUBLE);
1254 cpl_table_new_column(cubetable,
"Star_Background", CPL_TYPE_DOUBLE);
1255 cpl_table_new_column(cubetable,
"Star_Peak", CPL_TYPE_DOUBLE);
1256 cpl_table_new_column(cubetable,
"Star_Flux", CPL_TYPE_DOUBLE);
1257 cpl_table_new_column(cubetable,
"PSF_Peak_per_Flux", CPL_TYPE_DOUBLE);
1258 cpl_table_set_column_unit(cubetable,
"PSF_Peak_per_Flux",
"unitless");
1259 cpl_table_new_column(cubetable,
"Background_Noise", CPL_TYPE_DOUBLE);
1260 cpl_table_set_size(cubetable, ncube);
1263 cpl_table_set_size(cubetable, ncubetable + ncube);
1264 icubetable = ncubetable;
1268 sigmas = cpl_vector_wrap(nsigmas, psigmas);
1269 for (i = 0; i < ncube; i++) {
1270 const cpl_image * one = cpl_imagelist_get_const(cube, i);
1271 double cent_x, cent_y;
1272 double strehl, strehl_err, star_bg,star_peak, star_flux;
1273 double psf_peak, psf_flux, bg_noise;
1277 cpl_apertures_delete(apert);
1278 apert = cpl_apertures_extract(one, sigmas, &isigma);
1280 any_if(
"No object found in image %d/%d in frame %d", i+1, ncube, 1+idx);
1282 bug_if(irplib_apertures_find_max_flux(apert, &iflux, 1));
1284 cent_x = cpl_apertures_get_centroid_x(apert, iflux);
1285 cent_y = cpl_apertures_get_centroid_y(apert, iflux);
1286 cpl_vector_set(offsx, i, cent_x);
1287 cpl_vector_set(offsy, i, cent_y);
1289 cpl_msg_debug(cpl_func,
"Detected %d/%d sigma=%g-aperture(s) (x,y)"
1290 "=(%g,%g) (%d/%d) in %d/%d-image in frame %d", iflux,
1291 (
int)cpl_apertures_get_size(apert), psigmas[isigma],
1292 cent_x, cent_y, 1+(
int)isigma, nsigmas, 1+i, ncube,
1295 cpl_table_set_int(cubetable,
"Frame", i+icubetable, 1+idx);
1296 cpl_table_set_int(cubetable,
"Plane", i+icubetable, 1+i);
1297 cpl_table_set_double(cubetable,
"XCentroid", i+icubetable, cent_x);
1298 cpl_table_set_double(cubetable,
"YCentroid", i+icubetable, cent_y);
1302 cent_x, cent_y, pixscale,
1303 &strehl, &strehl_err,
1304 &star_bg, &star_peak, &star_flux,
1305 &psf_peak, &psf_flux,
1307 cpl_msg_info(cpl_func,
"Could not compute strehl for "
1308 "image %d in frame %d", 1+i, 1+idx);
1309 cpl_errorstate_dump(prestate, CPL_FALSE,
1310 irplib_errorstate_dump_debug);
1311 cpl_errorstate_set(prestate);
1313 cpl_table_set_invalid(cubetable,
"Strehl", i+icubetable);
1314 cpl_table_set_invalid(cubetable,
"Strehl_Error", i+icubetable);
1315 cpl_table_set_invalid(cubetable,
"Star_Background", i+icubetable);
1316 cpl_table_set_invalid(cubetable,
"Star_Peak", i+icubetable);
1317 cpl_table_set_invalid(cubetable,
"Star_Flux", i+icubetable);
1318 cpl_table_set_invalid(cubetable,
"PSF_Peak_per_Flux", i+icubetable);
1319 cpl_table_set_invalid(cubetable,
"Background_Noise", i+icubetable);
1320 cpl_vector_set(vstrehl, i, 0.0);
1323 cpl_vector_set(vstrehl, i, strehl);
1324 cpl_table_set_double(cubetable,
"Strehl", i+icubetable, strehl);
1325 cpl_table_set_double(cubetable,
"Strehl_Error", i+icubetable,
1327 cpl_table_set_double(cubetable,
"Star_Background", i+icubetable,
1329 cpl_table_set_double(cubetable,
"Star_Peak", i+icubetable,
1331 cpl_table_set_double(cubetable,
"Star_Flux", i+icubetable,
1333 cpl_table_set_double(cubetable,
"PSF_Peak_per_Flux", i+icubetable,
1335 cpl_table_set_double(cubetable,
"Background_Noise", i+icubetable,
1340 self = naco_img_jitter_saa_lucky(cube, vstrehl, offs, lucky);
1344 if (combined != NULL) {
1345 cpl_image_delete(combined[0]);
1349 cpl_bivector_delete(offs);
1350 (void)cpl_vector_unwrap(sigmas);
1351 cpl_apertures_delete(apert);
1352 cpl_vector_delete(vstrehl);
1354 cpl_ensure(
self != NULL, cpl_error_get_code(), NULL);
1372 static cpl_image * naco_img_jitter_find_sky_cube(
int isky,
int nskyplane,
1373 const cpl_array * iscube,
1374 const irplib_framelist * obj)
1377 cpl_image *
self = NULL;
1378 const int nframes = irplib_framelist_get_size(obj);
1379 cpl_imagelist * belowcube = NULL;
1380 cpl_imagelist * abovecube = NULL;
1381 cpl_imagelist * skycube = NULL;
1382 cpl_imagelist * mycube = NULL;
1383 cpl_image * mysky = NULL;
1384 cpl_mask * fillbpm = NULL;
1390 bug_if(isky >= nframes);
1391 bug_if(nframes != cpl_array_get_size(iscube));
1392 if (nskyplane > 0) skip_if_lt(nskyplane, 3,
"sky planes for median");
1395 (void)cpl_array_get_int(iscube, isky, &is_invalid);
1400 for (i = isky - 1; i >= 0; i++) {
1402 (void)cpl_array_get_int(iscube, i, &is_invalid);
1404 if (!is_invalid)
break;
1410 for (i = isky + 1; i < nframes; i++) {
1412 (void)cpl_array_get_int(iscube, i, &is_invalid);
1414 if (!is_invalid)
break;
1419 cpl_msg_info(cpl_func,
"Estimating sky for cube %d/%d via cubes %d and %d",
1420 1+isky, nframes, 1+ibelow, 1+iabove);
1424 const char * filename
1425 = cpl_frame_get_filename(irplib_framelist_get_const(obj, ibelow));
1427 if (nskyplane > 0) {
1429 const cpl_propertylist * plist
1430 = irplib_framelist_get_propertylist_const(obj, ibelow);
1432 const int istop = irplib_pfits_get_int(plist,
"NAXIS3") - 2;
1433 const int istart = NACO_MAX(0, istop - nskyplane + 1);
1435 skip_if_lt(istop - istart, 2,
"sky planes for median");
1437 belowcube = cpl_imagelist_new();
1439 for (i = istart; i <= istop; i++) {
1440 self = cpl_image_load(filename, CPL_TYPE_FLOAT, i, EXT0);
1442 any_if(
"Could not load plane %d from frame %d/%d, file=%s",
1443 1+i, 1+ibelow, nframes, filename);
1445 bug_if(cpl_imagelist_set(belowcube,
self, i - istart));
1451 belowcube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
1453 any_if(
"Could not load cube from frame %d/%d, file=%s",
1454 1+ibelow, nframes, filename);
1456 naxis3 = cpl_imagelist_get_size(belowcube);
1460 cpl_image_delete(cpl_imagelist_unset(belowcube, naxis3-1));
1466 if (iabove < nframes) {
1467 const char * filename
1468 = cpl_frame_get_filename(irplib_framelist_get_const(obj, iabove));
1470 if (nskyplane > 0) {
1472 const cpl_propertylist * plist
1473 = irplib_framelist_get_propertylist_const(obj, iabove);
1474 const int istart = 0;
1476 const int istop = NACO_MIN(nskyplane-1, irplib_pfits_get_int
1477 (plist,
"NAXIS3") - 2);
1479 skip_if_lt(istop - istart, 2,
"sky planes for median");
1481 abovecube = cpl_imagelist_new();
1483 for (i = istart; i <= istop; i++) {
1484 self = cpl_image_load(filename, CPL_TYPE_FLOAT, i, EXT0);
1486 any_if(
"Could not load plane %d from frame %d/%d, file=%s",
1487 1+i, 1+iabove, nframes, filename);
1489 bug_if(cpl_imagelist_set(abovecube,
self, i - istart));
1496 abovecube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
1498 any_if(
"Could not load cube from frame %d/%d, file=%s",
1499 1+iabove, nframes, filename);
1501 naxis3 = cpl_imagelist_get_size(abovecube);
1505 cpl_image_delete(cpl_imagelist_unset(abovecube, naxis3-1));
1510 error_if(belowcube == NULL && abovecube == NULL, CPL_ERROR_DATA_NOT_FOUND,
1511 "No cube(s) available for sky estimation among %d object frames",
1514 if (belowcube == NULL) {
1515 skycube = abovecube;
1516 }
else if (abovecube == NULL) {
1517 skycube = belowcube;
1521 const int nbelow = cpl_imagelist_get_size(belowcube);
1522 const int nabove = cpl_imagelist_get_size(abovecube);
1525 skycube = cpl_imagelist_new();
1527 for (i = 0; i < nbelow; i++) {
1528 skip_if(cpl_imagelist_set(skycube, cpl_imagelist_get(belowcube, i),
1531 for (i = 0; i < nabove; i++) {
1532 skip_if(cpl_imagelist_set(skycube, cpl_imagelist_get(abovecube, i),
1535 skip_if(cpl_imagelist_get_size(skycube) != nwrap);
1536 skip_if(nbelow + nabove != nwrap);
1539 self = cpl_imagelist_collapse_median_create(skycube);
1541 #ifndef NACO_IMG_JITTER_KEEP_SKY_OBJECTS
1542 if (belowcube == NULL || abovecube == NULL) {
1544 const cpl_mask * fill2bpm;
1545 const cpl_mask * selfbpm = NULL;
1546 const double lo_skysigma = 0.2;
1547 const double hi_skysigma = 5.0;
1549 skip_if(naco_img_jitter_reject_objects(
self, lo_skysigma, hi_skysigma));
1551 selfbpm = cpl_image_get_bpm_const(
self);
1553 if (selfbpm != NULL) {
1554 const cpl_mask * mybpm;
1558 const char * filename
1559 = cpl_frame_get_filename(irplib_framelist_get_const(obj, isky));
1562 mycube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
1564 any_if(
"Could not load cube from frame %d/%d, file=%s",
1565 1+isky, nframes, filename);
1567 naxis3 = cpl_imagelist_get_size(mycube);
1571 cpl_image_delete(cpl_imagelist_unset(mycube, naxis3-1));
1573 mysky = cpl_imagelist_collapse_median_create(mycube);
1575 skip_if(naco_img_jitter_reject_objects(mysky, lo_skysigma,
1581 mybpm = cpl_image_get_bpm_const(mysky);
1583 if (mybpm == NULL) {
1589 fillbpm = cpl_mask_duplicate(mybpm);
1590 bug_if(cpl_mask_not(fillbpm));
1591 bug_if(cpl_mask_and(fillbpm, selfbpm));
1596 cpl_msg_info(cpl_func,
"Filling %d object-pixels in sky image "
1597 "with %d sky-pixels from object image",
1598 (
int)cpl_mask_count(selfbpm),
1599 (
int)cpl_mask_count(fill2bpm));
1600 if (fill2bpm != selfbpm) {
1602 bug_if(cpl_image_reject_from_mask(
self, fill2bpm));
1605 if (fillbpm == NULL) {
1606 fillbpm = cpl_mask_duplicate(fill2bpm);
1607 }
else if (fillbpm != fill2bpm) {
1608 bug_if(cpl_mask_copy(fillbpm, fill2bpm, 1, 1));
1611 bug_if(cpl_image_fill_rejected(
self, 0.0));
1612 bug_if(cpl_image_accept_all(
self));
1614 bug_if(cpl_mask_not(fillbpm));
1615 bug_if(cpl_image_reject_from_mask(mysky, fillbpm));
1616 bug_if(cpl_image_fill_rejected(mysky, 0.0));
1617 bug_if(cpl_image_accept_all(mysky));
1618 bug_if(cpl_image_add(
self, mysky));
1625 if (cpl_error_get_code()) {
1626 cpl_image_delete(
self);
1631 if (skycube != belowcube && skycube != abovecube) {
1632 int nwrap = cpl_imagelist_get_size(skycube);
1636 (void)cpl_imagelist_unset(skycube, --nwrap);
1639 cpl_imagelist_delete(skycube);
1642 cpl_mask_delete(fillbpm);
1643 cpl_image_delete(mysky);
1644 cpl_imagelist_delete(mycube);
1645 cpl_imagelist_delete(belowcube);
1646 cpl_imagelist_delete(abovecube);
1665 cpl_error_code naco_img_jitter_imagelist_wrap_nocube(cpl_imagelist *
self,
1666 const cpl_array * iscube,
1667 cpl_imagelist * other)
1670 const int ncube = cpl_imagelist_get_size(other);
1671 int nwrap = cpl_imagelist_get_size(
self);
1674 bug_if(
self == NULL);
1675 bug_if(iscube == NULL);
1676 bug_if(other == NULL);
1678 bug_if(cpl_array_get_size(iscube) != ncube);
1680 for (i = 0; i < ncube; i++) {
1683 (void)cpl_array_get_int(iscube, i, &is_invalid);
1686 cpl_imagelist_set(
self, cpl_imagelist_get(other, i), nwrap);
1691 bug_if(cpl_imagelist_get_size(
self) != nwrap);
1695 return cpl_error_get_code();
1699 #ifndef NACO_IMG_JITTER_KEEP_SKY_OBJECTS
1713 static cpl_error_code naco_img_jitter_reject_objects(cpl_image *
self,
1718 double med_dist = DBL_MAX;
1719 double hi_threshold;
1720 cpl_mask * hi_objects = NULL;
1721 cpl_mask * lo_objects = NULL;
1722 cpl_mask * rejects = NULL;
1723 cpl_image * hi_label = NULL;
1724 cpl_image * lo_label = NULL;
1725 cpl_apertures * hi_apert = NULL;
1726 cpl_mask * kernel = NULL;
1729 bug_if(
self == NULL);
1730 bug_if(lo_sigma <= 0.0);
1731 bug_if(hi_sigma < lo_sigma);
1734 median = cpl_image_get_median_dev(
self, &med_dist);
1735 hi_threshold = median + hi_sigma * med_dist;
1738 hi_objects = cpl_mask_threshold_image_create(
self, hi_threshold, DBL_MAX);
1739 bug_if(hi_objects == NULL);
1743 kernel = cpl_mask_new(3, 3);
1744 bug_if(cpl_mask_not(kernel));
1745 bug_if(cpl_mask_filter(hi_objects, hi_objects, kernel, CPL_FILTER_OPENING,
1748 if (!cpl_mask_is_empty(hi_objects)) {
1752 const double lo_threshold = median + lo_sigma * med_dist;
1753 cpl_size hi_ilabel, hi_nlabel, lo_nlabel;
1756 lo_objects = cpl_mask_threshold_image_create(
self, lo_threshold, DBL_MAX);
1757 bug_if(lo_objects == NULL);
1758 bug_if(cpl_mask_filter(lo_objects, lo_objects, kernel,
1759 CPL_FILTER_OPENING, CPL_BORDER_ZERO));
1761 hi_label = cpl_image_labelise_mask_create(hi_objects, &hi_nlabel);
1762 lo_label = cpl_image_labelise_mask_create(lo_objects, &lo_nlabel);
1764 hi_apert = cpl_apertures_new_from_image(
self, hi_label);
1765 bug_if(hi_apert == NULL);
1767 for (hi_ilabel = 1; hi_ilabel <= hi_nlabel; hi_ilabel++) {
1769 const int pos_x = cpl_apertures_get_top_x(hi_apert, hi_ilabel);
1770 const int pos_y = cpl_apertures_get_top(hi_apert, hi_ilabel);
1773 const int lo_ilabel = (int)cpl_image_get(lo_label, pos_x, pos_y,
1777 cpl_mask_delete(rejects);
1778 rejects = cpl_mask_threshold_image_create(lo_label,
1779 (
double)lo_ilabel - 0.5,
1780 (
double)lo_ilabel + 0.5);
1783 cpl_mask_or(hi_objects, rejects);
1787 cpl_msg_info(cpl_func,
"Found %d object(s) of %d pixel(s) "
1788 "in sky image using sigmas %g and %g", (
int)hi_nlabel,
1789 (
int)cpl_mask_count(hi_objects), lo_sigma, hi_sigma);
1790 bug_if(cpl_image_reject_from_mask(
self, hi_objects));
1796 cpl_apertures_delete(hi_apert);
1797 cpl_image_delete(hi_label);
1798 cpl_image_delete(lo_label);
1799 cpl_mask_delete(kernel);
1800 cpl_mask_delete(hi_objects);
1801 cpl_mask_delete(lo_objects);
1802 cpl_mask_delete(rejects);
1804 return cpl_error_get_code();
1821 static cpl_image * naco_img_jitter_saa_lucky(
const cpl_imagelist * cube,
1822 const cpl_vector * strehl,
1823 const cpl_bivector * offs,
1827 cpl_image *
self = NULL;
1828 const int ncube = cpl_imagelist_get_size(cube);
1829 const int mcube = NACO_MAX(NACO_MIN(ncube, (
int)(0.5 + fraction * ncube)),
1831 cpl_imagelist * lcube = NULL;
1832 const cpl_imagelist * ucube;
1833 cpl_vector * lstrehl = NULL;
1836 cpl_bivector * loffs = cpl_bivector_duplicate(offs);
1837 cpl_vector * loffsx = cpl_bivector_get_x(loffs);
1838 cpl_vector * loffsy = cpl_bivector_get_y(loffs);
1839 cpl_table * tsort = NULL;
1840 cpl_propertylist * psort = NULL;
1844 bug_if(cpl_vector_get_size(strehl) != ncube);
1845 bug_if(cpl_bivector_get_size(offs) != ncube);
1846 bug_if(fraction <= 0.0);
1847 bug_if(fraction > 1.0);
1849 if (mcube < ncube) {
1853 lstrehl = cpl_vector_duplicate(strehl);
1855 tsort = cpl_table_new(ncube);
1856 psort = cpl_propertylist_new();
1859 bug_if(cpl_propertylist_append_bool(psort,
"LSTREHL", CPL_TRUE));
1861 bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(lstrehl),
1863 bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(loffsx),
1865 bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(loffsy),
1867 bug_if(cpl_table_new_column(tsort,
"INDEX", CPL_TYPE_INT));
1870 pindex = cpl_table_get_data_int(tsort,
"INDEX");
1871 for (i = 0; i < ncube; i++) {
1875 bug_if(cpl_table_sort(tsort, psort));
1878 lcube = cpl_imagelist_new();
1881 for (i = 0; i < mcube; i++) {
1882 const int j = pindex[i];
1883 const cpl_image * image = cpl_imagelist_get_const(cube, j);
1885 cpl_imagelist_set(lcube, (cpl_image*)image, i);
1890 bug_if(cpl_vector_set_size(loffsx, mcube));
1891 bug_if(cpl_vector_set_size(loffsy, mcube));
1893 strehlmin = cpl_vector_get(lstrehl, mcube - 1);
1894 cpl_vector_delete(lstrehl);
1897 cpl_msg_info(cpl_func,
"%g%% (%d/%d) lucky mode at Strehl=%g",
1898 100.0*fraction, mcube, ncube, strehlmin);
1900 ucube = lcube ? lcube : cube;
1902 self = naco_img_jitter_saa_center(ucube, loffs);
1903 any_if(
"Could not center and saa %d-cube", ncube);
1907 if (lcube != NULL) {
1909 for (i = cpl_imagelist_get_size(lcube); i > 0;) {
1910 (void)cpl_imagelist_unset(lcube, --i);
1913 cpl_imagelist_delete(lcube);
1916 cpl_vector_delete(lstrehl);
1918 cpl_bivector_delete(loffs);
1920 if (tsort != NULL) {
1921 if (cpl_table_has_column(tsort,
"LSTREHL"))
1922 (void)cpl_table_unwrap(tsort,
"LSTREHL");
1923 if (cpl_table_has_column(tsort,
"LOFFSX"))
1924 (
void)cpl_table_unwrap(tsort,
"LOFFSX");
1925 if (cpl_table_has_column(tsort,
"LOFFSY"))
1926 (void)cpl_table_unwrap(tsort,
"LOFFSY");
1927 cpl_table_delete(tsort);
1929 cpl_propertylist_delete(psort);
1945 cpl_error_code naco_img_jitter_find_strehl(
const cpl_imagelist *
self,
1946 const cpl_parameterlist * parlist,
1947 const irplib_framelist * objframes)
1950 const int nobj = irplib_framelist_get_size(objframes);
1951 cpl_apertures * apert = NULL;
1952 cpl_vector * sigmas = NULL;
1953 double psigmas[] = {5.0, 2.0, 1.0, 0.5};
1954 const int nsigmas = (int)(
sizeof(psigmas)/
sizeof(double));
1955 cpl_size isigma = 0;
1959 bug_if(cpl_imagelist_get_size(
self) != nobj);
1962 sigmas = cpl_vector_wrap(nsigmas, psigmas);
1964 for (i = 0; i < nobj; i++) {
1965 const cpl_propertylist * plist
1966 = irplib_framelist_get_propertylist_const(objframes, i);
1967 const cpl_image * oimage = cpl_imagelist_get_const(
self, i);
1971 double lam = DBL_MAX;
1972 double dlam = DBL_MAX;
1974 double cent_x, cent_y;
1975 double strehl = 0, strehl_err, star_bg,star_peak, star_flux;
1976 double psf_peak, psf_flux, bg_noise;
1980 skip_if(pixscale <= 0.0);
1983 "Frame %d has no info for filter %s", 1+i, filter);
1985 cpl_apertures_delete(apert);
1986 apert = cpl_apertures_extract(oimage, sigmas, &isigma);
1988 any_if(
"No object found in combined image of frame %d", 1+i);
1990 bug_if(irplib_apertures_find_max_flux(apert, &iflux, 1));
1992 cent_x = cpl_apertures_get_centroid_x(apert, iflux);
1993 cent_y = cpl_apertures_get_centroid_y(apert, iflux);
1996 cent_x, cent_y, pixscale,
1997 &strehl, &strehl_err,
1998 &star_bg, &star_peak, &star_flux,
1999 &psf_peak, &psf_flux,
2001 cpl_msg_info(cpl_func,
"Image of frame %d/%d has strehl=%g at (x,y)"
2002 "=(%g,%g)", 1+i, nobj, strehl, cent_x, cent_y);
2007 (void)cpl_vector_unwrap(sigmas);
2008 cpl_apertures_delete(apert);
2010 return cpl_error_get_code();
2024 static cpl_image * naco_img_jitter_saa_center(
const cpl_imagelist * cube,
2025 cpl_bivector * offs)
2028 const int ncube = cpl_imagelist_get_size(cube);
2029 cpl_image *
self = NULL;
2030 cpl_image ** combined = NULL;
2031 cpl_imagelist * ccube = NULL;
2032 const cpl_imagelist * ucube;
2033 cpl_vector * offsx = cpl_bivector_get_x(offs);
2034 cpl_vector * offsy = cpl_bivector_get_y(offs);
2035 double * doffsx = cpl_vector_get_data(offsx);
2036 double * doffsy = cpl_vector_get_data(offsy);
2037 const double med_x = cpl_vector_get_median_const(offsx);
2038 const double med_y = cpl_vector_get_median_const(offsy);
2039 double pos_x, pos_y;
2040 double minsqdist = DBL_MAX;
2045 bug_if(cpl_bivector_get_size(offs) != ncube);
2048 for (i = 0; i < ncube; i++) {
2049 const double x = cpl_vector_get(offsx, i);
2050 const double y = cpl_vector_get(offsy, i);
2052 = (x - med_x) * (x - med_x) + (y - med_y) * (y - med_y);
2054 if (sqdist < minsqdist) {
2060 cpl_msg_info(cpl_func,
"Plane %d/%d has minimal object distance %g "
2061 "from median (x,y)=(%g,%g)", 1+imin, ncube,
2062 sqrt(minsqdist), med_x, med_y);
2068 const cpl_image * image = cpl_imagelist_get_const(cube, imin);
2070 ccube = cpl_imagelist_new();
2072 bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, 0));
2074 for (i = 0; i < imin; i++) {
2075 image = cpl_imagelist_get_const(cube, i);
2076 bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, 1+i));
2078 for (i = 1+imin; i < ncube; i++) {
2079 image = cpl_imagelist_get_const(cube, i);
2080 bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, i));
2083 bug_if(cpl_imagelist_get_size(ccube) != ncube);
2086 pos_x = cpl_vector_get(offsx, imin);
2087 pos_y = cpl_vector_get(offsy, imin);
2090 (void)memmove(doffsx + 1, doffsx, (
size_t)imin *
sizeof(*doffsx));
2091 (void)memmove(doffsy + 1, doffsy, (
size_t)imin *
sizeof(*doffsy));
2094 cpl_vector_set(offsx, 0, pos_x);
2095 cpl_vector_set(offsy, 0, pos_y);
2097 ucube = ccube ? ccube : cube;
2100 cpl_vector_subtract_scalar(offsx, cpl_vector_get(offsx, 0));
2101 cpl_vector_subtract_scalar(offsy, cpl_vector_get(offsy, 0));
2102 cpl_vector_multiply_scalar(offsx, -1.0);
2103 cpl_vector_multiply_scalar(offsy, -1.0);
2105 combined = cpl_geom_img_offset_saa(ucube, offs, CPL_KERNEL_DEFAULT,
2106 0, 0, CPL_GEOM_FIRST, &pos_x, &pos_y);
2108 any_if(
"Could not shift and add %d-cube", ncube);
2110 cpl_msg_info(cpl_func,
"Shift-and-added %d-cube, 1st pos=(%g,%g)",
2111 ncube, pos_x, pos_y);
2114 cpl_image_delete(combined[1]);
2120 if (combined != NULL) {
2121 cpl_image_delete(combined[0]);
2122 cpl_image_delete(combined[1]);
2126 if (ccube != NULL) {
2128 for (i = cpl_imagelist_get_size(ccube); i > 0;) {
2129 (void)cpl_imagelist_unset(ccube, --i);
2132 cpl_imagelist_delete(ccube);