fors_image.c

00001 /* $Id: fors_image.c,v 1.60 2010/09/14 07:49:30 cizzo 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: cizzo $
00023  * $Date: 2010/09/14 07:49:30 $
00024  * $Revision: 1.60 $
00025  * $Name: fors-4_8_6 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <fors_image.h>
00033 
00034 #include <fors_dfs.h>
00035 #include <fors_utils.h>
00036 #include <fors_pfits.h>
00037 #include <fors_double.h>
00038 
00039 #include <moses.h>
00040 
00041 #include <cpl.h>
00042 
00043 #include <math.h>
00044 #include <stdbool.h>
00045 #include <stdio.h>
00046 
00062 struct _fors_image
00063 {
00064     cpl_image *data;
00065     cpl_image *variance;
00066 
00067     /* Invariants:
00068        The CPL images are non-NULL. 
00069        The variance image is everywhere non-negative.
00070        The CPL image types are FORS_IMAGE_TYPE.
00071        The CPL image bad pixel masks are unused
00072     */
00073 };
00074 
00078 const cpl_type FORS_IMAGE_TYPE = CPL_TYPE_FLOAT;
00079 #define FORS_IMAGE_TYPE_MAX FLT_MAX  /* Use a #define rather than a variable here
00080                                         to avoid type casting */
00081 
00082 #undef cleanup
00083 
00084 /* 
00085  * The following static function passes a max filter of given box
00086  * size on the input data buffer. The output data buffer must be
00087  * pre-allocated. The box size must be a positive odd integer.
00088  * Returns 0 on success.
00089  */
00090  
00091 static int 
00092 max_filter(const float *ibuffer, float *obuffer, int length, int size)
00093 {
00094     float  max;
00095     int    start = size / 2;
00096     int    end   = length - size / 2;
00097     int    i, j;
00098 
00099 
00100     for (i = start; i < end; i++) {
00101         max = ibuffer[i-start];
00102         for (j = i - start + 1; j <= i + start; j++)
00103             if (max < ibuffer[j])
00104                 max = ibuffer[j];
00105         obuffer[i] = max;
00106     }
00107 
00108     for (i = 0; i < start; i++)
00109         obuffer[i] = obuffer[start];
00110  
00111     for (i = end; i < length; i++)
00112         obuffer[i] = obuffer[end-1];
00113 
00114     return 0;
00115 }
00116 
00117 #define cleanup
00118 
00127 fors_image *
00128 fors_image_new(cpl_image *data, cpl_image *variance)
00129 {
00130     fors_image *image = NULL;
00131 
00132     assure( data != NULL, return NULL, NULL );
00133     assure( variance != NULL, return NULL, NULL );
00134     
00135     assure( cpl_image_get_type(data) == FORS_IMAGE_TYPE, return NULL,
00136             "Provided data image type is %s, must be %s",
00137             fors_type_get_string(cpl_image_get_type(data)),
00138             fors_type_get_string(FORS_IMAGE_TYPE) );
00139 
00140     assure( cpl_image_get_type(variance) == FORS_IMAGE_TYPE, return NULL,
00141             "Provided weight image type is %s, must be %s",
00142             fors_type_get_string(cpl_image_get_type(variance)),
00143             fors_type_get_string(FORS_IMAGE_TYPE) );
00144 
00145     assure( cpl_image_get_size_x(data) == cpl_image_get_size_x(variance) &&
00146             cpl_image_get_size_y(data) == cpl_image_get_size_y(variance),
00147             return NULL,
00148             "Incompatible data and weight image sizes: %dx%d and %dx%d",
00149             cpl_image_get_size_x(data), cpl_image_get_size_y(data),
00150             cpl_image_get_size_x(variance), cpl_image_get_size_y(variance));
00151 
00152     assure( cpl_image_get_min(variance) >= 0, return NULL,
00153             "Variances must be non-negative, minimum is %f",
00154             cpl_image_get_min(variance));
00155 
00156     image = cpl_malloc(sizeof(*image));
00157 
00158     image->data = data;
00159     image->variance = variance;
00160 
00161     return image;    
00162 }
00163 
00164 #undef cleanup
00165 #define cleanup
00166 
00171 fors_image *
00172 fors_image_duplicate(const fors_image *image)
00173 {
00174     assure( image != NULL, return NULL, NULL );
00175 
00176     return fors_image_new(cpl_image_duplicate(image->data),
00177                           cpl_image_duplicate(image->variance));
00178 }
00179 
00184 void
00185 fors_image_delete(fors_image **image)
00186 {
00187     if (image && *image) {
00188         cpl_image_delete((*image)->data);
00189         cpl_image_delete((*image)->variance);
00190         cpl_free(*image); *image = NULL;
00191     }
00192     return;
00193 }
00194 
00199 void
00200 fors_image_delete_const(const fors_image **image)
00201 {
00202     fors_image_delete((fors_image **)image);
00203 
00204     return;
00205 }
00206 
00207 /* not used */
00208 #if 0
00209 
00213 static void
00214 fors_image_dump(const fors_image *image, FILE *file)
00215 {
00216     if (image == NULL) {
00217         fprintf(file, "Null image\n");
00218     }
00219     else {
00220         cpl_stats *stats;
00221 
00222         fprintf(file, "Data:\n");
00223         stats = cpl_stats_new_from_image(image->data, CPL_STATS_ALL);
00224         cpl_stats_dump(stats, CPL_STATS_ALL, file);
00225         cpl_stats_delete(stats);
00226             
00227         fprintf(file, "Variance:\n");
00228         stats = cpl_stats_new_from_image(image->variance, CPL_STATS_ALL);
00229         cpl_stats_dump(stats, CPL_STATS_ALL, file);
00230         cpl_stats_delete(stats);
00231     }
00232     
00233     return;
00234 }
00235 #endif
00236 
00237 #undef cleanup
00238 #define cleanup \
00239 do { \
00240     double_list_delete(&sat_percent, double_delete); \
00241 } while (0)
00242 
00256 fors_image_list *
00257 fors_image_load_list(const cpl_frameset *frames, const fors_image *bias,
00258                      const fors_setting *setting,
00259                      double *saturated)
00260 {
00261     fors_image_list *ilist = fors_image_list_new();
00262     double_list *sat_percent = double_list_new();
00263     
00264     assure( frames != NULL, return ilist, NULL );
00265     assure( !cpl_frameset_is_empty(frames), return ilist, "Empty frameset");
00266 
00267     {
00268         const cpl_frame *f;
00269         
00270         for (f = cpl_frameset_get_first_const(frames);
00271              f != NULL;
00272              f = cpl_frameset_get_next_const(frames)) {
00273 
00274             double saturated_one;
00275             
00276             fors_image *i = fors_image_load(f, bias, setting,
00277                                             saturated != NULL ? 
00278                                             &saturated_one : NULL);
00279             assure( !cpl_error_get_code(), return ilist, NULL );
00280             
00281             fors_image_list_insert(ilist, i);
00282             if (saturated != NULL) {
00283                 double_list_insert(sat_percent, 
00284                                    double_duplicate(&saturated_one));
00285             }
00286         }
00287     }
00288 
00289     /* fixme: make sure input is consistent */
00290 
00291     /* Compute overall percentage as mean of each percentage.
00292        Valid because input frames have same size. */
00293     if (saturated != NULL) {
00294         *saturated = double_list_mean(sat_percent, double_eval, NULL);
00295     }
00296 
00297     cleanup;
00298     return ilist;
00299 }
00300 
00312 const fors_image_list *
00313 fors_image_load_list_const(const cpl_frameset *frames, const fors_image *bias,
00314                            const fors_setting *setting,
00315                            double *saturated)
00316 {
00317     return (const fors_image_list *)
00318         fors_image_load_list(frames, bias, setting, saturated);
00319 }
00320 
00321 #undef cleanup
00322 #define cleanup \
00323 do { \
00324     cpl_propertylist_delete(header); \
00325     cpl_table_delete(overscans); \
00326     cpl_image_delete(temp); \
00327     cpl_mask_delete(non_saturated); \
00328     fors_setting_delete(&frame_setting); \
00329 } while (0)
00330 
00348 fors_image *
00349 fors_image_load(const cpl_frame *frame, const fors_image *bias,
00350                 const fors_setting *setting,
00351                 double *saturated)
00352 {
00353     fors_image *image           = NULL;
00354     fors_setting *frame_setting = NULL;
00355     cpl_image *data             = NULL;
00356     cpl_image *variance         = NULL;
00357     cpl_image *temp             = NULL;
00358     cpl_propertylist *header    = NULL;
00359     cpl_table *overscans        = NULL;
00360     cpl_mask *non_saturated     = NULL;
00361     const char *filename;
00362     int extension= 0;
00363     const int plane = 0;
00364     double ocorr = 0.0;
00365     int has_overscans = 0;
00366     int i;
00367 
00368     assure( frame != NULL, return image, NULL );
00369     /* bias may be NULL */
00370     assure( setting != NULL, return image, NULL );
00371     filename = cpl_frame_get_filename(frame);
00372     assure( filename != NULL, return image, 
00373             "NULL filename received");
00374     
00375     cpl_msg_info(cpl_func, "Loading %s: %s",
00376                  /* fors_frame_get_group_string(frame), */
00377          (cpl_frame_get_tag(frame) != NULL) ? 
00378          cpl_frame_get_tag(frame) : "NULL",
00379                  filename);
00380 
00381     /* Verify instrument setting */
00382     fors_setting_verify(setting, frame, &frame_setting);
00383     assure( !cpl_error_get_code(), return image, 
00384             "Could not verify %s setting", 
00385             filename);
00386     
00387 
00388     /* Get header */
00389     header = cpl_propertylist_load(filename, extension);
00390     assure( !cpl_error_get_code(), return image, 
00391             "Could not load %s extension %d header", 
00392             filename, extension);
00393 
00394     /* Get data */
00395     data = cpl_image_load(filename, 
00396                           FORS_IMAGE_TYPE, plane, extension);
00397     
00398     assure( !cpl_error_get_code(), return image, 
00399             "Could not load image from %s extension %d", 
00400             filename, extension);
00401 
00402     /* Read, remove overscan areas */
00403     {
00404         int xlow, ylow, xhig, yhig;
00405     /* bool check_consistency = false; */
00406 
00407         overscans = mos_load_overscans_fors(header);
00408     /* Uses always ESO.DET.OUT1.*  which is fine even
00409        for old FORS data */
00410 
00411         assure( !cpl_error_get_code(), return image, 
00412                 "Could not read overscan information from %s extension %d", 
00413                 filename, extension);
00414 
00415         for (i = 1; i < cpl_table_get_nrow(overscans); i++) {
00416 
00417             /*
00418              * Overscan correction
00419              */
00420         
00421             xlow = cpl_table_get_int(overscans, "xlow", i, NULL);
00422             ylow = cpl_table_get_int(overscans, "ylow", i, NULL);
00423             xhig = cpl_table_get_int(overscans, "xhig", i, NULL);
00424             yhig = cpl_table_get_int(overscans, "yhig", i, NULL);
00425 
00426             temp = cpl_image_extract(data, xlow+1, ylow+1, xhig, yhig);
00427 
00428             ocorr += cpl_image_get_median(temp);
00429 
00430             cpl_image_delete(temp); temp = NULL;
00431         }
00432 
00433         if (cpl_table_get_nrow(overscans) > 1) {
00434             has_overscans = 1;
00435             ocorr /= cpl_table_get_nrow(overscans) - 1;
00436         }
00437 
00438         xlow = cpl_table_get_int(overscans, "xlow", 0, NULL);
00439         ylow = cpl_table_get_int(overscans, "ylow", 0, NULL);
00440         xhig = cpl_table_get_int(overscans, "xhig", 0, NULL);
00441         yhig = cpl_table_get_int(overscans, "yhig", 0, NULL);
00442         
00443         cpl_table_delete(overscans); overscans = NULL;
00444         
00445         temp = cpl_image_duplicate(data);
00446         cpl_image_delete(data);
00447         data = cpl_image_extract(temp, xlow+1, ylow+1, xhig, yhig);
00448         
00449         cpl_image_delete(temp); temp = NULL;
00450     }
00451 
00452     cpl_propertylist_delete(header); header = NULL;       
00453 
00454     /* Define variance */
00455     if (cpl_frame_get_nextensions(frame) == 0 || bias != NULL) {
00456 
00457         /* No error bars provided, assume RON only.
00458            If frame is not a bias, add photon noise later.
00459         */
00460 
00461         /* Define read-out-noise */
00462         variance = cpl_image_new(
00463             cpl_image_get_size_x(data),
00464             cpl_image_get_size_y(data),
00465             FORS_IMAGE_TYPE);        
00466 
00467         if (cpl_frame_get_group(frame) == CPL_FRAME_GROUP_CALIB) {
00468             cpl_msg_warning(cpl_func, 
00469                             "No error bars provided for calibration frame %s, "
00470                             "assuming no errors. For complete error propagation, "
00471                             "you may recreate this frame with this pipeline", 
00472                             filename);
00473         } else {
00474             cpl_image_add_scalar(variance, frame_setting->ron*frame_setting->ron);
00475         }
00476     }
00477     else {
00478 
00479         extension = 1;
00480         
00481         /* Get error bars */
00482         variance = cpl_image_load(filename, 
00483                                   FORS_IMAGE_TYPE, plane, extension);
00484         
00485         assure( !cpl_error_get_code(), return image, 
00486                 "Could not load image from %s extension %d", 
00487                 filename, extension);
00488 
00489         cpl_image_power(variance, 2);
00490 
00491         assure( cpl_image_get_min(variance) >= 0, return image,
00492                 "Illegal minimum variance: %g",
00493                 cpl_image_get_min(variance));
00494 
00495         cpl_image_delete(temp); temp = NULL;
00496     }
00497     
00498     image = fors_image_new(data, variance);
00499 
00500     /* Count saturated pixels */
00501     if (saturated != NULL) {
00502         double lo_cut = 0.5;
00503         double hi_cut = 65534.5;
00504         non_saturated = cpl_mask_threshold_image_create(
00505             data, lo_cut, hi_cut);
00506         
00507         *saturated = (cpl_image_get_size_x(data) * 
00508                       cpl_image_get_size_y(data) - 
00509                       cpl_mask_count(non_saturated)) * 100.0 / 
00510             (cpl_image_get_size_x(data) * 
00511              cpl_image_get_size_y(data));
00512 
00513         cpl_mask_delete(non_saturated); non_saturated = NULL;
00514 
00515         cpl_msg_debug(cpl_func,
00516                      "%f %% saturated pixels", *saturated);
00517     }        
00518     
00519     if (bias == NULL) {
00520         /* Done. No bias to subtract */
00521     }
00522     else {
00523         assure( cpl_frame_get_group(frame) == CPL_FRAME_GROUP_RAW,
00524                 return image,
00525                 "Refusing to subtract bias from non-raw (%s) input frame: %s",
00526                 fors_frame_get_group_string(frame),
00527                 filename);
00528         
00529         cpl_msg_debug(cpl_func, "Subtracting bias from %s", filename);
00530         
00531         fors_image_subtract(image, bias);
00532         
00533         assure( !cpl_error_get_code(), return image, 
00534                 "Bias subtraction failed" );
00535 
00536         if (has_overscans) {
00537 
00538             /*
00539              * Overscan correction
00540              */
00541 
00542             ocorr -= cpl_image_get_median(bias->data);
00543 
00544             cpl_msg_info(cpl_func, 
00545                          "Overscan correction applied: %.2f ADUs", ocorr);
00546 
00547             fors_image_subtract_scalar(image, ocorr, -1);
00548         }
00549         
00550         /* Variance is now (ron**2  +  bias_noise**2).
00551            Add photonic noise:
00552            
00553            variance := variance + |f|/conad
00554         */
00555 
00556         double conad = 1.0 / frame_setting->average_gain;
00557 
00558         temp = cpl_image_divide_scalar_create(image->data, conad);
00559         cpl_image_abs(temp);
00560 
00561         cpl_image_add(image->variance, temp);
00562     }
00563     
00564     cleanup;
00565     return image;
00566 }
00567 
00568 
00569 #undef cleanup
00570 #define cleanup \
00571 do { \
00572     cpl_image_delete(sigma); \
00573 } while(0)
00574 
00583 void
00584 fors_image_save(const fors_image *image, const cpl_propertylist *header,
00585                 const char *filename)
00586 {
00587     cpl_propertylist *extension_header = NULL;
00588     cpl_image *sigma = NULL;
00589 
00590     assure( image != NULL, return, NULL );
00591     /* header may be NULL */
00592     assure( filename != NULL, return, NULL );
00593     
00594     cpl_image_save(image->data, filename, CPL_BPP_IEEE_FLOAT, header,
00595                    CPL_IO_DEFAULT);
00596     assure( !cpl_error_get_code(), return, 
00597             "Cannot save product %s", filename);
00598     
00599     sigma = cpl_image_power_create(image->variance, 0.5);
00600     /* This would probably be faster if sqrt() is used rather than pow */
00601 
00602     cpl_image_save(sigma, filename, CPL_BPP_IEEE_FLOAT, extension_header,
00603                    CPL_IO_EXTEND);
00604     assure( !cpl_error_get_code(), return, 
00605             "Cannot save product %s", filename);
00606     
00607     cleanup;
00608     return;
00609 }
00610 
00611 
00612 #undef cleanup
00613 #define cleanup \
00614 do { \
00615     cpl_image_delete(var_bkg); \
00616     cpl_image_delete(sigma_bkg); \
00617 } while(0)
00618 
00629 void
00630 fors_image_save_sex(const fors_image *image, const cpl_propertylist *header,
00631                     const char *filename_dat,
00632                     const char *filename_var,
00633                     int radius)
00634 {
00635     cpl_propertylist *extension_header = NULL;
00636     cpl_image *sigma_bkg = NULL;
00637     cpl_image *var_bkg = NULL;
00638 
00639     assure( image != NULL, return, NULL );
00640     /* header may be NULL */
00641     assure( filename_dat != NULL, return, NULL );
00642     assure( filename_var != NULL, return, NULL );
00643 
00644     cpl_image_save(image->data, filename_dat, CPL_BPP_IEEE_FLOAT, header,
00645                    CPL_IO_DEFAULT);
00646     assure( !cpl_error_get_code(), return, 
00647             "Cannot save product %s", filename_dat);
00648     
00649     /* Sextractor wants as input the background error bars,
00650        i.e. excluding sources.
00651        Therefore filter away sources but keep the sharp edges
00652        between the illuminated / non-illuminated areas.
00653 
00654        I.e. use a median filter, average filter would not work.
00655     */
00656 
00657     cpl_msg_info(cpl_func, "Creating background error map");
00658 
00659     bool filter_data = false;  /* filter the variance image */
00660     int xstep = radius/2; /* 25 points sampling grid 
00661                              . . . . .
00662                              . . . . .
00663                              . . . . .
00664                              . . . . .
00665                              . . . . .
00666                            */
00667     int ystep = radius/2;
00668     int xstart = 1;
00669     int ystart = 1;
00670     int xend = fors_image_get_size_x(image);
00671     int yend = fors_image_get_size_y(image);
00672 
00673 
00674     var_bkg = fors_image_filter_median_create(image, 
00675                                               radius,
00676                                               radius,
00677                                               xstart, ystart,
00678                                               xend, yend,
00679                                               xstep, ystep,
00680                                               filter_data);
00681     assure( !cpl_error_get_code(), return, 
00682             "Median filtering failed");
00683 
00684     sigma_bkg = cpl_image_power_create(var_bkg, 0.5);
00685 
00686     cpl_image_save(sigma_bkg, filename_var,
00687                    CPL_BPP_IEEE_FLOAT, extension_header,
00688                    CPL_IO_DEFAULT);
00689     assure( !cpl_error_get_code(), return, 
00690             "Cannot save product %s", filename_var);
00691 
00692     cleanup;
00693     return;
00694 }
00695 
00696 #undef cleanup
00697 #define cleanup
00698 
00703 int fors_image_get_size_x(const fors_image *image)
00704 {
00705     assure( image != NULL, return -1, NULL );
00706     return cpl_image_get_size_x(image->data);
00707 }
00708 
00709 #undef cleanup
00710 #define cleanup
00711 
00716 int fors_image_get_size_y(const fors_image *image)
00717 {
00718     assure( image != NULL, return -1, NULL );
00719     return cpl_image_get_size_y(image->data);
00720 }
00721 
00722 #undef cleanup
00723 #define cleanup
00724 
00728 const float *fors_image_get_data_const(const fors_image *image)
00729 {
00730     assure( image != NULL, return NULL, NULL );
00731 
00732     assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return NULL, NULL );
00733     /* This function (including API) would need to change
00734        if the pixel type changes */
00735 
00736     return cpl_image_get_data_float(image->data);
00737 }
00738 
00739 #undef cleanup
00740 #define cleanup
00741 
00748 void
00749 fors_image_abs(fors_image *image)
00750 {
00751     assure( image != NULL, return, NULL );
00752 
00753     cpl_image_abs(image->data);
00754 
00755     return;
00756 }
00757 
00758 #undef cleanup
00759 #define cleanup
00760 
00767 void
00768 fors_image_square(fors_image *image)
00769 {
00770     assure( image != NULL, return, NULL );
00771 
00772     cpl_image_multiply(image->data, image->data);
00773     /* It is an undocumented feature of CPL that you
00774        can pass the same image to cpl_image_multiply and get
00775        the right answer. Let us hope it does not change...
00776     */
00777     cpl_image_multiply_scalar(image->variance, 2);
00778 
00779     return;
00780 }
00781 
00782 
00783 #undef cleanup
00784 #define cleanup \
00785 do { \
00786     cpl_image_delete(temp); \
00787 } while(0)
00788 
00796 void
00797 fors_image_subtract(fors_image *left, const fors_image *right)
00798 {
00799     cpl_image *temp = NULL;
00800     assure( left != NULL, return, NULL );
00801     assure( right != NULL, return, NULL );
00802 
00803     cpl_image_subtract(left->data, right->data);
00804 
00805     /*  variance_left := variance_left + variance_right */
00806     cpl_image_add(left->variance, right->variance);
00807 
00808     cleanup;
00809     return;
00810 }
00811 
00812 #undef cleanup
00813 #define cleanup
00814 
00824 void
00825 fors_image_multiply_noerr(fors_image *left, const cpl_image *right)
00826 {
00827     assure( left != NULL, return, NULL );
00828     assure( right != NULL, return, NULL );
00829     assure( cpl_image_get_size_x(left->data) == cpl_image_get_size_x(right) &&
00830             cpl_image_get_size_y(left->data) == cpl_image_get_size_y(right),
00831             return, "Incompatible image sizes: %dx%d and %dx%d",
00832             cpl_image_get_size_x(left->data),
00833             cpl_image_get_size_y(left->data),
00834             cpl_image_get_size_x(right),
00835             cpl_image_get_size_y(right));
00836 
00837     cpl_image_multiply(left->data, right);
00838     cpl_image_multiply(left->variance, right);
00839     cpl_image_multiply(left->variance, right);
00840 
00841     return;
00842 }
00843 
00844 #undef cleanup
00845 #define cleanup
00846 
00862 void
00863 fors_image_divide_noerr(fors_image *left, cpl_image *right)
00864 {
00865     assure( left != NULL, return, NULL );
00866     assure( right != NULL, return, NULL );
00867     assure( cpl_image_get_size_x(left->data) == cpl_image_get_size_x(right) &&
00868             cpl_image_get_size_y(left->data) == cpl_image_get_size_y(right),
00869             return, "Incompatible image sizes: %dx%d and %dx%d",
00870             cpl_image_get_size_x(left->data),
00871             cpl_image_get_size_y(left->data),
00872             cpl_image_get_size_x(right),
00873             cpl_image_get_size_y(right));
00874 
00875     int x, y;
00876     int nx = cpl_image_get_size_x(right);
00877     int ny = cpl_image_get_size_y(right);
00878     float *datal = cpl_image_get_data_float(left->data);
00879     float *datav = cpl_image_get_data_float(left->variance);
00880     float *datar = cpl_image_get_data_float(right);
00881     for (y = 0; y < ny; y++) {
00882         for (x = 0; x < nx; x++) {
00883             if (datar[x + nx*y] == 0) {
00884                 datar[x + nx*y] = 1;
00885                 datal[x + nx*y] = 1;
00886 
00887                 datav[x + nx*y] = FORS_IMAGE_TYPE_MAX;
00888             }
00889         }
00890     }
00891 
00892     cpl_image_divide(left->data, right);
00893     cpl_image_divide(left->variance, right);
00894     cpl_image_divide(left->variance, right);
00895 
00896     return;
00897 }
00898 
00899 #undef cleanup
00900 #define cleanup \
00901 do { \
00902     fors_image_delete(&dupl); \
00903 } while(0)
00904 
00924 void
00925 fors_image_divide(fors_image *left, const fors_image *right)
00926 {
00927     fors_image *dupl = NULL;
00928 
00929     assure( left  != NULL, return, NULL );
00930     assure( right != NULL, return, NULL );
00931 
00932     dupl = fors_image_duplicate(right);
00933 
00934     cpl_image_divide(left->data, dupl->data); 
00935     /* This CPL function divides by zero by setting  x/0 = 1 for all x */
00936 
00937     cpl_image_multiply(dupl->variance, left->data);
00938     cpl_image_multiply(dupl->variance, left->data);
00939 
00940     /* Now  dupl->variance = sigma2^2 * data1^2 / data2^2 */
00941 
00942     cpl_image_add(left->variance, dupl->variance);
00943 
00944     /* Now  left->variance = sigma1^2 + sigma2^2 * data1^2 / data2^2 */
00945 
00946     cpl_image_divide(left->variance, dupl->data);
00947     cpl_image_divide(left->variance, dupl->data);
00948     /* QED */
00949 
00950     /* Handle division by zero */
00951     int x, y;
00952     int nx = cpl_image_get_size_x(left->data);
00953     int ny = cpl_image_get_size_y(left->data);
00954     float *datal = cpl_image_get_data_float(left->data);
00955     float *datav = cpl_image_get_data_float(left->variance);
00956     float *datar = cpl_image_get_data_float(right->data);
00957     for (y = 0; y < ny; y++) {
00958         for (x = 0; x < nx; x++) {
00959             if (datar[x + nx*y] == 0) {
00960                 datal[x + nx*y] = 1;
00961                 datav[x + nx*y] = FORS_IMAGE_TYPE_MAX;
00962             }
00963         }
00964     }
00965 
00966     cleanup;
00967     return;
00968 }
00969 
00970 #undef cleanup
00971 #define cleanup \
00972 do { \
00973     cpl_image_delete(s22d12); \
00974 } while(0)
00975 
00986 void
00987 fors_image_multiply(fors_image *left, const fors_image *right)
00988 {
00989     cpl_image *s22d12 = NULL;
00990 
00991     assure( left  != NULL, return, NULL );
00992     assure( right != NULL, return, NULL );
00993 
00994     s22d12 = cpl_image_duplicate(right->variance);
00995     cpl_image_multiply(s22d12, left->data);
00996     cpl_image_multiply(s22d12, left->data);
00997     
00998     cpl_image_multiply(left->variance, right->data);
00999     cpl_image_multiply(left->variance, right->data);
01000     cpl_image_add(left->variance, s22d12);
01001 
01002     cpl_image_multiply(left->data, right->data);
01003 
01004     cleanup;
01005     return;
01006 }
01007 
01008 
01009 #undef cleanup
01010 #define cleanup
01011 
01023 void fors_image_subtract_scalar(fors_image *image, double s, double ds)
01024 {
01025     assure( image != NULL, return, NULL );
01026     assure( ds <= 0, return, "Unsupported");
01027 
01028     cpl_image_subtract_scalar(image->data, s);
01029 
01030     return;
01031 }
01032 
01033 
01034 #undef cleanup
01035 #define cleanup
01036 
01048 void fors_image_divide_scalar(fors_image *image, double s, double ds)
01049 {
01050     assure( image != NULL, return, NULL );
01051     assure( s != 0, return, "Division by zero");
01052     assure( ds <= 0, return, "Unsupported");
01053 
01054     cpl_image_divide_scalar(image->data, s);
01055     cpl_image_divide_scalar(image->variance, s*s);
01056     
01057     return;
01058 }
01059 
01060 #undef cleanup
01061 #define cleanup
01062 
01074 void fors_image_multiply_scalar(fors_image *image, double s, double ds)
01075 {
01076     assure( image != NULL, return, NULL );
01077     assure( ds <= 0, return, "Unsupported");
01078 
01079     cpl_image_multiply_scalar(image->data, s);
01080     cpl_image_multiply_scalar(image->variance, s*s);
01081 
01082     return;
01083 }
01084 
01085 #undef cleanup
01086 #define cleanup \
01087 do { \
01088     cpl_image_delete(temp); \
01089 } while(0)
01090 
01103 void fors_image_exponential(fors_image *image, double b, double db)
01104 {
01105     cpl_image *temp = NULL;
01106 
01107     assure( image != NULL, return, NULL );
01108     assure( b >= 0, return, "Negative base: %f", b);
01109     assure( db <= 0, return, "Unsupported");
01110 
01111     cpl_image_exponential(image->data, b);
01112 
01113     double lnb = log(b);
01114     
01115     cpl_image_multiply_scalar(image->variance, lnb*lnb);
01116     cpl_image_multiply(image->variance, image->data);
01117     cpl_image_multiply(image->variance, image->data);
01118 
01119     return;
01120 }
01121 
01122 
01123 #undef cleanup
01124 #define cleanup
01125 
01130 double
01131 fors_image_get_min(const fors_image *image)
01132 {
01133     assure( image != NULL, return 0, NULL );
01134 
01135     return cpl_image_get_min(image->data);
01136 }
01137 
01138 #undef cleanup
01139 #define cleanup
01140 
01145 double
01146 fors_image_get_max(const fors_image *image)
01147 {
01148     assure( image != NULL, return 0, NULL );
01149 
01150     return cpl_image_get_max(image->data);
01151 }
01152 
01153 #undef cleanup
01154 #define cleanup
01155 
01161 double
01162 fors_image_get_mean(const fors_image *image, double *dmean)
01163 {
01164     assure( image != NULL, return 0, NULL );
01165     assure( dmean == NULL, return 0, "Unsupported");
01166 
01167     return cpl_image_get_mean(image->data);
01168 }
01169 
01170 #undef cleanup
01171 #define cleanup
01172 
01178 double
01179 fors_image_get_median(const fors_image *image, double *dmedian)
01180 {
01181     assure( image != NULL, return 0, NULL );
01182     assure( dmedian == NULL, return 0, "Unsupported");
01183 
01184     return cpl_image_get_median(image->data);
01185 }
01186 
01187 
01188 #undef cleanup
01189 #define cleanup
01190 
01204 void fors_image_crop(fors_image *image,
01205              int xlo, int ylo,
01206              int xhi, int yhi)
01207 {
01208     /* CPL is missing the function to locally extract an image,
01209        so this this inefficient CPL function */
01210     assure( image != NULL, return, NULL );
01211     assure( 1 <= xlo && xlo <= xhi && xhi <= fors_image_get_size_x(image) &&
01212             1 <= ylo && ylo <= yhi && yhi <= fors_image_get_size_y(image),
01213             return, "Cannot extraction region (%d, %d) - (%d, %d) of "
01214             "%dx%d image",
01215             xlo, ylo, xhi, yhi,
01216             fors_image_get_size_x(image),
01217             fors_image_get_size_y(image));
01218     
01219     cpl_image *new_data = cpl_image_extract(image->data,
01220                                             xlo, ylo,
01221                                             xhi, yhi);
01222     cpl_image_delete(image->data);
01223 
01224     cpl_image* new_variance = cpl_image_extract(image->variance,
01225                                                 xlo, ylo,
01226                                                 xhi, yhi);
01227     cpl_image_delete(image->variance);
01228 
01229     image->data = new_data;
01230     image->variance = new_variance;
01231 
01232     return;
01233 }
01234 
01260 cpl_image *
01261 fors_image_filter_median_create(const fors_image *image, 
01262                                 int xradius,
01263                                 int yradius,
01264                                 int xstart, 
01265                                 int ystart,
01266                                 int xend,
01267                                 int yend,
01268                                 int xstep,
01269                                 int ystep,
01270                                 bool use_data)
01271 {
01272     const cpl_image *input = NULL;
01273     cpl_image *smooth = NULL;
01274     int nx, ny;
01275     
01276     assure( image != NULL, return smooth, NULL );
01277     passure( image->data != NULL, return smooth );
01278     passure( image->variance != NULL, return smooth );
01279     
01280     input = (use_data) ? image->data : image->variance;
01281 
01282     nx = cpl_image_get_size_x(input);
01283     ny = cpl_image_get_size_y(input);
01284 
01285     if (xstep < 1) xstep = 1;
01286     if (ystep < 1) ystep = 1;
01287 
01288     assure( 1 <= xstart && xstart <= xend && xend <= nx &&
01289             1 <= ystart && ystart <= yend && yend <= ny, return smooth,
01290             "Illegal region (%d, %d) - (%d, %d) of %dx%d image",
01291             xstart, ystart,
01292             xend, yend,
01293             nx, ny);
01294     
01295     smooth = cpl_image_duplicate(input);
01296 
01297     /* For efficiency reasons, assume that the image type is float */
01298     assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return smooth, NULL );
01299 
01300     const float *input_data  = cpl_image_get_data_float_const(input);
01301     float *smooth_data = cpl_image_get_data_float(smooth);
01302     float *data = cpl_malloc((2*yradius + 1)*(2*xradius + 1)*sizeof(*data));
01303     
01304     int y;
01305     for (y = ystart; y < yend; y++) {
01306         /*
01307           Sample kernel on grid which always contains the central pixel
01308           
01309           Trim window (note: this will cause fewer values to
01310           be used for the median near the region borders 
01311         */
01312         int ylo = y - (yradius/ystep) * ystep;
01313         int yhi = y + (yradius/ystep) * ystep;
01314         
01315         while (ylo < ystart) ylo += ystep;
01316         while (yhi > yend  ) yhi -= ystep;
01317         
01318         int x;
01319         for (x = xstart; x < xend; x++) {
01320             int xlo = x - (xradius/xstep) * xstep;
01321             int xhi = x + (xradius/xstep) * xstep;
01322             
01323             while (xlo < xstart) xlo += xstep;
01324             while (xhi > xend  ) xhi -= xstep;
01325             
01326             /* Collect data */
01327             int k = 0;
01328             int j, i;
01329             for (j = ylo; j <= yhi; j += ystep) {
01330                 for (i = xlo; i <= xhi; i += xstep) {
01331                     data[k++] = input_data[ (i-1) + (j-1)*nx ];
01332                 }
01333             }
01334         
01335             /* Get median */
01336             smooth_data[ (x-1) + (y-1)*nx ] = 
01337                                fors_tools_get_median_float(data, k);
01338         }
01339     }
01340 
01341     cpl_free(data);
01342     return smooth;
01343 }
01344 
01345 #undef cleanup
01346 #define cleanup \
01347 do { \
01348     cpl_image_delete(input); \
01349 } while(0)
01350 cpl_image *
01351 fors_image_flat_fit_create(fors_image *image, 
01352                            int step, 
01353                            int degree, 
01354                            float level)
01355 {
01356     cpl_image *temp = NULL;
01357     cpl_image *input = NULL;
01358     cpl_image *smooth = NULL;
01359     int nx, ny;
01360 
01361     assure( image != NULL, return smooth, NULL );
01362     passure( image->data != NULL, return smooth );
01363     assure( step > 0, return smooth, NULL );
01364     assure( degree >= 0, return smooth, NULL );
01365 
01366 
01367     temp = image->data;
01368 
01369     nx = cpl_image_get_size_x(temp);
01370     ny = cpl_image_get_size_y(temp);
01371 
01372     /* 
01373      * For efficiency reasons, assume that the image type is float 
01374      */
01375 
01376     assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return smooth, NULL );
01377 
01378     /*
01379      * Apply light median filter, to eliminate big outliers from fit
01380      */
01381 
01382     input = mos_image_filter_median(image->data, 3, 3);
01383 
01384     const float *input_data = cpl_image_get_data_float_const(input);
01385 
01386     /*
01387      * First of all, count how many points will have to be fitted
01388      */
01389 
01390     int x, y, pos;
01391     int count = 0;
01392     for (y = 0; y < ny; y += step) {
01393         pos = y*nx;
01394         for (x = 0; x < nx; x += step, pos += step) {
01395             if (input_data[pos] > level) {
01396                 count++;
01397             }
01398         }
01399     }
01400 
01401     if (count < (degree+1)*(degree+2)) {
01402         step = sqrt((nx*nx)/((degree+1)*(degree+2))) / 2;
01403         if (step == 0)
01404             step = 1;
01405         cpl_msg_error(cpl_func, "Flat field image too small (%dx%d). "
01406                       "Please provide a smaller resampling step (a good "
01407                       "value would be %d)", nx, ny, step);
01408         cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
01409         cleanup;
01410         return NULL;
01411     }
01412 
01413 
01414     /*
01415      * Fill position and flux vectors with appropriate values
01416      */
01417 
01418     cpl_bivector *positions = cpl_bivector_new(count);
01419     double *xpos = cpl_bivector_get_x_data(positions);
01420     double *ypos = cpl_bivector_get_y_data(positions);
01421     cpl_vector *fluxes = cpl_vector_new(count);
01422     double *flux = cpl_vector_get_data(fluxes);
01423 
01424     count = 0;
01425     for (y = 0; y < ny; y += step) {
01426         pos = y*nx;
01427         for (x = 0; x < nx; x += step, pos += step) {
01428             if (input_data[pos] > level) {
01429                 xpos[count] = x;
01430                 ypos[count] = y;
01431                 flux[count] = input_data[pos];
01432                 count++;
01433             }
01434         }
01435     }
01436 
01437     cpl_image_delete(input); input = NULL;
01438 
01439     /*
01440      * Do the fit, and fill the output image with the model
01441      * values in all pixels.
01442      */
01443 
01444     cpl_polynomial *model = cpl_polynomial_fit_2d_create(positions,
01445                                                          fluxes,
01446                                                          degree,
01447                                                          NULL);
01448 
01449     cpl_bivector_delete(positions);
01450     cpl_vector_delete(fluxes);
01451 
01452     smooth = cpl_image_new(nx, ny, FORS_IMAGE_TYPE);
01453     float *smooth_data = cpl_image_get_data_float(smooth);
01454 
01455     cpl_vector *point = cpl_vector_new(2);
01456     double *dpoint = cpl_vector_get_data(point);
01457 
01458     for (y = 0; y < ny; y++) {
01459         pos = y*nx;
01460         dpoint[1] = y;
01461         for (x = 0; x < nx; x++, pos++) {
01462             dpoint[0] = x;
01463             smooth_data[pos] = cpl_polynomial_eval(model, point);
01464         }
01465     }
01466 
01467     cpl_polynomial_delete(model);
01468     cpl_vector_delete(point);
01469 
01470     cleanup;
01471     return smooth;
01472 
01473 }
01474 
01475 #undef cleanup
01476 #define cleanup
01477 
01493 cpl_image *
01494 fors_image_filter_max_create(const fors_image *image, 
01495                              int xradius,
01496                              int yradius,
01497                              bool use_data)
01498 {
01499     const cpl_image *input = NULL;
01500     cpl_image *hmaxima = NULL;
01501     cpl_image *maxima = NULL;
01502     int nx, ny;
01503     
01504     assure( image != NULL, return maxima, NULL );
01505     passure( image->data != NULL, return maxima );
01506     passure( image->variance != NULL, return maxima );
01507     
01508     input = (use_data) ? image->data : image->variance;
01509 
01510     nx = cpl_image_get_size_x(input);
01511     ny = cpl_image_get_size_y(input);
01512 
01513     /*
01514      * Allocate space for horizontal max filter result.
01515      */
01516 
01517     hmaxima = cpl_image_duplicate(input);
01518 
01519     /* For efficiency reasons, assume that the image type is float */
01520     assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return maxima, NULL );
01521 
01522     float *input_data  = (float *)cpl_image_get_data_float_const(input);
01523     float *maxima_data = cpl_image_get_data_float(hmaxima);
01524 
01525     int y;
01526     for (y = 0; y < ny; y++) {
01527         const float *irow = input_data + y * nx;
01528         float       *orow = maxima_data + y * nx;
01529         max_filter(irow, orow, nx, 2*xradius+1);
01530     }
01531 
01532     cpl_image_turn(hmaxima, 1);
01533 
01534     /*
01535      * Allocate space for vertical max filter result.
01536      */
01537 
01538     maxima = cpl_image_duplicate(hmaxima);
01539     input_data  = cpl_image_get_data_float(hmaxima);
01540     maxima_data = cpl_image_get_data_float(maxima);
01541 
01542     /*
01543      * Now nx is the y size of the rotated image...
01544      */
01545 
01546     int x;
01547     for (x = 0; x < nx; x++) {
01548         const float *irow = input_data + x * ny;
01549         float       *orow = maxima_data + x * ny;
01550         max_filter(irow, orow, ny, 2*yradius+1);
01551     }
01552 
01553     cpl_image_delete(hmaxima);
01554 
01555     cpl_image_turn(maxima, -1);
01556     
01557     return maxima;
01558 }
01559 
01560 #undef cleanup
01561 #define cleanup
01562 
01568 double
01569 fors_image_get_stdev(const fors_image *image, double *dstdev)
01570 {
01571     assure( image != NULL, return 0, NULL );
01572     assure( dstdev == NULL, return 0, "Unsupported");
01573 
01574     return cpl_image_get_stdev(image->data);
01575 }
01576 #undef cleanup
01577 #define cleanup \
01578 do { \
01579     cpl_mask_delete(rejected); \
01580     cpl_image_delete(im); \
01581 } while (0)
01582 
01590 double fors_image_get_stdev_robust(const fors_image *image, 
01591                    double cut,
01592                    double *dstdev)
01593 {
01594     cpl_mask *rejected = NULL;
01595     cpl_image *im = NULL;
01596 
01597     assure( image != NULL, return 0, NULL );
01598     assure( cut > 0, return 0, "Illegal cut: %f", cut );
01599     assure( dstdev == NULL, return 0, "Unsupported");
01600 
01601     double median = fors_image_get_median(image, NULL);
01602 
01603     im = cpl_image_duplicate(image->data);
01604     cpl_image_subtract_scalar(im, median); 
01605     cpl_image_power(im, 2);
01606     /* Now squared residuals wrt median */
01607     
01608     rejected = cpl_mask_threshold_image_create(image->data,
01609                                                median - cut,
01610                                                median + cut);
01611     cpl_mask_not(rejected);
01612     cpl_image_reject_from_mask(im, rejected);
01613 
01614     double robust_stdev = sqrt(cpl_image_get_mean(im));
01615 
01616     cleanup;
01617     return robust_stdev;
01618 }
01619 
01620 #undef cleanup
01621 #define cleanup
01622 
01632 double
01633 fors_image_get_error_mean(const fors_image *image, double *dmean)
01634 {
01635     double avg;
01636 
01637     assure( image != NULL, return 0, NULL );
01638     assure( dmean == NULL, return 0, "Unsupported");
01639 
01640     avg = cpl_image_get_mean(image->variance);
01641 
01642     /* This should never happen, but avoid sqrt of negative value in any case */
01643     assure( avg >= 0, return -1, "Average variance is %f", avg);
01644     
01645     return sqrt(avg);
01646 }
01647 
01648 
01649 #undef cleanup
01650 #define cleanup \
01651 do { \
01652     cpl_imagelist_delete(datlist); \
01653     cpl_imagelist_delete(varlist); \
01654 } while (0)
01655 
01664 fors_image *
01665 fors_image_collapse_create(const fors_image_list *images)
01666 {
01667     cpl_imagelist *datlist = NULL;
01668     cpl_imagelist *varlist = NULL;
01669     cpl_image *data = NULL;
01670     cpl_image *variance = NULL;
01671     const fors_image *i;
01672     int N = 0;
01673     
01674     assure( images != NULL, return NULL, NULL );
01675     assure( fors_image_list_size(images) > 0, return NULL, 
01676             "Cannot stack zero images");
01677 
01678     i = fors_image_list_first_const(images);
01679 
01680     datlist = cpl_imagelist_new();
01681     varlist = cpl_imagelist_new();
01682 
01683     while(i != NULL) {
01684 
01685         /* Append current image to image lists */
01686         cpl_imagelist_set(datlist, 
01687                           cpl_image_duplicate(i->data), 
01688                           cpl_imagelist_get_size(datlist));
01689         cpl_imagelist_set(varlist,
01690                           cpl_image_duplicate(i->variance),
01691                           cpl_imagelist_get_size(varlist));
01692         i = fors_image_list_next_const(images);
01693         N++;
01694     }
01695 
01696 #ifdef CPL_IS_NOT_CRAP
01697     data    = cpl_imagelist_collapse_create(datlist);
01698 
01699     variance = cpl_imagelist_collapse_create(varlist);
01700 #else
01701     data    = fors_imagelist_collapse_create(datlist);
01702 
01703     variance = fors_imagelist_collapse_create(varlist);
01704 #endif
01705 
01706     cpl_image_divide_scalar(variance, N);
01707 
01708     cleanup;
01709     return fors_image_new(data, variance);
01710 }
01711 
01712 
01713 #undef cleanup
01714 #define cleanup \
01715 do { \
01716     cpl_imagelist_delete(datlist); \
01717     cpl_imagelist_delete(varlist); \
01718 } while (0)
01719 
01730 fors_image *
01731 fors_image_collapse_minmax_create(const fors_image_list *images, 
01732                                   int low, int high)
01733 {
01734     cpl_imagelist *datlist = NULL;
01735     cpl_imagelist *varlist = NULL;
01736     cpl_image *data = NULL;
01737     cpl_image *variance = NULL;
01738     const fors_image *i;
01739     int N = 0;
01740     
01741     assure( images != NULL, return NULL, NULL );
01742     assure( fors_image_list_size(images) >  low + high, return NULL, 
01743             "Cannot reject more images than there are");
01744     assure( low*high >= 0 && low+high > 0, return NULL, 
01745             "Invalid minmax rejection criteria");
01746 
01747     i = fors_image_list_first_const(images);
01748 
01749     datlist = cpl_imagelist_new();
01750     varlist = cpl_imagelist_new();
01751 
01752     while(i != NULL) {
01753 
01754         /* Append current image to image lists */
01755         cpl_imagelist_set(datlist, 
01756                           cpl_image_duplicate(i->data), 
01757                           cpl_imagelist_get_size(datlist));
01758         cpl_imagelist_set(varlist,
01759                           cpl_image_duplicate(i->variance),
01760                           cpl_imagelist_get_size(varlist));
01761         i = fors_image_list_next_const(images);
01762         N++;
01763     }
01764 
01765     data     = cpl_imagelist_collapse_minmax_create(datlist, low, high);
01766     variance = cpl_imagelist_collapse_minmax_create(varlist, low, high);
01767 
01768     cpl_image_divide_scalar(variance, N);
01769 
01770     cleanup;
01771     return fors_image_new(data, variance);
01772 }
01773 
01786 fors_image *
01787 fors_image_collapse_ksigma_create(const fors_image_list *images, 
01788                                   int low, int high, int iter)
01789 {
01790     cpl_imagelist *datlist = NULL;
01791     cpl_imagelist *varlist = NULL;
01792     cpl_image *data = NULL;
01793     cpl_image *variance = NULL;
01794     cpl_image *ngood = NULL;
01795     const fors_image *i;
01796     
01797     assure( images != NULL, return NULL, NULL );
01798 
01799     i = fors_image_list_first_const(images);
01800 
01801     datlist = cpl_imagelist_new();
01802     varlist = cpl_imagelist_new();
01803     
01804     while(i != NULL) {
01805 
01806         /* Append current image to image lists */
01807         cpl_imagelist_set(datlist,
01808                           cpl_image_duplicate(i->data),
01809                           cpl_imagelist_get_size(datlist));
01810         cpl_imagelist_set(varlist,
01811                           cpl_image_duplicate(i->variance),
01812                           cpl_imagelist_get_size(varlist));
01813         i = fors_image_list_next_const(images);
01814     }
01815 
01816     data     = mos_ksigma_stack(datlist, low, high, iter, &ngood);
01817     variance = cpl_imagelist_collapse_create(varlist);
01818 
01819     cpl_image_divide(variance, ngood);
01820 
01821     cpl_image_delete(ngood);
01822     cleanup;
01823 
01824     return fors_image_new(data, variance);
01825 }
01826 
01838 fors_image *
01839 fors_image_collapse_median_create(const fors_image_list *images)
01840 {
01841     cpl_imagelist *datlist = NULL;
01842     cpl_imagelist *varlist = NULL;
01843     cpl_image *data = NULL;
01844     cpl_image *variance = NULL;
01845     const fors_image *i;
01846     int N = 0;
01847 
01848     assure( images != NULL, return NULL, NULL );
01849     assure( fors_image_list_size(images) > 0, return NULL, 
01850             "Cannot stack zero images");
01851 
01852     i = fors_image_list_first_const(images);
01853     
01854     datlist = cpl_imagelist_new();
01855     varlist = cpl_imagelist_new();
01856     while(i != NULL) {
01857         /* Append to image lists */
01858         cpl_imagelist_set(datlist, 
01859                           cpl_image_duplicate(i->data), 
01860                           cpl_imagelist_get_size(datlist));
01861         cpl_imagelist_set(varlist,
01862                           cpl_image_duplicate(i->variance),
01863                           cpl_imagelist_get_size(varlist));
01864 
01865         i = fors_image_list_next_const(images);
01866         N++;
01867     }
01868     
01869 #ifdef CPL_IS_NOT_CRAP
01870     data    = cpl_imagelist_collapse_median_create(datlist);
01871 
01872     variance = cpl_imagelist_collapse_create(varlist);
01873 #else
01874     data    = fors_imagelist_collapse_median_create(datlist);
01875 
01876     variance = fors_imagelist_collapse_create(varlist);
01877 #endif
01878 
01879     cpl_image_divide_scalar(variance, N);
01880 
01881     cpl_image_multiply_scalar(variance, 
01882                   fors_utils_median_corr(N) * 
01883                   fors_utils_median_corr(N));
01884     
01885     cleanup;
01886     return fors_image_new(data, variance);
01887 }
01888 
01889 #undef cleanup
01890 #define cleanup
01891 
01908 void fors_image_draw(fors_image *image, int type,
01909              double x, double y,
01910              int radius, double color)
01911 {
01912     assure( image != NULL, return, NULL );
01913 
01914     assure( type == 0 || type == 1 || type == 2,
01915             return , "Unsupported type %d", type);
01916 
01917     assure( radius > 0, return, NULL );
01918 
01919     if (type == 2) {
01920         int i;
01921         for (i = 0; i < 360; i++) {
01922             /* Step size of 1 degree is arbitrary */
01923 
01924             int px = x + radius*cos(i/(2*M_PI));
01925             int py = y + radius*sin(i/(2*M_PI));
01926             
01927             if (1 <= px && px <= cpl_image_get_size_x(image->data) &&
01928                 1 <= py && py <= cpl_image_get_size_y(image->data)) {
01929                 cpl_image_set(image->data, px, py, color);
01930                 cpl_image_set(image->variance, px, py, color > 0 ? color : 0);
01931             }
01932         }
01933     }
01934     else {
01935         int i;
01936 
01937         for (i = -radius; i <= radius; i++) {
01938 
01939             int px, py;
01940             
01941             if (type == 0) {
01942                 px = x + i;
01943                 py = y;
01944             }
01945             else {
01946                 px = x;
01947                 py = y + i;
01948             }
01949             
01950             if (1 <= px && px <= cpl_image_get_size_x(image->data) &&
01951                 1 <= py && py <= cpl_image_get_size_y(image->data)) {
01952                 cpl_image_set(image->data    , px, py, color);
01953                 cpl_image_set(image->variance, px, py, color > 0 ? color : 0);
01954             }
01955         }
01956     }
01957 
01958     return;
01959 }
01960 
01961 #define LIST_DEFINE
01962 #undef LIST_ELEM
01963 #define LIST_ELEM fors_image
01964 #include <list.h>
01965 

Generated on Fri Mar 4 09:46:00 2011 for FORS Pipeline Reference Manual by  doxygen 1.4.7