00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031
00032
00033
00034
00035
00036 #include "naco_recipe.h"
00037 #include "irplib_calib.h"
00038 #include "irplib_strehl.h"
00039
00040
00041 #include <string.h>
00042
00043
00044
00045
00046
00047 #define RECIPE_STRING "naco_img_jitter"
00048
00049 #define EXT0 0
00050
00051 #define NACO_MIN(A,B) ((A) < (B) ? (A) : (B))
00052 #define NACO_MAX(A,B) ((A) > (B) ? (A) : (B))
00053
00054
00055
00056
00057
00058 #ifndef NACO_IMG_JITTER_KEEP_SKY_OBJECTS
00059 static cpl_error_code naco_img_jitter_reject_objects(cpl_image *, double,
00060 double);
00061 #endif
00062
00063 static cpl_error_code naco_img_jitter_find_strehl(const cpl_imagelist *,
00064 const irplib_framelist *);
00065
00066 static cpl_image * naco_img_jitter_saa_center(const cpl_imagelist *,
00067 cpl_bivector *);
00068
00069 static cpl_image * naco_img_jitter_saa_lucky(const cpl_imagelist *,
00070 const cpl_vector *,
00071 const cpl_bivector *, double);
00072
00073 static cpl_image * naco_img_jitter_find_sky_cube(int, int, const cpl_array *,
00074 const irplib_framelist *);
00075
00076 static cpl_error_code naco_img_jitter_imagelist_wrap_nocube(cpl_imagelist *,
00077 const cpl_array *,
00078 cpl_imagelist *);
00079
00080
00081 static cpl_image * naco_img_jitter_combine_cube(cpl_table *, const cpl_imagelist *,
00082 const cpl_propertylist *,
00083 const cpl_parameterlist *, int);
00084
00085 static cpl_error_code naco_img_jitter_check_cube(const cpl_imagelist *,
00086 const cpl_image *);
00087
00088 static cpl_error_code naco_img_jitter_do_cube(cpl_imagelist *, cpl_table *,
00089 cpl_propertylist *,
00090 const cpl_array *,
00091 const irplib_framelist *,
00092 const cpl_parameterlist *);
00093
00094 static
00095 cpl_error_code naco_img_jitter_load_objimages(cpl_imagelist *, cpl_array *,
00096 const irplib_framelist *,
00097 const cpl_parameterlist *);
00098
00099 static cpl_image ** naco_img_jitter_reduce(cpl_imagelist *, cpl_table *,
00100 cpl_propertylist *,
00101 const irplib_framelist *,
00102 const irplib_framelist *,
00103 const cpl_parameterlist *,
00104 const char *,
00105 const char *,
00106 const char *,
00107 cpl_boolean *);
00108
00109 static cpl_image * naco_img_jitter_find_sky(cpl_propertylist *,
00110 const cpl_imagelist *,
00111 const cpl_imagelist *);
00112 static cpl_image ** naco_img_jitter_saa(cpl_imagelist *,
00113 const irplib_framelist *,
00114 const cpl_parameterlist *);
00115 static cpl_error_code naco_img_jitter_qc(cpl_propertylist *, cpl_propertylist *,
00116 const irplib_framelist *,
00117 const cpl_image *, cpl_boolean);
00118 static cpl_error_code naco_img_jitter_qc_apertures(cpl_propertylist *,
00119 const irplib_framelist *,
00120 const cpl_image *);
00121 static cpl_error_code naco_img_jitter_save(cpl_frameset *,
00122 const cpl_parameterlist *,
00123 const cpl_propertylist *,
00124 const cpl_propertylist *,
00125 const cpl_imagelist *,
00126 const cpl_image *,
00127 const cpl_image *,
00128 const cpl_table *);
00129
00130 NACO_RECIPE_DEFINE(naco_img_jitter,
00131 NACO_PARAM_OFFSETS |
00132 NACO_PARAM_OBJECTS |
00133 NACO_PARAM_ODDEVEN |
00134 NACO_PARAM_XCORR |
00135 NACO_PARAM_UNION |
00136 NACO_PARAM_COMBINE |
00137 NACO_PARAM_SKYPLANE|
00138 NACO_PARAM_CUBEMODE|
00139 NACO_PARAM_LUCK_STR|
00140 NACO_PARAM_SAVECUBE|
00141 NACO_PARAM_REJ_HILO,
00142 "Jitter recipe",
00143 RECIPE_STRING " -- NACO imaging jitter recipe.\n"
00144 "The files listed in the Set Of Frames (sof-file) "
00145 "must be tagged:\n"
00146 "NACO-raw-file.fits "NACO_IMG_JITTER_OBJ" or\n"
00147 "NACO-raw-file.fits "NACO_IMG_JITTER_SKY" or\n"
00148 "NACO-raw-file.fits "NACO_IMG_JITTER_OBJ_POL" or\n"
00149 "NACO-raw-file.fits "NACO_IMG_JITTER_SKY_POL" or\n"
00150 "NACO-flat-file.fits "NACO_CALIB_FLAT" or\n"
00151 "NACO-bpm-file.fits "NACO_CALIB_BPM" or\n"
00152 "NACO-dark-file.fits "NACO_CALIB_DARK"\n");
00153
00154
00158
00159
00160
00161
00162
00163
00164
00171
00172 static int naco_img_jitter(cpl_frameset * framelist,
00173 const cpl_parameterlist * parlist)
00174 {
00175 cpl_errorstate cleanstate = cpl_errorstate_get();
00176 irplib_framelist * allframes = NULL;
00177 irplib_framelist * objframes = NULL;
00178 irplib_framelist * skyframes = NULL;
00179 cpl_propertylist * qclist = cpl_propertylist_new();
00180 cpl_propertylist * paflist = cpl_propertylist_new();
00181 cpl_imagelist * objimages = cpl_imagelist_new();
00182 cpl_image ** combined = NULL;
00183 cpl_table * cubetable = cpl_table_new(1);
00184 const char * badpix;
00185 const char * dark;
00186 const char * flat;
00187 cpl_boolean drop_wcs = CPL_FALSE;
00188
00189
00190
00191 skip_if (naco_dfs_set_groups(framelist));
00192
00193 allframes = irplib_framelist_cast(framelist);
00194 skip_if(allframes == NULL);
00195
00196 objframes = irplib_framelist_extract_regexp(allframes,
00197 "^(" NACO_IMG_JITTER_OBJ "|"
00198 NACO_IMG_JITTER_OBJ_POL ")$",
00199 CPL_FALSE);
00200 skip_if(objframes == NULL);
00201
00202 skyframes = irplib_framelist_extract_regexp(allframes,
00203 "^(" NACO_IMG_JITTER_SKY "|"
00204 NACO_IMG_JITTER_SKY_POL ")$",
00205 CPL_FALSE);
00206 irplib_framelist_empty(allframes);
00207 if (skyframes == NULL) {
00208 naco_error_reset("The set of frames has no sky frames:");
00209 }
00210
00211 flat = irplib_frameset_find_file(framelist, NACO_CALIB_FLAT);
00212 bug_if(0);
00213
00214 badpix = irplib_frameset_find_file(framelist, NACO_CALIB_BPM);
00215 bug_if(0);
00216
00217 dark = irplib_frameset_find_file(framelist, NACO_CALIB_DARK);
00218 bug_if(0);
00219
00220 skip_if(irplib_framelist_load_propertylist(objframes, 0, 0, "^("
00221 NACO_PFITS_REGEXP_JITTER_FIRST
00222 ")$", CPL_FALSE));
00223
00224 skip_if(irplib_framelist_load_propertylist_all(objframes, 0, "^("
00225 NACO_PFITS_REGEXP_JITTER_ALL
00226 ")$", CPL_FALSE));
00227
00228
00229 cpl_msg_info(cpl_func, "Apply the data recombination");
00230 combined = naco_img_jitter_reduce(objimages, cubetable, qclist, objframes,
00231 skyframes, parlist, dark, flat, badpix,
00232 &drop_wcs);
00233
00234 skip_if (combined == NULL);
00235
00236 irplib_framelist_empty(skyframes);
00237
00238
00239 cpl_msg_info(cpl_func, "Compute QC parameters from the combined image");
00240 skip_if (naco_img_jitter_qc(qclist, paflist, objframes, combined[0], drop_wcs));
00241
00242 irplib_framelist_empty(objframes);
00243
00244
00245 cpl_msg_info(cpl_func, "Save the products");
00246
00247
00248 bug_if (cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,
00249 cpl_table_get_ncol(cubetable) > 0 ?
00250 NACO_IMG_JITTER_CUBE :
00251 NACO_IMG_JITTER_COMB));
00252
00253 skip_if (naco_img_jitter_save(framelist, parlist, qclist, paflist,
00254 objimages,
00255 combined[0], combined[1], cubetable));
00256
00257 end_skip;
00258
00259 if (combined != NULL) {
00260 cpl_image_delete(combined[0]);
00261 cpl_image_delete(combined[1]);
00262 cpl_free(combined);
00263 }
00264 cpl_imagelist_delete(objimages);
00265 irplib_framelist_delete(allframes);
00266 irplib_framelist_delete(objframes);
00267 irplib_framelist_delete(skyframes);
00268 cpl_propertylist_delete(qclist);
00269 cpl_propertylist_delete(paflist);
00270 cpl_table_delete(cubetable);
00271
00272 return cpl_error_get_code();
00273 }
00274
00275
00290
00291 static cpl_image ** naco_img_jitter_reduce(cpl_imagelist * objimages,
00292 cpl_table * cubetable,
00293 cpl_propertylist * qclist,
00294 const irplib_framelist * obj,
00295 const irplib_framelist * sky,
00296 const cpl_parameterlist * parlist,
00297 const char * dark,
00298 const char * flat,
00299 const char * bpm,
00300 cpl_boolean * pdid_resize)
00301 {
00302 cpl_errorstate prestate = cpl_errorstate_get();
00303 const int nobj = irplib_framelist_get_size(obj);
00304 cpl_imagelist * nocubeimgs = NULL;
00305 cpl_imagelist * skyimages = NULL;
00306 cpl_image * skyimage = NULL;
00307 cpl_image ** combined = NULL;
00308 cpl_array * iscube = NULL;
00309 cpl_boolean has_cube = CPL_FALSE;
00310 const char * scubemode = naco_parameterlist_get_string
00311 (parlist, RECIPE_STRING, NACO_PARAM_CUBEMODE);
00312 int inocube = 0;
00313
00314
00315 bug_if(pdid_resize == NULL);
00316 bug_if(scubemode == NULL);
00317
00318 skip_if (irplib_framelist_contains(obj, NACO_PFITS_DOUBLE_CUMOFFSETX,
00319 CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
00320
00321 skip_if (irplib_framelist_contains(obj, NACO_PFITS_DOUBLE_CUMOFFSETY,
00322 CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
00323
00324
00325 cpl_msg_info(cpl_func, "Loading the %d object and %d sky images",
00326 irplib_framelist_get_size(obj),
00327 sky == NULL ? 0 : irplib_framelist_get_size(sky));
00328
00329 iscube = cpl_array_new(nobj, CPL_TYPE_INT);
00330
00331 (void)naco_img_jitter_load_objimages(objimages, iscube, obj, parlist);
00332
00333 any_if("Could not load the %d object images", nobj);
00334
00335 cpl_msg_info(cpl_func, "Loaded %d object images", nobj);
00336
00337 skip_if(cpl_imagelist_get_size(objimages) != nobj);
00338
00339 skip_if (irplib_flat_dark_bpm_calib(objimages, flat, dark, bpm));
00340
00341 cpl_msg_info(cpl_func, "Sky estimation and correction");
00342
00343 if (scubemode[0] == 'a') {
00344
00345 const int mcube = nobj - cpl_array_count_invalid(iscube);
00346
00347 if (mcube > 0) {
00348 cpl_msg_info(cpl_func, "Collapsing %d cube(s) with no shifting",
00349 mcube);
00350 cpl_array_delete(iscube);
00351 iscube = cpl_array_new(nobj, CPL_TYPE_INT);
00352 }
00353 }
00354
00355 if (cpl_array_has_valid(iscube)) {
00356 has_cube = CPL_TRUE;
00357
00358 skip_if(naco_img_jitter_do_cube(objimages, cubetable, qclist,
00359 iscube, obj, parlist));
00360
00361 #ifdef NACO_IMG_JITTER_DEVELOPMENT
00362 skip_if(cpl_imagelist_save(objimages, "Collapsed.fits", CPL_BPP_IEEE_FLOAT,
00363 NULL, CPL_IO_CREATE));
00364 #endif
00365 }
00366
00367 if (cpl_array_has_invalid(iscube)) {
00368
00369 nocubeimgs = has_cube ? cpl_imagelist_new() : objimages;
00370 if (has_cube) {
00371 skip_if(naco_img_jitter_imagelist_wrap_nocube(nocubeimgs, iscube,
00372 objimages));
00373 inocube = cpl_imagelist_get_size(nocubeimgs);
00374 }
00375
00376
00377 if (sky != NULL) {
00378 skyimages = irplib_imagelist_load_framelist(sky, CPL_TYPE_FLOAT, 0, 0);
00379 any_if("Could not load sky images");
00380 skip_if (irplib_flat_dark_bpm_calib(skyimages, flat, dark, bpm));
00381 }
00382
00383 skyimage = naco_img_jitter_find_sky(qclist, nocubeimgs, skyimages);
00384 any_if("Could not estimate sky");
00385
00386 cpl_imagelist_delete(skyimages);
00387 skyimages = NULL;
00388
00389
00390 skip_if (cpl_imagelist_subtract_image(nocubeimgs, skyimage));
00391 }
00392
00393
00394 if(naco_img_jitter_find_strehl(objimages, obj)) {
00395 irplib_error_recover(prestate, "Could not compute Strehl-ratio "
00396 "for %d frame(s)", nobj);
00397 }
00398
00399
00400 cpl_msg_info(cpl_func, "Shift and add");
00401 combined = naco_img_jitter_saa(objimages, obj, parlist);
00402 skip_if (combined == NULL);
00403
00404 *pdid_resize = (cpl_boolean)
00405 (cpl_image_get_size_x(combined[0])
00406 != cpl_image_get_size_x(cpl_imagelist_get_const(objimages, 0)) ||
00407 cpl_image_get_size_y(combined[0])
00408 != cpl_image_get_size_y(cpl_imagelist_get_const(objimages, 0)));
00409
00410 end_skip;
00411
00412
00413 for (;inocube > 0;) {
00414 (void)cpl_imagelist_unset(nocubeimgs, --inocube);
00415 }
00416
00417 if (nocubeimgs != objimages) cpl_imagelist_delete(nocubeimgs);
00418 cpl_imagelist_delete(skyimages);
00419 cpl_image_delete(skyimage);
00420 cpl_array_delete(iscube);
00421
00422 return combined;
00423 }
00424
00425
00433
00434 static cpl_image * naco_img_jitter_find_sky(cpl_propertylist * qclist,
00435 const cpl_imagelist * objs,
00436 const cpl_imagelist * skys)
00437 {
00438 cpl_image * self = NULL;
00439
00440 if (skys != NULL) {
00441
00442 self = cpl_imagelist_collapse_median_create(skys);
00443 any_if("Could not compute the median of %d sky images",
00444 (int)cpl_imagelist_get_size(skys));
00445 } else {
00446
00447
00448 self = cpl_imagelist_collapse_median_create(objs);
00449 any_if("Could not compute the median of %d object images",
00450 (int)cpl_imagelist_get_size(objs));
00451 }
00452
00453
00454 bug_if(cpl_propertylist_append_double(qclist, "ESO QC BACKGD",
00455 cpl_image_get_median(self)));
00456 bug_if(cpl_propertylist_append_double(qclist, "ESO QC BACKGD STDEV",
00457 cpl_image_get_stdev(self)));
00458
00459 end_skip;
00460
00461 return self;
00462 }
00463
00464
00472
00473 static cpl_image ** naco_img_jitter_saa(cpl_imagelist * imlist,
00474 const irplib_framelist * objframes,
00475 const cpl_parameterlist * parlist)
00476 {
00477 const char * sval;
00478 cpl_bivector * offsets_est = NULL;
00479 cpl_bivector * objs = NULL;
00480 cpl_image ** combined = NULL;
00481 cpl_vector * sigmas = NULL;
00482 double psigmas[] = {5.0, 2.0, 1.0, 0.5};
00483 const char * offsets;
00484 const char * objects;
00485 #ifdef NACO_USE_ODDEVEN
00486 cpl_boolean oddeven_flag;
00487 #endif
00488 const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
00489 const int nfiles = cpl_imagelist_get_size(imlist);
00490 int sx, sy, mx, my;
00491 int rej_low, rej_high;
00492 const char * combine_string;
00493 cpl_geom_combine combine_mode;
00494
00495
00496 bug_if(0);
00497 bug_if (irplib_framelist_get_size(objframes) != nfiles);
00498
00499
00500
00501
00502 offsets = naco_parameterlist_get_string(parlist, RECIPE_STRING,
00503 NACO_PARAM_OFFSETS);
00504
00505 objects = naco_parameterlist_get_string(parlist, RECIPE_STRING,
00506 NACO_PARAM_OBJECTS);
00507 #ifdef NACO_USE_ODDEVEN
00508
00509 oddeven_flag = naco_parameterlist_get_bool(parlist, RECIPE_STRING,
00510 NACO_PARAM_ODDEVEN);
00511 #endif
00512
00513
00514 sval = naco_parameterlist_get_string(parlist, RECIPE_STRING,
00515 NACO_PARAM_XCORR);
00516 bug_if (sval == NULL);
00517
00518 skip_if (sscanf(sval, "%d %d %d %d", &sx, &sy, &mx, &my) != 4);
00519
00520 combine_string = naco_parameterlist_get_string(parlist, RECIPE_STRING,
00521 NACO_PARAM_COMBINE);
00522
00523 bug_if (combine_string == NULL);
00524
00525 if (combine_string[0] == 'u')
00526 combine_mode = CPL_GEOM_UNION;
00527 else if (combine_string[0] == 'f')
00528 combine_mode = CPL_GEOM_FIRST;
00529 else if (combine_string[0] == 'i')
00530 combine_mode = CPL_GEOM_INTERSECT;
00531 else
00532 skip_if(1);
00533
00534
00535 sval = naco_parameterlist_get_string(parlist, RECIPE_STRING,
00536 NACO_PARAM_REJ_HILO);
00537 bug_if (sval == NULL);
00538
00539 skip_if (sscanf(sval, "%d %d", &rej_low, &rej_high) != 2);
00540
00541
00542
00543 cpl_msg_info(cpl_func, "Get the offsets estimation");
00544 offsets_est = NULL;
00545 if (offsets &&
00546 offsets[0] != (char)0) {
00547
00548 offsets_est = cpl_bivector_read(offsets);
00549 if (offsets_est == NULL ||
00550 cpl_bivector_get_size(offsets_est) != nfiles) {
00551 cpl_msg_error(cpl_func, "Cannot get offsets from %s",
00552 offsets);
00553 skip_if(1);
00554 }
00555 } else {
00556 double * offsets_est_x;
00557 double * offsets_est_y;
00558 double offx0 = DBL_MAX;
00559 double offy0 = DBL_MAX;
00560 int i;
00561
00562
00563 offsets_est = cpl_bivector_new(nfiles);
00564 offsets_est_x = cpl_bivector_get_x_data(offsets_est);
00565 offsets_est_y = cpl_bivector_get_y_data(offsets_est);
00566 for (i=0 ; i < nfiles ; i++) {
00567 const cpl_propertylist * plist
00568 = irplib_framelist_get_propertylist_const(objframes, i);
00569
00570
00571 if (i == 0) {
00572 offx0 = naco_pfits_get_cumoffsetx(plist);
00573 offy0 = naco_pfits_get_cumoffsety(plist);
00574 }
00575
00576
00577 offsets_est_x[i] = offx0 - naco_pfits_get_cumoffsetx(plist);
00578 offsets_est_y[i] = offy0 - naco_pfits_get_cumoffsety(plist);
00579
00580 bug_if(0);
00581 }
00582 }
00583
00584
00585 if (objects &&
00586 objects[0] != (char)0) {
00587 cpl_msg_info(cpl_func, "Get the user provided correlation objects");
00588
00589 objs = cpl_bivector_read(objects);
00590 if (objs==NULL) {
00591 cpl_msg_error(cpl_func, "Cannot get objects from %s",
00592 objects);
00593 skip_if (1);
00594 }
00595 }
00596
00597
00598 sigmas = cpl_vector_wrap(nsigmas, psigmas);
00599
00600
00601 cpl_msg_info(cpl_func, "Recombine the images set");
00602 combined = cpl_geom_img_offset_combine(imlist, offsets_est, 1, objs,
00603 sigmas, NULL, sx, sy, mx, my,
00604 rej_low, rej_high, combine_mode);
00605
00606 skip_if (combined == NULL);
00607
00608 end_skip;
00609
00610 cpl_bivector_delete(offsets_est);
00611 cpl_bivector_delete(objs);
00612 cpl_vector_unwrap(sigmas);
00613
00614 return combined;
00615 }
00616
00617
00627
00628 static cpl_error_code naco_img_jitter_qc(cpl_propertylist * qclist,
00629 cpl_propertylist * paflist,
00630 const irplib_framelist * objframes,
00631 const cpl_image * combined,
00632 cpl_boolean drop_wcs)
00633 {
00634 cpl_errorstate cleanstate = cpl_errorstate_get();
00635 const cpl_propertylist * reflist
00636 = irplib_framelist_get_propertylist_const(objframes, 0);
00637 const char * sval;
00638
00639
00640 bug_if(combined == NULL);
00641
00642 bug_if(cpl_propertylist_copy_property_regexp(paflist, reflist, "^("
00643 NACO_PFITS_REGEXP_JITTER_PAF
00644 ")$", 0));
00645
00646 if (naco_img_jitter_qc_apertures(qclist, objframes, combined)) {
00647 naco_error_reset("Could not compute all QC parameters");
00648 }
00649
00650 sval = naco_pfits_get_filter(reflist);
00651 if (cpl_error_get_code()) {
00652 naco_error_reset("Could not get FITS key:");
00653 } else {
00654 cpl_propertylist_append_string(qclist, "ESO QC FILTER OBS", sval);
00655 }
00656 sval = naco_pfits_get_opti3_name(reflist);
00657 if (cpl_error_get_code()) {
00658 naco_error_reset("Could not get FITS key:");
00659 } else {
00660 cpl_propertylist_append_string(qclist, "ESO QC FILTER NDENS", sval);
00661 }
00662 sval = naco_pfits_get_opti4_name(reflist);
00663 if (cpl_error_get_code()) {
00664 naco_error_reset("Could not get FITS key:");
00665 } else {
00666 cpl_propertylist_append_string(qclist, "ESO QC FILTER POL", sval);
00667 }
00668
00669 bug_if(0);
00670
00671 bug_if (cpl_propertylist_append(paflist, qclist));
00672
00673 if (drop_wcs) {
00674 cpl_propertylist * pcopy = cpl_propertylist_new();
00675 const cpl_error_code error
00676 = cpl_propertylist_copy_property_regexp(pcopy, reflist, "^("
00677 IRPLIB_PFITS_WCS_REGEXP
00678 ")$", 0);
00679 if (!error && cpl_propertylist_get_size(pcopy) > 0) {
00680 cpl_msg_warning(cpl_func, "Combined image will have no WCS "
00681 "coordinates");
00682 }
00683 cpl_propertylist_delete(pcopy);
00684
00685 bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
00686 NACO_PFITS_REGEXP_JITTER_COPY
00687 ")$", 0));
00688 } else {
00689 bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
00690 IRPLIB_PFITS_WCS_REGEXP "|"
00691 NACO_PFITS_REGEXP_JITTER_COPY
00692 ")$", 0));
00693 }
00694
00695 if (cpl_propertylist_has(qclist, "AIRMASS"))
00696 bug_if (irplib_pfits_set_airmass(qclist, objframes));
00697
00698 end_skip;
00699
00700 return cpl_error_get_code();
00701 }
00702
00703
00711
00712 static cpl_error_code naco_img_jitter_qc_apertures(cpl_propertylist * qclist,
00713 const irplib_framelist *
00714 objframes,
00715 const cpl_image * combined)
00716 {
00717 const cpl_propertylist * reflist
00718 = irplib_framelist_get_propertylist_const(objframes, 0);
00719
00720 cpl_apertures * aperts = NULL;
00721 cpl_bivector * fwhms = NULL;
00722 cpl_vector * fwhms_sum = NULL;
00723 cpl_vector * sigmas = NULL;
00724 double * fwhms_x;
00725 double * fwhms_y;
00726 double * fwhms_sum_data;
00727 int nb_val, nb_good;
00728 double f_min, f_max;
00729 double psigmas[] = {5.0, 2.0, 1.0, 0.5};
00730 const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
00731 cpl_size isigma;
00732 int i;
00733
00734 const double pixscale = naco_pfits_get_pixscale(reflist);
00735
00736 const double seeing_min_arcsec = 0.1;
00737 const double seeing_max_arcsec = 5.0;
00738 const double seeing_fwhm_var = 0.2;
00739
00740 double iq, fwhm_pix, fwhm_arcsec;
00741
00742
00743
00744 cpl_msg_info(cpl_func, "Detecting apertures using %d sigma-levels "
00745 "ranging from %g down to %g", nsigmas, psigmas[0],
00746 psigmas[nsigmas-1]);
00747
00748
00749 skip_if( pixscale <= 0.0 );
00750 bug_if( seeing_min_arcsec < 0.0);
00751
00752
00753 sigmas = cpl_vector_wrap(nsigmas, psigmas);
00754
00755 aperts = cpl_apertures_extract(combined, sigmas, &isigma);
00756 if (aperts == NULL) {
00757 cpl_msg_warning(cpl_func, "Could not detect any apertures in combined "
00758 "image");
00759 skip_if(1);
00760 }
00761 bug_if(0);
00762
00763
00764 fwhms = cpl_apertures_get_fwhm(combined, aperts);
00765 if (fwhms == NULL) {
00766 cpl_msg_warning(cpl_func, "Could not compute any FWHMs of the "
00767 "apertures in the combined image");
00768 skip_if(1);
00769 }
00770 bug_if(0);
00771 cpl_apertures_delete(aperts);
00772 aperts = NULL;
00773
00774
00775 nb_val = cpl_bivector_get_size(fwhms);
00776 fwhms_x = cpl_bivector_get_x_data(fwhms);
00777 fwhms_y = cpl_bivector_get_y_data(fwhms);
00778
00779
00780 nb_good = 0;
00781 for (i=0 ; i < nb_val ; i++) {
00782 if (fwhms_x[i] <= 0.0 || fwhms_y[i] <= 0.0) continue;
00783 fwhms_x[nb_good] = fwhms_x[i];
00784 fwhms_y[nb_good] = fwhms_y[i];
00785 nb_good++;
00786 }
00787
00788 cpl_msg_info(cpl_func, "Detected %d (%d) apertures at sigma=%g",
00789 nb_good, nb_val, psigmas[isigma]);
00790
00791 skip_if_lt (nb_good, 1, "aperture with a FWHM");
00792
00793 nb_val = nb_good;
00794
00795 bug_if(cpl_vector_set_size(cpl_bivector_get_x(fwhms), nb_val));
00796 bug_if(cpl_vector_set_size(cpl_bivector_get_y(fwhms), nb_val));
00797 fwhms_x = cpl_bivector_get_x_data(fwhms);
00798 fwhms_y = cpl_bivector_get_y_data(fwhms);
00799
00800
00801 fwhms_sum = cpl_vector_new(nb_good);
00802 fwhms_sum_data = cpl_vector_get_data(fwhms_sum);
00803 for (i=0; i < nb_good; i++) {
00804 fwhms_sum_data[i] = fwhms_x[i] + fwhms_y[i];
00805 }
00806
00807 fwhm_pix = 0.5 * cpl_vector_get_median(fwhms_sum);
00808
00809 bug_if(cpl_propertylist_append_double(qclist, "ESO QC FWHM PIX", fwhm_pix));
00810
00811 fwhm_arcsec = fwhm_pix * pixscale;
00812
00813 bug_if(cpl_propertylist_append_double(qclist, "ESO QC FWHM ARCSEC",
00814 fwhm_arcsec));
00815
00816
00817
00818
00819
00820 f_min = seeing_min_arcsec / pixscale;
00821 f_max = seeing_max_arcsec / pixscale;
00822
00823
00824 nb_good = 0;
00825 for (i=0 ; i < nb_val ; i++) {
00826 const double fx = fwhms_x[i];
00827 const double fy = fwhms_y[i];
00828
00829 if (fx <= f_min || f_max <= fx || fy <= f_min || f_max <= fy) continue;
00830 if (fabs(fx-fy) >= 0.5 * (fx + fy) * seeing_fwhm_var) continue;
00831
00832 fwhms_sum_data[nb_good] = fx + fy;
00833 nb_good++;
00834 }
00835
00836 cpl_msg_info(cpl_func, "%d of the apertures have FWHMs within the range "
00837 "%g to %g and eccentricity within %g", nb_good, f_min, f_max,
00838 seeing_fwhm_var);
00839
00840 skip_if_lt (nb_good, 1, "aperture with a good FWHM");
00841
00842 bug_if(cpl_vector_set_size(fwhms_sum, nb_good));
00843
00844
00845 iq = pixscale * 0.5 * cpl_vector_get_median(fwhms_sum);
00846
00847 bug_if(cpl_propertylist_append_double(qclist, "ESO QC IQ", iq));
00848
00849 end_skip;
00850
00851 cpl_vector_delete(fwhms_sum);
00852 cpl_bivector_delete(fwhms);
00853 cpl_vector_unwrap(sigmas);
00854 cpl_apertures_delete(aperts);
00855
00856 return cpl_error_get_code();
00857 }
00858
00859
00872
00873 static cpl_error_code naco_img_jitter_save(cpl_frameset * set,
00874 const cpl_parameterlist * parlist,
00875 const cpl_propertylist * qclist,
00876 const cpl_propertylist * paflist,
00877 const cpl_imagelist * objimages,
00878 const cpl_image * combined,
00879 const cpl_image * contrib,
00880 const cpl_table * cubetable)
00881 {
00882
00883 const cpl_boolean is_cube = cpl_table_get_ncol(cubetable) > 0
00884 ? CPL_TRUE : CPL_FALSE;
00885 const char * procatg = is_cube ? NACO_IMG_JITTER_CUBE
00886 : NACO_IMG_JITTER_COMB;
00887 cpl_propertylist * xtlist = cpl_propertylist_new();
00888 const cpl_boolean save_cube =
00889 naco_parameterlist_get_bool(parlist, RECIPE_STRING,
00890 NACO_PARAM_SAVECUBE);
00891
00892 bug_if (0);
00893 bug_if (contrib == NULL);
00894
00895
00896 skip_if (irplib_dfs_save_image(set, parlist, set, combined,
00897 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
00898 procatg, qclist, NULL,
00899 naco_pipe_id, RECIPE_STRING CPL_DFS_FITS));
00900
00901 bug_if(cpl_propertylist_append_string(xtlist, "EXTNAME",
00902 "Contribution Map"));
00903 skip_if (cpl_image_save(contrib, RECIPE_STRING CPL_DFS_FITS,
00904 CPL_BPP_16_SIGNED, xtlist, CPL_IO_EXTEND));
00905
00906 if (is_cube) {
00907
00908 bug_if(cpl_propertylist_update_string(xtlist, "EXTNAME",
00909 "Plane Properties"));
00910 skip_if (cpl_table_save(cubetable, NULL, xtlist,
00911 RECIPE_STRING CPL_DFS_FITS, CPL_IO_EXTEND));
00912 }
00913
00914 if (save_cube) {
00915 bug_if(cpl_propertylist_update_string(xtlist, "EXTNAME",
00916 "Corrected object images"));
00917 skip_if (cpl_imagelist_save(objimages, RECIPE_STRING CPL_DFS_FITS,
00918 CPL_BPP_IEEE_FLOAT, xtlist, CPL_IO_EXTEND));
00919 }
00920
00921 #ifdef NACO_SAVE_PAF
00922 skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, paflist,
00923 RECIPE_STRING CPL_DFS_PAF));
00924 #else
00925 bug_if(paflist == NULL);
00926 #endif
00927
00928 end_skip;
00929
00930 cpl_propertylist_delete(xtlist);
00931
00932 return cpl_error_get_code();
00933
00934 }
00935
00936
00948
00949 static
00950 cpl_error_code naco_img_jitter_load_objimages(cpl_imagelist * objlist,
00951 cpl_array * iscube,
00952 const irplib_framelist * self,
00953 const cpl_parameterlist * parlist)
00954 {
00955 const int nframes = irplib_framelist_get_size(self);
00956 cpl_image * image = NULL;
00957 int i;
00958
00959 bug_if(objlist == NULL);
00960 bug_if(self == NULL);
00961 bug_if(iscube == NULL);
00962 bug_if(parlist == NULL);
00963
00964 for (i=0; i < nframes; i++, image = NULL) {
00965 const char * filename
00966 = cpl_frame_get_filename(irplib_framelist_get_const(self, i));
00967 const cpl_propertylist * plist
00968 = irplib_framelist_get_propertylist_const(self, i);
00969 const int naxis3 = cpl_propertylist_has(plist, "NAXIS3") ?
00970 cpl_propertylist_get_int(plist, "NAXIS3") : 1;
00971
00972
00973 if (naxis3 > 2) {
00974
00975 bug_if(cpl_array_set_int(iscube, i, 1));
00976
00977
00978
00979
00980
00981
00982
00983 image = cpl_image_load(filename, CPL_TYPE_FLOAT, naxis3-1, EXT0);
00984
00985 any_if("Could not load %d-cube-sum from frame %d/%d, file=%s",
00986 naxis3-1, i+1, nframes, filename);
00987
00988 } else {
00989 image = cpl_image_load(filename, CPL_TYPE_FLOAT, 0, EXT0);
00990
00991 any_if("Could not load FITS-image from extension %d in frame "
00992 "%d/%d, file=%s", EXT0, i+1, nframes, filename);
00993
00994 }
00995 bug_if(cpl_imagelist_set(objlist, image, i));
00996 }
00997
00998 end_skip;
00999
01000 cpl_image_delete(image);
01001
01002 return cpl_error_get_code();
01003
01004 }
01005
01006
01014
01015 static cpl_error_code naco_img_jitter_check_cube(const cpl_imagelist * self,
01016 const cpl_image * sum)
01017 {
01018 cpl_image * accu = cpl_imagelist_collapse_create(self);
01019 double err;
01020
01021 cpl_image_subtract(accu, sum);
01022
01023 err = cpl_image_get_absflux(accu);
01024
01025 if (err > 0.0) {
01026 err /= cpl_image_get_size_x(sum) * cpl_image_get_size_y(sum);
01027
01028 cpl_msg_info(cpl_func, "Average per-pixel error in final sum frame "
01029 "in %d-cube: %g", (int)cpl_imagelist_get_size(self), err);
01030 }
01031
01032 cpl_image_delete(accu);
01033
01034 return cpl_error_get_code();
01035 }
01036
01037
01038
01050
01051 static cpl_error_code naco_img_jitter_do_cube(cpl_imagelist * self,
01052 cpl_table * cubetable,
01053 cpl_propertylist * qclist,
01054 const cpl_array * iscube,
01055 const irplib_framelist * obj,
01056 const cpl_parameterlist * parlist)
01057 {
01058
01059 const int nframes = irplib_framelist_get_size(obj);
01060 cpl_imagelist * onelist = NULL;
01061 cpl_image * sum = NULL;
01062 cpl_image * onesky = NULL;
01063 const int nskyplane = naco_parameterlist_get_int(parlist,
01064 RECIPE_STRING,
01065 NACO_PARAM_SKYPLANE);
01066 cpl_vector * skymedians = cpl_vector_new(nframes);
01067 int nsky = 0;
01068 int i;
01069
01070 bug_if(self == NULL);
01071 bug_if(cubetable == NULL);
01072 bug_if(qclist == NULL);
01073 bug_if(obj == NULL);
01074 bug_if(parlist == NULL);
01075 bug_if(nframes != cpl_array_get_size(iscube));
01076 bug_if(nframes != cpl_imagelist_get_size(self));
01077
01078
01079 for (i=0; i < nframes; i++) {
01080 int is_invalid = 0;
01081
01082 (void)cpl_array_get_int(iscube, i, &is_invalid);
01083
01084 if (!is_invalid) {
01085 const char * filename
01086 = cpl_frame_get_filename(irplib_framelist_get_const(obj, i));
01087 const cpl_propertylist * plist
01088 = irplib_framelist_get_propertylist_const(obj, i);
01089 double skymedian;
01090 int naxis3;
01091
01092
01093 cpl_image_delete(onesky);
01094 onesky = naco_img_jitter_find_sky_cube(i, nskyplane, iscube, obj);
01095 any_if("Could not estimate sky for frame %d/%d, file=%s",
01096 i+1, nframes, filename);
01097
01098 skymedian = cpl_image_get_median(onesky);
01099 #ifdef NACO_IMG_JITTER_DEVELOPMENT
01100 if (onelist == NULL) {
01101
01102
01103
01104 bug_if(cpl_propertylist_append_double(qclist, "ESO QC BACKGD",
01105 skymedian));
01106
01107 cpl_image_save(onesky, "Sky.fits", CPL_BPP_IEEE_FLOAT, NULL,
01108 CPL_IO_CREATE);
01109 } else {
01110 cpl_image_save(onesky, "Sky.fits", CPL_BPP_IEEE_FLOAT, NULL,
01111 CPL_IO_EXTEND);
01112 }
01113 #endif
01114 cpl_imagelist_delete(onelist);
01115 onelist = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
01116
01117 any_if("Could not load cube from frame %d/%d, file=%s",
01118 i+1, nframes, filename);
01119
01120 naxis3 = cpl_imagelist_get_size(onelist);
01121
01122 cpl_msg_info(cpl_func, "Processing %d-cube from frame %d/%d, "
01123 "file=%s. Median of sky-estimate: %g",
01124 naxis3-1, i+1, nframes, filename, skymedian);
01125 cpl_vector_set(skymedians, nsky++, skymedian);
01126
01127 bug_if(naxis3 < 3);
01128
01129 sum = cpl_imagelist_unset(onelist, naxis3-1);
01130
01131 bug_if(naco_img_jitter_check_cube(onelist, sum));
01132
01133 skip_if(cpl_imagelist_subtract_image(onelist, onesky));
01134
01135 cpl_image_delete(sum);
01136 sum = naco_img_jitter_combine_cube(cubetable, onelist, plist,
01137 parlist, i);
01138 any_if("Could not combine %d images from frame %d/%d, file=%s",
01139 naxis3-1, i+1, nframes, filename);
01140
01141 bug_if(cpl_imagelist_set(self, sum, i));
01142 sum = NULL;
01143 }
01144 }
01145
01146 if (nsky > 1) {
01147 double skystdev, skymean;
01148
01149 bug_if(cpl_vector_set_size(skymedians, nsky));
01150
01151 skymean = cpl_vector_get_mean(skymedians);
01152 skystdev = cpl_vector_get_stdev(skymedians);
01153
01154 cpl_msg_info(cpl_func, "Mean and stdev of %d medians of sky estimates: "
01155 "%g %g", nsky, skymean, skystdev);
01156
01157 bug_if(cpl_propertylist_append_double(qclist, "ESO QC SKY STDEV",
01158 skystdev));
01159 }
01160
01161 end_skip;
01162
01163 cpl_imagelist_delete(onelist);
01164 cpl_image_delete(sum);
01165 cpl_image_delete(onesky);
01166 cpl_vector_delete(skymedians);
01167
01168 return cpl_error_get_code();
01169 }
01170
01171
01172
01173
01184
01185 static
01186 cpl_image * naco_img_jitter_combine_cube(cpl_table * cubetable,
01187 const cpl_imagelist * cube,
01188 const cpl_propertylist * plist,
01189 const cpl_parameterlist * parlist,
01190 int idx)
01191 {
01192
01193 cpl_errorstate prestate = cpl_errorstate_get();
01194 cpl_image * self = NULL;
01195 const int ncube = cpl_imagelist_get_size(cube);
01196 cpl_image ** combined = NULL;
01197 cpl_apertures * apert = NULL;
01198 cpl_bivector * offs = cpl_bivector_new(ncube);
01199 cpl_vector * offsx = cpl_bivector_get_x(offs);
01200 cpl_vector * offsy = cpl_bivector_get_y(offs);
01201 cpl_vector * sigmas = NULL;
01202 cpl_vector * vstrehl = cpl_vector_new(ncube);
01203 double psigmas[] = {5.0, 2.0, 1.0, 0.5};
01204 const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
01205
01206
01207 const double rstar = 0.5 * STREHL_STAR_RADIUS;
01208 const double rbgint = 0.5 * STREHL_BACKGROUND_R1;
01209 const double rbgext = 0.5 * STREHL_BACKGROUND_R2;
01210 const double pixscale = naco_pfits_get_pixscale(plist);
01211 const double lucky = naco_parameterlist_get_double(parlist,
01212 RECIPE_STRING,
01213 NACO_PARAM_LUCK_STR);
01214 const char * filter = naco_pfits_get_filter(plist);
01215 double lam = DBL_MAX;
01216 double dlam = DBL_MAX;
01217 cpl_size isigma = 0;
01218 const int ncubetable = cpl_table_get_nrow(cubetable);
01219 int icubetable;
01220 int i;
01221
01222
01223 skip_if(rbgext <= rbgint);
01224 skip_if(pixscale <= 0.0);
01225
01226 irplib_check(naco_get_filter_infos(filter, &lam, &dlam),
01227 "Frame has no info for filter %s", filter);
01228
01229 cpl_msg_debug(cpl_func, "Frame %d has pixelscale [Arcsecond/pixel]=%g, "
01230 "Central wavelength [micron]=%g, Filter bandwidth "
01231 "[micron]=%g", 1+idx, pixscale, lam, dlam);
01232 cpl_msg_debug(cpl_func, "Frame %d assumes Rstar [pixel]=%g, Rint "
01233 "[pixel]=%g, Rext [pixel]=%g", 1+idx, rstar/pixscale,
01234 rbgint/pixscale, rbgext/pixscale);
01235
01236 if (cpl_table_get_ncol(cubetable) == 0) {
01237 cpl_table_new_column(cubetable, "Frame", CPL_TYPE_INT);
01238 cpl_table_new_column(cubetable, "Plane", CPL_TYPE_INT);
01239 cpl_table_new_column(cubetable, "XCentroid", CPL_TYPE_DOUBLE);
01240 cpl_table_new_column(cubetable, "YCentroid", CPL_TYPE_DOUBLE);
01241 cpl_table_set_column_unit(cubetable, "XCentroid", "pixel");
01242 cpl_table_set_column_unit(cubetable, "YCentroid", "pixel");
01243 cpl_table_new_column(cubetable, "Strehl", CPL_TYPE_DOUBLE);
01244 cpl_table_new_column(cubetable, "Strehl_Error", CPL_TYPE_DOUBLE);
01245 cpl_table_new_column(cubetable, "Star_Background", CPL_TYPE_DOUBLE);
01246 cpl_table_new_column(cubetable, "Star_Peak", CPL_TYPE_DOUBLE);
01247 cpl_table_new_column(cubetable, "Star_Flux", CPL_TYPE_DOUBLE);
01248 cpl_table_new_column(cubetable, "PSF_Peak_per_Flux", CPL_TYPE_DOUBLE);
01249 cpl_table_set_column_unit(cubetable, "PSF_Peak_per_Flux", "unitless");
01250 cpl_table_new_column(cubetable, "Background_Noise", CPL_TYPE_DOUBLE);
01251 cpl_table_set_size(cubetable, ncube);
01252 icubetable = 0;
01253 } else {
01254 cpl_table_set_size(cubetable, ncubetable + ncube);
01255 icubetable = ncubetable;
01256 }
01257
01258
01259 sigmas = cpl_vector_wrap(nsigmas, psigmas);
01260 for (i = 0; i < ncube; i++) {
01261 const cpl_image * one = cpl_imagelist_get_const(cube, i);
01262 double cent_x, cent_y;
01263 double strehl, strehl_err, star_bg,star_peak, star_flux;
01264 double psf_peak, psf_flux, bg_noise;
01265 int iflux;
01266
01267
01268 cpl_apertures_delete(apert);
01269 apert = cpl_apertures_extract(one, sigmas, &isigma);
01270
01271 any_if("No object found in image %d/%d in frame %d", i+1, ncube, 1+idx);
01272
01273 bug_if(irplib_apertures_find_max_flux(apert, &iflux, 1));
01274
01275 cent_x = cpl_apertures_get_centroid_x(apert, iflux);
01276 cent_y = cpl_apertures_get_centroid_y(apert, iflux);
01277 cpl_vector_set(offsx, i, cent_x);
01278 cpl_vector_set(offsy, i, cent_y);
01279
01280 cpl_msg_debug(cpl_func, "Detected %d/%d sigma=%g-aperture(s) (x,y)"
01281 "=(%g,%g) (%d/%d) in %d/%d-image in frame %d", iflux,
01282 (int)cpl_apertures_get_size(apert), psigmas[isigma],
01283 cent_x, cent_y, 1+(int)isigma, nsigmas, 1+i, ncube,
01284 1+idx);
01285
01286 cpl_table_set_int(cubetable, "Frame", i+icubetable, 1+idx);
01287 cpl_table_set_int(cubetable, "Plane", i+icubetable, 1+i);
01288 cpl_table_set_double(cubetable, "XCentroid", i+icubetable, cent_x);
01289 cpl_table_set_double(cubetable, "YCentroid", i+icubetable, cent_y);
01290
01291
01292 if (irplib_strehl_compute(one, STREHL_M1, STREHL_M2, lam, dlam,
01293 pixscale, STREHL_BOX_SIZE, cent_x, cent_y,
01294 rstar, rbgint, rbgext, -1, -1,
01295 &strehl, &strehl_err,
01296 &star_bg, &star_peak, &star_flux,
01297 &psf_peak, &psf_flux,
01298 &bg_noise)) {
01299 cpl_msg_info(cpl_func, "Could not compute strehl for "
01300 "image %d in frame %d", 1+i, 1+idx);
01301 cpl_errorstate_dump(prestate, CPL_FALSE,
01302 irplib_errorstate_dump_debug);
01303 cpl_errorstate_set(prestate);
01304
01305 cpl_table_set_invalid(cubetable, "Strehl", i+icubetable);
01306 cpl_table_set_invalid(cubetable, "Strehl_Error", i+icubetable);
01307 cpl_table_set_invalid(cubetable, "Star_Background", i+icubetable);
01308 cpl_table_set_invalid(cubetable, "Star_Peak", i+icubetable);
01309 cpl_table_set_invalid(cubetable, "Star_Flux", i+icubetable);
01310 cpl_table_set_invalid(cubetable, "PSF_Peak_per_Flux", i+icubetable);
01311 cpl_table_set_invalid(cubetable, "Background_Noise", i+icubetable);
01312 cpl_vector_set(vstrehl, i, 0.0);
01313
01314 } else {
01315 cpl_vector_set(vstrehl, i, strehl);
01316 cpl_table_set_double(cubetable, "Strehl", i+icubetable, strehl);
01317 cpl_table_set_double(cubetable, "Strehl_Error", i+icubetable,
01318 strehl_err);
01319 cpl_table_set_double(cubetable, "Star_Background", i+icubetable,
01320 star_bg);
01321 cpl_table_set_double(cubetable, "Star_Peak", i+icubetable,
01322 star_peak);
01323 cpl_table_set_double(cubetable, "Star_Flux", i+icubetable,
01324 star_flux);
01325 cpl_table_set_double(cubetable, "PSF_Peak_per_Flux", i+icubetable,
01326 psf_peak/psf_flux);
01327 cpl_table_set_double(cubetable, "Background_Noise", i+icubetable,
01328 bg_noise);
01329 }
01330 }
01331
01332 self = naco_img_jitter_saa_lucky(cube, vstrehl, offs, lucky);
01333
01334 end_skip;
01335
01336 if (combined != NULL) {
01337 cpl_image_delete(combined[0]);
01338 cpl_free(combined);
01339 }
01340
01341 cpl_bivector_delete(offs);
01342 (void)cpl_vector_unwrap(sigmas);
01343 cpl_apertures_delete(apert);
01344 cpl_vector_delete(vstrehl);
01345
01346 cpl_ensure(self != NULL, cpl_error_get_code(), NULL);
01347
01348 return self;
01349
01350 }
01351
01352
01353
01363
01364 static cpl_image * naco_img_jitter_find_sky_cube(int isky, int nskyplane,
01365 const cpl_array * iscube,
01366 const irplib_framelist * obj)
01367 {
01368
01369 cpl_image * self = NULL;
01370 const int nframes = irplib_framelist_get_size(obj);
01371 cpl_imagelist * belowcube = NULL;
01372 cpl_imagelist * abovecube = NULL;
01373 cpl_imagelist * skycube = NULL;
01374 cpl_imagelist * mycube = NULL;
01375 cpl_image * mysky = NULL;
01376 cpl_mask * fillbpm = NULL;
01377 int is_invalid = 0;
01378 int ibelow, iabove;
01379 int i;
01380
01381 bug_if(isky < 0);
01382 bug_if(isky >= nframes);
01383 bug_if(nframes != cpl_array_get_size(iscube));
01384 if (nskyplane > 0) skip_if_lt(nskyplane, 3, "sky planes for median");
01385
01386
01387 (void)cpl_array_get_int(iscube, isky, &is_invalid);
01388
01389 bug_if(is_invalid);
01390
01391
01392 for (i = isky - 1; i >= 0; i++) {
01393
01394 (void)cpl_array_get_int(iscube, i, &is_invalid);
01395
01396 if (!is_invalid) break;
01397 }
01398
01399 ibelow = i;
01400
01401
01402 for (i = isky + 1; i < nframes; i++) {
01403
01404 (void)cpl_array_get_int(iscube, i, &is_invalid);
01405
01406 if (!is_invalid) break;
01407 }
01408
01409 iabove = i;
01410
01411 cpl_msg_info(cpl_func, "Estimating sky for cube %d/%d via cubes %d and %d",
01412 1+isky, nframes, 1+ibelow, 1+iabove);
01413
01414
01415 if (ibelow >= 0) {
01416 const char * filename
01417 = cpl_frame_get_filename(irplib_framelist_get_const(obj, ibelow));
01418
01419 if (nskyplane > 0) {
01420
01421 const cpl_propertylist * plist
01422 = irplib_framelist_get_propertylist_const(obj, ibelow);
01423
01424 const int istop = irplib_pfits_get_int(plist, "NAXIS3") - 2;
01425 const int istart = NACO_MAX(0, istop - nskyplane + 1);
01426
01427 skip_if_lt(istop - istart, 2, "sky planes for median");
01428
01429 belowcube = cpl_imagelist_new();
01430
01431 for (i = istart; i <= istop; i++) {
01432 self = cpl_image_load(filename, CPL_TYPE_FLOAT, i, EXT0);
01433
01434 any_if("Could not load plane %d from frame %d/%d, file=%s",
01435 1+i, 1+ibelow, nframes, filename);
01436
01437 bug_if(cpl_imagelist_set(belowcube, self, i - istart));
01438 }
01439
01440 } else {
01441 int naxis3;
01442
01443 belowcube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
01444
01445 any_if("Could not load cube from frame %d/%d, file=%s",
01446 1+ibelow, nframes, filename);
01447
01448 naxis3 = cpl_imagelist_get_size(belowcube);
01449
01450 bug_if(naxis3 < 3);
01451
01452 cpl_image_delete(cpl_imagelist_unset(belowcube, naxis3-1));
01453
01454 }
01455
01456 }
01457
01458 if (iabove < nframes) {
01459 const char * filename
01460 = cpl_frame_get_filename(irplib_framelist_get_const(obj, iabove));
01461
01462 if (nskyplane > 0) {
01463
01464 const cpl_propertylist * plist
01465 = irplib_framelist_get_propertylist_const(obj, iabove);
01466 const int istart = 0;
01467
01468 const int istop = NACO_MIN(nskyplane-1, irplib_pfits_get_int
01469 (plist, "NAXIS3") - 2);
01470
01471 skip_if_lt(istop - istart, 2, "sky planes for median");
01472
01473 abovecube = cpl_imagelist_new();
01474
01475 for (i = istart; i <= istop; i++) {
01476 self = cpl_image_load(filename, CPL_TYPE_FLOAT, i, EXT0);
01477
01478 any_if("Could not load plane %d from frame %d/%d, file=%s",
01479 1+i, 1+iabove, nframes, filename);
01480
01481 bug_if(cpl_imagelist_set(abovecube, self, i - istart));
01482 }
01483
01484 } else {
01485
01486 int naxis3;
01487
01488 abovecube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
01489
01490 any_if("Could not load cube from frame %d/%d, file=%s",
01491 1+iabove, nframes, filename);
01492
01493 naxis3 = cpl_imagelist_get_size(abovecube);
01494
01495 bug_if(naxis3 < 3);
01496
01497 cpl_image_delete(cpl_imagelist_unset(abovecube, naxis3-1));
01498 }
01499
01500 }
01501
01502 error_if(belowcube == NULL && abovecube == NULL, CPL_ERROR_DATA_NOT_FOUND,
01503 "No cube(s) available for sky estimation among %d object frames",
01504 nframes);
01505
01506 if (belowcube == NULL) {
01507 skycube = abovecube;
01508 } else if (abovecube == NULL) {
01509 skycube = belowcube;
01510 } else {
01511
01512
01513 const int nbelow = cpl_imagelist_get_size(belowcube);
01514 const int nabove = cpl_imagelist_get_size(abovecube);
01515 int nwrap = 0;
01516
01517 skycube = cpl_imagelist_new();
01518
01519 for (i = 0; i < nbelow; i++) {
01520 skip_if(cpl_imagelist_set(skycube, cpl_imagelist_get(belowcube, i),
01521 nwrap++));
01522 }
01523 for (i = 0; i < nabove; i++) {
01524 skip_if(cpl_imagelist_set(skycube, cpl_imagelist_get(abovecube, i),
01525 nwrap++));
01526 }
01527 skip_if(cpl_imagelist_get_size(skycube) != nwrap);
01528 skip_if(nbelow + nabove != nwrap);
01529 }
01530
01531 self = cpl_imagelist_collapse_median_create(skycube);
01532
01533 #ifndef NACO_IMG_JITTER_KEEP_SKY_OBJECTS
01534 if (belowcube == NULL || abovecube == NULL) {
01535
01536 const cpl_mask * fill2bpm;
01537 const cpl_mask * selfbpm = NULL;
01538 const double lo_skysigma = 0.2;
01539 const double hi_skysigma = 5.0;
01540
01541 skip_if(naco_img_jitter_reject_objects(self, lo_skysigma, hi_skysigma));
01542
01543 selfbpm = cpl_image_get_bpm_const(self);
01544
01545 if (selfbpm != NULL) {
01546 const cpl_mask * mybpm;
01547
01548
01549
01550 const char * filename
01551 = cpl_frame_get_filename(irplib_framelist_get_const(obj, isky));
01552 int naxis3;
01553
01554 mycube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
01555
01556 any_if("Could not load cube from frame %d/%d, file=%s",
01557 1+isky, nframes, filename);
01558
01559 naxis3 = cpl_imagelist_get_size(mycube);
01560
01561 bug_if(naxis3 < 3);
01562
01563 cpl_image_delete(cpl_imagelist_unset(mycube, naxis3-1));
01564
01565 mysky = cpl_imagelist_collapse_median_create(mycube);
01566
01567 skip_if(naco_img_jitter_reject_objects(mysky, lo_skysigma,
01568 hi_skysigma));
01569
01570
01571
01572
01573 mybpm = cpl_image_get_bpm_const(mysky);
01574
01575 if (mybpm == NULL) {
01576
01577 fill2bpm = selfbpm;
01578 } else {
01579
01580
01581 fillbpm = cpl_mask_duplicate(mybpm);
01582 bug_if(cpl_mask_not(fillbpm));
01583 bug_if(cpl_mask_and(fillbpm, selfbpm));
01584
01585 fill2bpm = fillbpm;
01586
01587 }
01588 cpl_msg_info(cpl_func, "Filling %d object-pixels in sky image "
01589 "with %d sky-pixels from object image",
01590 (int)cpl_mask_count(selfbpm),
01591 (int)cpl_mask_count(fill2bpm));
01592 if (fill2bpm != selfbpm) {
01593
01594 bug_if(cpl_image_reject_from_mask(self, fill2bpm));
01595 }
01596
01597 if (fillbpm == NULL) {
01598 fillbpm = cpl_mask_duplicate(fill2bpm);
01599 } else if (fillbpm != fill2bpm) {
01600 bug_if(cpl_mask_copy(fillbpm, fill2bpm, 1, 1));
01601 }
01602
01603 bug_if(cpl_image_fill_rejected(self, 0.0));
01604 bug_if(cpl_image_accept_all(self));
01605
01606 bug_if(cpl_mask_not(fillbpm));
01607 bug_if(cpl_image_reject_from_mask(mysky, fillbpm));
01608 bug_if(cpl_image_fill_rejected(mysky, 0.0));
01609 bug_if(cpl_image_accept_all(mysky));
01610 bug_if(cpl_image_add(self, mysky));
01611 }
01612 }
01613 #endif
01614
01615 end_skip;
01616
01617 if (cpl_error_get_code()) {
01618 cpl_image_delete(self);
01619 self = NULL;
01620 }
01621
01622
01623 if (skycube != belowcube && skycube != abovecube) {
01624 int nwrap = cpl_imagelist_get_size(skycube);
01625
01626
01627 for (;nwrap > 0;) {
01628 (void)cpl_imagelist_unset(skycube, --nwrap);
01629 }
01630
01631 cpl_imagelist_delete(skycube);
01632 }
01633
01634 cpl_mask_delete(fillbpm);
01635 cpl_image_delete(mysky);
01636 cpl_imagelist_delete(mycube);
01637 cpl_imagelist_delete(belowcube);
01638 cpl_imagelist_delete(abovecube);
01639
01640 return self;
01641 }
01642
01643
01644
01655
01656 static
01657 cpl_error_code naco_img_jitter_imagelist_wrap_nocube(cpl_imagelist * self,
01658 const cpl_array * iscube,
01659 cpl_imagelist * other)
01660 {
01661
01662 const int ncube = cpl_imagelist_get_size(other);
01663 int nwrap = cpl_imagelist_get_size(self);
01664 int i;
01665
01666 bug_if(self == NULL);
01667 bug_if(iscube == NULL);
01668 bug_if(other == NULL);
01669 bug_if(nwrap != 0);
01670 bug_if(cpl_array_get_size(iscube) != ncube);
01671
01672 for (i = 0; i < ncube; i++) {
01673 int is_invalid;
01674
01675 (void)cpl_array_get_int(iscube, i, &is_invalid);
01676
01677 if (is_invalid) {
01678 cpl_imagelist_set(self, cpl_imagelist_get(other, i), nwrap);
01679 nwrap++;
01680 }
01681 }
01682
01683 bug_if(cpl_imagelist_get_size(self) != nwrap);
01684
01685 end_skip;
01686
01687 return cpl_error_get_code();
01688 }
01689
01690
01691 #ifndef NACO_IMG_JITTER_KEEP_SKY_OBJECTS
01692
01693
01704
01705 static cpl_error_code naco_img_jitter_reject_objects(cpl_image * self,
01706 double lo_sigma,
01707 double hi_sigma)
01708 {
01709 double median;
01710 double med_dist = DBL_MAX;
01711 double hi_threshold;
01712 cpl_mask * hi_objects = NULL;
01713 cpl_mask * lo_objects = NULL;
01714 cpl_mask * rejects = NULL;
01715 cpl_image * hi_label = NULL;
01716 cpl_image * lo_label = NULL;
01717 cpl_apertures * hi_apert = NULL;
01718 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
01719 cpl_mask * kernel = NULL;
01720 #else
01721 cpl_matrix * kernel = NULL;
01722 #endif
01723
01724
01725 bug_if(self == NULL);
01726 bug_if(lo_sigma <= 0.0);
01727 bug_if(hi_sigma < lo_sigma);
01728
01729
01730 median = cpl_image_get_median_dev(self, &med_dist);
01731 hi_threshold = median + hi_sigma * med_dist;
01732
01733
01734 hi_objects = cpl_mask_threshold_image_create(self, hi_threshold, DBL_MAX);
01735 bug_if(hi_objects == NULL);
01736
01737
01738
01739 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
01740 kernel = cpl_mask_new(3, 3);
01741 bug_if(cpl_mask_not(kernel));
01742 bug_if(cpl_mask_filter(hi_objects, hi_objects, kernel, CPL_FILTER_OPENING,
01743 CPL_BORDER_ZERO));
01744 #else
01745 kernel = cpl_matrix_new(3, 3);
01746 bug_if(cpl_matrix_fill(kernel, 1.0));
01747 bug_if (cpl_mask_opening(hi_objects, kernel));
01748 #endif
01749
01750 if (!cpl_mask_is_empty(hi_objects)) {
01751
01752
01753
01754 const double lo_threshold = median + lo_sigma * med_dist;
01755 cpl_size hi_ilabel, hi_nlabel, lo_nlabel;
01756
01757
01758 lo_objects = cpl_mask_threshold_image_create(self, lo_threshold, DBL_MAX);
01759 bug_if(lo_objects == NULL);
01760 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
01761 bug_if(cpl_mask_filter(lo_objects, lo_objects, kernel,
01762 CPL_FILTER_OPENING, CPL_BORDER_ZERO));
01763 #else
01764 bug_if (cpl_mask_opening(lo_objects, kernel));
01765 #endif
01766
01767 hi_label = cpl_image_labelise_mask_create(hi_objects, &hi_nlabel);
01768 lo_label = cpl_image_labelise_mask_create(lo_objects, &lo_nlabel);
01769
01770 hi_apert = cpl_apertures_new_from_image(self, hi_label);
01771 bug_if(hi_apert == NULL);
01772
01773 for (hi_ilabel = 1; hi_ilabel <= hi_nlabel; hi_ilabel++) {
01774
01775 const int pos_x = cpl_apertures_get_top_x(hi_apert, hi_ilabel);
01776 const int pos_y = cpl_apertures_get_top(hi_apert, hi_ilabel);
01777
01778 int is_rejected;
01779 const int lo_ilabel = (int)cpl_image_get(lo_label, pos_x, pos_y,
01780 &is_rejected);
01781
01782
01783 cpl_mask_delete(rejects);
01784 rejects = cpl_mask_threshold_image_create(lo_label,
01785 (double)lo_ilabel - 0.5,
01786 (double)lo_ilabel + 0.5);
01787
01788
01789 cpl_mask_or(hi_objects, rejects);
01790
01791 }
01792
01793 cpl_msg_info(cpl_func, "Found %d object(s) of %d pixel(s) "
01794 "in sky image using sigmas %g and %g", (int)hi_nlabel,
01795 (int)cpl_mask_count(hi_objects), lo_sigma, hi_sigma);
01796 bug_if(cpl_image_reject_from_mask(self, hi_objects));
01797
01798 }
01799
01800 end_skip;
01801
01802 cpl_apertures_delete(hi_apert);
01803 cpl_image_delete(hi_label);
01804 cpl_image_delete(lo_label);
01805 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
01806 cpl_mask_delete(kernel);
01807 #else
01808 cpl_matrix_delete(kernel);
01809 #endif
01810 cpl_mask_delete(hi_objects);
01811 cpl_mask_delete(lo_objects);
01812 cpl_mask_delete(rejects);
01813
01814 return cpl_error_get_code();
01815 }
01816 #endif
01817
01818
01819
01820
01830
01831 static cpl_image * naco_img_jitter_saa_lucky(const cpl_imagelist * cube,
01832 const cpl_vector * strehl,
01833 const cpl_bivector * offs,
01834 double fraction)
01835 {
01836
01837 cpl_image * self = NULL;
01838 const int ncube = cpl_imagelist_get_size(cube);
01839 const int mcube = NACO_MAX(NACO_MIN(ncube, (int)(0.5 + fraction * ncube)),
01840 1);
01841 cpl_imagelist * lcube = NULL;
01842 const cpl_imagelist * ucube;
01843 cpl_vector * lstrehl = mcube == ncube ? (cpl_vector*)strehl
01844 : cpl_vector_duplicate(strehl);
01845
01846
01847 cpl_bivector * loffs = cpl_bivector_duplicate(offs);
01848 cpl_vector * loffsx = cpl_bivector_get_x(loffs);
01849 cpl_vector * loffsy = cpl_bivector_get_y(loffs);
01850 cpl_table * tsort = NULL;
01851 cpl_propertylist * psort = NULL;
01852 int i;
01853
01854
01855 bug_if(cpl_vector_get_size(strehl) != ncube);
01856 bug_if(cpl_bivector_get_size(offs) != ncube);
01857 bug_if(fraction <= 0.0);
01858 bug_if(fraction > 1.0);
01859
01860 if (mcube < ncube) {
01861 double strehlmin;
01862 int * pindex;
01863
01864 tsort = cpl_table_new(ncube);
01865 psort = cpl_propertylist_new();
01866
01867
01868 bug_if(cpl_propertylist_append_bool(psort, "LSTREHL", CPL_TRUE));
01869
01870 bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(lstrehl),
01871 "LSTREHL"));
01872 bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(loffsx),
01873 "LOFFSX"));
01874 bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(loffsy),
01875 "LOFFSY"));
01876 bug_if(cpl_table_new_column(tsort, "INDEX", CPL_TYPE_INT));
01877
01878
01879 pindex = cpl_table_get_data_int(tsort, "INDEX");
01880 for (i = 0; i < ncube; i++) {
01881 pindex[i] = i;
01882 }
01883
01884 bug_if(cpl_table_sort(tsort, psort));
01885
01886
01887 lcube = cpl_imagelist_new();
01888
01889
01890 for (i = 0; i < mcube; i++) {
01891 const int j = pindex[i];
01892 const cpl_image * image = cpl_imagelist_get_const(cube, j);
01893
01894 cpl_imagelist_set(lcube, (cpl_image*)image, i);
01895 }
01896
01897
01898
01899 bug_if(cpl_vector_set_size(loffsx, mcube));
01900 bug_if(cpl_vector_set_size(loffsy, mcube));
01901
01902 strehlmin = cpl_vector_get(lstrehl, mcube - 1);
01903 cpl_vector_delete(lstrehl);
01904 lstrehl = NULL;
01905
01906 cpl_msg_info(cpl_func, "%g%% (%d/%d) lucky mode at Strehl=%g",
01907 100.0*fraction, mcube, ncube, strehlmin);
01908 }
01909 ucube = lcube ? lcube : cube;
01910
01911 self = naco_img_jitter_saa_center(ucube, loffs);
01912 any_if("Could not center and saa %d-cube", ncube);
01913
01914 end_skip;
01915
01916 if (lcube != NULL) {
01917
01918 for (i = cpl_imagelist_get_size(lcube); i > 0;) {
01919 (void)cpl_imagelist_unset(lcube, --i);
01920 }
01921
01922 cpl_imagelist_delete(lcube);
01923 }
01924
01925 if (lstrehl != strehl)
01926 cpl_vector_delete(lstrehl);
01927
01928 cpl_bivector_delete(loffs);
01929
01930 if (tsort != NULL) {
01931 if (cpl_table_has_column(tsort, "LSTREHL"))
01932 (void)cpl_table_unwrap(tsort, "LSTREHL");
01933 if (cpl_table_has_column(tsort, "LOFFSX"))
01934 (void)cpl_table_unwrap(tsort, "LOFFSX");
01935 if (cpl_table_has_column(tsort, "LOFFSY"))
01936 (void)cpl_table_unwrap(tsort, "LOFFSY");
01937 cpl_table_delete(tsort);
01938 }
01939 cpl_propertylist_delete(psort);
01940
01941 return self;
01942 }
01943
01944
01945
01953
01954 static
01955 cpl_error_code naco_img_jitter_find_strehl(const cpl_imagelist * self,
01956 const irplib_framelist * objframes)
01957 {
01958
01959 const int nobj = irplib_framelist_get_size(objframes);
01960 cpl_apertures * apert = NULL;
01961 cpl_vector * sigmas = NULL;
01962 double psigmas[] = {5.0, 2.0, 1.0, 0.5};
01963 const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
01964
01965
01966 const double rstar = 0.5 * STREHL_STAR_RADIUS;
01967 const double rbgint = 0.5 * STREHL_BACKGROUND_R1;
01968 const double rbgext = 0.5 * STREHL_BACKGROUND_R2;
01969 cpl_size isigma = 0;
01970 int i;
01971
01972
01973 skip_if(rbgext <= rbgint);
01974
01975 bug_if(cpl_imagelist_get_size(self) != nobj);
01976
01977
01978 sigmas = cpl_vector_wrap(nsigmas, psigmas);
01979
01980 for (i = 0; i < nobj; i++) {
01981 const cpl_propertylist * plist
01982 = irplib_framelist_get_propertylist_const(objframes, i);
01983 const cpl_image * oimage = cpl_imagelist_get_const(self, i);
01984
01985 const double pixscale = naco_pfits_get_pixscale(plist);
01986 const char * filter = naco_pfits_get_filter(plist);
01987 double lam = DBL_MAX;
01988 double dlam = DBL_MAX;
01989
01990 double cent_x, cent_y;
01991 double strehl = 0, strehl_err, star_bg,star_peak, star_flux;
01992 double psf_peak, psf_flux, bg_noise;
01993 int iflux;
01994
01995
01996 skip_if(pixscale <= 0.0);
01997
01998 irplib_check(naco_get_filter_infos(filter, &lam, &dlam),
01999 "Frame %d has no info for filter %s", 1+i, filter);
02000
02001 cpl_apertures_delete(apert);
02002 apert = cpl_apertures_extract(oimage, sigmas, &isigma);
02003
02004 any_if("No object found in combined image of frame %d", 1+i);
02005
02006 bug_if(irplib_apertures_find_max_flux(apert, &iflux, 1));
02007
02008 cent_x = cpl_apertures_get_centroid_x(apert, iflux);
02009 cent_y = cpl_apertures_get_centroid_y(apert, iflux);
02010
02011 skip_if (irplib_strehl_compute(oimage, STREHL_M1, STREHL_M2, lam, dlam,
02012 pixscale, STREHL_BOX_SIZE, cent_x, cent_y,
02013 rstar, rbgint, rbgext, -1, -1,
02014 &strehl, &strehl_err,
02015 &star_bg, &star_peak, &star_flux,
02016 &psf_peak, &psf_flux,
02017 &bg_noise));
02018 cpl_msg_info(cpl_func, "Image of frame %d/%d has strehl=%g at (x,y)"
02019 "=(%g,%g)", 1+i, nobj, strehl, cent_x, cent_y);
02020 }
02021
02022 end_skip;
02023
02024 (void)cpl_vector_unwrap(sigmas);
02025 cpl_apertures_delete(apert);
02026
02027 return cpl_error_get_code();
02028 }
02029
02030
02031
02032
02040
02041 static cpl_image * naco_img_jitter_saa_center(const cpl_imagelist * cube,
02042 cpl_bivector * offs)
02043 {
02044
02045 const int ncube = cpl_imagelist_get_size(cube);
02046 cpl_image * self = NULL;
02047 const cpl_image * image;
02048 cpl_image ** combined = NULL;
02049 cpl_imagelist * ccube = NULL;
02050 const cpl_imagelist * ucube;
02051 cpl_vector * offsx = cpl_bivector_get_x(offs);
02052 cpl_vector * offsy = cpl_bivector_get_y(offs);
02053 double * doffsx = cpl_vector_get_data(offsx);
02054 double * doffsy = cpl_vector_get_data(offsy);
02055 const double med_x = cpl_vector_get_median_const(offsx);
02056 const double med_y = cpl_vector_get_median_const(offsy);
02057 double pos_x, pos_y;
02058 double minsqdist = DBL_MAX;
02059 int imin = -1;
02060 int i;
02061
02062
02063 bug_if(cpl_bivector_get_size(offs) != ncube);
02064
02065
02066 for (i = 0; i < ncube; i++) {
02067 const double x = cpl_vector_get(offsx, i);
02068 const double y = cpl_vector_get(offsy, i);
02069 const double sqdist
02070 = (x - med_x) * (x - med_x) + (y - med_y) * (y - med_y);
02071
02072 if (sqdist < minsqdist) {
02073 minsqdist = sqdist;
02074 imin = i;
02075 }
02076 }
02077
02078 cpl_msg_info(cpl_func, "Plane %d/%d has minimal object distance %g "
02079 "from median (x,y)=(%g,%g)", 1+imin, ncube,
02080 sqrt(minsqdist), med_x, med_y);
02081
02082
02083 if (imin > 0) {
02084
02085
02086 ccube = cpl_imagelist_new();
02087
02088 image = cpl_imagelist_get_const(cube, imin);
02089 bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, 0));
02090
02091 for (i = 0; i < imin; i++) {
02092 image = cpl_imagelist_get_const(cube, i);
02093 bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, 1+i));
02094 }
02095 for (i = 1+imin; i < ncube; i++) {
02096 image = cpl_imagelist_get_const(cube, i);
02097 bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, i));
02098 }
02099
02100 bug_if(cpl_imagelist_get_size(ccube) != ncube);
02101
02102
02103 pos_x = cpl_vector_get(offsx, imin);
02104 pos_y = cpl_vector_get(offsy, imin);
02105
02106
02107 memmove(doffsx + 1, doffsx, (size_t)imin * sizeof(*doffsx));
02108 memmove(doffsy + 1, doffsy, (size_t)imin * sizeof(*doffsy));
02109
02110
02111 cpl_vector_set(offsx, 0, pos_x);
02112 cpl_vector_set(offsy, 0, pos_y);
02113 }
02114 ucube = ccube ? ccube : cube;
02115
02116
02117 cpl_vector_subtract_scalar(offsx, cpl_vector_get(offsx, 0));
02118 cpl_vector_subtract_scalar(offsy, cpl_vector_get(offsy, 0));
02119 cpl_vector_multiply_scalar(offsx, -1.0);
02120 cpl_vector_multiply_scalar(offsy, -1.0);
02121
02122 combined = cpl_geom_img_offset_saa(ucube, offs, CPL_KERNEL_DEFAULT,
02123 0, 0, CPL_GEOM_FIRST, &pos_x, &pos_y);
02124
02125 any_if("Could not shift and add %d-cube", ncube);
02126
02127 cpl_msg_info(cpl_func, "Shift-and-added %d-cube, 1st pos=(%g,%g)",
02128 ncube, pos_x, pos_y);
02129
02130 self = combined[0];
02131 cpl_image_delete(combined[1]);
02132 combined[0] = NULL;
02133 combined[1] = NULL;
02134
02135 end_skip;
02136
02137 if (combined != NULL) {
02138 cpl_image_delete(combined[0]);
02139 cpl_image_delete(combined[1]);
02140 cpl_free(combined);
02141 }
02142
02143 if (ccube != NULL) {
02144
02145 for (i = cpl_imagelist_get_size(ccube); i > 0;) {
02146 (void)cpl_imagelist_unset(ccube, --i);
02147 }
02148
02149 cpl_imagelist_delete(ccube);
02150 }
02151
02152 return self;
02153 }