sinfo_distortion.c

00001 /* $Id: sinfo_distortion.c,v 1.37 2012/03/05 16:34:06 amodigli Exp $
00002  *
00003  * This file is part of the irplib package
00004  * Copyright (C) 2002,2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: amodigli $
00023  * $Date: 2012/03/05 16:34:06 $
00024  * $Revision: 1.37 $
00025  * $Name: HEAD $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 #include <sinfo_cpl_size.h>
00032 
00033 /*----------------------------------------------------------------------------
00034                                    Includes
00035  ----------------------------------------------------------------------------*/
00036 
00037 #include <cpl.h>
00038 #include <sinfo_cpl_size.h>
00039 #include <math.h>
00040 
00041 
00042 #include "sinfo_distortion.h"
00043 #include "sinfo_functions.h"
00044 #include "sinfo_msg.h"
00045 #include "sinfo_error.h"
00046 #include "irplib_flat.h"
00047 #include "sinfo_utils_wrappers.h"
00048 //#include "sinfo_irplib_cpl_wrp.h"
00049 #include "sinfo_utilities.h"
00050 /*-----------------------------------------------------------------------------
00051                                    Define
00052  ----------------------------------------------------------------------------*/
00053 
00054 #define ARC_NBSAMPLES       20
00055 #define ARC_THRESHFACT      (1.0/3.0)
00056 #define ARC_MINGOODPIX      100
00057 #define ARC_MINARCLENFACT   1.19   /* 1.1-2 */
00058 #define ARC_MINNBARCS       32     /* 4-32 */
00059 #define ARC_RANGE_FACT      3.0
00060 #define ARC_WINDOWSIZE      10  /* 32 */
00061 
00062 #define TRESH_MEDIAN_MIN    0.0
00063 #define TRESH_SIGMA_MAX     200.0
00064 
00066 /*---------------------------------------------------------------------------*/
00070 /*---------------------------------------------------------------------------*/
00071 
00072 /*----------------------------------------------------------------------------
00073                                 Functions prototypes
00074  ----------------------------------------------------------------------------*/
00075 static cpl_apertures *
00076 sinfo_distortion_detect_arcs_new(cpl_image* ,cpl_image   **,
00077                                  int,int,double,int,int,int,int,double,int);
00078 
00079 static
00080 cpl_apertures * sinfo_distortion_detect_arcs(cpl_image *,
00081         cpl_image **, int, int, int, int, int, int) ;
00082 static int
00083 sinfo_distortion_fill_badzones(cpl_image *, int, int, int, int, double) ;
00084 static int
00085 sinfo_distortion_threshold1d(cpl_image *, double, cpl_image *, double) ;
00086 static int
00087 sinfo_distortion_purge_arcs(cpl_image *, cpl_apertures **,
00088                             cpl_image **, int, int, double) ;
00089 static cpl_bivector **
00090 sinfo_distortion_get_arc_positions(cpl_image *,
00091                                    cpl_image *,
00092                                    cpl_apertures *, int, double **) ;
00093 static double sinfo_distortion_fine_pos(cpl_image *, cpl_image *, int, int) ;
00094 static int sinfo_distortion_sub_hor_lowpass(cpl_image *, int) ;
00095 static cpl_image * sinfo_distortion_remove_ramp(const cpl_image *) ;
00096 static cpl_image *
00097 sinfo_distortion_smooth(cpl_image* inp,const int r,const int d);
00098 
00099 
00100 
00101 
00102 /*----------------------------------------------------------------------------
00103                                 Functions code
00104  ----------------------------------------------------------------------------*/
00105 
00106 
00107 /*---------------------------------------------------------------------------*/
00117 static cpl_image *
00118 sinfo_distortion_smooth(cpl_image* inp,const int r,const int d)
00119 {
00120 
00121   int sx=0;
00122   int sy=0;
00123   int i=0;
00124   int j=0;
00125   int z=0;
00126 
00127   float sum;
00128   cpl_image* out=NULL;
00129   float* pi=NULL;
00130   float* po=NULL;
00131   int min=0;
00132 
00133   cknull(inp,"Null input image!");
00134   check_nomsg(sx=cpl_image_get_size_x(inp));
00135   check_nomsg(sy=cpl_image_get_size_y(inp));
00136   check_nomsg(out=cpl_image_duplicate(inp));
00137   check_nomsg(pi=cpl_image_get_data_float(inp));
00138   check_nomsg(po=cpl_image_get_data_float(out));
00139   min = r/2;
00140   switch (d) {
00141   case 0:
00142     for(j=0;j<sy;j++) {
00143       for(i=min;i<sx-min;i++) {
00144     sum=0;
00145     for(z=i-min;z<i+min+1;z++) {
00146       sum+=pi[z+j*sx];
00147     }
00148         po[i+j*sx]=sum/r;
00149       }
00150     }
00151     break;
00152 
00153   case 1:
00154     for(i=0;i<sx;i++) {
00155       for(j=min;j<sy-min;j++) {
00156     sum=0;
00157     for(z=j-min;z<j+min+1;z++) {
00158       sum+=pi[i+z*sx];
00159     }
00160         po[i+j*sx]=sum;
00161       }
00162     }
00163     break;
00164 
00165   default:
00166     sinfo_msg_error("case not supported");
00167     goto cleanup;
00168 
00169   }
00170   check_nomsg(cpl_image_delete(inp));
00171   return out;
00172  cleanup:
00173   return NULL;
00174 }
00175 
00176 /*---------------------------------------------------------------------------*/
00189 cpl_image *
00190 sinfo_distortion_image_restore(const cpl_image* inp,
00191                                const int r,
00192                                const int d,
00193                                const double kappa,
00194                                const int ks_method,
00195                                const int n)
00196 {
00197 
00198   int sx=0;
00199   int sy=0;
00200   int i=0;
00201   int j=0;
00202   int z=0;
00203   int k=0;
00204 
00205 
00206   cpl_image* out=NULL;
00207   const float* pi=NULL;
00208   float* po=NULL;
00209   int min=0;
00210   cpl_vector* vec=NULL;
00211   double* pv=NULL;
00212   double mean=0;
00213   double median=0;
00214 
00215   cknull(inp,"Null input image!");
00216   check_nomsg(sx=cpl_image_get_size_x(inp));
00217   check_nomsg(sy=cpl_image_get_size_y(inp));
00218   check_nomsg(out=cpl_image_duplicate(inp));
00219   check_nomsg(pi=cpl_image_get_data_float_const(inp));
00220   check_nomsg(po=cpl_image_get_data_float(out));
00221   min = r/2;
00222   check_nomsg(vec=cpl_vector_new(r));
00223   check_nomsg(pv=cpl_vector_get_data(vec));
00224   switch (d) {
00225   case 0:
00226     for(j=0;j<sy;j++) {
00227       for(i=min;i<sx-min;i++) {
00228     k=0;
00229     for(z=i-min;z<i+min+1;z++) {
00230       pv[k]=(double)pi[z+j*sx];
00231           k++;
00232     }
00233         cknull_nomsg(vec=sinfo_vector_clip(vec,kappa,n,ks_method));
00234         check_nomsg(mean=cpl_vector_get_mean(vec));
00235         check_nomsg(median=cpl_vector_get_mean(vec));
00236         po[i+j*sx]+=(mean-median);
00237       }
00238     }
00239     break;
00240 
00241   case 1:
00242     for(i=0;i<sx;i++) {
00243       for(j=min;j<sy-min;j++) {
00244         k=0;
00245     for(z=j-min;z<j+min+1;z++) {
00246       pv[k]=(double)pi[i+z*sx];
00247           k++;
00248     }
00249         cknull_nomsg(vec=sinfo_vector_clip(vec,kappa,n,ks_method));
00250         check_nomsg(mean=cpl_vector_get_mean(vec));
00251         check_nomsg(median=cpl_vector_get_mean(vec));
00252         po[i+j*sx]+=(mean-median);
00253       }
00254     }
00255     break;
00256 
00257   default:
00258     sinfo_msg_error("case not supported");
00259     goto cleanup;
00260 
00261   }
00262   check_nomsg(cpl_image_delete((cpl_image*)inp));
00263   return out;
00264  cleanup:
00265   return NULL;
00266 }
00267 
00268 /*---------------------------------------------------------------------------*/
00292 /*---------------------------------------------------------------------------*/
00293 cpl_polynomial * sinfo_distortion_estimate_new(
00294         const cpl_image *   org,
00295         int                 xmin,
00296         int                 ymin,
00297         int                 xmax,
00298         int                 ymax,
00299         int                 auto_ramp_sub,
00300         int                 arc_sat,
00301         int                 max_arc_width,
00302         double              kappa,
00303         double              arcs_min_arclen_factor,
00304         int                 arcs_window_size,
00305         int                 smooth_rad,
00306         int                 degree,
00307         double              offset,
00308         cpl_apertures   **  arcs)
00309 {
00310     cpl_image       *   local_im ;
00311     cpl_image       *   label_image ;
00312     double              rightmost, leftmost ;
00313     cpl_bivector    **  arcs_pos ;
00314     double          *   parc_posx ;
00315     double          *   parc_posy ;
00316     double          *   lines_pos ;
00317     cpl_bivector    *   grid ;
00318     double          *   pgridx ;
00319     double          *   pgridy ;
00320     cpl_vector      *   values_to_fit ;
00321     double          *   pvalues_to_fit ;
00322     int                 min_arc_range ;
00323     int                 n_calib ;
00324     int                 n_arcs ;
00325     cpl_polynomial  *   poly2d ;
00326     int                 nx ;
00327     int                 i, j ;
00328 
00329     /* AMO added to use offset */
00330     cpl_vector    *     lines_pos_tmp ;
00331     cpl_bivector    *   grid_tmp ;
00332     cpl_vector* grid_tot=0;
00333     double* pgrid_tmp_x=NULL;
00334     double* pgrid_tmp_y=NULL;
00335     double* pgrid_tot=NULL;
00336     double* plines_pos_tmp=NULL;
00337     int n_lines=0;
00338     int k=0;
00339 
00340 
00341     /* Check entries */
00342     if (org == NULL) return NULL ;
00343     if (kappa < 0.0) return NULL ;
00344 
00345     /* Initialise */
00346     n_calib = ARC_NBSAMPLES ;
00347     nx = cpl_image_get_size_x(org) ;
00348 
00349     if (auto_ramp_sub) {
00350         local_im = sinfo_distortion_remove_ramp(org) ;
00351     } else {
00352         /* Local copy of input image */
00353         local_im = cpl_image_duplicate(org) ;
00354     }
00355     if (local_im == NULL) {
00356         cpl_msg_error(cpl_func, "Cannot clean the image") ;
00357         return NULL ;
00358     }
00359     if(smooth_rad > 1) {
00360       local_im=sinfo_distortion_smooth(local_im,smooth_rad,1);
00361       //cpl_image_save(local_im,"out_local_im.fits",CPL_BPP_IEEE_FLOAT,
00362       //               NULL,CPL_IO_DEFAULT);
00363       //local_im=sinfo_distortion_image_restore(local_im,smooth_rad,1,2,0,2);
00364       //cpl_image_save(local_im,"out_local_im_post.fits",
00365       //               CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
00366 
00367     }
00368     /* Detect the arcs in the input image */
00369     cpl_msg_info(cpl_func, "Detect arcs") ;
00370     if ((*arcs = sinfo_distortion_detect_arcs_new(local_im,
00371                     &label_image,
00372                     arc_sat, max_arc_width, kappa,
00373                     xmin, ymin, xmax, ymax,
00374                     arcs_min_arclen_factor,arcs_window_size)) == NULL) {
00375         cpl_image_delete(local_im) ;
00376         cpl_msg_error(cpl_func, "Cannot detect the arcs") ;
00377         return NULL ;
00378     }
00379     n_arcs = cpl_apertures_get_size(*arcs) ;
00380     cpl_msg_info(cpl_func, "%d detected arcs", n_arcs) ;
00381 
00382     /* Check that the arcs are not concentrated in the same zone */
00383     rightmost = leftmost = cpl_apertures_get_pos_x(*arcs, 1) ;
00384     for (i=1 ; i<n_arcs ; i++) {
00385         if (cpl_apertures_get_pos_x(*arcs, i+1) < leftmost)
00386             leftmost = cpl_apertures_get_pos_x(*arcs, i+1) ;
00387         if (cpl_apertures_get_pos_x(*arcs, i+1) > rightmost)
00388             rightmost = cpl_apertures_get_pos_x(*arcs, i+1) ;
00389     }
00390     min_arc_range = (int)(nx / ARC_RANGE_FACT) ;
00391     if ((int)(rightmost-leftmost) < min_arc_range) {
00392         cpl_msg_error(cpl_func, "too narrow range (%g-%g)<%d",
00393                 rightmost, leftmost, min_arc_range) ;
00394         cpl_apertures_delete(*arcs) ;
00395         cpl_image_delete(local_im) ;
00396         cpl_image_delete(label_image) ;
00397         return NULL ;
00398     }
00399 
00400     /* Create a 2-D deformation grid with detected arcs */
00401     cpl_msg_info(cpl_func, "Create deformation grid") ;
00402     lines_pos = cpl_malloc(n_arcs * sizeof(double)) ;
00403     if ((arcs_pos = sinfo_distortion_get_arc_positions(local_im,
00404                     label_image, *arcs, n_calib, &lines_pos))==NULL){
00405         cpl_msg_error(cpl_func, "cannot get arcs positions") ;
00406         cpl_apertures_delete(*arcs) ;
00407         cpl_image_delete(local_im) ;
00408         cpl_free(lines_pos) ;
00409         cpl_image_delete(label_image) ;
00410         return NULL ;
00411     }
00412     cpl_image_delete(label_image) ;
00413     cpl_image_delete(local_im) ;
00414 
00415     /* Prepare the fitting */
00416     lines_pos_tmp=cpl_vector_new(n_arcs);
00417     plines_pos_tmp=cpl_vector_get_data(lines_pos_tmp);
00418 
00419 
00420     sinfo_msg("Fit the 2d polynomial") ;
00421     grid = cpl_bivector_new(n_arcs * n_calib) ;
00422     pgridx = cpl_bivector_get_x_data(grid) ;
00423     pgridy = cpl_bivector_get_y_data(grid) ;
00424     values_to_fit = cpl_vector_new(n_arcs * n_calib) ;
00425     pvalues_to_fit = cpl_vector_get_data(values_to_fit) ;
00426 
00427     for (i=0 ; i<n_arcs ; i++) {
00428         parc_posx = cpl_bivector_get_x_data(arcs_pos[i]) ;
00429         parc_posy = cpl_bivector_get_y_data(arcs_pos[i]) ;
00430         for (j=0 ; j<n_calib ; j++) {
00431             plines_pos_tmp[i]=lines_pos[i] ;
00432             pgridx[j+i*n_calib] = lines_pos[i] ;
00433             pgridy[j+i*n_calib] = parc_posy[j] ;
00434             pvalues_to_fit[j+i*n_calib] = parc_posx[j] ;
00435         }
00436     }
00437     /* AMO new to use offset */
00438     n_lines= n_arcs/32.0;
00439     if(n_lines < 1) {
00440       n_lines=1;
00441     }
00442     cpl_vector_sort(lines_pos_tmp,1);
00443     plines_pos_tmp=cpl_vector_get_data(lines_pos_tmp);
00444     grid_tmp=cpl_bivector_duplicate(grid);
00445     grid_tot=cpl_vector_new(n_calib);
00446     pgrid_tmp_x = cpl_bivector_get_x_data(grid_tmp) ;
00447     pgrid_tmp_y = cpl_bivector_get_y_data(grid_tmp) ;
00448     pgrid_tot = cpl_vector_get_data(grid_tot);
00449     for(j=0;j<n_calib;j++) {
00450       pgrid_tot[j]=0;
00451       for(i=n_lines ;i<n_arcs;i=i+n_lines)
00452     {
00453       for(k=0;k<n_lines;k++) {
00454         pgrid_tot[j] += (plines_pos_tmp[i+k]-
00455                              plines_pos_tmp[k]);
00456         /*
00457             sinfo_msg("diff=%g",(plines_pos_tmp[i+k]-
00458                  plines_pos_tmp[k]));
00459         */
00460       }
00461     }
00462       /*
00463       sinfo_msg("j=%d pgrid_tot=%g",j,pgrid_tot[j]);
00464       */
00465     }
00466 
00467     for(j=0;j<n_calib;j++) {
00468       for (i=0 ; i<n_arcs ; i++) {
00469      pgridx[j+i*n_calib]=pgridx[j+i*n_calib]*
00470                              ((nx/32.0)*n_lines*(31*32/2))/pgrid_tot[j]-offset;
00471      /*
00472          sinfo_msg_error("AMo after corr grid[%d,%d]=%g",
00473                           i,k,pgridx[k+i*n_calib]);
00474      */
00475      pgrid_tmp_x[j+i*n_calib]=pgrid_tmp_x[j+i*n_calib]*
00476                                   ((nx/32.0)*n_lines*(31*32/2))/pgrid_tot[j]-
00477                                   offset;
00478 
00479       }
00480     }
00481     cpl_vector_delete(lines_pos_tmp);
00482     cpl_bivector_delete(grid_tmp);
00483     cpl_vector_delete(grid_tot);
00484     /* end AMO: to use the offset */
00485 
00486 
00487     for (i=0 ; i<n_arcs ; i++) cpl_bivector_delete(arcs_pos[i]) ;
00488     cpl_free(arcs_pos) ;
00489     cpl_free(lines_pos) ;
00490 
00491     /* Apply the fitting */
00492     if ((poly2d = sinfo_polynomial_fit_2d_create(grid, values_to_fit,
00493                     degree, NULL))==NULL) {
00494         cpl_msg_error(cpl_func, "cannot apply the 2d fit") ;
00495         cpl_bivector_delete(grid) ;
00496         cpl_vector_delete(values_to_fit) ;
00497         cpl_apertures_delete(*arcs) ;
00498         return NULL ;
00499     }
00500 
00501     /* Free and return */
00502     cpl_bivector_delete(grid) ;
00503     cpl_vector_delete(values_to_fit) ;
00504     return poly2d ;
00505 }
00506 
00507 
00508 
00509 /*---------------------------------------------------------------------------*/
00525 /*---------------------------------------------------------------------------*/
00526 static cpl_apertures * sinfo_distortion_detect_arcs_new(
00527         cpl_image   *   im,
00528         cpl_image   **  label_im,
00529         int             arc_sat,
00530         int             max_arc_width,
00531         double          kappa,
00532         int             xmin,
00533         int             ymin,
00534         int             xmax,
00535         int             ymax,
00536         double arcs_min_arclen_factor,
00537         int arcs_window_size)
00538 {
00539     cpl_image       *   filt_im ;
00540     cpl_matrix      *   filter ;
00541     cpl_image       *   collapsed ;
00542     cpl_mask        *   bin_im ;
00543     double              threshold, fillval, median_val, sigma ;
00544     int                 min_arclen = 0 ;
00545     cpl_apertures   *   det ;
00546     cpl_size                 nobj ;
00547     int                 ngoodpix ;
00548     int                 ny ;
00549 
00550     ny = cpl_image_get_size_y(im) ;
00551     /* Default values for output parameters */
00552     *label_im = NULL ;
00553 
00554     /* Clear zones to be ignored (to avoid false detections) */
00555     median_val = cpl_image_get_median_dev(im, &sigma) ;
00556     fillval = median_val-sigma/2.0 ;
00557     if (sinfo_distortion_fill_badzones(im, xmin, ymin, xmax, ymax,
00558                 fillval) == -1) {
00559         cpl_msg_error(cpl_func, "cannot fill bad zones") ;
00560         return NULL ;
00561     }
00562     /* Median vertical filter */
00563     filter = cpl_matrix_new(3, 1) ;
00564     cpl_matrix_fill(filter, 1.0) ;
00565     /* filt_im = cpl_image_filter_median(im, filter) ; */
00566     filt_im = cpl_image_duplicate(im) ;
00567     cpl_matrix_delete(filter) ;
00568 
00569     /* Subtract a low-pass */
00570     /* AMO: suppressed as may remove arcs */
00571     if (sinfo_distortion_sub_hor_lowpass(filt_im, arcs_window_size) == -1) {
00572         cpl_image_delete(filt_im) ;
00573         return NULL ;
00574     }
00575     //cpl_image_save(filt_im,"out_filt_im_lp.fits",CPL_BPP_IEEE_FLOAT,
00576     //               NULL,CPL_IO_DEFAULT);
00577 
00578     /* Get relevant stats for thresholding */
00579     median_val = cpl_image_get_median_dev(filt_im, &sigma) ;
00580 
00581     /* Correct median_val and sigma if necessary */
00582     if (median_val < TRESH_MEDIAN_MIN) median_val = TRESH_MEDIAN_MIN ;
00583     if (sigma > TRESH_SIGMA_MAX) sigma = TRESH_SIGMA_MAX ;
00584 
00585     /* Set the threshold */
00586     threshold = median_val + sigma * kappa ;
00587 
00588     /* Collapse the image */
00589     collapsed = cpl_image_collapse_median_create(filt_im, 0, 0, 0) ;
00590 
00591     /* Threshold to keep only the arcs - use of the collapsed image */
00592     if (sinfo_distortion_threshold1d(filt_im, median_val,
00593                                      collapsed, 0.0)==-1) {
00594         cpl_msg_error(cpl_func, "cannot threshold the filtered image") ;
00595         cpl_image_delete(filt_im) ;
00596         cpl_image_delete(collapsed) ;
00597         return NULL ;
00598     }
00599     cpl_image_delete(collapsed) ;
00600 
00601     /* Binarize the image */
00602     bin_im = cpl_mask_threshold_image_create(filt_im, threshold,
00603             SINFO_DBL_MAX);
00604     cpl_image_delete(filt_im) ;
00605     if (bin_im == NULL) {
00606         cpl_msg_error(cpl_func, "cannot binarise the image") ;
00607         return NULL ;
00608     }
00609 
00610     /* Test if there are enough good pixels */
00611     ngoodpix = cpl_mask_count(bin_im) ;
00612     if (ngoodpix < ARC_MINGOODPIX) {
00613         cpl_msg_error(cpl_func, "Too few (%d) white pixels", ngoodpix) ;
00614         cpl_mask_delete(bin_im) ;
00615         return NULL ;
00616     }
00617 
00618     /* Apply a morphological closing to clean the isolated pixels */
00619     filter = cpl_matrix_new(3, 3) ;
00620     cpl_matrix_fill(filter, 1.0) ;
00621     cpl_mask_closing(bin_im, filter) ;
00622     cpl_matrix_delete(filter) ;
00623 
00624     /* Labelize pixel map to a label image */
00625     *label_im = cpl_image_labelise_mask_create(bin_im, &nobj) ;
00626     cpl_mask_delete(bin_im) ;
00627     //cpl_image_save(*label_im,"out_label_im.fits",CPL_BPP_IEEE_FLOAT,
00628     //               NULL,CPL_IO_DEFAULT);
00629 
00630     /* Compute statistics on objects */
00631     if ((det = cpl_apertures_new_from_image(im, *label_im)) == NULL) {
00632         cpl_msg_error(cpl_func, "Cannot compute arcs stats") ;
00633         cpl_image_delete(*label_im) ;
00634         *label_im = NULL ;
00635         return NULL ;
00636     }
00637     /* Set min_arclen */
00638     min_arclen = (int)(ny /arcs_min_arclen_factor) ;
00639     //cpl_image_save(im,"out_im.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
00640 
00641     /* Purge non-relevant arcs */
00642     /* cpl_apertures_dump(det,stdout); */
00643     if (sinfo_distortion_purge_arcs(im, &det, label_im, min_arclen,
00644                 max_arc_width, arc_sat) == -1) {
00645         cpl_msg_error(cpl_func, "Cannot purge the arcs") ;
00646         cpl_image_delete(*label_im) ;
00647         *label_im = NULL ;
00648         cpl_apertures_delete(det) ;
00649         return NULL ;
00650     }
00651     /* cpl_apertures_dump(det,stdout); */
00652     if (cpl_apertures_get_size(det) < ARC_MINNBARCS) {
00653         cpl_msg_error(cpl_func, "Not enough valid arcs (%" 
00654                       CPL_SIZE_FORMAT " < %d)",
00655                 cpl_apertures_get_size(det), ARC_MINNBARCS) ;
00656         cpl_image_delete(*label_im) ;
00657         *label_im = NULL ;
00658         cpl_apertures_delete(det) ;
00659         return NULL ;
00660     }
00661 
00662     /* Return  */
00663     return det ;
00664 }
00665 
00666 
00667 
00668 /*---------------------------------------------------------------------------*/
00692 /*---------------------------------------------------------------------------*/
00693 cpl_polynomial * sinfo_distortion_estimate(
00694         const cpl_image *   org,
00695         int                 xmin,
00696         int                 ymin,
00697         int                 xmax,
00698         int                 ymax,
00699         int                 auto_ramp_sub,
00700         int                 arc_sat,
00701         int                 max_arc_width,
00702         int                 degree,
00703         double              offset,
00704         cpl_apertures   **  arcs)
00705 {
00706     const char      *   fctid = "sinfo_distortion_estimate" ;
00707     cpl_image       *   local_im ;
00708     cpl_image       *   label_image ;
00709     double              rightmost, leftmost ;
00710     cpl_bivector    **  arcs_pos ;
00711     double          *   parc_posx ;
00712     double          *   parc_posy ;
00713     double          *   lines_pos ;
00714     cpl_bivector    *   grid ;
00715     double          *   pgridx ;
00716     double          *   pgridy ;
00717     cpl_vector      *   values_to_fit ;
00718     double          *   pvalues_to_fit ;
00719     int                 min_arc_range ;
00720     int                 n_calib ;
00721     int                 n_arcs ;
00722     cpl_polynomial  *   poly2d ;
00723     int                 nx ;
00724     int                 i, j ;
00725 
00726     /* AMO added to use offset */
00727     cpl_vector    *     lines_pos_tmp ;
00728     cpl_bivector    *   grid_tmp ;
00729     int n_lines=0;
00730     int k=0;
00731     cpl_vector* grid_tot=0;
00732     double* pgrid_tmp_x=NULL;
00733     double* pgrid_tmp_y=NULL;
00734     double* pgrid_tot=NULL;
00735     double* plines_pos_tmp=NULL;
00736 
00737     /* Check entries */
00738     if (org == NULL) return NULL ;
00739 
00740     /* Initialise */
00741     n_calib = ARC_NBSAMPLES ;
00742     nx = cpl_image_get_size_x(org) ;
00743 
00744     if (auto_ramp_sub) {
00745         local_im = sinfo_distortion_remove_ramp(org) ;
00746     } else {
00747         /* Local copy of input image */
00748         local_im = cpl_image_duplicate(org) ;
00749     }
00750     if (local_im == NULL) {
00751         cpl_msg_error(fctid, "Cannot clean the image") ;
00752         return NULL ;
00753     }
00754 
00755     /* Detect the arcs in the input image */
00756     cpl_msg_info(fctid, "Detect arcs") ;
00757     if ((*arcs = sinfo_distortion_detect_arcs(local_im,
00758                     &label_image,
00759                     arc_sat, max_arc_width,
00760                     xmin, ymin, xmax, ymax)) == NULL) {
00761         cpl_image_delete(local_im) ;
00762         cpl_msg_error(fctid, "Cannot detect the arcs") ;
00763         return NULL ;
00764     }
00765     n_arcs = cpl_apertures_get_size(*arcs) ;
00766     cpl_msg_info(fctid, "%d detected arcs", n_arcs) ;
00767 
00768     /* Check that the arcs are not concentrated in the same zone */
00769     rightmost = leftmost = cpl_apertures_get_pos_x(*arcs, 1) ;
00770     for (i=1 ; i<n_arcs ; i++) {
00771         if (cpl_apertures_get_pos_x(*arcs, i+1) < leftmost)
00772             leftmost = cpl_apertures_get_pos_x(*arcs, i+1) ;
00773         if (cpl_apertures_get_pos_x(*arcs, i+1) > rightmost)
00774             rightmost = cpl_apertures_get_pos_x(*arcs, i+1) ;
00775     }
00776     min_arc_range = (int)(nx / ARC_RANGE_FACT) ;
00777     if ((int)(rightmost-leftmost) < min_arc_range) {
00778         cpl_msg_error(fctid, "too narrow range (%g-%g)<%d",
00779                 rightmost, leftmost, min_arc_range) ;
00780         cpl_apertures_delete(*arcs) ;
00781         cpl_image_delete(local_im) ;
00782         cpl_image_delete(label_image) ;
00783         return NULL ;
00784     }
00785 
00786     /* Create a 2-D deformation grid with detected arcs */
00787     cpl_msg_info(fctid, "Create deformation grid") ;
00788     lines_pos = cpl_malloc(n_arcs * sizeof(double)) ;
00789     if ((arcs_pos = sinfo_distortion_get_arc_positions(local_im,
00790                     label_image, *arcs, n_calib, &lines_pos))==NULL){
00791         cpl_msg_error(fctid, "cannot get arcs positions") ;
00792         cpl_apertures_delete(*arcs) ;
00793         cpl_image_delete(local_im) ;
00794         cpl_free(lines_pos) ;
00795         cpl_image_delete(label_image) ;
00796         return NULL ;
00797     }
00798     cpl_image_delete(label_image) ;
00799     cpl_image_delete(local_im) ;
00800 
00801     /* Prepare the fitting */
00802     lines_pos_tmp=cpl_vector_new(n_arcs);
00803     plines_pos_tmp=cpl_vector_get_data(lines_pos_tmp);
00804 
00805     cpl_msg_info(fctid, "Fit the 2d polynomial") ;
00806     grid = cpl_bivector_new(n_arcs * n_calib) ;
00807     pgridx = cpl_bivector_get_x_data(grid) ;
00808     pgridy = cpl_bivector_get_y_data(grid) ;
00809     values_to_fit = cpl_vector_new(n_arcs * n_calib) ;
00810     pvalues_to_fit = cpl_vector_get_data(values_to_fit) ;
00811     for (i=0 ; i<n_arcs ; i++) {
00812         parc_posx = cpl_bivector_get_x_data(arcs_pos[i]) ;
00813         parc_posy = cpl_bivector_get_y_data(arcs_pos[i]) ;
00814         for (j=0 ; j<n_calib ; j++) {
00815             plines_pos_tmp[i]=lines_pos[i] ;
00816             pgridx[j+i*n_calib] = lines_pos[i] ;
00817             pgridy[j+i*n_calib] = parc_posy[j] ;
00818             pvalues_to_fit[j+i*n_calib] = parc_posx[j];
00819 
00820 /*
00821       sinfo_msg("pgridx=%g pgridy=%g pvalues=%g",
00822           pgridx[j+i*n_calib],pgridy[j+i*n_calib],pvalues_to_fit[j+i*n_calib]);
00823 */
00824         }
00825     }
00826 
00827 
00828     /* AMO new to use offset */
00829     n_lines= n_arcs/32.0;
00830     if(n_lines < 1) {
00831       n_lines=1;
00832     }
00833     cpl_vector_sort(lines_pos_tmp,1);
00834     plines_pos_tmp=cpl_vector_get_data(lines_pos_tmp);
00835 
00836     grid_tmp=cpl_bivector_duplicate(grid);
00837     grid_tot=cpl_vector_new(n_calib);
00838     pgrid_tmp_x = cpl_bivector_get_x_data(grid_tmp) ;
00839     pgrid_tmp_y = cpl_bivector_get_y_data(grid_tmp) ;
00840     pgrid_tot = cpl_vector_get_data(grid_tot);
00841     for(j=0;j<n_calib;j++) {
00842       pgrid_tot[j]=0;
00843       for(i=n_lines ;i<n_arcs;i=i+n_lines)
00844     {
00845       for(k=0;k<n_lines;k++) {
00846         pgrid_tot[j] += (plines_pos_tmp[i+k]-
00847                              plines_pos_tmp[k]);
00848         /*
00849             sinfo_msg("diff=%g",(plines_pos_tmp[i+k]-
00850                  plines_pos_tmp[k]));
00851         */
00852       }
00853     }
00854       /*
00855       sinfo_msg("j=%d pgrid_tot=%g",j,pgrid_tot[j]);
00856       */
00857     }
00858 
00859     for(j=0;j<n_calib;j++) {
00860       for (i=0 ; i<n_arcs ; i++) {
00861      pgridx[j+i*n_calib]=pgridx[j+i*n_calib]*
00862                              ((nx/32.0)*n_lines*(31*32/2))/pgrid_tot[j]-offset;
00863      /*
00864          sinfo_msg_error("AMo after corr grid[%d,%d]=%g",
00865                           i,k,pgridx[k+i*n_calib]);
00866      */
00867      pgrid_tmp_x[j+i*n_calib]=pgrid_tmp_x[j+i*n_calib]*
00868                                   ((nx/32.0)*n_lines*(31*32/2))/pgrid_tot[j]-
00869                                    offset;
00870 
00871       }
00872     }
00873     /* end AMO: to use the offset */
00874 
00875 
00876     for (i=0 ; i<n_arcs ; i++) cpl_bivector_delete(arcs_pos[i]) ;
00877     cpl_free(arcs_pos) ;
00878     cpl_free(lines_pos) ;
00879 
00880     /* Apply the fitting */
00881     if ((poly2d = sinfo_polynomial_fit_2d_create(grid, values_to_fit,
00882                     degree, NULL))==NULL) {
00883         cpl_msg_error(fctid, "cannot apply the 2d fit") ;
00884         cpl_bivector_delete(grid) ;
00885         cpl_vector_delete(values_to_fit) ;
00886         cpl_apertures_delete(*arcs) ;
00887         return NULL ;
00888     }
00889 
00890     /* Free and return */
00891     cpl_bivector_delete(grid) ;
00892     cpl_vector_delete(values_to_fit) ;
00893     return poly2d ;
00894 }
00895 
00898 /*---------------------------------------------------------------------------*/
00913 /*---------------------------------------------------------------------------*/
00914 static cpl_apertures * sinfo_distortion_detect_arcs(
00915         cpl_image   *   im,
00916         cpl_image   **  label_im,
00917         int             arc_sat,
00918         int             max_arc_width,
00919         int             xmin,
00920         int             ymin,
00921         int             xmax,
00922         int             ymax)
00923 {
00924     const char      *   fctid = "sinfo_distortion_detect_arcs" ;
00925     cpl_image       *   filt_im ;
00926     cpl_matrix      *   filter ;
00927     cpl_image       *   collapsed ;
00928     cpl_mask        *   bin_im ;
00929     double              threshold, fillval, median_val, sigma ;
00930     int                 min_arclen = 0 ;
00931     cpl_apertures   *   det ;
00932     cpl_size                 nobj ;
00933     int                 ngoodpix ;
00934     int                 ny ;
00935 
00936     ny = cpl_image_get_size_y(im) ;
00937 
00938     /* Default values for output parameters */
00939     *label_im = NULL ;
00940 
00941     /* Clear zones to be ignored (to avoid false detections) */
00942     median_val = cpl_image_get_median_dev(im, &sigma) ;
00943     fillval = median_val-sigma/2.0 ;
00944     if (sinfo_distortion_fill_badzones(im, xmin, ymin, xmax, ymax,
00945                 fillval) == -1) {
00946         cpl_msg_error(fctid, "cannot fill bad zones") ;
00947         return NULL ;
00948     }
00949 
00950     /* Median vertical filter */
00951     filter = cpl_matrix_new(3, 1) ;
00952     cpl_matrix_fill(filter, 1.0) ;
00953     /* filt_im = cpl_image_filter_median(im, filter) ; */
00954     filt_im = cpl_image_duplicate(im) ;
00955     cpl_matrix_delete(filter) ;
00956 
00957     /* Subtract a low-pass */
00958     if (sinfo_distortion_sub_hor_lowpass(filt_im, ARC_WINDOWSIZE) == -1) {
00959         cpl_image_delete(filt_im) ;
00960         return NULL ;
00961     }
00962 
00963     /* Get relevant stats for thresholding */
00964     median_val = cpl_image_get_median_dev(filt_im, &sigma) ;
00965 
00966     /* Correct median_val and sigma if necessary */
00967     if (median_val < TRESH_MEDIAN_MIN) median_val = TRESH_MEDIAN_MIN ;
00968     if (sigma > TRESH_SIGMA_MAX) sigma = TRESH_SIGMA_MAX ;
00969 
00970     /* Set the threshold */
00971     threshold = median_val + sigma * ARC_THRESHFACT ;
00972 
00973     /* Collapse the image */
00974     collapsed = cpl_image_collapse_median_create(filt_im, 0, 0, 0) ;
00975 
00976     /* Threshold to keep only the arcs - use of the collapsed image */
00977     if (sinfo_distortion_threshold1d(filt_im, median_val,
00978                                      collapsed, 0.0)==-1) {
00979         cpl_msg_error(fctid, "cannot threshold the filtered image") ;
00980         cpl_image_delete(filt_im) ;
00981         cpl_image_delete(collapsed) ;
00982         return NULL ;
00983     }
00984     cpl_image_delete(collapsed) ;
00985 
00986     /* Binarize the image */
00987     bin_im = cpl_mask_threshold_image_create(filt_im, threshold,
00988             SINFO_DBL_MAX);
00989     cpl_image_delete(filt_im) ;
00990     if (bin_im == NULL) {
00991         cpl_msg_error(fctid, "cannot binarise the image") ;
00992         return NULL ;
00993     }
00994 
00995     /* Test if there are enough good pixels */
00996     ngoodpix = cpl_mask_count(bin_im) ;
00997     if (ngoodpix < ARC_MINGOODPIX) {
00998         cpl_msg_error(fctid, "Too few (%d) white pixels", ngoodpix) ;
00999         cpl_mask_delete(bin_im) ;
01000         return NULL ;
01001     }
01002 
01003     /* Apply a morphological closing to clean the isolated pixels */
01004     filter = cpl_matrix_new(3, 3) ;
01005     cpl_matrix_fill(filter, 1.0) ;
01006     cpl_mask_closing(bin_im, filter) ;
01007     cpl_matrix_delete(filter) ;
01008 
01009     /* Labelize pixel map to a label image */
01010     *label_im = cpl_image_labelise_mask_create(bin_im, &nobj) ;
01011     cpl_mask_delete(bin_im) ;
01012 
01013     /* Compute statistics on objects */
01014     if ((det = cpl_apertures_new_from_image(im, *label_im)) == NULL) {
01015         cpl_msg_error(fctid, "Cannot compute arcs stats") ;
01016         cpl_image_delete(*label_im) ;
01017         *label_im = NULL ;
01018         return NULL ;
01019     }
01020 
01021     /* Set min_arclen */
01022     min_arclen = (int)(ny / ARC_MINARCLENFACT) ;
01023 
01024     /* Purge non-relevant arcs */
01025     if (sinfo_distortion_purge_arcs(im, &det, label_im, min_arclen,
01026                 max_arc_width, arc_sat) == -1) {
01027         cpl_msg_error(fctid, "Cannot purge the arcs") ;
01028         cpl_image_delete(*label_im) ;
01029         *label_im = NULL ;
01030         cpl_apertures_delete(det) ;
01031         return NULL ;
01032     }
01033     if (cpl_apertures_get_size(det) < ARC_MINNBARCS) {
01034         cpl_msg_error(fctid, "Not enough valid arcs (%" 
01035                       CPL_SIZE_FORMAT " < %d)",
01036                 cpl_apertures_get_size(det), ARC_MINNBARCS) ;
01037         cpl_image_delete(*label_im) ;
01038         *label_im = NULL ;
01039         cpl_apertures_delete(det) ;
01040         return NULL ;
01041     }
01042 
01043     /* Return  */
01044     return det ;
01045 }
01046 
01047 static int sinfo_distortion_fill_badzones(
01048         cpl_image   *   im,
01049         int             xmin,
01050         int             ymin,
01051         int             xmax,
01052         int             ymax,
01053         double          fillval)
01054 {
01055     float       *   pfi ;
01056     int             nx, ny ;
01057     int             i, j ;
01058 
01059     /* Check entries */
01060     if (im == NULL) return -1 ;
01061     if (cpl_image_get_type(im) != CPL_TYPE_FLOAT) return -1 ;
01062 
01063     /* Get the data */
01064     pfi = cpl_image_get_data_float(im) ;
01065     nx = cpl_image_get_size_x(im) ;
01066     ny = cpl_image_get_size_y(im) ;
01067 
01068     /* Fill the zone */
01069     for (i=0 ; i<nx ; i++) {
01070         for (j=0 ; j<ny ; j++) {
01071             if ((i<xmin-1) || (i>xmax-1) || (j<ymin-1) || (j>ymax-1)) {
01072                 pfi[i+j*nx] = (float)fillval ;
01073             }
01074         }
01075     }
01076     return 0 ;
01077 }
01078 
01079 static int sinfo_distortion_threshold1d(
01080         cpl_image   *   im,
01081         double          threshold,
01082         cpl_image   *   im1d,
01083         double          newval)
01084 {
01085     float       *   pim ;
01086     float       *   pim1d ;
01087     int             nx, ny ;
01088     int             i, j ;
01089 
01090     /* Check entries */
01091     if (im == NULL) return -1 ;
01092     if (im1d == NULL) return -1 ;
01093     if (cpl_image_get_type(im) != CPL_TYPE_FLOAT) return -1 ;
01094     if (cpl_image_get_type(im1d) != CPL_TYPE_FLOAT) return -1 ;
01095 
01096     /* Get access to the im / im1d data */
01097     pim = cpl_image_get_data_float(im) ;
01098     pim1d = cpl_image_get_data_float(im1d) ;
01099     nx = cpl_image_get_size_x(im) ;
01100     ny = cpl_image_get_size_y(im) ;
01101 
01102     /* Apply the thresholding */
01103     for (i=0 ; i<nx ; i++)
01104         if (pim1d[i] < threshold) {
01105             for (j=0 ; j<ny ; j++) pim[i+j*nx] = (float)newval ;
01106         }
01107 
01108     /* Return */
01109     return 0 ;
01110 }
01111 
01112 static int sinfo_distortion_sub_hor_lowpass(
01113         cpl_image   *   im,
01114         int             filt_size)
01115 {
01116     cpl_vector  *   linehi ;
01117     cpl_vector  *   linelo ;
01118     cpl_vector  *   avglinehi ;
01119     cpl_vector  *   avglinelo ;
01120     double      *   pavglinehi ;
01121     float       *   pim ;
01122     int             lopos, hipos, nx, ny ;
01123     int             i, j ;
01124 
01125     /* Test entries */
01126     if (im == NULL) return -1 ;
01127     if (filt_size <= 0) return -1 ;
01128 
01129     /* Initialise */
01130     nx = cpl_image_get_size_x(im) ;
01131     ny = cpl_image_get_size_y(im) ;
01132     lopos = (int)(ny/4) ;
01133     hipos = (int)(3*ny/4) ;
01134 
01135     /* Get the vectors out of the image */
01136     if ((linehi = cpl_vector_new_from_image_row(im, hipos)) == NULL) {
01137         return -1 ;
01138     }
01139     if ((linelo = cpl_vector_new_from_image_row(im, lopos)) == NULL) {
01140         cpl_vector_delete(linehi) ;
01141         return -1 ;
01142     }
01143 
01144     /* Filter the vectors */
01145     if ((avglinehi = cpl_vector_filter_median_create(linehi,
01146                     filt_size)) == NULL) {
01147         cpl_vector_delete(linehi) ;
01148         cpl_vector_delete(linelo) ;
01149         return -1 ;
01150     }
01151     cpl_vector_delete(linehi) ;
01152 
01153     if ((avglinelo = cpl_vector_filter_median_create(linelo,
01154                     filt_size)) == NULL) {
01155         cpl_vector_delete(linelo) ;
01156         cpl_vector_delete(avglinehi) ;
01157         return -1 ;
01158     }
01159     cpl_vector_delete(linelo) ;
01160 
01161     /* Average the filtered vectors to get the low freq signal */
01162     cpl_vector_add(avglinehi, avglinelo) ;
01163     cpl_vector_delete(avglinelo) ;
01164     cpl_vector_divide_scalar(avglinehi, 2.0) ;
01165 
01166     /* Subtract the low frequency signal */
01167     pavglinehi = cpl_vector_get_data(avglinehi) ;
01168     pim = cpl_image_get_data_float(im) ;
01169     for (i=0 ; i<nx ; i++) {
01170         for (j=0 ; j<ny ; j++) {
01171             pim[i+j*nx] -= pavglinehi[i] ;
01172         }
01173     }
01174     cpl_vector_delete(avglinehi) ;
01175 
01176     return 0 ;
01177 }
01178 
01179 
01180 
01181 
01182 
01183 
01184 
01185 
01186 static int sinfo_distortion_purge_arcs(
01187         cpl_image       *   im,
01188         cpl_apertures   **  arcs,
01189         cpl_image       **  lab_im,
01190         int                 min_arclen,
01191         int                 max_arcwidth,
01192         double              arc_sat)
01193 {
01194     const char  *   fctid = "sinfo_distortion_purge_arcs" ;
01195     int             nb_arcs ;
01196     int         *   selection ;
01197     int             arclen, arcwidth, edge ;
01198     double          mean ;
01199     int         *   plabim ;
01200     cpl_mask    *   bin_im ;
01201     int             nx, ny ;
01202     int             i, j ;
01203 
01204     /* Check entries */
01205     if (arcs == NULL) return -1 ;
01206     if (*arcs == NULL) return -1 ;
01207     if (*lab_im == NULL) return -1 ;
01208 
01209     /* Get number of arcs */
01210     nb_arcs = cpl_apertures_get_size(*arcs) ;
01211     nx = cpl_image_get_size_x(*lab_im) ;
01212     ny = cpl_image_get_size_y(*lab_im) ;
01213 
01214     /* Allocate selection array */
01215     selection = cpl_malloc(nb_arcs * sizeof(int)) ;
01216     /* Loop on the different arcs candidates */
01217     /* sinfo_msg("min_arclen=%d max_arcwidth=%d",min_arclen,max_arcwidth); */
01218     for (i=0 ; i<nb_arcs ; i++) {
01219         arclen = cpl_apertures_get_top(*arcs, i+1) -
01220             cpl_apertures_get_bottom(*arcs, i+1) + 1 ;
01221         arcwidth = cpl_apertures_get_right(*arcs, i+1) -
01222             cpl_apertures_get_left(*arcs, i+1) + 1 ;
01223         edge = cpl_apertures_get_left_y(*arcs, i+1) ;
01224         mean = cpl_apertures_get_mean(*arcs, i+1) ;
01225 
01226         /* Test if the current object is a valid arc */
01227 
01228         if (
01229             (arclen>min_arclen) &&
01230         (arcwidth<max_arcwidth) &&
01231             (edge>0) &&
01232             (mean < arc_sat)) {
01233       /*
01234         sinfo_msg_warning("Take Pos=%5.4d len=%d width=%d edge=%d mean=%f ",
01235     (cpl_apertures_get_right(*arcs, i+1)+cpl_apertures_get_left(*arcs, i+1))/2,
01236      arclen,arcwidth,edge,mean);
01237       */
01238             selection[i] = 1 ;
01239         } else {
01240       /*
01241     sinfo_msg_warning("Rej Pos=%5.4d len=%d width=%d edge=%d mean=%f i=%d",
01242          (cpl_apertures_get_right(*arcs, i+1)+
01243           cpl_apertures_get_left(*arcs, i+1))/2,arclen,arcwidth,edge,mean,i);
01244       */
01245             selection[i] = 0 ;
01246         }
01247     }
01248 
01249     /* Update the labelised image by erasing non valid arcs */
01250     for (i=0 ; i<nb_arcs ; i++) {
01251         if (selection[i] == 0) {
01252             plabim = cpl_image_get_data_int(*lab_im) ;
01253             for (j=0 ; j<nx*ny ; j++) {
01254                 if (plabim[j] == i+1) plabim[j] = 0 ;
01255             }
01256         }
01257     }
01258     cpl_free(selection) ;
01259 
01260     /* Reset the labels to have consecutive ones */
01261     bin_im = cpl_mask_threshold_image_create(*lab_im, 0.5, SINFO_DBL_MAX) ;
01262     cpl_image_delete(*lab_im) ;
01263     *lab_im = cpl_image_labelise_mask_create(bin_im, NULL) ;
01264     cpl_mask_delete(bin_im) ;
01265 
01266     /* Purge the bad arcs */
01267     cpl_apertures_delete(*arcs) ;
01268     *arcs = cpl_apertures_new_from_image(im, *lab_im) ;
01269 
01270     /* Check if there are some valid arcs */
01271     if (cpl_apertures_get_size(*arcs) <= 0) {
01272         cpl_msg_error(fctid, "No valid arc found") ;
01273         return -1 ;
01274     }
01275     /* Return  */
01276     return 0 ;
01277 }
01278 
01279 static cpl_bivector **
01280 sinfo_distortion_get_arc_positions(
01281         cpl_image       *   in,
01282         cpl_image       *   label_im,
01283         cpl_apertures   *   det,
01284         int                 nb_samples,
01285         double          **  lines_pos)
01286 {
01287     const char      *   fctid = "sinfo_distortion_get_arc_positions" ;
01288     int                 n_arcs ;
01289     cpl_image       *   filt_img ;
01290     cpl_matrix      *   kernel ;
01291     cpl_bivector    **  pos ;
01292     double          *   biv_x ;
01293     double          *   biv_y ;
01294     double              x_finepos ;
01295     int             *   plabel_im ;
01296     int             *   arcs_samples_y ;
01297     int             *   computed ;
01298     double              arclen ;
01299     int                 use_this_arc ;
01300     int                 obj ;
01301     int                 nx, ny ;
01302     int                 i, j, k ;
01303 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
01304     cpl_mask*          mask=NULL;
01305 #endif
01306 
01307     /* Check entries */
01308 
01309     /* Initialise */
01310     n_arcs = cpl_apertures_get_size(det) ;
01311     nx = cpl_image_get_size_x(label_im) ;
01312     ny = cpl_image_get_size_y(label_im) ;
01313 
01314     /* Allocate positions (pos. of n_arcs*nb_samples pts on the arcs) */
01315     pos = cpl_calloc(n_arcs, sizeof(cpl_bivector*)) ;
01316     for (i=0 ; i<n_arcs ; i++) pos[i] = cpl_bivector_new(nb_samples) ;
01317 
01318     /* Median filter on input image */
01319     kernel = cpl_matrix_new(3, 3) ;
01320     cpl_matrix_fill(kernel, 1.0) ;
01321 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
01322     filt_img=cpl_image_duplicate(in);
01323     mask=cpl_mask_new(3,3);
01324     cpl_mask_not(mask);
01325     cpl_image_filter_mask(filt_img,in,mask,CPL_FILTER_MEDIAN,CPL_BORDER_FILTER);
01326     cpl_mask_delete(mask);
01327 #else
01328     filt_img = cpl_image_filter_median(in, kernel) ;
01329 #endif
01330     cpl_matrix_delete(kernel) ;
01331 
01332     /* Measured Arcs coordinates along curvature */
01333     arcs_samples_y = cpl_malloc(n_arcs * nb_samples * sizeof(int)) ;
01334     computed = cpl_calloc(n_arcs*nb_samples, sizeof(int)) ;
01335 
01336     /* Find out the Y coordinates along the arcs  */
01337     for (j=0 ; j<n_arcs ; j++) {
01338         arclen = cpl_apertures_get_top(det,j+1) -
01339             cpl_apertures_get_bottom(det,j+1) + 1 ;
01340         for (i=0 ; i<nb_samples ; i++) {
01341             arcs_samples_y[i+j*nb_samples] =
01342                 (int)(cpl_apertures_get_bottom(det, j+1) +
01343                       (arclen * (i + 0.5)) / (double)nb_samples) ;
01344         }
01345     }
01346 
01347     /* Find out the X coord. at nb_samples Y positions on all arcs */
01348     plabel_im = cpl_image_get_data_int(label_im) ;
01349     for (i=0 ; i<nx ; i++) {
01350         for (j=0 ; j<ny ; j++) {
01351             /* use_this_arc is set to 1 if we are on the arc at a y */
01352             /* coordinate where the x coord should be found */
01353             obj = plabel_im[i + j * nx] ;
01354             /* Handle background */
01355             if (obj==0) continue ;
01356             /* Decrease by one to index the array from 0 */
01357             else obj-- ;
01358 
01359             use_this_arc = 0 ;
01360             for (k=0 ; k<nb_samples ; k++) {
01361                 if (arcs_samples_y[k+obj*nb_samples] == j) {
01362                     use_this_arc = 1 ;
01363                     break ;
01364                 }
01365             }
01366             if ((use_this_arc)  && (computed[k+obj*nb_samples] == 0)) {
01367                 /* Find x coordinate of obj at the Y coord. */
01368                 if ((x_finepos = sinfo_distortion_fine_pos(filt_img,
01369                                 label_im, i, j)) < 0.0) {
01370                     cpl_msg_error(fctid, "cannot find fine arc position") ;
01371                     cpl_image_delete(filt_img) ;
01372                     cpl_free(arcs_samples_y);
01373                     cpl_free(computed) ;
01374                     for (i=0 ; i<n_arcs ; i++) cpl_bivector_delete(pos[i]);
01375                     cpl_free(pos) ;
01376                     return NULL ;
01377                 } else {
01378                     biv_x = cpl_bivector_get_x_data(pos[obj]) ;
01379                     biv_y = cpl_bivector_get_y_data(pos[obj]) ;
01380                     biv_x[k] = x_finepos ;
01381                     biv_y[k] = j ;
01382                     (*lines_pos)[obj] = cpl_apertures_get_centroid_x(det,obj+1);
01383                     computed[k+obj*nb_samples] = 1 ;
01384                 }
01385             }
01386         }
01387     }
01388 
01389     /* Free and return */
01390     cpl_image_delete(filt_img) ;
01391     cpl_free(arcs_samples_y) ;
01392     cpl_free(computed) ;
01393     return pos ;
01394 }
01395 
01396 static double
01397 sinfo_distortion_fine_pos(
01398         cpl_image   *   im,
01399         cpl_image   *   label_im,
01400         int             x,
01401         int             y)
01402 {
01403     float   *   pim ;
01404     int     *   plabel_im ;
01405     int         objnum ;
01406     int         curr_obj ;
01407     int         start_pos ;
01408     double      grav_c ;
01409     double      sum ;
01410     double      max ;
01411     double      val ;
01412     int         maxpos ;
01413     int         im_extrem ;
01414     double      arc_pos ;
01415     int         nx ;
01416 
01417     /* Initialize */
01418     nx = cpl_image_get_size_x(im) ;
01419     grav_c = 0.0 ;
01420     sum    = 0.0 ;
01421     start_pos = x ;
01422     maxpos = start_pos ;
01423     pim = cpl_image_get_data_float(im) ;
01424     max    = (double)pim[start_pos + y * nx] ;
01425     plabel_im = cpl_image_get_data_int(label_im) ;
01426     objnum = plabel_im[start_pos + y * nx] ;
01427     im_extrem = nx ;
01428 
01429     /* While we stay in the same object... */
01430     do {
01431         val = (double)pim[start_pos + y * nx] ;
01432         if (start_pos == 0) grav_c = 0.0 ;
01433         else grav_c += start_pos * val ;
01434         sum += val ;
01435         if (val > max) {
01436             max = val ;
01437             maxpos = start_pos ;
01438         }
01439 
01440         /* Next point */
01441         start_pos++ ;
01442 
01443         curr_obj = plabel_im[start_pos + y * nx] ;
01444     } while (curr_obj == objnum) ;
01445 
01446     /* Returned position is the gravity center or the max in bad cases */
01447     if ((fabs(grav_c) < 1.0e-40) || (fabs(sum) < 1.0e-40)) {
01448         arc_pos = maxpos ;
01449     } else {
01450         arc_pos = grav_c / sum ;
01451         if (fabs(arc_pos) >= start_pos) arc_pos = maxpos ;
01452     }
01453 
01454     /* Return */
01455     return arc_pos ;
01456 }
01457 
01458 /*---------------------------------------------------------------------------*/
01464 /*---------------------------------------------------------------------------*/
01465 #define IS_NB_TESTPOINTS    8
01466 #define IS_MIN_SLOPE        0.01
01467 #define IS_MAX_SLOPE_DIF    0.075
01468 #define IS_MAX_FIT_EDGE_DIF 0.05
01469 #define IS_MIN_RAMP         10.0
01470 #define IS_MAX_MNERR        13.0
01471 #define IS_MAX_MNERR_DIF    8.0
01472 #define IS_MAX_INTER_DIF    20.0
01473 #define IS_SKIPZONE         2.5
01474 #define SQR(x) ((x)*(x))
01475 static cpl_image * sinfo_distortion_remove_ramp(const cpl_image * in)
01476 {
01477     const char      *   fctid = "sinfo_distortion_remove_ramp" ;
01478     int                 ramp_present ;
01479     int                 nx, ny ;
01480     int                 y, yhi, ylo;
01481     cpl_vector      *   tmp_vector ;
01482     cpl_bivector    *   testpointlo ;
01483     double          *   testpointlo_x ;
01484     double          *   testpointlo_y ;
01485     cpl_bivector    *   testpointhi ;
01486     double          *   testpointhi_x ;
01487     double          *   testpointhi_y ;
01488     int                 spacing;
01489     double              rampdif, fitslope;
01490     double          *   pol_coefhi,
01491                     *   pol_coeflo ;
01492     cpl_vector      *   median ;
01493     double          *   median_data ;
01494     double              medianerrlo, medianerrhi;
01495     double              slope ;
01496     cpl_image       *   out ;
01497     float           *   pout ;
01498     float               val ;
01499     int                 i, j ;
01500 
01501     /* Initialise */
01502     nx = cpl_image_get_size_x(in) ;
01503     ny = cpl_image_get_size_y(in) ;
01504 
01505     /* Check entries */
01506     if (in==NULL) return NULL ;
01507 
01508     if (ny<IS_SKIPZONE*IS_NB_TESTPOINTS){
01509         cpl_msg_error(fctid, "image has %d lines, min=%d ",
01510                 ny, (int)(IS_SKIPZONE*IS_NB_TESTPOINTS*2));
01511         return NULL ;
01512     }
01513 
01514     slope=0.0 ;
01515     spacing= ny / (IS_SKIPZONE*IS_NB_TESTPOINTS) ;
01516     yhi = (int)(ny/2) ;
01517     ylo = yhi - 1 ;
01518     /* Fill the vectors */
01519     testpointhi = cpl_bivector_new(IS_NB_TESTPOINTS) ;
01520     testpointhi_x = cpl_bivector_get_x_data(testpointhi) ;
01521     testpointhi_y = cpl_bivector_get_y_data(testpointhi) ;
01522     testpointlo = cpl_bivector_new(IS_NB_TESTPOINTS) ;
01523     testpointlo_x = cpl_bivector_get_x_data(testpointlo) ;
01524     testpointlo_y = cpl_bivector_get_y_data(testpointlo) ;
01525     for (i=0 ; i<IS_NB_TESTPOINTS ; i++) {
01526         y = yhi + i * spacing;
01527         tmp_vector = cpl_vector_new_from_image_row(in, y+1) ;
01528         testpointhi_x[i] = y - ny / 2;
01529         testpointhi_y[i] = cpl_vector_get_median_const(tmp_vector) ;
01530         cpl_vector_delete(tmp_vector) ;
01531         y = ylo - i * spacing;
01532         tmp_vector = cpl_vector_new_from_image_row(in, y+1) ;
01533         testpointlo_x[IS_NB_TESTPOINTS-i-1] = y ;
01534         testpointlo_y[IS_NB_TESTPOINTS-i-1]=
01535       cpl_vector_get_median_const(tmp_vector);
01536         cpl_vector_delete(tmp_vector) ;
01537     }
01538 
01539     /* Apply the fit */
01540     pol_coefhi = irplib_flat_fit_slope_robust(testpointhi_x,
01541             testpointhi_y, IS_NB_TESTPOINTS) ;
01542     pol_coeflo = irplib_flat_fit_slope_robust(testpointlo_x,
01543             testpointlo_y, IS_NB_TESTPOINTS) ;
01544 
01545     /* Compute the errors */
01546     median = cpl_vector_new(IS_NB_TESTPOINTS) ;
01547     median_data = cpl_vector_get_data(median) ;
01548     for (i=0 ; i<IS_NB_TESTPOINTS ; i++) {
01549         median_data[i]=SQR(testpointhi_y[i]
01550                 - pol_coefhi[0] - pol_coefhi[1] * testpointhi_x[i]);
01551     }
01552     medianerrhi = cpl_vector_get_median_const(median) ;
01553     for (i=0; i<IS_NB_TESTPOINTS; i++) {
01554         median_data[i]=SQR(testpointlo_y[i]
01555                 - pol_coeflo[0] - pol_coeflo[1] * testpointlo_x[i]);
01556     }
01557     medianerrlo = cpl_vector_get_median_const(median) ;
01558     cpl_vector_delete(median) ;
01559     rampdif = testpointlo_y[IS_NB_TESTPOINTS-1] - testpointhi_y[0];
01560     slope = rampdif / (ny/2.0) ;
01561     fitslope = (pol_coefhi[1] + pol_coeflo[1]) / 2.0 ;
01562 
01563     cpl_bivector_delete(testpointlo);
01564     cpl_bivector_delete(testpointhi);
01565 
01566     /* Decide if there is a ramp or not  */
01567     if (fabs(rampdif)<IS_MIN_RAMP ||
01568             fabs(pol_coefhi[1]) < IS_MIN_SLOPE ||
01569             fabs(pol_coeflo[1]) < IS_MIN_SLOPE ||
01570             pol_coefhi[1]/pol_coeflo[1]<0.5 ||
01571             pol_coefhi[1]/pol_coeflo[1]>2.0 ||
01572             fabs(pol_coefhi[1]-pol_coeflo[1])>IS_MAX_SLOPE_DIF ||
01573             fabs(pol_coefhi[0]-pol_coeflo[0]) > IS_MAX_INTER_DIF ||
01574             medianerrlo> IS_MAX_MNERR ||
01575             medianerrhi> IS_MAX_MNERR ||
01576             fabs(medianerrlo-medianerrhi) >IS_MAX_MNERR_DIF ||
01577             fabs(slope-fitslope) > IS_MAX_FIT_EDGE_DIF ||
01578             slope/fitslope<0.5 ||
01579             slope/fitslope>2.0) ramp_present = 0 ;
01580     else ramp_present = 1 ;
01581 
01582     cpl_free(pol_coeflo) ;
01583     cpl_free(pol_coefhi) ;
01584 
01585     /* Correct the ramp if it is there */
01586     out = cpl_image_duplicate(in) ;
01587     pout = cpl_image_get_data_float(out) ;
01588     if (ramp_present == 1) {
01589         for (j=0 ; j<ny/2 ; j++) {
01590             val = slope * (j-ny/2) ;
01591             for (i=0 ; i<nx ; i++)
01592                 pout[i+j*nx] -= val ;
01593         }
01594         for (j=ny/2 ; j<ny ; j++) {
01595             val = slope * (j-ny) ;
01596             for (i=0 ; i<nx ; i++)
01597                 pout[i+j*nx] -= val ;
01598         }
01599 
01600     }
01601 
01602     return out ;
01603 }
01604 

Generated on 3 Mar 2013 for SINFONI Pipeline Reference Manual by  doxygen 1.6.1