SINFONI Pipeline Reference Manual  2.5.2
sinfo_distortion.c
1 /* $Id: sinfo_distortion.c,v 1.37 2012-03-05 16:34:06 amodigli Exp $
2  *
3  * This file is part of the irplib package
4  * Copyright (C) 2002,2003 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: amodigli $
23  * $Date: 2012-03-05 16:34:06 $
24  * $Revision: 1.37 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include <sinfo_cpl_size.h>
32 
33 /*----------------------------------------------------------------------------
34  Includes
35  ----------------------------------------------------------------------------*/
36 
37 #include <cpl.h>
38 #include <sinfo_cpl_size.h>
39 #include <math.h>
40 
41 
42 #include "sinfo_distortion.h"
43 #include "sinfo_functions.h"
44 #include "sinfo_msg.h"
45 #include "sinfo_error.h"
46 #include "irplib_flat.h"
47 #include "sinfo_utils_wrappers.h"
48 //#include "sinfo_irplib_cpl_wrp.h"
49 #include "sinfo_utilities.h"
50 /*-----------------------------------------------------------------------------
51  Define
52  ----------------------------------------------------------------------------*/
53 
54 #define ARC_NBSAMPLES 20
55 #define ARC_THRESHFACT (1.0/3.0)
56 #define ARC_MINGOODPIX 100
57 #define ARC_MINARCLENFACT 1.19 /* 1.1-2 */
58 #define ARC_MINNBARCS 32 /* 4-32 */
59 #define ARC_RANGE_FACT 3.0
60 #define ARC_WINDOWSIZE 10 /* 32 */
61 
62 #define TRESH_MEDIAN_MIN 0.0
63 #define TRESH_SIGMA_MAX 200.0
64 
66 /*---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------*/
71 
72 /*----------------------------------------------------------------------------
73  Functions prototypes
74  ----------------------------------------------------------------------------*/
75 static cpl_apertures *
76 sinfo_distortion_detect_arcs_new(cpl_image* ,cpl_image **,
77  int,int,double,int,int,int,int,double,int);
78 
79 static
80 cpl_apertures * sinfo_distortion_detect_arcs(cpl_image *,
81  cpl_image **, int, int, int, int, int, int) ;
82 static int
83 sinfo_distortion_fill_badzones(cpl_image *, int, int, int, int, double) ;
84 static int
85 sinfo_distortion_threshold1d(cpl_image *, double, cpl_image *, double) ;
86 static int
87 sinfo_distortion_purge_arcs(cpl_image *, cpl_apertures **,
88  cpl_image **, int, int, double) ;
89 static cpl_bivector **
90 sinfo_distortion_get_arc_positions(cpl_image *,
91  cpl_image *,
92  cpl_apertures *, int, double **) ;
93 static double sinfo_distortion_fine_pos(cpl_image *, cpl_image *, int, int) ;
94 static int sinfo_distortion_sub_hor_lowpass(cpl_image *, int) ;
95 static cpl_image * sinfo_distortion_remove_ramp(const cpl_image *) ;
96 static cpl_image *
97 sinfo_distortion_smooth(cpl_image* inp,const int r,const int d);
98 
99 
100 
101 
102 /*----------------------------------------------------------------------------
103  Functions code
104  ----------------------------------------------------------------------------*/
105 
106 
107 /*---------------------------------------------------------------------------*/
117 static cpl_image *
118 sinfo_distortion_smooth(cpl_image* inp,const int r,const int d)
119 {
120 
121  int sx=0;
122  int sy=0;
123  int i=0;
124  int j=0;
125  int z=0;
126 
127  float sum;
128  cpl_image* out=NULL;
129  float* pi=NULL;
130  float* po=NULL;
131  int min=0;
132 
133  cknull(inp,"Null input image!");
134  check_nomsg(sx=cpl_image_get_size_x(inp));
135  check_nomsg(sy=cpl_image_get_size_y(inp));
136  check_nomsg(out=cpl_image_duplicate(inp));
137  check_nomsg(pi=cpl_image_get_data_float(inp));
138  check_nomsg(po=cpl_image_get_data_float(out));
139  min = r/2;
140  switch (d) {
141  case 0:
142  for(j=0;j<sy;j++) {
143  for(i=min;i<sx-min;i++) {
144  sum=0;
145  for(z=i-min;z<i+min+1;z++) {
146  sum+=pi[z+j*sx];
147  }
148  po[i+j*sx]=sum/r;
149  }
150  }
151  break;
152 
153  case 1:
154  for(i=0;i<sx;i++) {
155  for(j=min;j<sy-min;j++) {
156  sum=0;
157  for(z=j-min;z<j+min+1;z++) {
158  sum+=pi[i+z*sx];
159  }
160  po[i+j*sx]=sum;
161  }
162  }
163  break;
164 
165  default:
166  sinfo_msg_error("case not supported");
167  goto cleanup;
168 
169  }
170  check_nomsg(cpl_image_delete(inp));
171  return out;
172  cleanup:
173  return NULL;
174 }
175 
176 /*---------------------------------------------------------------------------*/
189 cpl_image *
190 sinfo_distortion_image_restore(const cpl_image* inp,
191  const int r,
192  const int d,
193  const double kappa,
194  const int ks_method,
195  const int n)
196 {
197 
198  int sx=0;
199  int sy=0;
200  int i=0;
201  int j=0;
202  int z=0;
203  int k=0;
204 
205 
206  cpl_image* out=NULL;
207  const float* pi=NULL;
208  float* po=NULL;
209  int min=0;
210  cpl_vector* vec=NULL;
211  double* pv=NULL;
212  double mean=0;
213  double median=0;
214 
215  cknull(inp,"Null input image!");
216  check_nomsg(sx=cpl_image_get_size_x(inp));
217  check_nomsg(sy=cpl_image_get_size_y(inp));
218  check_nomsg(out=cpl_image_duplicate(inp));
219  check_nomsg(pi=cpl_image_get_data_float_const(inp));
220  check_nomsg(po=cpl_image_get_data_float(out));
221  min = r/2;
222  check_nomsg(vec=cpl_vector_new(r));
223  check_nomsg(pv=cpl_vector_get_data(vec));
224  switch (d) {
225  case 0:
226  for(j=0;j<sy;j++) {
227  for(i=min;i<sx-min;i++) {
228  k=0;
229  for(z=i-min;z<i+min+1;z++) {
230  pv[k]=(double)pi[z+j*sx];
231  k++;
232  }
233  cknull_nomsg(vec=sinfo_vector_clip(vec,kappa,n,ks_method));
234  check_nomsg(mean=cpl_vector_get_mean(vec));
235  check_nomsg(median=cpl_vector_get_mean(vec));
236  po[i+j*sx]+=(mean-median);
237  }
238  }
239  break;
240 
241  case 1:
242  for(i=0;i<sx;i++) {
243  for(j=min;j<sy-min;j++) {
244  k=0;
245  for(z=j-min;z<j+min+1;z++) {
246  pv[k]=(double)pi[i+z*sx];
247  k++;
248  }
249  cknull_nomsg(vec=sinfo_vector_clip(vec,kappa,n,ks_method));
250  check_nomsg(mean=cpl_vector_get_mean(vec));
251  check_nomsg(median=cpl_vector_get_mean(vec));
252  po[i+j*sx]+=(mean-median);
253  }
254  }
255  break;
256 
257  default:
258  sinfo_msg_error("case not supported");
259  goto cleanup;
260 
261  }
262  check_nomsg(cpl_image_delete((cpl_image*)inp));
263  return out;
264  cleanup:
265  return NULL;
266 }
267 
268 /*---------------------------------------------------------------------------*/
292 /*---------------------------------------------------------------------------*/
293 cpl_polynomial * sinfo_distortion_estimate_new(
294  const cpl_image * org,
295  int xmin,
296  int ymin,
297  int xmax,
298  int ymax,
299  int auto_ramp_sub,
300  int arc_sat,
301  int max_arc_width,
302  double kappa,
303  double arcs_min_arclen_factor,
304  int arcs_window_size,
305  int smooth_rad,
306  int degree,
307  double offset,
308  cpl_apertures ** arcs)
309 {
310  cpl_image * local_im ;
311  cpl_image * label_image ;
312  double rightmost, leftmost ;
313  cpl_bivector ** arcs_pos ;
314  double * parc_posx ;
315  double * parc_posy ;
316  double * lines_pos ;
317  cpl_bivector * grid ;
318  double * pgridx ;
319  double * pgridy ;
320  cpl_vector * values_to_fit ;
321  double * pvalues_to_fit ;
322  int min_arc_range ;
323  int n_calib ;
324  int n_arcs ;
325  cpl_polynomial * poly2d ;
326  int nx ;
327  int i, j ;
328 
329  /* AMO added to use offset */
330  cpl_vector * lines_pos_tmp ;
331  cpl_bivector * grid_tmp ;
332  cpl_vector* grid_tot=0;
333  double* pgrid_tmp_x=NULL;
334  //double* pgrid_tmp_y=NULL;
335  double* pgrid_tot=NULL;
336  double* plines_pos_tmp=NULL;
337  int n_lines=0;
338  int k=0;
339 
340 
341  /* Check entries */
342  if (org == NULL) return NULL ;
343  if (kappa < 0.0) return NULL ;
344 
345  /* Initialise */
346  n_calib = ARC_NBSAMPLES ;
347  nx = cpl_image_get_size_x(org) ;
348 
349  if (auto_ramp_sub) {
350  local_im = sinfo_distortion_remove_ramp(org) ;
351  } else {
352  /* Local copy of input image */
353  local_im = cpl_image_duplicate(org) ;
354  }
355  if (local_im == NULL) {
356  cpl_msg_error(cpl_func, "Cannot clean the image") ;
357  return NULL ;
358  }
359  if(smooth_rad > 1) {
360  local_im=sinfo_distortion_smooth(local_im,smooth_rad,1);
361  //cpl_image_save(local_im,"out_local_im.fits",CPL_BPP_IEEE_FLOAT,
362  // NULL,CPL_IO_DEFAULT);
363  //local_im=sinfo_distortion_image_restore(local_im,smooth_rad,1,2,0,2);
364  //cpl_image_save(local_im,"out_local_im_post.fits",
365  // CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
366 
367  }
368  /* Detect the arcs in the input image */
369  cpl_msg_info(cpl_func, "Detect arcs") ;
370  if ((*arcs = sinfo_distortion_detect_arcs_new(local_im,
371  &label_image,
372  arc_sat, max_arc_width, kappa,
373  xmin, ymin, xmax, ymax,
374  arcs_min_arclen_factor,arcs_window_size)) == NULL) {
375  cpl_image_delete(local_im) ;
376  cpl_msg_error(cpl_func, "Cannot detect the arcs") ;
377  return NULL ;
378  }
379  n_arcs = cpl_apertures_get_size(*arcs) ;
380  cpl_msg_info(cpl_func, "%d detected arcs", n_arcs) ;
381 
382  /* Check that the arcs are not concentrated in the same zone */
383  rightmost = leftmost = cpl_apertures_get_pos_x(*arcs, 1) ;
384  for (i=1 ; i<n_arcs ; i++) {
385  if (cpl_apertures_get_pos_x(*arcs, i+1) < leftmost)
386  leftmost = cpl_apertures_get_pos_x(*arcs, i+1) ;
387  if (cpl_apertures_get_pos_x(*arcs, i+1) > rightmost)
388  rightmost = cpl_apertures_get_pos_x(*arcs, i+1) ;
389  }
390  min_arc_range = (int)(nx / ARC_RANGE_FACT) ;
391  if ((int)(rightmost-leftmost) < min_arc_range) {
392  cpl_msg_error(cpl_func, "too narrow range (%g-%g)<%d",
393  rightmost, leftmost, min_arc_range) ;
394  cpl_apertures_delete(*arcs) ;
395  cpl_image_delete(local_im) ;
396  cpl_image_delete(label_image) ;
397  return NULL ;
398  }
399 
400  /* Create a 2-D deformation grid with detected arcs */
401  cpl_msg_info(cpl_func, "Create deformation grid") ;
402  lines_pos = cpl_malloc(n_arcs * sizeof(double)) ;
403  if ((arcs_pos = sinfo_distortion_get_arc_positions(local_im,
404  label_image, *arcs, n_calib, &lines_pos))==NULL){
405  cpl_msg_error(cpl_func, "cannot get arcs positions") ;
406  cpl_apertures_delete(*arcs) ;
407  cpl_image_delete(local_im) ;
408  cpl_free(lines_pos) ;
409  cpl_image_delete(label_image) ;
410  return NULL ;
411  }
412  cpl_image_delete(label_image) ;
413  cpl_image_delete(local_im) ;
414 
415  /* Prepare the fitting */
416  lines_pos_tmp=cpl_vector_new(n_arcs);
417  plines_pos_tmp=cpl_vector_get_data(lines_pos_tmp);
418 
419 
420  sinfo_msg("Fit the 2d polynomial") ;
421  grid = cpl_bivector_new(n_arcs * n_calib) ;
422  pgridx = cpl_bivector_get_x_data(grid) ;
423  pgridy = cpl_bivector_get_y_data(grid) ;
424  values_to_fit = cpl_vector_new(n_arcs * n_calib) ;
425  pvalues_to_fit = cpl_vector_get_data(values_to_fit) ;
426 
427  for (i=0 ; i<n_arcs ; i++) {
428  parc_posx = cpl_bivector_get_x_data(arcs_pos[i]) ;
429  parc_posy = cpl_bivector_get_y_data(arcs_pos[i]) ;
430  for (j=0 ; j<n_calib ; j++) {
431  plines_pos_tmp[i]=lines_pos[i] ;
432  pgridx[j+i*n_calib] = lines_pos[i] ;
433  pgridy[j+i*n_calib] = parc_posy[j] ;
434  pvalues_to_fit[j+i*n_calib] = parc_posx[j] ;
435  }
436  }
437  /* AMO new to use offset */
438  n_lines= n_arcs/32.0;
439  if(n_lines < 1) {
440  n_lines=1;
441  }
442  cpl_vector_sort(lines_pos_tmp,1);
443  plines_pos_tmp=cpl_vector_get_data(lines_pos_tmp);
444  grid_tmp=cpl_bivector_duplicate(grid);
445  grid_tot=cpl_vector_new(n_calib);
446  pgrid_tmp_x = cpl_bivector_get_x_data(grid_tmp) ;
447  //pgrid_tmp_y = cpl_bivector_get_y_data(grid_tmp) ;
448  pgrid_tot = cpl_vector_get_data(grid_tot);
449  for(j=0;j<n_calib;j++) {
450  pgrid_tot[j]=0;
451  for(i=n_lines ;i<n_arcs;i=i+n_lines)
452  {
453  for(k=0;k<n_lines;k++) {
454  pgrid_tot[j] += (plines_pos_tmp[i+k]-
455  plines_pos_tmp[k]);
456  /*
457  sinfo_msg("diff=%g",(plines_pos_tmp[i+k]-
458  plines_pos_tmp[k]));
459  */
460  }
461  }
462  /*
463  sinfo_msg("j=%d pgrid_tot=%g",j,pgrid_tot[j]);
464  */
465  }
466 
467  for(j=0;j<n_calib;j++) {
468  for (i=0 ; i<n_arcs ; i++) {
469  pgridx[j+i*n_calib]=pgridx[j+i*n_calib]*
470  ((nx/32.0)*n_lines*(31*32/2))/pgrid_tot[j]-offset;
471  /*
472  sinfo_msg_error("AMo after corr grid[%d,%d]=%g",
473  i,k,pgridx[k+i*n_calib]);
474  */
475  pgrid_tmp_x[j+i*n_calib]=pgrid_tmp_x[j+i*n_calib]*
476  ((nx/32.0)*n_lines*(31*32/2))/pgrid_tot[j]-
477  offset;
478 
479  }
480  }
481  cpl_vector_delete(lines_pos_tmp);
482  cpl_bivector_delete(grid_tmp);
483  cpl_vector_delete(grid_tot);
484  /* end AMO: to use the offset */
485 
486 
487  for (i=0 ; i<n_arcs ; i++) cpl_bivector_delete(arcs_pos[i]) ;
488  cpl_free(arcs_pos) ;
489  cpl_free(lines_pos) ;
490 
491  /* Apply the fitting */
492  if ((poly2d = sinfo_polynomial_fit_2d_create(grid, values_to_fit,
493  degree, NULL))==NULL) {
494  cpl_msg_error(cpl_func, "cannot apply the 2d fit") ;
495  cpl_bivector_delete(grid) ;
496  cpl_vector_delete(values_to_fit) ;
497  cpl_apertures_delete(*arcs) ;
498  return NULL ;
499  }
500 
501  /* Free and return */
502  cpl_bivector_delete(grid) ;
503  cpl_vector_delete(values_to_fit) ;
504  return poly2d ;
505 }
506 
507 
508 
509 /*---------------------------------------------------------------------------*/
525 /*---------------------------------------------------------------------------*/
526 static cpl_apertures * sinfo_distortion_detect_arcs_new(
527  cpl_image * im,
528  cpl_image ** label_im,
529  int arc_sat,
530  int max_arc_width,
531  double kappa,
532  int xmin,
533  int ymin,
534  int xmax,
535  int ymax,
536  double arcs_min_arclen_factor,
537  int arcs_window_size)
538 {
539  cpl_image * filt_im ;
540  cpl_matrix * filter ;
541  cpl_image * collapsed ;
542  cpl_mask * bin_im ;
543  double threshold, fillval, median_val, sigma ;
544  int min_arclen = 0 ;
545  cpl_apertures * det ;
546  cpl_size nobj ;
547  int ngoodpix ;
548  int ny ;
549 
550  ny = cpl_image_get_size_y(im) ;
551  /* Default values for output parameters */
552  *label_im = NULL ;
553 
554  /* Clear zones to be ignored (to avoid false detections) */
555  median_val = cpl_image_get_median_dev(im, &sigma) ;
556  fillval = median_val-sigma/2.0 ;
557  if (sinfo_distortion_fill_badzones(im, xmin, ymin, xmax, ymax,
558  fillval) == -1) {
559  cpl_msg_error(cpl_func, "cannot fill bad zones") ;
560  return NULL ;
561  }
562  /* Median vertical filter */
563  filter = cpl_matrix_new(3, 1) ;
564  cpl_matrix_fill(filter, 1.0) ;
565  /* filt_im = cpl_image_filter_median(im, filter) ; */
566  filt_im = cpl_image_duplicate(im) ;
567  cpl_matrix_delete(filter) ;
568 
569  /* Subtract a low-pass */
570  /* AMO: suppressed as may remove arcs */
571  if (sinfo_distortion_sub_hor_lowpass(filt_im, arcs_window_size) == -1) {
572  cpl_image_delete(filt_im) ;
573  return NULL ;
574  }
575  //cpl_image_save(filt_im,"out_filt_im_lp.fits",CPL_BPP_IEEE_FLOAT,
576  // NULL,CPL_IO_DEFAULT);
577 
578  /* Get relevant stats for thresholding */
579  median_val = cpl_image_get_median_dev(filt_im, &sigma) ;
580 
581  /* Correct median_val and sigma if necessary */
582  if (median_val < TRESH_MEDIAN_MIN) median_val = TRESH_MEDIAN_MIN ;
583  if (sigma > TRESH_SIGMA_MAX) sigma = TRESH_SIGMA_MAX ;
584 
585  /* Set the threshold */
586  threshold = median_val + sigma * kappa ;
587 
588  /* Collapse the image */
589  collapsed = cpl_image_collapse_median_create(filt_im, 0, 0, 0) ;
590 
591  /* Threshold to keep only the arcs - use of the collapsed image */
592  if (sinfo_distortion_threshold1d(filt_im, median_val,
593  collapsed, 0.0)==-1) {
594  cpl_msg_error(cpl_func, "cannot threshold the filtered image") ;
595  cpl_image_delete(filt_im) ;
596  cpl_image_delete(collapsed) ;
597  return NULL ;
598  }
599  cpl_image_delete(collapsed) ;
600 
601  /* Binarize the image */
602  bin_im = cpl_mask_threshold_image_create(filt_im, threshold,
603  SINFO_DBL_MAX);
604  cpl_image_delete(filt_im) ;
605  if (bin_im == NULL) {
606  cpl_msg_error(cpl_func, "cannot binarise the image") ;
607  return NULL ;
608  }
609 
610  /* Test if there are enough good pixels */
611  ngoodpix = cpl_mask_count(bin_im) ;
612  if (ngoodpix < ARC_MINGOODPIX) {
613  cpl_msg_error(cpl_func, "Too few (%d) white pixels", ngoodpix) ;
614  cpl_mask_delete(bin_im) ;
615  return NULL ;
616  }
617 
618  /* Apply a morphological closing to clean the isolated pixels */
619  filter = cpl_matrix_new(3, 3) ;
620  cpl_matrix_fill(filter, 1.0) ;
621  cpl_mask_closing(bin_im, filter) ;
622  cpl_matrix_delete(filter) ;
623 
624  /* Labelize pixel map to a label image */
625  *label_im = cpl_image_labelise_mask_create(bin_im, &nobj) ;
626  cpl_mask_delete(bin_im) ;
627  //cpl_image_save(*label_im,"out_label_im.fits",CPL_BPP_IEEE_FLOAT,
628  // NULL,CPL_IO_DEFAULT);
629 
630  /* Compute statistics on objects */
631  if ((det = cpl_apertures_new_from_image(im, *label_im)) == NULL) {
632  cpl_msg_error(cpl_func, "Cannot compute arcs stats") ;
633  cpl_image_delete(*label_im) ;
634  *label_im = NULL ;
635  return NULL ;
636  }
637  /* Set min_arclen */
638  min_arclen = (int)(ny /arcs_min_arclen_factor) ;
639  //cpl_image_save(im,"out_im.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
640 
641  /* Purge non-relevant arcs */
642  /* cpl_apertures_dump(det,stdout); */
643  if (sinfo_distortion_purge_arcs(im, &det, label_im, min_arclen,
644  max_arc_width, arc_sat) == -1) {
645  cpl_msg_error(cpl_func, "Cannot purge the arcs") ;
646  cpl_image_delete(*label_im) ;
647  *label_im = NULL ;
648  cpl_apertures_delete(det) ;
649  return NULL ;
650  }
651  /* cpl_apertures_dump(det,stdout); */
652  if (cpl_apertures_get_size(det) < ARC_MINNBARCS) {
653  cpl_msg_error(cpl_func, "Not enough valid arcs (%"
654  CPL_SIZE_FORMAT " < %d)",
655  cpl_apertures_get_size(det), ARC_MINNBARCS) ;
656  cpl_image_delete(*label_im) ;
657  *label_im = NULL ;
658  cpl_apertures_delete(det) ;
659  return NULL ;
660  }
661 
662  /* Return */
663  return det ;
664 }
665 
666 
667 
668 /*---------------------------------------------------------------------------*/
692 /*---------------------------------------------------------------------------*/
693 cpl_polynomial * sinfo_distortion_estimate(
694  const cpl_image * org,
695  int xmin,
696  int ymin,
697  int xmax,
698  int ymax,
699  int auto_ramp_sub,
700  int arc_sat,
701  int max_arc_width,
702  int degree,
703  double offset,
704  cpl_apertures ** arcs)
705 {
706  const char * fctid = "sinfo_distortion_estimate" ;
707  cpl_image * local_im ;
708  cpl_image * label_image ;
709  double rightmost, leftmost ;
710  cpl_bivector ** arcs_pos ;
711  double * parc_posx ;
712  double * parc_posy ;
713  double * lines_pos ;
714  cpl_bivector * grid ;
715  double * pgridx ;
716  double * pgridy ;
717  cpl_vector * values_to_fit ;
718  double * pvalues_to_fit ;
719  int min_arc_range ;
720  int n_calib ;
721  int n_arcs ;
722  cpl_polynomial * poly2d ;
723  int nx ;
724  int i, j ;
725 
726  /* AMO added to use offset */
727  cpl_vector * lines_pos_tmp ;
728  cpl_bivector * grid_tmp ;
729  int n_lines=0;
730  int k=0;
731  cpl_vector* grid_tot=0;
732  double* pgrid_tmp_x=NULL;
733  //double* pgrid_tmp_y=NULL;
734  double* pgrid_tot=NULL;
735  double* plines_pos_tmp=NULL;
736 
737  /* Check entries */
738  if (org == NULL) return NULL ;
739 
740  /* Initialise */
741  n_calib = ARC_NBSAMPLES ;
742  nx = cpl_image_get_size_x(org) ;
743 
744  if (auto_ramp_sub) {
745  local_im = sinfo_distortion_remove_ramp(org) ;
746  } else {
747  /* Local copy of input image */
748  local_im = cpl_image_duplicate(org) ;
749  }
750  if (local_im == NULL) {
751  cpl_msg_error(fctid, "Cannot clean the image") ;
752  return NULL ;
753  }
754 
755  /* Detect the arcs in the input image */
756  cpl_msg_info(fctid, "Detect arcs") ;
757  if ((*arcs = sinfo_distortion_detect_arcs(local_im,
758  &label_image,
759  arc_sat, max_arc_width,
760  xmin, ymin, xmax, ymax)) == NULL) {
761  cpl_image_delete(local_im) ;
762  cpl_msg_error(fctid, "Cannot detect the arcs") ;
763  return NULL ;
764  }
765  n_arcs = cpl_apertures_get_size(*arcs) ;
766  cpl_msg_info(fctid, "%d detected arcs", n_arcs) ;
767 
768  /* Check that the arcs are not concentrated in the same zone */
769  rightmost = leftmost = cpl_apertures_get_pos_x(*arcs, 1) ;
770  for (i=1 ; i<n_arcs ; i++) {
771  if (cpl_apertures_get_pos_x(*arcs, i+1) < leftmost)
772  leftmost = cpl_apertures_get_pos_x(*arcs, i+1) ;
773  if (cpl_apertures_get_pos_x(*arcs, i+1) > rightmost)
774  rightmost = cpl_apertures_get_pos_x(*arcs, i+1) ;
775  }
776  min_arc_range = (int)(nx / ARC_RANGE_FACT) ;
777  if ((int)(rightmost-leftmost) < min_arc_range) {
778  cpl_msg_error(fctid, "too narrow range (%g-%g)<%d",
779  rightmost, leftmost, min_arc_range) ;
780  cpl_apertures_delete(*arcs) ;
781  cpl_image_delete(local_im) ;
782  cpl_image_delete(label_image) ;
783  return NULL ;
784  }
785 
786  /* Create a 2-D deformation grid with detected arcs */
787  cpl_msg_info(fctid, "Create deformation grid") ;
788  lines_pos = cpl_malloc(n_arcs * sizeof(double)) ;
789  if ((arcs_pos = sinfo_distortion_get_arc_positions(local_im,
790  label_image, *arcs, n_calib, &lines_pos))==NULL){
791  cpl_msg_error(fctid, "cannot get arcs positions") ;
792  cpl_apertures_delete(*arcs) ;
793  cpl_image_delete(local_im) ;
794  cpl_free(lines_pos) ;
795  cpl_image_delete(label_image) ;
796  return NULL ;
797  }
798  cpl_image_delete(label_image) ;
799  cpl_image_delete(local_im) ;
800 
801  /* Prepare the fitting */
802  lines_pos_tmp=cpl_vector_new(n_arcs);
803  plines_pos_tmp=cpl_vector_get_data(lines_pos_tmp);
804 
805  cpl_msg_info(fctid, "Fit the 2d polynomial") ;
806  grid = cpl_bivector_new(n_arcs * n_calib) ;
807  pgridx = cpl_bivector_get_x_data(grid) ;
808  pgridy = cpl_bivector_get_y_data(grid) ;
809  values_to_fit = cpl_vector_new(n_arcs * n_calib) ;
810  pvalues_to_fit = cpl_vector_get_data(values_to_fit) ;
811  for (i=0 ; i<n_arcs ; i++) {
812  parc_posx = cpl_bivector_get_x_data(arcs_pos[i]) ;
813  parc_posy = cpl_bivector_get_y_data(arcs_pos[i]) ;
814  for (j=0 ; j<n_calib ; j++) {
815  plines_pos_tmp[i]=lines_pos[i] ;
816  pgridx[j+i*n_calib] = lines_pos[i] ;
817  pgridy[j+i*n_calib] = parc_posy[j] ;
818  pvalues_to_fit[j+i*n_calib] = parc_posx[j];
819 
820 /*
821  sinfo_msg("pgridx=%g pgridy=%g pvalues=%g",
822  pgridx[j+i*n_calib],pgridy[j+i*n_calib],pvalues_to_fit[j+i*n_calib]);
823 */
824  }
825  }
826 
827 
828  /* AMO new to use offset */
829  n_lines= n_arcs/32.0;
830  if(n_lines < 1) {
831  n_lines=1;
832  }
833  cpl_vector_sort(lines_pos_tmp,1);
834  plines_pos_tmp=cpl_vector_get_data(lines_pos_tmp);
835 
836  grid_tmp=cpl_bivector_duplicate(grid);
837  grid_tot=cpl_vector_new(n_calib);
838  pgrid_tmp_x = cpl_bivector_get_x_data(grid_tmp) ;
839  //pgrid_tmp_y = cpl_bivector_get_y_data(grid_tmp) ;
840  pgrid_tot = cpl_vector_get_data(grid_tot);
841  for(j=0;j<n_calib;j++) {
842  pgrid_tot[j]=0;
843  for(i=n_lines ;i<n_arcs;i=i+n_lines)
844  {
845  for(k=0;k<n_lines;k++) {
846  pgrid_tot[j] += (plines_pos_tmp[i+k]-
847  plines_pos_tmp[k]);
848  /*
849  sinfo_msg("diff=%g",(plines_pos_tmp[i+k]-
850  plines_pos_tmp[k]));
851  */
852  }
853  }
854  /*
855  sinfo_msg("j=%d pgrid_tot=%g",j,pgrid_tot[j]);
856  */
857  }
858 
859  for(j=0;j<n_calib;j++) {
860  for (i=0 ; i<n_arcs ; i++) {
861  pgridx[j+i*n_calib]=pgridx[j+i*n_calib]*
862  ((nx/32.0)*n_lines*(31*32/2))/pgrid_tot[j]-offset;
863  /*
864  sinfo_msg_error("AMo after corr grid[%d,%d]=%g",
865  i,k,pgridx[k+i*n_calib]);
866  */
867  pgrid_tmp_x[j+i*n_calib]=pgrid_tmp_x[j+i*n_calib]*
868  ((nx/32.0)*n_lines*(31*32/2))/pgrid_tot[j]-
869  offset;
870 
871  }
872  }
873  /* end AMO: to use the offset */
874 
875 
876  for (i=0 ; i<n_arcs ; i++) cpl_bivector_delete(arcs_pos[i]) ;
877  cpl_free(arcs_pos) ;
878  cpl_free(lines_pos) ;
879 
880  /* Apply the fitting */
881  if ((poly2d = sinfo_polynomial_fit_2d_create(grid, values_to_fit,
882  degree, NULL))==NULL) {
883  cpl_msg_error(fctid, "cannot apply the 2d fit") ;
884  cpl_bivector_delete(grid) ;
885  cpl_vector_delete(values_to_fit) ;
886  cpl_apertures_delete(*arcs) ;
887  return NULL ;
888  }
889 
890  /* Free and return */
891  cpl_bivector_delete(grid) ;
892  cpl_vector_delete(values_to_fit) ;
893  return poly2d ;
894 }
895 
898 /*---------------------------------------------------------------------------*/
913 /*---------------------------------------------------------------------------*/
914 static cpl_apertures * sinfo_distortion_detect_arcs(
915  cpl_image * im,
916  cpl_image ** label_im,
917  int arc_sat,
918  int max_arc_width,
919  int xmin,
920  int ymin,
921  int xmax,
922  int ymax)
923 {
924  const char * fctid = "sinfo_distortion_detect_arcs" ;
925  cpl_image * filt_im ;
926  cpl_matrix * filter ;
927  cpl_image * collapsed ;
928  cpl_mask * bin_im ;
929  double threshold, fillval, median_val, sigma ;
930  int min_arclen = 0 ;
931  cpl_apertures * det ;
932  cpl_size nobj ;
933  int ngoodpix ;
934  int ny ;
935 
936  ny = cpl_image_get_size_y(im) ;
937 
938  /* Default values for output parameters */
939  *label_im = NULL ;
940 
941  /* Clear zones to be ignored (to avoid false detections) */
942  median_val = cpl_image_get_median_dev(im, &sigma) ;
943  fillval = median_val-sigma/2.0 ;
944  if (sinfo_distortion_fill_badzones(im, xmin, ymin, xmax, ymax,
945  fillval) == -1) {
946  cpl_msg_error(fctid, "cannot fill bad zones") ;
947  return NULL ;
948  }
949 
950  /* Median vertical filter */
951  filter = cpl_matrix_new(3, 1) ;
952  cpl_matrix_fill(filter, 1.0) ;
953  /* filt_im = cpl_image_filter_median(im, filter) ; */
954  filt_im = cpl_image_duplicate(im) ;
955  cpl_matrix_delete(filter) ;
956 
957  /* Subtract a low-pass */
958  if (sinfo_distortion_sub_hor_lowpass(filt_im, ARC_WINDOWSIZE) == -1) {
959  cpl_image_delete(filt_im) ;
960  return NULL ;
961  }
962 
963  /* Get relevant stats for thresholding */
964  median_val = cpl_image_get_median_dev(filt_im, &sigma) ;
965 
966  /* Correct median_val and sigma if necessary */
967  if (median_val < TRESH_MEDIAN_MIN) median_val = TRESH_MEDIAN_MIN ;
968  if (sigma > TRESH_SIGMA_MAX) sigma = TRESH_SIGMA_MAX ;
969 
970  /* Set the threshold */
971  threshold = median_val + sigma * ARC_THRESHFACT ;
972 
973  /* Collapse the image */
974  collapsed = cpl_image_collapse_median_create(filt_im, 0, 0, 0) ;
975 
976  /* Threshold to keep only the arcs - use of the collapsed image */
977  if (sinfo_distortion_threshold1d(filt_im, median_val,
978  collapsed, 0.0)==-1) {
979  cpl_msg_error(fctid, "cannot threshold the filtered image") ;
980  cpl_image_delete(filt_im) ;
981  cpl_image_delete(collapsed) ;
982  return NULL ;
983  }
984  cpl_image_delete(collapsed) ;
985 
986  /* Binarize the image */
987  bin_im = cpl_mask_threshold_image_create(filt_im, threshold,
988  SINFO_DBL_MAX);
989  cpl_image_delete(filt_im) ;
990  if (bin_im == NULL) {
991  cpl_msg_error(fctid, "cannot binarise the image") ;
992  return NULL ;
993  }
994 
995  /* Test if there are enough good pixels */
996  ngoodpix = cpl_mask_count(bin_im) ;
997  if (ngoodpix < ARC_MINGOODPIX) {
998  cpl_msg_error(fctid, "Too few (%d) white pixels", ngoodpix) ;
999  cpl_mask_delete(bin_im) ;
1000  return NULL ;
1001  }
1002 
1003  /* Apply a morphological closing to clean the isolated pixels */
1004  filter = cpl_matrix_new(3, 3) ;
1005  cpl_matrix_fill(filter, 1.0) ;
1006  cpl_mask_closing(bin_im, filter) ;
1007  cpl_matrix_delete(filter) ;
1008 
1009  /* Labelize pixel map to a label image */
1010  *label_im = cpl_image_labelise_mask_create(bin_im, &nobj) ;
1011  cpl_mask_delete(bin_im) ;
1012 
1013  /* Compute statistics on objects */
1014  if ((det = cpl_apertures_new_from_image(im, *label_im)) == NULL) {
1015  cpl_msg_error(fctid, "Cannot compute arcs stats") ;
1016  cpl_image_delete(*label_im) ;
1017  *label_im = NULL ;
1018  return NULL ;
1019  }
1020 
1021  /* Set min_arclen */
1022  min_arclen = (int)(ny / ARC_MINARCLENFACT) ;
1023 
1024  /* Purge non-relevant arcs */
1025  if (sinfo_distortion_purge_arcs(im, &det, label_im, min_arclen,
1026  max_arc_width, arc_sat) == -1) {
1027  cpl_msg_error(fctid, "Cannot purge the arcs") ;
1028  cpl_image_delete(*label_im) ;
1029  *label_im = NULL ;
1030  cpl_apertures_delete(det) ;
1031  return NULL ;
1032  }
1033  if (cpl_apertures_get_size(det) < ARC_MINNBARCS) {
1034  cpl_msg_error(fctid, "Not enough valid arcs (%"
1035  CPL_SIZE_FORMAT " < %d)",
1036  cpl_apertures_get_size(det), ARC_MINNBARCS) ;
1037  cpl_image_delete(*label_im) ;
1038  *label_im = NULL ;
1039  cpl_apertures_delete(det) ;
1040  return NULL ;
1041  }
1042 
1043  /* Return */
1044  return det ;
1045 }
1046 
1047 static int sinfo_distortion_fill_badzones(
1048  cpl_image * im,
1049  int xmin,
1050  int ymin,
1051  int xmax,
1052  int ymax,
1053  double fillval)
1054 {
1055  float * pfi ;
1056  int nx, ny ;
1057  int i, j ;
1058 
1059  /* Check entries */
1060  if (im == NULL) return -1 ;
1061  if (cpl_image_get_type(im) != CPL_TYPE_FLOAT) return -1 ;
1062 
1063  /* Get the data */
1064  pfi = cpl_image_get_data_float(im) ;
1065  nx = cpl_image_get_size_x(im) ;
1066  ny = cpl_image_get_size_y(im) ;
1067 
1068  /* Fill the zone */
1069  for (i=0 ; i<nx ; i++) {
1070  for (j=0 ; j<ny ; j++) {
1071  if ((i<xmin-1) || (i>xmax-1) || (j<ymin-1) || (j>ymax-1)) {
1072  pfi[i+j*nx] = (float)fillval ;
1073  }
1074  }
1075  }
1076  return 0 ;
1077 }
1078 
1079 static int sinfo_distortion_threshold1d(
1080  cpl_image * im,
1081  double threshold,
1082  cpl_image * im1d,
1083  double newval)
1084 {
1085  float * pim ;
1086  float * pim1d ;
1087  int nx, ny ;
1088  int i, j ;
1089 
1090  /* Check entries */
1091  if (im == NULL) return -1 ;
1092  if (im1d == NULL) return -1 ;
1093  if (cpl_image_get_type(im) != CPL_TYPE_FLOAT) return -1 ;
1094  if (cpl_image_get_type(im1d) != CPL_TYPE_FLOAT) return -1 ;
1095 
1096  /* Get access to the im / im1d data */
1097  pim = cpl_image_get_data_float(im) ;
1098  pim1d = cpl_image_get_data_float(im1d) ;
1099  nx = cpl_image_get_size_x(im) ;
1100  ny = cpl_image_get_size_y(im) ;
1101 
1102  /* Apply the thresholding */
1103  for (i=0 ; i<nx ; i++)
1104  if (pim1d[i] < threshold) {
1105  for (j=0 ; j<ny ; j++) pim[i+j*nx] = (float)newval ;
1106  }
1107 
1108  /* Return */
1109  return 0 ;
1110 }
1111 
1112 static int sinfo_distortion_sub_hor_lowpass(
1113  cpl_image * im,
1114  int filt_size)
1115 {
1116  cpl_vector * linehi ;
1117  cpl_vector * linelo ;
1118  cpl_vector * avglinehi ;
1119  cpl_vector * avglinelo ;
1120  double * pavglinehi ;
1121  float * pim ;
1122  int lopos, hipos, nx, ny ;
1123  int i, j ;
1124 
1125  /* Test entries */
1126  if (im == NULL) return -1 ;
1127  if (filt_size <= 0) return -1 ;
1128 
1129  /* Initialise */
1130  nx = cpl_image_get_size_x(im) ;
1131  ny = cpl_image_get_size_y(im) ;
1132  lopos = (int)(ny/4) ;
1133  hipos = (int)(3*ny/4) ;
1134 
1135  /* Get the vectors out of the image */
1136  if ((linehi = cpl_vector_new_from_image_row(im, hipos)) == NULL) {
1137  return -1 ;
1138  }
1139  if ((linelo = cpl_vector_new_from_image_row(im, lopos)) == NULL) {
1140  cpl_vector_delete(linehi) ;
1141  return -1 ;
1142  }
1143 
1144  /* Filter the vectors */
1145  if ((avglinehi = cpl_vector_filter_median_create(linehi,
1146  filt_size)) == NULL) {
1147  cpl_vector_delete(linehi) ;
1148  cpl_vector_delete(linelo) ;
1149  return -1 ;
1150  }
1151  cpl_vector_delete(linehi) ;
1152 
1153  if ((avglinelo = cpl_vector_filter_median_create(linelo,
1154  filt_size)) == NULL) {
1155  cpl_vector_delete(linelo) ;
1156  cpl_vector_delete(avglinehi) ;
1157  return -1 ;
1158  }
1159  cpl_vector_delete(linelo) ;
1160 
1161  /* Average the filtered vectors to get the low freq signal */
1162  cpl_vector_add(avglinehi, avglinelo) ;
1163  cpl_vector_delete(avglinelo) ;
1164  cpl_vector_divide_scalar(avglinehi, 2.0) ;
1165 
1166  /* Subtract the low frequency signal */
1167  pavglinehi = cpl_vector_get_data(avglinehi) ;
1168  pim = cpl_image_get_data_float(im) ;
1169  for (i=0 ; i<nx ; i++) {
1170  for (j=0 ; j<ny ; j++) {
1171  pim[i+j*nx] -= pavglinehi[i] ;
1172  }
1173  }
1174  cpl_vector_delete(avglinehi) ;
1175 
1176  return 0 ;
1177 }
1178 
1179 
1180 
1181 
1182 
1183 
1184 
1185 
1186 static int sinfo_distortion_purge_arcs(
1187  cpl_image * im,
1188  cpl_apertures ** arcs,
1189  cpl_image ** lab_im,
1190  int min_arclen,
1191  int max_arcwidth,
1192  double arc_sat)
1193 {
1194  const char * fctid = "sinfo_distortion_purge_arcs" ;
1195  int nb_arcs ;
1196  int * selection ;
1197  int arclen, arcwidth, edge ;
1198  double mean ;
1199  int * plabim ;
1200  cpl_mask * bin_im ;
1201  int nx, ny ;
1202  int i, j ;
1203 
1204  /* Check entries */
1205  if (arcs == NULL) return -1 ;
1206  if (*arcs == NULL) return -1 ;
1207  if (*lab_im == NULL) return -1 ;
1208 
1209  /* Get number of arcs */
1210  nb_arcs = cpl_apertures_get_size(*arcs) ;
1211  nx = cpl_image_get_size_x(*lab_im) ;
1212  ny = cpl_image_get_size_y(*lab_im) ;
1213 
1214  /* Allocate selection array */
1215  selection = cpl_malloc(nb_arcs * sizeof(int)) ;
1216  /* Loop on the different arcs candidates */
1217  /* sinfo_msg("min_arclen=%d max_arcwidth=%d",min_arclen,max_arcwidth); */
1218  for (i=0 ; i<nb_arcs ; i++) {
1219  arclen = cpl_apertures_get_top(*arcs, i+1) -
1220  cpl_apertures_get_bottom(*arcs, i+1) + 1 ;
1221  arcwidth = cpl_apertures_get_right(*arcs, i+1) -
1222  cpl_apertures_get_left(*arcs, i+1) + 1 ;
1223  edge = cpl_apertures_get_left_y(*arcs, i+1) ;
1224  mean = cpl_apertures_get_mean(*arcs, i+1) ;
1225 
1226  /* Test if the current object is a valid arc */
1227 
1228  if (
1229  (arclen>min_arclen) &&
1230  (arcwidth<max_arcwidth) &&
1231  (edge>0) &&
1232  (mean < arc_sat)) {
1233  /*
1234  sinfo_msg_warning("Take Pos=%5.4d len=%d width=%d edge=%d mean=%f ",
1235  (cpl_apertures_get_right(*arcs, i+1)+cpl_apertures_get_left(*arcs, i+1))/2,
1236  arclen,arcwidth,edge,mean);
1237  */
1238  selection[i] = 1 ;
1239  } else {
1240  /*
1241  sinfo_msg_warning("Rej Pos=%5.4d len=%d width=%d edge=%d mean=%f i=%d",
1242  (cpl_apertures_get_right(*arcs, i+1)+
1243  cpl_apertures_get_left(*arcs, i+1))/2,arclen,arcwidth,edge,mean,i);
1244  */
1245  selection[i] = 0 ;
1246  }
1247  }
1248 
1249  /* Update the labelised image by erasing non valid arcs */
1250  for (i=0 ; i<nb_arcs ; i++) {
1251  if (selection[i] == 0) {
1252  plabim = cpl_image_get_data_int(*lab_im) ;
1253  for (j=0 ; j<nx*ny ; j++) {
1254  if (plabim[j] == i+1) plabim[j] = 0 ;
1255  }
1256  }
1257  }
1258  cpl_free(selection) ;
1259 
1260  /* Reset the labels to have consecutive ones */
1261  bin_im = cpl_mask_threshold_image_create(*lab_im, 0.5, SINFO_DBL_MAX) ;
1262  cpl_image_delete(*lab_im) ;
1263  *lab_im = cpl_image_labelise_mask_create(bin_im, NULL) ;
1264  cpl_mask_delete(bin_im) ;
1265 
1266  /* Purge the bad arcs */
1267  cpl_apertures_delete(*arcs) ;
1268  *arcs = cpl_apertures_new_from_image(im, *lab_im) ;
1269 
1270  /* Check if there are some valid arcs */
1271  if (cpl_apertures_get_size(*arcs) <= 0) {
1272  cpl_msg_error(fctid, "No valid arc found") ;
1273  return -1 ;
1274  }
1275  /* Return */
1276  return 0 ;
1277 }
1278 
1279 static cpl_bivector **
1280 sinfo_distortion_get_arc_positions(
1281  cpl_image * in,
1282  cpl_image * label_im,
1283  cpl_apertures * det,
1284  int nb_samples,
1285  double ** lines_pos)
1286 {
1287  const char * fctid = "sinfo_distortion_get_arc_positions" ;
1288  int n_arcs ;
1289  cpl_image * filt_img ;
1290  cpl_matrix * kernel ;
1291  cpl_bivector ** pos ;
1292  double * biv_x ;
1293  double * biv_y ;
1294  double x_finepos ;
1295  int * plabel_im ;
1296  int * arcs_samples_y ;
1297  int * computed ;
1298  double arclen ;
1299  int use_this_arc ;
1300  int obj ;
1301  int nx, ny ;
1302  int i, j, k ;
1303  cpl_mask* mask=NULL;
1304 
1305  /* Check entries */
1306 
1307  /* Initialise */
1308  n_arcs = cpl_apertures_get_size(det) ;
1309  nx = cpl_image_get_size_x(label_im) ;
1310  ny = cpl_image_get_size_y(label_im) ;
1311 
1312  /* Allocate positions (pos. of n_arcs*nb_samples pts on the arcs) */
1313  pos = cpl_calloc(n_arcs, sizeof(cpl_bivector*)) ;
1314  for (i=0 ; i<n_arcs ; i++) pos[i] = cpl_bivector_new(nb_samples) ;
1315 
1316  /* Median filter on input image */
1317  kernel = cpl_matrix_new(3, 3) ;
1318  cpl_matrix_fill(kernel, 1.0) ;
1319  filt_img=cpl_image_duplicate(in);
1320  mask=cpl_mask_new(3,3);
1321  cpl_mask_not(mask);
1322  cpl_image_filter_mask(filt_img,in,mask,CPL_FILTER_MEDIAN,CPL_BORDER_FILTER);
1323  cpl_mask_delete(mask);
1324 
1325  cpl_matrix_delete(kernel) ;
1326 
1327  /* Measured Arcs coordinates along curvature */
1328  arcs_samples_y = cpl_malloc(n_arcs * nb_samples * sizeof(int)) ;
1329  computed = cpl_calloc(n_arcs*nb_samples, sizeof(int)) ;
1330 
1331  /* Find out the Y coordinates along the arcs */
1332  for (j=0 ; j<n_arcs ; j++) {
1333  arclen = cpl_apertures_get_top(det,j+1) -
1334  cpl_apertures_get_bottom(det,j+1) + 1 ;
1335  for (i=0 ; i<nb_samples ; i++) {
1336  arcs_samples_y[i+j*nb_samples] =
1337  (int)(cpl_apertures_get_bottom(det, j+1) +
1338  (arclen * (i + 0.5)) / (double)nb_samples) ;
1339  }
1340  }
1341 
1342  /* Find out the X coord. at nb_samples Y positions on all arcs */
1343  plabel_im = cpl_image_get_data_int(label_im) ;
1344  for (i=0 ; i<nx ; i++) {
1345  for (j=0 ; j<ny ; j++) {
1346  /* use_this_arc is set to 1 if we are on the arc at a y */
1347  /* coordinate where the x coord should be found */
1348  obj = plabel_im[i + j * nx] ;
1349  /* Handle background */
1350  if (obj==0) continue ;
1351  /* Decrease by one to index the array from 0 */
1352  else obj-- ;
1353 
1354  use_this_arc = 0 ;
1355  for (k=0 ; k<nb_samples ; k++) {
1356  if (arcs_samples_y[k+obj*nb_samples] == j) {
1357  use_this_arc = 1 ;
1358  break ;
1359  }
1360  }
1361  if ((use_this_arc) && (computed[k+obj*nb_samples] == 0)) {
1362  /* Find x coordinate of obj at the Y coord. */
1363  if ((x_finepos = sinfo_distortion_fine_pos(filt_img,
1364  label_im, i, j)) < 0.0) {
1365  cpl_msg_error(fctid, "cannot find fine arc position") ;
1366  cpl_image_delete(filt_img) ;
1367  cpl_free(arcs_samples_y);
1368  cpl_free(computed) ;
1369  for (i=0 ; i<n_arcs ; i++) cpl_bivector_delete(pos[i]);
1370  cpl_free(pos) ;
1371  return NULL ;
1372  } else {
1373  biv_x = cpl_bivector_get_x_data(pos[obj]) ;
1374  biv_y = cpl_bivector_get_y_data(pos[obj]) ;
1375  biv_x[k] = x_finepos ;
1376  biv_y[k] = j ;
1377  (*lines_pos)[obj] = cpl_apertures_get_centroid_x(det,obj+1);
1378  computed[k+obj*nb_samples] = 1 ;
1379  }
1380  }
1381  }
1382  }
1383 
1384  /* Free and return */
1385  cpl_image_delete(filt_img) ;
1386  cpl_free(arcs_samples_y) ;
1387  cpl_free(computed) ;
1388  return pos ;
1389 }
1390 
1391 static double
1392 sinfo_distortion_fine_pos(
1393  cpl_image * im,
1394  cpl_image * label_im,
1395  int x,
1396  int y)
1397 {
1398  float * pim ;
1399  int * plabel_im ;
1400  int objnum ;
1401  int curr_obj ;
1402  int start_pos ;
1403  double grav_c ;
1404  double sum ;
1405  double max ;
1406  double val ;
1407  int maxpos ;
1408  //int im_extrem ;
1409  double arc_pos ;
1410  int nx ;
1411 
1412  /* Initialize */
1413  nx = cpl_image_get_size_x(im) ;
1414  grav_c = 0.0 ;
1415  sum = 0.0 ;
1416  start_pos = x ;
1417  maxpos = start_pos ;
1418  pim = cpl_image_get_data_float(im) ;
1419  max = (double)pim[start_pos + y * nx] ;
1420  plabel_im = cpl_image_get_data_int(label_im) ;
1421  objnum = plabel_im[start_pos + y * nx] ;
1422  //im_extrem = nx ;
1423 
1424  /* While we stay in the same object... */
1425  do {
1426  val = (double)pim[start_pos + y * nx] ;
1427  if (start_pos == 0) grav_c = 0.0 ;
1428  else grav_c += start_pos * val ;
1429  sum += val ;
1430  if (val > max) {
1431  max = val ;
1432  maxpos = start_pos ;
1433  }
1434 
1435  /* Next point */
1436  start_pos++ ;
1437 
1438  curr_obj = plabel_im[start_pos + y * nx] ;
1439  } while (curr_obj == objnum) ;
1440 
1441  /* Returned position is the gravity center or the max in bad cases */
1442  if ((fabs(grav_c) < 1.0e-40) || (fabs(sum) < 1.0e-40)) {
1443  arc_pos = maxpos ;
1444  } else {
1445  arc_pos = grav_c / sum ;
1446  if (fabs(arc_pos) >= start_pos) arc_pos = maxpos ;
1447  }
1448 
1449  /* Return */
1450  return arc_pos ;
1451 }
1452 
1453 /*---------------------------------------------------------------------------*/
1459 /*---------------------------------------------------------------------------*/
1460 #define IS_NB_TESTPOINTS 8
1461 #define IS_MIN_SLOPE 0.01
1462 #define IS_MAX_SLOPE_DIF 0.075
1463 #define IS_MAX_FIT_EDGE_DIF 0.05
1464 #define IS_MIN_RAMP 10.0
1465 #define IS_MAX_MNERR 13.0
1466 #define IS_MAX_MNERR_DIF 8.0
1467 #define IS_MAX_INTER_DIF 20.0
1468 #define IS_SKIPZONE 2.5
1469 #define SQR(x) ((x)*(x))
1470 static cpl_image * sinfo_distortion_remove_ramp(const cpl_image * in)
1471 {
1472  const char * fctid = "sinfo_distortion_remove_ramp" ;
1473  int ramp_present ;
1474  int nx, ny ;
1475  int y, yhi, ylo;
1476  cpl_vector * tmp_vector ;
1477  cpl_bivector * testpointlo ;
1478  double * testpointlo_x ;
1479  double * testpointlo_y ;
1480  cpl_bivector * testpointhi ;
1481  double * testpointhi_x ;
1482  double * testpointhi_y ;
1483  int spacing;
1484  double rampdif, fitslope;
1485  double * pol_coefhi,
1486  * pol_coeflo ;
1487  cpl_vector * median ;
1488  double * median_data ;
1489  double medianerrlo, medianerrhi;
1490  double slope ;
1491  cpl_image * out ;
1492  float * pout ;
1493  float val ;
1494  int i, j ;
1495 
1496  /* Initialise */
1497  nx = cpl_image_get_size_x(in) ;
1498  ny = cpl_image_get_size_y(in) ;
1499 
1500  /* Check entries */
1501  if (in==NULL) return NULL ;
1502 
1503  if (ny<IS_SKIPZONE*IS_NB_TESTPOINTS){
1504  cpl_msg_error(fctid, "image has %d lines, min=%d ",
1505  ny, (int)(IS_SKIPZONE*IS_NB_TESTPOINTS*2));
1506  return NULL ;
1507  }
1508 
1509  slope=0.0 ;
1510  spacing= ny / (IS_SKIPZONE*IS_NB_TESTPOINTS) ;
1511  yhi = (int)(ny/2) ;
1512  ylo = yhi - 1 ;
1513  /* Fill the vectors */
1514  testpointhi = cpl_bivector_new(IS_NB_TESTPOINTS) ;
1515  testpointhi_x = cpl_bivector_get_x_data(testpointhi) ;
1516  testpointhi_y = cpl_bivector_get_y_data(testpointhi) ;
1517  testpointlo = cpl_bivector_new(IS_NB_TESTPOINTS) ;
1518  testpointlo_x = cpl_bivector_get_x_data(testpointlo) ;
1519  testpointlo_y = cpl_bivector_get_y_data(testpointlo) ;
1520  for (i=0 ; i<IS_NB_TESTPOINTS ; i++) {
1521  y = yhi + i * spacing;
1522  tmp_vector = cpl_vector_new_from_image_row(in, y+1) ;
1523  testpointhi_x[i] = y - ny / 2;
1524  testpointhi_y[i] = cpl_vector_get_median_const(tmp_vector) ;
1525  cpl_vector_delete(tmp_vector) ;
1526  y = ylo - i * spacing;
1527  tmp_vector = cpl_vector_new_from_image_row(in, y+1) ;
1528  testpointlo_x[IS_NB_TESTPOINTS-i-1] = y ;
1529  testpointlo_y[IS_NB_TESTPOINTS-i-1]=
1530  cpl_vector_get_median_const(tmp_vector);
1531  cpl_vector_delete(tmp_vector) ;
1532  }
1533 
1534  /* Apply the fit */
1535  pol_coefhi = irplib_flat_fit_slope_robust(testpointhi_x,
1536  testpointhi_y, IS_NB_TESTPOINTS) ;
1537  pol_coeflo = irplib_flat_fit_slope_robust(testpointlo_x,
1538  testpointlo_y, IS_NB_TESTPOINTS) ;
1539 
1540  /* Compute the errors */
1541  median = cpl_vector_new(IS_NB_TESTPOINTS) ;
1542  median_data = cpl_vector_get_data(median) ;
1543  for (i=0 ; i<IS_NB_TESTPOINTS ; i++) {
1544  median_data[i]=SQR(testpointhi_y[i]
1545  - pol_coefhi[0] - pol_coefhi[1] * testpointhi_x[i]);
1546  }
1547  medianerrhi = cpl_vector_get_median_const(median) ;
1548  for (i=0; i<IS_NB_TESTPOINTS; i++) {
1549  median_data[i]=SQR(testpointlo_y[i]
1550  - pol_coeflo[0] - pol_coeflo[1] * testpointlo_x[i]);
1551  }
1552  medianerrlo = cpl_vector_get_median_const(median) ;
1553  cpl_vector_delete(median) ;
1554  rampdif = testpointlo_y[IS_NB_TESTPOINTS-1] - testpointhi_y[0];
1555  slope = rampdif / (ny/2.0) ;
1556  fitslope = (pol_coefhi[1] + pol_coeflo[1]) / 2.0 ;
1557 
1558  cpl_bivector_delete(testpointlo);
1559  cpl_bivector_delete(testpointhi);
1560 
1561  /* Decide if there is a ramp or not */
1562  if (fabs(rampdif)<IS_MIN_RAMP ||
1563  fabs(pol_coefhi[1]) < IS_MIN_SLOPE ||
1564  fabs(pol_coeflo[1]) < IS_MIN_SLOPE ||
1565  pol_coefhi[1]/pol_coeflo[1]<0.5 ||
1566  pol_coefhi[1]/pol_coeflo[1]>2.0 ||
1567  fabs(pol_coefhi[1]-pol_coeflo[1])>IS_MAX_SLOPE_DIF ||
1568  fabs(pol_coefhi[0]-pol_coeflo[0]) > IS_MAX_INTER_DIF ||
1569  medianerrlo> IS_MAX_MNERR ||
1570  medianerrhi> IS_MAX_MNERR ||
1571  fabs(medianerrlo-medianerrhi) >IS_MAX_MNERR_DIF ||
1572  fabs(slope-fitslope) > IS_MAX_FIT_EDGE_DIF ||
1573  slope/fitslope<0.5 ||
1574  slope/fitslope>2.0) ramp_present = 0 ;
1575  else ramp_present = 1 ;
1576 
1577  cpl_free(pol_coeflo) ;
1578  cpl_free(pol_coefhi) ;
1579 
1580  /* Correct the ramp if it is there */
1581  out = cpl_image_duplicate(in) ;
1582  pout = cpl_image_get_data_float(out) ;
1583  if (ramp_present == 1) {
1584  for (j=0 ; j<ny/2 ; j++) {
1585  val = slope * (j-ny/2) ;
1586  for (i=0 ; i<nx ; i++)
1587  pout[i+j*nx] -= val ;
1588  }
1589  for (j=ny/2 ; j<ny ; j++) {
1590  val = slope * (j-ny) ;
1591  for (i=0 ; i<nx ; i++)
1592  pout[i+j*nx] -= val ;
1593  }
1594 
1595  }
1596 
1597  return out ;
1598 }
1599