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