FORS Pipeline Reference Manual 4.9.9
fors/fors_extract.c
00001 /* $Id: fors_extract.c,v 1.45 2011/10/13 14:29:24 cgarcia Exp $
00002  *
00003  * This file is part of the FORS Library
00004  * Copyright (C) 2002-2010 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00019  */
00020 
00021 /*
00022  * $Author: cgarcia $
00023  * $Date: 2011/10/13 14:29:24 $
00024  * $Revision: 1.45 $
00025  * $Name: fors-4_9_9 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <fors_extract.h>
00033 #include <fors_star.h>
00034 
00035 #include <fors_tools.h>
00036 #include <fors_dfs.h>
00037 #include <fors_pfits.h>
00038 #include <fors_utils.h>
00039 
00040 #include <cpl.h>
00041 
00042 #include <string.h>
00043 #include <stdbool.h>
00044 #include <math.h>
00045 
00052 /*-----------------------------------------------------------------------------
00053     (Proto)types
00054  -----------------------------------------------------------------------------*/
00055 
00056 struct _extract_method
00057 {
00058     enum {SEX, TEST} method;
00059     const char *sex_exe;
00060     const char *sex_config;
00061     const char *sex_mag;
00062     const char *sex_magerr;
00063     int sex_radius;
00064 };
00065 
00066 static fors_star_list *
00067 extract_sex(                                const fors_image *image,
00068                                             const fors_setting *setting,
00069                                             const char *sex_exe,
00070                                             const char *sex_config,
00071                                             const char *sex_mag,
00072                                             const char *sex_magerr,
00073                                             int radius,
00074                                             double magsyserr,
00075                                             fors_extract_sky_stats *sky_stats,
00076                                             cpl_image **background,
00077                                             cpl_table **extracted_sources);
00078 
00079 static fors_star_list *
00080 extract_test(                               fors_extract_sky_stats *sky_stats,
00081                                             cpl_image **background,
00082                                             cpl_table **extracted_sources);
00083 
00084 /*-----------------------------------------------------------------------------
00085     Implementation
00086  -----------------------------------------------------------------------------*/
00087 
00088 /*----------------------------------------------------------------------------*/
00098 /*----------------------------------------------------------------------------*/
00099 bool
00100 fors_extract_check_sex_flag(                unsigned int    sex_flag)
00101 {
00102     return (sex_flag == 0x0);
00103 }
00104 
00105 /*----------------------------------------------------------------------------*/
00120 /*----------------------------------------------------------------------------*/
00121 bool
00122 fors_extract_check_sex_star(                const fors_star *star,
00123                                             const cpl_image *ref_img)
00124 {
00125     bool    success = 1;
00126     
00127     if (star == NULL)
00128         return 0;
00129     
00130     success &= fors_star_check_values(star);
00131     
00132     success &= (star->magnitude < 98);
00133     
00134     if (ref_img != NULL)
00135     {
00136         success &= star->pixel->x >= 1;
00137         success &= star->pixel->x <= cpl_image_get_size_x(ref_img);
00138         success &= star->pixel->y >= 1;
00139         success &= star->pixel->y <= cpl_image_get_size_y(ref_img);
00140     }
00141     
00142     return success;
00143 }
00144 
00145 /*----------------------------------------------------------------------------*/
00151 /*----------------------------------------------------------------------------*/
00152 void 
00153 fors_extract_define_parameters(             cpl_parameterlist *parameters, 
00154                                             const char *context)
00155 {
00156     cpl_parameter *p;
00157     const char *full_name = NULL;
00158     const char *name;
00159     
00160     /*
00161     name = "extract_method";
00162     full_name = cpl_sprintf("%s.%s", context, name);
00163     p = cpl_parameter_new_enum(full_name,
00164                                CPL_TYPE_STRING,
00165                                "Source extraction method",
00166                                context,
00167                                "sex", 2,
00168                                "sex", "test");
00169     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00170     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00171     cpl_parameterlist_append(parameters, p);
00172     cpl_free((void *)full_name);
00173     */
00174 
00175     name = "sex_exe";
00176     full_name = cpl_sprintf("%s.%s", context, name);
00177     p = cpl_parameter_new_value(full_name,
00178                                 CPL_TYPE_STRING,
00179                                 "SExtractor executable",
00180                                 context,
00181                                 FORS_SEXTRACTOR_PATH "/sex");
00182     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00183     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00184     cpl_parameterlist_append(parameters, p);
00185     cpl_free((void *)full_name);
00186     
00187     name = "sex_config";
00188     full_name = cpl_sprintf("%s.%s", context, name);
00189     p = cpl_parameter_new_value(full_name,
00190                                 CPL_TYPE_STRING,
00191                                 "SExtractor configuration file",
00192                                 context,
00193                                 FORS_SEXTRACTOR_CONFIG "/fors.sex");
00194     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00195     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00196     cpl_parameterlist_append(parameters, p);
00197     cpl_free((void *)full_name);
00198     
00199     
00200     name = "sex_mag";
00201     full_name = cpl_sprintf("%s.%s", context, name);
00202     p = cpl_parameter_new_value(full_name,
00203                                 CPL_TYPE_STRING,
00204                                 "SExtractor magnitude",
00205                                 context,
00206                                 "MAG_APER");
00207     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00208     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00209     cpl_parameterlist_append(parameters, p);
00210     cpl_free((void *)full_name);
00211     
00212     name = "sex_magerr";
00213     full_name = cpl_sprintf("%s.%s", context, name);
00214     p = cpl_parameter_new_value(full_name,
00215                                 CPL_TYPE_STRING,
00216                                 "SExtractor magnitude error",
00217                                 context,
00218                                 "MAGERR_APER");
00219     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00220     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00221     cpl_parameterlist_append(parameters, p);
00222     cpl_free((void *)full_name);
00223 
00224     name = "sex_radius";
00225     full_name = cpl_sprintf("%s.%s", context, name);
00226     p = cpl_parameter_new_value(full_name,
00227                                 CPL_TYPE_INT,
00228                                 "Background error map median filter "
00229                                 "radius (unbinned pixels)",
00230                                 context,
00231                                 64);
00232     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00233     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00234     cpl_parameterlist_append(parameters, p);
00235     cpl_free((void *)full_name); full_name = NULL;
00236     
00237     return;
00238 }
00239 
00240 /*----------------------------------------------------------------------------*/
00241 #undef cleanup
00242 #define cleanup \
00243 do { \
00244     cpl_free((void *)name); \
00245     cpl_free((void *)method); \
00246 } while (0)
00247 
00256 /*----------------------------------------------------------------------------*/
00257 extract_method *
00258 fors_extract_method_new(                    const cpl_parameterlist *parameters,
00259                                             const char *context)
00260 {
00261     extract_method *em = cpl_malloc(sizeof(*em));
00262     const char *name = NULL;
00263     const char *method = NULL;
00264 
00265     cpl_msg_info(cpl_func, "Extraction method:");
00266 
00267     cpl_msg_indent_more();
00268     //"sex" method is the default. The parameter won't appear when calling
00269     //the recipe from esorex, but it will in the unit tests fors_zeropoint-test,
00270     //fors_img_science-test.
00271     name = cpl_sprintf("%s.%s", context, "extract_method");
00272     if(cpl_parameterlist_find_const(parameters, name) == NULL)
00273         method = cpl_sprintf("%s", "sex");
00274     else
00275         method = cpl_sprintf("%s",dfs_get_parameter_string_const(parameters, name));
00276     cpl_free((void *)name); name = NULL;
00277     cpl_msg_indent_less();
00278 
00279     assure( !cpl_error_get_code(), return NULL, NULL );
00280     assure( method != NULL, return NULL, NULL );
00281 
00282     if (strcmp(method, "sex") == 0) {
00283         em->method = SEX;
00284         
00285         cpl_msg_indent_more();
00286         name = cpl_sprintf("%s.%s", context, "sex_exe");
00287         em->sex_exe = dfs_get_parameter_string_const(parameters, 
00288                                                      name);
00289         cpl_free((void *)name); name = NULL;
00290         cpl_msg_indent_less();
00291 
00292         
00293         cpl_msg_indent_more();
00294         name = cpl_sprintf("%s.%s", context, "sex_config");
00295         em->sex_config = dfs_get_parameter_string_const(parameters, 
00296                                                      name);
00297         cpl_free((void *)name); name = NULL;
00298         cpl_msg_indent_less();
00299 
00300 
00301 
00302         cpl_msg_indent_more();
00303         name = cpl_sprintf("%s.%s", context, "sex_mag");
00304         em->sex_mag = dfs_get_parameter_string_const(parameters, 
00305                                                      name);
00306         cpl_free((void *)name); name = NULL;
00307         cpl_msg_indent_less();
00308 
00309 
00310         cpl_msg_indent_more();
00311         name = cpl_sprintf("%s.%s", context, "sex_magerr");
00312         em->sex_magerr = dfs_get_parameter_string_const(parameters, 
00313                                                         name);
00314         cpl_free((void *)name); name = NULL;
00315         cpl_msg_indent_less();
00316 
00317 
00318         cpl_msg_indent_more();
00319         name = cpl_sprintf("%s.%s", context, "sex_radius");
00320         em->sex_radius = dfs_get_parameter_int_const(parameters, 
00321                                            name);
00322         cpl_free((void *)name); name = NULL;
00323         cpl_msg_indent_less();
00324     }
00325     else if (strcmp(method, "test") == 0) {
00326         em->method = TEST;
00327     }
00328     else {
00329         assure( false, return NULL, "Unknown extraction method '%s'", method);
00330     }
00331 
00332     cleanup;
00333     return em;
00334 }
00335 
00336 /*----------------------------------------------------------------------------*/
00340 /*----------------------------------------------------------------------------*/
00341 void
00342 fors_extract_method_delete(                 extract_method **em)
00343 {
00344     if (em && *em) {
00345         cpl_free(*em); *em = NULL;
00346     }
00347     return;
00348 }
00349 
00350 /*----------------------------------------------------------------------------*/
00351 #undef cleanup
00352 #define cleanup
00353 
00363 /*----------------------------------------------------------------------------*/
00364 fors_star_list *
00365 fors_extract(                               const fors_image *image, 
00366                                             const fors_setting *setting,
00367                                             const extract_method *em,
00368                                             double magsyserr,
00369                                             fors_extract_sky_stats *sky_stats,
00370                                             cpl_image **background,
00371                                             cpl_table **extracted_sources)
00372 {
00373     assure( em != NULL, return NULL, NULL );
00374 
00375     cpl_msg_info(cpl_func, "Extracting sources");
00376     
00377     switch (em->method ) {
00378     case SEX: return extract_sex(image, setting,
00379                                  em->sex_exe,
00380                                  em->sex_config,
00381                                  em->sex_mag,
00382                                  em->sex_magerr,
00383                                  em->sex_radius,
00384                                  magsyserr,
00385                                  sky_stats,
00386                                  background,
00387                                  extracted_sources); break;
00388     case TEST: return extract_test(sky_stats, background, extracted_sources); break;
00389     default:
00390         assure( false, return NULL, "Unknown method %d", em->method );
00391         break;
00392     }
00393 }
00394 
00395 /*----------------------------------------------------------------------------*/
00396 #undef cleanup
00397 #define cleanup \
00398 do { \
00399     cpl_table_delete(out); out = NULL; \
00400     cpl_free((void *)command); \
00401     cpl_image_delete(work_back); work_back = NULL; \
00402     cpl_image_delete(bmaxsigma); bmaxsigma = NULL; \
00403     cpl_image_delete(bsigma); bsigma = NULL; \
00404     fors_image_delete(&fbsigma); \
00405 } while (0)
00406 
00429 /*----------------------------------------------------------------------------*/
00430 static fors_star_list *
00431 extract_sex(                                const fors_image *image,
00432                                             const fors_setting *setting,
00433                                             const char *sex_exe,
00434                                             const char *sex_config,
00435                                             const char *sex_mag,
00436                                             const char *sex_magerr,
00437                                             int radius,
00438                                             double magsyserr,
00439                                             fors_extract_sky_stats *sky_stats,
00440                                             cpl_image **background,
00441                                             cpl_table **extracted_sources)
00442 {
00443     const char *const filename_data  = "sextract_data.fits";
00444     const char *const filename_sigma = "sextract_bkg_sigma.fits";
00445     const char *const filename_cat   = "sextract_cat.fits";
00446     const char *const filename_bkg   = "sextract_bkg.fits";
00447     cpl_table *out = NULL;
00448     const char *command = NULL;
00449     fors_star_list *stars = NULL;
00450     cpl_image *work_back = NULL;
00451     cpl_image *bmaxsigma = NULL;
00452     cpl_image *bsigma = NULL;
00453     fors_image *fbsigma = NULL;
00454     fors_image *cropped = NULL;
00455     int croplx, croply, cropux, cropuy;
00456     const char *const filename_data_full  = "sextract_data_full.fits";
00457     const char *const filename_sigma_full = "sextract_bkg_sigma_full.fits";
00458     int        vignetted = 1;
00459 
00460     assure( setting != NULL, return NULL, NULL );
00461 
00462     assure( image != NULL, return NULL, NULL );
00463 
00464     assure( sky_stats != NULL, return NULL, NULL );
00465     assure( background != NULL, return NULL, NULL );
00466 
00467 
00468     /*
00469      * In case of new chips, crop
00470      */
00471 
00472     if (strcmp(setting->chip_id, "CCID20-14-5-6") == 0) {
00473         croplx =  380 / setting->binx;
00474         croply =  626 / setting->biny;
00475         cropux = 3714 / setting->binx;
00476         cropuy = 2048 / setting->biny;
00477     }
00478     else if (strcmp(setting->chip_id, "CCID20-14-5-3") == 0) {
00479         croplx =  380 / setting->binx;
00480         croply =    2 / setting->biny;
00481         cropux = 3714 / setting->binx;
00482         cropuy = 1920 / setting->biny;
00483     }
00484     else if (strncmp(setting->chip_id, "Marl", 4) == 0) {
00485         croplx =  380 / setting->binx;
00486         croply =  694 / setting->biny;
00487         cropux = 3690 / setting->binx;
00488         cropuy = 2048 / setting->biny;
00489     }
00490     else if (strncmp(setting->chip_id, "Norm", 4) == 0) {
00491         croplx =  380 / setting->binx;
00492         croply =    2 / setting->biny;
00493         cropux = 3690 / setting->binx;
00494         cropuy = 1894 / setting->biny;
00495     }
00496     else {
00497         vignetted = 0;
00498     }
00499 
00500     cropped = (fors_image *)image;       /* As a default.... */
00501 
00502     if (vignetted) {
00503        fors_image_save_sex(image, NULL,
00504                             filename_data_full,
00505                             filename_sigma_full,
00506                             radius);
00507 
00508         assure( !cpl_error_get_code(), return NULL,
00509                 "Could not save image to %s and %s",
00510                 filename_data_full, filename_sigma_full);
00511 
00512         cropped = fors_image_duplicate(image);
00513         fors_image_crop(cropped, croplx, croply, cropux, cropuy);
00514     }
00515 
00516     /* provide data and error bars in separate files,
00517        pass to sextractor */
00518 
00519     fors_image_save_sex(cropped, NULL,
00520                         filename_data,
00521                         filename_sigma,
00522                         radius);
00523     assure( !cpl_error_get_code(), return NULL,
00524             "Could not save image to %s and %s",
00525             filename_data, filename_sigma);
00526 
00527     if (vignetted)
00528         fors_image_delete(&cropped);
00529 
00530     
00531     /*
00532      * A = load filename_sigma
00533      *
00534      * M = fors_image_max_filter(A)
00535      *
00536      * |A-M|
00537      */
00538 
00539     command = cpl_sprintf("%s %s,%s "
00540                           "-c %s "
00541                           /* Use SExtractor's double mode which is probably
00542                              more tested and more bugfree than the
00543                              single image mode */
00544                           "-GAIN %f "   /* Different terminology here:
00545                                            SExtractor-gain == ESO-conad,
00546                                            unit = e- / ADU
00547                                         */
00548                           "-PIXEL_SCALE %f "
00549                           "-CHECKIMAGE_TYPE BACKGROUND "
00550                           "-CHECKIMAGE_NAME %s "
00551                           "-WEIGHT_TYPE MAP_RMS "
00552                           "-WEIGHT_IMAGE %s,%s "
00553                           "-CATALOG_TYPE FITS_1.0 "
00554                           "-CATALOG_NAME %s",
00555                           sex_exe,
00556                           filename_data, filename_data,
00557                           sex_config,
00558                           1.0/setting->average_gain,
00559                           setting->pixel_scale,
00560                           filename_bkg,
00561                           filename_sigma, filename_sigma,
00562                           filename_cat);
00563 
00564     cpl_msg_info(cpl_func, "Running '%s'", command);
00565 
00566     assure( system(command) == 0, return stars, "'%s' failed", command);
00567 
00568     /* 
00569      * The background map is here used just to evaluate a QC parameter,
00570      * and is also returned to the caller.
00571      */
00572     {
00573         int plane = 0;
00574         int extension = 0;
00575 
00576         *background = cpl_image_load(filename_bkg,
00577                                      CPL_TYPE_FLOAT, plane, extension);
00578 
00579         assure( !cpl_error_get_code(), return NULL,
00580                 "Could not load SExtractor background image %s",
00581                 filename_bkg );
00582 
00583         if (vignetted) {
00584             work_back = cpl_image_new(fors_image_get_size_x(image), 
00585                                       fors_image_get_size_y(image),
00586                                       CPL_TYPE_FLOAT);
00587             cpl_image_copy(work_back, *background, croplx, croply);
00588 
00589             assure( !cpl_error_get_code(), return NULL,
00590                     "Could not insert background image %s",
00591                     filename_bkg );
00592 
00593             cpl_image_delete(*background);
00594             *background = work_back;
00595             work_back = NULL;
00596         }
00597         
00598         /* 
00599          * To avoid using the non-illuminated parts, use only the central 
00600          * 100x100 window.
00601          *
00602          * It does not make too much sense to trend these QC parameters
00603          * anyway because they mostly describe the individual science 
00604          * exposures.
00605          */
00606 
00607         int nx = cpl_image_get_size_x(*background);
00608         int ny = cpl_image_get_size_y(*background);
00609         int xlo = nx/2 - 50;
00610         int xhi = nx/2 + 50;
00611         int ylo = ny/2 - 50;
00612         int yhi = ny/2 + 50;
00613         
00614         if (xlo <   0) xlo = 0;       /* Just in case... */
00615         if (xhi >= nx) xhi = nx - 1;
00616         if (ylo <   0) ylo = 0;
00617         if (yhi >= ny) yhi = ny - 1;
00618 
00619         work_back = cpl_image_duplicate(*background);
00620         
00621         sky_stats->mean   = cpl_image_get_mean_window(work_back, 
00622                                                       xlo, ylo, xhi, yhi);
00623         sky_stats->median = cpl_image_get_median_window(work_back, 
00624                                                  xlo, ylo, xhi, yhi);
00625         cpl_image_subtract_scalar(work_back, sky_stats->median);
00626         cpl_image_abs(work_back);
00627         sky_stats->rms    = cpl_image_get_median_window(work_back, 
00628                                                         xlo, ylo, xhi, yhi)
00629                           * STDEV_PR_MAD;
00630 
00631         cpl_image_delete(work_back); work_back = NULL;
00632 
00633         assure( !cpl_error_get_code(), return NULL,
00634                 "Could not calculate sky statistics" );
00635 
00636     }
00637     
00638     cpl_msg_info(cpl_func, "Background = %f +- %f ADU",
00639                  sky_stats->median, sky_stats->rms);
00640 
00641     /* 
00642      * SExtractors background estimation is not reliable near
00643      * non-illuminated areas. The underestimated background 
00644      * leads to false detections.
00645      * Therefore, reject sources which are too close to the
00646      * illumination edge. The edge is masked using a max filter 
00647      * on the smoothed variance image of the background map. 
00648      * The filter must have comparable size to the SExtractor 
00649      * BACK_SIZE parameter. The discrimination level is half-way
00650      * between the high-variance and low-variance regions.
00651      */
00652 
00653     float level;
00654     {
00655         int xradius = 64;
00656         int yradius = 64;
00657         int plane = 0;
00658         int extension = 0;
00659         float maxima;
00660         float minima;
00661 
00662         if (vignetted) {
00663             bsigma = cpl_image_load(filename_sigma_full,
00664                                     CPL_TYPE_FLOAT, plane, extension);
00665         }
00666         else {
00667             bsigma = cpl_image_load(filename_sigma,
00668                                     CPL_TYPE_FLOAT, plane, extension);
00669         }
00670 
00671         assure( !cpl_error_get_code(), return NULL,
00672                 "Could not load SExtractor background error image %s",
00673                 filename_sigma );
00674 
00675         /*
00676          * Duplication is necessary for creating the fors_image
00677          * to be passed to fors_image_filter_max_create()
00678          */
00679         
00680         /* this wraps the fors_image around the cpl images,
00681          * so set them to NULL */
00682 
00683         fbsigma = fors_image_new(cpl_image_duplicate(bsigma), bsigma);
00684         bsigma = NULL;
00685 
00686         {
00687             bool use_variance = true;
00688             bmaxsigma = fors_image_filter_max_create(fbsigma, xradius, 
00689                                                      yradius, use_variance);
00690 
00691      /* cpl_image_save(bmaxsigma, "/tmp/test.fits", CPL_BPP_IEEE_FLOAT, NULL,
00692                               CPL_IO_DEFAULT); */
00693             
00694         }
00695 
00696         fors_image_delete(&fbsigma);
00697 
00698         /*
00699           This is not robust if there are no non-illuminated areas.
00700 
00701           maxima = cpl_image_get_max(bmaxsigma);
00702           minima = cpl_image_get_min(bmaxsigma);
00703           level = (maxima + minima) / 2; 
00704         */
00705         
00706         /* 5 sigma rejection */
00707         level = cpl_image_get_median(bmaxsigma) * 5;
00708 
00709         cpl_msg_debug(cpl_func, "Threshold level = %f",
00710                       level);
00711 
00712     }
00713 
00714     out = cpl_table_load(filename_cat, 1, 1);
00715 
00716     assure( !cpl_error_get_code(), return NULL,
00717             "Could not load SExtractor output table %s",
00718             filename_cat); 
00719 
00720     /* Validate sextractor output */
00721     assure( cpl_table_has_column(out, "FLAGS"), return NULL,
00722             "%s: Missing column: %s", filename_cat, "FLAGS");
00723 
00724     assure( cpl_table_has_column(out, "CLASS_STAR"), return NULL,
00725             "%s: Missing column: %s", filename_cat, "CLASS_STAR");
00726 
00727     assure( cpl_table_has_column(out, "BACKGROUND"), return NULL,
00728             "%s: Missing column: %s", filename_cat, "BACKGROUND");
00729 
00730     assure( cpl_table_has_column(out, "X_IMAGE"), return NULL,
00731             "%s: Missing column: %s", filename_cat, "X_IMAGE");
00732 
00733     assure( cpl_table_has_column(out, "Y_IMAGE"), return NULL,
00734             "%s: Missing column: %s", filename_cat, "Y_IMAGE");
00735 
00736     assure( cpl_table_has_column(out, "FWHM_IMAGE"), return NULL,
00737             "%s: Missing column: %s", filename_cat, "FWHM_IMAGE");
00738 
00739     assure( cpl_table_has_column(out, "A_IMAGE"), return NULL,
00740             "%s: Missing column: %s", filename_cat, "A_IMAGE");
00741 
00742     assure( cpl_table_has_column(out, "B_IMAGE"), return NULL,
00743             "%s: Missing column: %s", filename_cat, "B_IMAGE");
00744 
00745     assure( cpl_table_has_column(out, "THETA_IMAGE"), return NULL,
00746             "%s: Missing column: %s", filename_cat, "THETA_IMAGE");
00747 
00748     assure( cpl_table_has_column(out, sex_mag), return NULL,
00749             "%s: Missing column: %s", filename_cat, sex_mag);
00750 
00751     assure( cpl_table_has_column(out, sex_magerr), return NULL,
00752             "%s: Missing column: %s", filename_cat, sex_magerr);
00753 
00754 
00755     /* cpl_table_dump_structure(out, stdout); */
00756 
00757     if (vignetted) {
00758         cpl_table_add_scalar(out, "X_IMAGE", croplx - 1);
00759         cpl_table_add_scalar(out, "Y_IMAGE", croply - 1);
00760     }
00761 
00762     stars = fors_star_list_new();
00763 
00764     {
00765         int i;
00766         int bkg_rejected = 0;
00767         int rejected = 0;
00768         float *bdata = cpl_image_get_data(bmaxsigma);
00769         int nx = cpl_image_get_size_x(bmaxsigma);
00770         int ny = cpl_image_get_size_y(bmaxsigma);
00771 
00772         for (i = 0; i < cpl_table_get_nrow(out); i++) {
00773             fors_star       *s = NULL;
00774             unsigned int    flags = 0x0;
00775             int             x, y, tmp;
00776             double          bg_err;
00777             
00778             s = fors_star_new_from_table(   out,
00779                                             i,
00780                                             "X_IMAGE",
00781                                             "Y_IMAGE",
00782                                             "FWHM_IMAGE",
00783                                             "A_IMAGE",
00784                                             "B_IMAGE",
00785                                             "THETA_IMAGE", 
00786                                             sex_mag,
00787                                             sex_magerr,
00788                                             "CLASS_STAR");
00789             (*s).orientation *= M_PI/180;
00790             (*s).semi_major *= setting->binx;
00791             (*s).semi_minor *= setting->binx;
00792             (*s).fwhm *= setting->binx;
00793             (*s).dmagnitude = sqrt((*s).dmagnitude * (*s).dmagnitude + magsyserr * magsyserr);
00794             
00795             flags = cpl_table_get_int(      out, "FLAGS", i, NULL);
00796             
00797             x = (int)(s->pixel->x + 0.5);
00798             y = (int)(s->pixel->y + 0.5);
00799             if (x >= 1 && x <= nx && y >= 1 && y <= ny)
00800                 bg_err = cpl_image_get(bmaxsigma, x, y, &tmp);
00801             else
00802                 bg_err = -1.0;
00803             
00804             if (fors_extract_check_sex_flag(flags)
00805                 && fors_extract_check_sex_star(s, bmaxsigma)
00806                 && bg_err < level)
00807             {
00808                 cpl_msg_debug(              cpl_func,
00809                                             "Source at (%f, %f): fwhm = %f px",
00810                                             s->pixel->x, s->pixel->y, s->fwhm);
00811                 assure(                     !cpl_error_get_code(), return NULL,
00812                                             "Could not read SExtractor "
00813                                             "output table %s",
00814                                             filename_cat);
00815                 fors_star_list_insert(stars, s);
00816             }
00817             else
00818             {
00819                 cpl_msg_debug(              cpl_func,
00820                                             "Rejecting source at (%f, %f): "
00821                                             "flags = 0x%x; fwhm = %f pix; "
00822                                             "background error = %f; "
00823                                             "level = %f; "
00824                                             "background = %f",
00825                                             s->pixel->x, s->pixel->y,
00826                                             flags, s->fwhm,
00827                                             bg_err, level,
00828                                             cpl_table_get_float(
00829                                                 out, "BACKGROUND", i, NULL));
00830                 fors_star_delete(&s);
00831                 rejected++;
00832                 if (bg_err >= level)
00833                     bkg_rejected++;
00834             }
00835         }
00836         
00837         cpl_msg_info(cpl_func, "%d sources sextracted, %d rejected", 
00838                      fors_star_list_size(stars) + rejected,
00839                      rejected);
00840     }
00841     
00842     if (extracted_sources != NULL) {
00843         *extracted_sources = cpl_table_duplicate(out);
00844     }
00845     
00846     cleanup;
00847     return stars;
00848 }
00849 
00850 /*----------------------------------------------------------------------------*/
00851 #undef cleanup
00852 #define cleanup
00853 
00865 /*----------------------------------------------------------------------------*/
00866 static fors_star_list *
00867 extract_test(                               fors_extract_sky_stats *sky_stats,
00868                                             cpl_image **background,
00869                                             cpl_table **extracted_sources)
00870 {
00871     assure( sky_stats != NULL, return NULL, NULL );
00872     assure( background != NULL, return NULL, NULL );
00873     
00874     sky_stats->mean = 1;
00875     sky_stats->median = 2;
00876     sky_stats->rms = 3;
00877 
00878     *background = cpl_image_new(10, 20, CPL_TYPE_FLOAT); /* Zero, wrong size */
00879 
00880     fors_star_list *stars = fors_star_list_new();
00881 
00882     struct {
00883         double x, y, magnitude, dmagnitude;
00884     } 
00885     data[] = {
00886         {100 ,  200, -10, 0.01},
00887         {1100,  200, -11, 0.01},
00888         {1   ,  5  , -10, 0.01},
00889         {100 , 1200, -12, 0.01},
00890         {1100, 1200, -13, 0.01}
00891     };
00892        
00893     int N = sizeof(data) / sizeof(*data);
00894     int i;
00895     double a = 2;
00896     double b = 1;
00897     double fwhm = 1.5;
00898     double orientation = 1.0; /* radians */
00899 
00900     for (i = 0; i < N; i++) {
00901         fors_star_list_insert(stars,
00902                               fors_star_new(data[i].x,
00903                                             data[i].y,
00904                                             fwhm,
00905                                             a, b, orientation,
00906                                             data[i].magnitude,
00907                                             data[i].dmagnitude,
00908                                             1.0));
00909     }
00910 
00911     if (extracted_sources != NULL) {
00912         *extracted_sources = fors_create_sources_table(stars);
00913         
00914         assure (!cpl_error_get_code(), return NULL, 
00915                 "Could not create extracted sources table");
00916     }
00917     
00918     return stars;
00919 }
00920