00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027
00028
00029
00030
00031 #include <string.h>
00032 #include <strings.h>
00033 #include <cpl.h>
00034
00035 #include "muse_exp_align_z.h"
00036
00037
00048
00051
00052
00053
00054 static const char *muse_exp_align_help =
00055 "Compute the coordinate offset for each input field-of-view image with respect to a reference. The created list of coordinate offsets can then be used in muse_exp_combine as the field coordinate offsets to properly align the exposures during their combination.";
00056
00057 static const char *muse_exp_align_help_esorex =
00058 "\n\nInput frames for raw frame tag \"IMAGE_FOV\":\n"
00059 "\n Frame tag Type Req #Fr Description"
00060 "\n -------------------- ---- --- --- ------------"
00061 "\n IMAGE_FOV raw Y >=2 Input field-of-view images"
00062 "\n\nProduct frames for raw frame tag \"IMAGE_FOV\":\n"
00063 "\n Frame tag Level Description"
00064 "\n -------------------- -------- ------------"
00065 "\n OFFSET_LIST final List of computed coordinate offsets.";
00066
00067
00075
00076 static cpl_recipeconfig *
00077 muse_exp_align_new_recipeconfig(void)
00078 {
00079 cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
00080
00081 cpl_recipeconfig_set_tag(recipeconfig, "IMAGE_FOV", 2, -1);
00082 cpl_recipeconfig_set_output(recipeconfig, "IMAGE_FOV", "OFFSET_LIST");
00083
00084 return recipeconfig;
00085 }
00086
00087
00097
00098 static cpl_error_code
00099 muse_exp_align_prepare_header(const char *aFrametag, cpl_propertylist *aHeader)
00100 {
00101 cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
00102 cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
00103 if (!strcmp(aFrametag, "OFFSET_LIST")) {
00104 muse_processing_prepare_property(aHeader, "ESO QC EXPALIGN NDET[0-9]+",
00105 CPL_TYPE_INT,
00106 "Number of detected sources for input image i");
00107 muse_processing_prepare_property(aHeader, "ESO QC EXPALIGN NMATCH[0-9]+",
00108 CPL_TYPE_INT,
00109 "Median number of matches of input image i with other images");
00110 muse_processing_prepare_property(aHeader, "ESO QC EXPALIGN NMATCH MIN",
00111 CPL_TYPE_INT,
00112 "Minimum of the median number of matches for all input images");
00113 muse_processing_prepare_property(aHeader, "ESO QC EXPALIGN NOMATCH",
00114 CPL_TYPE_INT,
00115 "Number of input images that do not have any matches with other images");
00116 muse_processing_prepare_property(aHeader, "ESO QC EXPALIGN OFFSET RA MIN",
00117 CPL_TYPE_DOUBLE,
00118 "[deg] RA minimum offset.");
00119 muse_processing_prepare_property(aHeader, "ESO QC EXPALIGN OFFSET RA MAX",
00120 CPL_TYPE_DOUBLE,
00121 "[deg] RA maximum offset.");
00122 muse_processing_prepare_property(aHeader, "ESO QC EXPALIGN OFFSET RA MEAN",
00123 CPL_TYPE_DOUBLE,
00124 "[deg] RA mean offset.");
00125 muse_processing_prepare_property(aHeader, "ESO QC EXPALIGN OFFSET RA STDEV",
00126 CPL_TYPE_DOUBLE,
00127 "[deg] Standard deviation of RA offsets.");
00128 muse_processing_prepare_property(aHeader, "ESO QC EXPALIGN OFFSET DEC MIN",
00129 CPL_TYPE_DOUBLE,
00130 "[deg] DEC minimum offset.");
00131 muse_processing_prepare_property(aHeader, "ESO QC EXPALIGN OFFSET DEC MAX",
00132 CPL_TYPE_DOUBLE,
00133 "[deg] DEC maximum offset.");
00134 muse_processing_prepare_property(aHeader, "ESO QC EXPALIGN OFFSET DEC MEAN",
00135 CPL_TYPE_DOUBLE,
00136 "[deg] DEC mean offset.");
00137 muse_processing_prepare_property(aHeader, "ESO QC EXPALIGN OFFSET DEC STDEV",
00138 CPL_TYPE_DOUBLE,
00139 "[deg] Standard deviation of DEC offsets.");
00140 } else {
00141 cpl_msg_warning(__func__, "Frame tag %s is not defined", aFrametag);
00142 return CPL_ERROR_ILLEGAL_INPUT;
00143 }
00144 return CPL_ERROR_NONE;
00145 }
00146
00147
00156
00157 static cpl_frame_level
00158 muse_exp_align_get_frame_level(const char *aFrametag)
00159 {
00160 if (!aFrametag) {
00161 return CPL_FRAME_LEVEL_NONE;
00162 }
00163 if (!strcmp(aFrametag, "OFFSET_LIST")) {
00164 return CPL_FRAME_LEVEL_FINAL;
00165 }
00166 return CPL_FRAME_LEVEL_NONE;
00167 }
00168
00169
00178
00179 static muse_frame_mode
00180 muse_exp_align_get_frame_mode(const char *aFrametag)
00181 {
00182 if (!aFrametag) {
00183 return MUSE_FRAME_MODE_ALL;
00184 }
00185 if (!strcmp(aFrametag, "OFFSET_LIST")) {
00186 return MUSE_FRAME_MODE_MASTER;
00187 }
00188 return MUSE_FRAME_MODE_ALL;
00189 }
00190
00191
00201
00202 static int
00203 muse_exp_align_create(cpl_plugin *aPlugin)
00204 {
00205
00206 cpl_recipe *recipe;
00207 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
00208 recipe = (cpl_recipe *)aPlugin;
00209 } else {
00210 return -1;
00211 }
00212
00213
00214
00215 muse_processinginfo_register(recipe,
00216 muse_exp_align_new_recipeconfig(),
00217 muse_exp_align_prepare_header,
00218 muse_exp_align_get_frame_level,
00219 muse_exp_align_get_frame_mode);
00220
00221
00222
00223 if (muse_cplframework() == MUSE_CPLFRAMEWORK_ESOREX) {
00224 cpl_msg_set_time_on();
00225 }
00226
00227
00228 recipe->parameters = cpl_parameterlist_new();
00229
00230 cpl_parameter *p;
00231
00232
00233
00234
00235 p = cpl_parameter_new_value("muse.muse_exp_align.rsearch",
00236 CPL_TYPE_STRING,
00237 "Search radius (in arcsec) for each iteration of the offset computation.",
00238 "muse.muse_exp_align",
00239 (const char *)"30.,4.,2.,0.8");
00240 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "rsearch");
00241 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rsearch");
00242
00243 cpl_parameterlist_append(recipe->parameters, p);
00244
00245
00246
00247
00248
00249 p = cpl_parameter_new_value("muse.muse_exp_align.nbins",
00250 CPL_TYPE_INT,
00251 "Number of bins to use for 2D histogram on the first iteration of the offset computation.",
00252 "muse.muse_exp_align",
00253 (int)60);
00254 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nbins");
00255 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nbins");
00256
00257 cpl_parameterlist_append(recipe->parameters, p);
00258
00259
00260 p = cpl_parameter_new_value("muse.muse_exp_align.weight",
00261 CPL_TYPE_BOOL,
00262 "Use weighting.",
00263 "muse.muse_exp_align",
00264 (int)TRUE);
00265 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "weight");
00266 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "weight");
00267
00268 cpl_parameterlist_append(recipe->parameters, p);
00269
00270
00271 p = cpl_parameter_new_value("muse.muse_exp_align.fwhm",
00272 CPL_TYPE_DOUBLE,
00273 "FWHM in pixels of the convolution filter.",
00274 "muse.muse_exp_align",
00275 (double)5.);
00276 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "fwhm");
00277 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fwhm");
00278
00279 cpl_parameterlist_append(recipe->parameters, p);
00280
00281
00282
00283
00284
00285 p = cpl_parameter_new_value("muse.muse_exp_align.threshold",
00286 CPL_TYPE_DOUBLE,
00287 "Initial intensity threshold for detecting point sources in sigma above background RMS.",
00288 "muse.muse_exp_align",
00289 (double)15.);
00290 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "threshold");
00291 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "threshold");
00292
00293 cpl_parameterlist_append(recipe->parameters, p);
00294
00295
00296 p = cpl_parameter_new_value("muse.muse_exp_align.step",
00297 CPL_TYPE_DOUBLE,
00298 "Increment/decrement of the threshold value in subsequent iterations.",
00299 "muse.muse_exp_align",
00300 (double)0.5);
00301 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "step");
00302 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "step");
00303
00304 cpl_parameterlist_append(recipe->parameters, p);
00305
00306
00307 p = cpl_parameter_new_value("muse.muse_exp_align.iterations",
00308 CPL_TYPE_INT,
00309 "Maximum number of iterations used for detecting sources.",
00310 "muse.muse_exp_align",
00311 (int)100000);
00312 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "iterations");
00313 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "iterations");
00314
00315 cpl_parameterlist_append(recipe->parameters, p);
00316
00317
00318 p = cpl_parameter_new_value("muse.muse_exp_align.srcmin",
00319 CPL_TYPE_INT,
00320 "Minimum number of sources which must be found.",
00321 "muse.muse_exp_align",
00322 (int)5);
00323 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "srcmin");
00324 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "srcmin");
00325
00326 cpl_parameterlist_append(recipe->parameters, p);
00327
00328
00329 p = cpl_parameter_new_value("muse.muse_exp_align.srcmax",
00330 CPL_TYPE_INT,
00331 "Maximum number of sources which may be found.",
00332 "muse.muse_exp_align",
00333 (int)80);
00334 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "srcmax");
00335 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "srcmax");
00336
00337 cpl_parameterlist_append(recipe->parameters, p);
00338
00339
00340 p = cpl_parameter_new_value("muse.muse_exp_align.roundmin",
00341 CPL_TYPE_DOUBLE,
00342 "Lower limit of the allowed point-source roundness.",
00343 "muse.muse_exp_align",
00344 (double)-1.);
00345 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "roundmin");
00346 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "roundmin");
00347
00348 cpl_parameterlist_append(recipe->parameters, p);
00349
00350
00351 p = cpl_parameter_new_value("muse.muse_exp_align.roundmax",
00352 CPL_TYPE_DOUBLE,
00353 "Upper limit of the allowed point-source roundness.",
00354 "muse.muse_exp_align",
00355 (double)1.);
00356 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "roundmax");
00357 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "roundmax");
00358
00359 cpl_parameterlist_append(recipe->parameters, p);
00360
00361
00362 p = cpl_parameter_new_value("muse.muse_exp_align.sharpmin",
00363 CPL_TYPE_DOUBLE,
00364 "Lower limit of the allowed point-source sharpness.",
00365 "muse.muse_exp_align",
00366 (double)0.2);
00367 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "sharpmin");
00368 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sharpmin");
00369
00370 cpl_parameterlist_append(recipe->parameters, p);
00371
00372
00373 p = cpl_parameter_new_value("muse.muse_exp_align.sharpmax",
00374 CPL_TYPE_DOUBLE,
00375 "Upper limit of the allowed point-source sharpness.",
00376 "muse.muse_exp_align",
00377 (double)1.);
00378 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "sharpmax");
00379 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sharpmax");
00380
00381 cpl_parameterlist_append(recipe->parameters, p);
00382
00383 return 0;
00384 }
00385
00386
00397
00398 static int
00399 muse_exp_align_params_fill(muse_exp_align_params_t *aParams, cpl_parameterlist *aParameters)
00400 {
00401 cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
00402 cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
00403 cpl_parameter *p;
00404
00405 p = cpl_parameterlist_find(aParameters, "muse.muse_exp_align.rsearch");
00406 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00407 aParams->rsearch = cpl_parameter_get_string(p);
00408
00409 p = cpl_parameterlist_find(aParameters, "muse.muse_exp_align.nbins");
00410 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00411 aParams->nbins = cpl_parameter_get_int(p);
00412
00413 p = cpl_parameterlist_find(aParameters, "muse.muse_exp_align.weight");
00414 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00415 aParams->weight = cpl_parameter_get_bool(p);
00416
00417 p = cpl_parameterlist_find(aParameters, "muse.muse_exp_align.fwhm");
00418 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00419 aParams->fwhm = cpl_parameter_get_double(p);
00420
00421 p = cpl_parameterlist_find(aParameters, "muse.muse_exp_align.threshold");
00422 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00423 aParams->threshold = cpl_parameter_get_double(p);
00424
00425 p = cpl_parameterlist_find(aParameters, "muse.muse_exp_align.step");
00426 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00427 aParams->step = cpl_parameter_get_double(p);
00428
00429 p = cpl_parameterlist_find(aParameters, "muse.muse_exp_align.iterations");
00430 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00431 aParams->iterations = cpl_parameter_get_int(p);
00432
00433 p = cpl_parameterlist_find(aParameters, "muse.muse_exp_align.srcmin");
00434 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00435 aParams->srcmin = cpl_parameter_get_int(p);
00436
00437 p = cpl_parameterlist_find(aParameters, "muse.muse_exp_align.srcmax");
00438 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00439 aParams->srcmax = cpl_parameter_get_int(p);
00440
00441 p = cpl_parameterlist_find(aParameters, "muse.muse_exp_align.roundmin");
00442 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00443 aParams->roundmin = cpl_parameter_get_double(p);
00444
00445 p = cpl_parameterlist_find(aParameters, "muse.muse_exp_align.roundmax");
00446 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00447 aParams->roundmax = cpl_parameter_get_double(p);
00448
00449 p = cpl_parameterlist_find(aParameters, "muse.muse_exp_align.sharpmin");
00450 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00451 aParams->sharpmin = cpl_parameter_get_double(p);
00452
00453 p = cpl_parameterlist_find(aParameters, "muse.muse_exp_align.sharpmax");
00454 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00455 aParams->sharpmax = cpl_parameter_get_double(p);
00456
00457 return 0;
00458 }
00459
00460
00467
00468 static int
00469 muse_exp_align_exec(cpl_plugin *aPlugin)
00470 {
00471 if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
00472 return -1;
00473 }
00474 muse_processing_recipeinfo(aPlugin);
00475 cpl_recipe *recipe = (cpl_recipe *)aPlugin;
00476 cpl_msg_set_threadid_on();
00477
00478 cpl_frameset *usedframes = cpl_frameset_new(),
00479 *outframes = cpl_frameset_new();
00480 muse_exp_align_params_t params;
00481 muse_exp_align_params_fill(¶ms, recipe->parameters);
00482
00483 cpl_errorstate prestate = cpl_errorstate_get();
00484
00485 muse_processing *proc = muse_processing_new("muse_exp_align",
00486 recipe);
00487 int rc = muse_exp_align_compute(proc, ¶ms);
00488 cpl_frameset_join(usedframes, proc->usedframes);
00489 cpl_frameset_join(outframes, proc->outframes);
00490 muse_processing_delete(proc);
00491
00492 if (!cpl_errorstate_is_equal(prestate)) {
00493
00494 cpl_errorstate_dump(prestate, CPL_FALSE, muse_cplerrorstate_dump_some);
00495
00496 cpl_msg_set_level(CPL_MSG_INFO);
00497 }
00498
00499 muse_cplframeset_erase_duplicate(usedframes);
00500 muse_cplframeset_erase_duplicate(outframes);
00501
00502
00503
00504
00505
00506 muse_cplframeset_erase_all(recipe->frames);
00507 cpl_frameset_join(recipe->frames, usedframes);
00508 cpl_frameset_join(recipe->frames, outframes);
00509 cpl_frameset_delete(usedframes);
00510 cpl_frameset_delete(outframes);
00511 return rc;
00512 }
00513
00514
00521
00522 static int
00523 muse_exp_align_destroy(cpl_plugin *aPlugin)
00524 {
00525
00526 cpl_recipe *recipe;
00527 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
00528 recipe = (cpl_recipe *)aPlugin;
00529 } else {
00530 return -1;
00531 }
00532
00533
00534 cpl_parameterlist_delete(recipe->parameters);
00535 muse_processinginfo_delete(recipe);
00536 return 0;
00537 }
00538
00539
00549
00550 int
00551 cpl_plugin_get_info(cpl_pluginlist *aList)
00552 {
00553 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00554 cpl_plugin *plugin = &recipe->interface;
00555
00556 char *helptext;
00557 if (muse_cplframework() == MUSE_CPLFRAMEWORK_ESOREX) {
00558 helptext = cpl_sprintf("%s%s", muse_exp_align_help,
00559 muse_exp_align_help_esorex);
00560 } else {
00561 helptext = cpl_sprintf("%s", muse_exp_align_help);
00562 }
00563
00564
00565 cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
00566 CPL_PLUGIN_TYPE_RECIPE,
00567 "muse_exp_align",
00568 "Create a coordinate offset table to be used to align exposures during exposure combination.",
00569 helptext,
00570 "Ralf Palsa",
00571 "usd-help@eso.org",
00572 muse_get_license(),
00573 muse_exp_align_create,
00574 muse_exp_align_exec,
00575 muse_exp_align_destroy);
00576 cpl_pluginlist_append(aList, plugin);
00577 cpl_free(helptext);
00578
00579 return 0;
00580 }
00581