sinfo_distortion.c

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

Generated on 8 Mar 2011 for SINFONI Pipeline Reference Manual by  doxygen 1.6.1