irplib_distortion.c

00001 /* $Id: irplib_distortion.c,v 1.11 2007/07/23 14:53:14 yjung 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: yjung $
00023  * $Date: 2007/07/23 14:53:14 $
00024  * $Revision: 1.11 $
00025  * $Name: uves-4_2_2 $
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 #include <float.h>
00039 
00040 #include "irplib_flat.h"
00041 #include "irplib_distortion.h"
00042 
00043 /*-----------------------------------------------------------------------------
00044                                    Define
00045  -----------------------------------------------------------------------------*/
00046 
00047 #define ARC_NBSAMPLES       20
00048 #define ARC_MINGOODPIX      100
00049 #define ARC_MINARCLENFACT   2.0
00050 #define ARC_MINNBARCS       4
00051 #define ARC_RANGE_FACT      3.0
00052 #define ARC_WINDOWSIZE      32
00053 
00054 #define TRESH_MEDIAN_MIN    0.0
00055 #define TRESH_SIGMA_MAX     200.0
00056 
00057 /*----------------------------------------------------------------------------*/
00061 /*----------------------------------------------------------------------------*/
00062 
00063 /*-----------------------------------------------------------------------------
00064                                 Functions prototypes
00065  -----------------------------------------------------------------------------*/
00066 
00067 static cpl_apertures * irplib_distortion_detect_arcs(cpl_image *,
00068         cpl_image **, int, int, double, int, int, int, int) ;
00069 static int irplib_distortion_fill_badzones(cpl_image *, int, int, int, int, 
00070         double) ;
00071 static int irplib_distortion_threshold1d(cpl_image *, double, cpl_image *, 
00072         double) ;
00073 static int irplib_distortion_purge_arcs(cpl_image *, cpl_apertures **, 
00074         cpl_image **, int, int, double) ;
00075 static cpl_bivector ** irplib_distortion_get_arc_positions(cpl_image *,
00076         cpl_image *, cpl_apertures *, int, double **) ;
00077 static double irplib_distortion_fine_pos(cpl_image *, cpl_image *, int, int) ;
00078 static int irplib_distortion_sub_hor_lowpass(cpl_image *, int) ;
00079 static cpl_image * irplib_distortion_remove_ramp(const cpl_image *) ; 
00080 
00081 /*-----------------------------------------------------------------------------
00082                                 Functions code
00083  -----------------------------------------------------------------------------*/
00084 
00087 /*----------------------------------------------------------------------------*/
00111 /*----------------------------------------------------------------------------*/
00112 cpl_polynomial * irplib_distortion_estimate(
00113         const cpl_image *   org,
00114         int                 xmin,
00115         int                 ymin,
00116         int                 xmax,
00117         int                 ymax,
00118         int                 auto_ramp_sub,
00119         int                 arc_sat,
00120         int                 max_arc_width,
00121         double              kappa,
00122         int                 degree,
00123         cpl_apertures   **  arcs)
00124 {
00125     cpl_image       *   local_im ;
00126     cpl_image       *   label_image ;
00127     double              rightmost, leftmost ;
00128     cpl_bivector    **  arcs_pos ;
00129     double          *   parc_posx ;
00130     double          *   parc_posy ;
00131     double          *   lines_pos ;
00132     cpl_bivector    *   grid ;
00133     double          *   pgridx ;
00134     double          *   pgridy ;
00135     cpl_vector      *   values_to_fit ;
00136     double          *   pvalues_to_fit ;
00137     int                 min_arc_range ;
00138     int                 n_calib ;
00139     int                 n_arcs ;
00140     cpl_polynomial  *   poly2d ;
00141     int                 nx ;
00142     int                 i, j ;
00143 
00144     /* Check entries */
00145     if (org == NULL) return NULL ;
00146     if (kappa < 0.0) return NULL ;
00147 
00148     /* Initialise */
00149     n_calib = ARC_NBSAMPLES ;
00150     nx = cpl_image_get_size_x(org) ;
00151 
00152     if (auto_ramp_sub) {
00153         local_im = irplib_distortion_remove_ramp(org) ;
00154     } else {
00155         /* Local copy of input image */
00156         local_im = cpl_image_duplicate(org) ;
00157     }
00158     if (local_im == NULL) {
00159         cpl_msg_error(cpl_func, "Cannot clean the image") ;
00160         return NULL ;
00161     }
00162 
00163     /* Detect the arcs in the input image */
00164     cpl_msg_info(cpl_func, "Detect arcs") ;
00165     if ((*arcs = irplib_distortion_detect_arcs(local_im,
00166                     &label_image,
00167                     arc_sat, max_arc_width, kappa,
00168                     xmin, ymin, xmax, ymax)) == NULL) {
00169         cpl_image_delete(local_im) ;
00170         cpl_msg_error(cpl_func, "Cannot detect the arcs") ;
00171         return NULL ;
00172     }
00173     n_arcs = cpl_apertures_get_size(*arcs) ;
00174     cpl_msg_info(cpl_func, "%d detected arcs", n_arcs) ;
00175 
00176     /* Check that the arcs are not concentrated in the same zone */
00177     rightmost = leftmost = cpl_apertures_get_max_x(*arcs, 1) ;
00178     for (i=1 ; i<n_arcs ; i++) {
00179         if (cpl_apertures_get_max_x(*arcs, i+1) < leftmost)
00180             leftmost = cpl_apertures_get_max_x(*arcs, i+1) ;
00181         if (cpl_apertures_get_max_x(*arcs, i+1) > rightmost)
00182             rightmost = cpl_apertures_get_max_x(*arcs, i+1) ;
00183     }
00184     min_arc_range = (int)(nx / ARC_RANGE_FACT) ;
00185     if ((int)(rightmost-leftmost) < min_arc_range) {
00186         cpl_msg_error(cpl_func, "too narrow range (%g-%g)<%d",
00187                 rightmost, leftmost, min_arc_range) ;
00188         cpl_apertures_delete(*arcs) ;
00189         cpl_image_delete(local_im) ;
00190         cpl_image_delete(label_image) ;
00191         return NULL ;
00192     }
00193 
00194     /* Create a 2-D deformation grid with detected arcs */
00195     cpl_msg_info(cpl_func, "Create deformation grid") ;
00196     lines_pos = cpl_malloc(n_arcs * sizeof(double)) ;
00197     if ((arcs_pos = irplib_distortion_get_arc_positions(local_im,
00198                     label_image, *arcs, n_calib, &lines_pos))==NULL){
00199         cpl_msg_error(cpl_func, "cannot get arcs positions") ;
00200         cpl_apertures_delete(*arcs) ;
00201         cpl_image_delete(local_im) ;
00202         cpl_free(lines_pos) ;
00203         cpl_image_delete(label_image) ;
00204         return NULL ;
00205     }
00206     cpl_image_delete(label_image) ;
00207     cpl_image_delete(local_im) ;
00208 
00209     /* Prepare the fitting */
00210     cpl_msg_info(cpl_func, "Fit the 2d polynomial") ;
00211     grid = cpl_bivector_new(n_arcs * n_calib) ;
00212     pgridx = cpl_bivector_get_x_data(grid) ;
00213     pgridy = cpl_bivector_get_y_data(grid) ;
00214     values_to_fit = cpl_vector_new(n_arcs * n_calib) ;
00215     pvalues_to_fit = cpl_vector_get_data(values_to_fit) ;
00216     for (i=0 ; i<n_arcs ; i++) {
00217         parc_posx = cpl_bivector_get_x_data(arcs_pos[i]) ;
00218         parc_posy = cpl_bivector_get_y_data(arcs_pos[i]) ;
00219         for (j=0 ; j<n_calib ; j++) {
00220             pgridx[j+i*n_calib] = lines_pos[i] ;
00221             pgridy[j+i*n_calib] = parc_posy[j] ;
00222             pvalues_to_fit[j+i*n_calib] = parc_posx[j] ;
00223         }
00224     }
00225     for (i=0 ; i<n_arcs ; i++) cpl_bivector_delete(arcs_pos[i]) ;
00226     cpl_free(arcs_pos) ;
00227     cpl_free(lines_pos) ;
00228 
00229     /* Apply the fitting */
00230     if ((poly2d = cpl_polynomial_fit_2d_create(grid, values_to_fit,
00231                     degree, NULL))==NULL) {
00232         cpl_msg_error(cpl_func, "cannot apply the 2d fit") ;
00233         cpl_bivector_delete(grid) ;
00234         cpl_vector_delete(values_to_fit) ;
00235         cpl_apertures_delete(*arcs) ;
00236         return NULL ;
00237     }
00238 
00239     /* Free and return */
00240     cpl_bivector_delete(grid) ;
00241     cpl_vector_delete(values_to_fit) ;
00242     return poly2d ;
00243 }
00244 
00247 /*----------------------------------------------------------------------------*/
00263 /*----------------------------------------------------------------------------*/
00264 static cpl_apertures * irplib_distortion_detect_arcs(
00265         cpl_image   *   im,
00266         cpl_image   **  label_im,
00267         int             arc_sat,
00268         int             max_arc_width,
00269         double          kappa,
00270         int             xmin,
00271         int             ymin,
00272         int             xmax,
00273         int             ymax)
00274 {
00275     cpl_image       *   filt_im ;
00276     cpl_matrix      *   filter ;
00277     cpl_image       *   collapsed ;
00278     cpl_mask        *   bin_im ;
00279     double              threshold, fillval, median_val, sigma ;
00280     int                 min_arclen = 0 ;
00281     cpl_apertures   *   det ;
00282     int                 nobj ;
00283     int                 ngoodpix ;
00284     int                 ny ;
00285 
00286     ny = cpl_image_get_size_y(im) ;
00287     
00288     /* Default values for output parameters */
00289     *label_im = NULL ;
00290 
00291     /* Clear zones to be ignored (to avoid false detections) */
00292     median_val = cpl_image_get_median_dev(im, &sigma) ;
00293     fillval = median_val-sigma/2.0 ;
00294     if (irplib_distortion_fill_badzones(im, xmin, ymin, xmax, ymax,
00295                 fillval) == -1) {
00296         cpl_msg_error(cpl_func, "cannot fill bad zones") ;
00297         return NULL ;
00298     }
00299 
00300     /* Median vertical filter */
00301     filter = cpl_matrix_new(3, 1) ;
00302     cpl_matrix_fill(filter, 1.0) ;
00303     /* filt_im = cpl_image_filter_median(im, filter) ; */
00304     filt_im = cpl_image_duplicate(im) ;
00305     cpl_matrix_delete(filter) ;
00306 
00307     /* Subtract a low-pass */
00308     if (irplib_distortion_sub_hor_lowpass(filt_im, ARC_WINDOWSIZE) == -1) {
00309         cpl_image_delete(filt_im) ;
00310         return NULL ;
00311     }
00312     
00313     /* Get relevant stats for thresholding */
00314     median_val = cpl_image_get_median_dev(filt_im, &sigma) ;
00315 
00316     /* Correct median_val and sigma if necessary */
00317     if (median_val < TRESH_MEDIAN_MIN) median_val = TRESH_MEDIAN_MIN ;
00318     if (sigma > TRESH_SIGMA_MAX) sigma = TRESH_SIGMA_MAX ;
00319 
00320     /* Set the threshold */
00321     threshold = median_val + sigma * kappa ;
00322 
00323     /* Collapse the image */
00324     collapsed = cpl_image_collapse_median_create(filt_im, 0, 0, 0) ;
00325 
00326     /* Threshold to keep only the arcs - use of the collapsed image */
00327     if (irplib_distortion_threshold1d(filt_im, median_val, collapsed, 0.0)==-1) {
00328         cpl_msg_error(cpl_func, "cannot threshold the filtered image") ;
00329         cpl_image_delete(filt_im) ;
00330         cpl_image_delete(collapsed) ;
00331         return NULL ;
00332     }
00333     cpl_image_delete(collapsed) ;
00334 
00335     /* Binarize the image */
00336     bin_im = cpl_mask_threshold_image_create(filt_im, threshold, 
00337             DBL_MAX);
00338     cpl_image_delete(filt_im) ;
00339     if (bin_im == NULL) {
00340         cpl_msg_error(cpl_func, "cannot binarise the image") ;
00341         return NULL ;
00342     }
00343 
00344     /* Test if there are enough good pixels */
00345     ngoodpix = cpl_mask_count(bin_im) ;
00346     if (ngoodpix < ARC_MINGOODPIX) {
00347         cpl_msg_error(cpl_func, "Too few (%d) white pixels", ngoodpix) ;
00348         cpl_mask_delete(bin_im) ;
00349         return NULL ;
00350     }
00351 
00352     /* Apply a morphological closing to clean the isolated pixels */
00353     filter = cpl_matrix_new(3, 3) ;
00354     cpl_matrix_fill(filter, 1.0) ;
00355     cpl_mask_erosion(bin_im, filter) ;
00356     cpl_mask_dilation(bin_im, filter) ;
00357     cpl_matrix_delete(filter) ;
00358 
00359     /* Labelize pixel map to a label image */
00360     *label_im = cpl_image_labelise_mask_create(bin_im, &nobj) ;
00361     cpl_mask_delete(bin_im) ;
00362 
00363     /* Compute statistics on objects */
00364     if ((det = cpl_apertures_new_from_image(im, *label_im)) == NULL) {
00365         cpl_msg_error(cpl_func, "Cannot compute arcs stats") ;
00366         cpl_image_delete(*label_im) ;
00367         *label_im = NULL ;
00368         return NULL ;
00369     }
00370 
00371     /* Set min_arclen */
00372     min_arclen = (int)(ny / ARC_MINARCLENFACT) ;
00373 
00374     /* Purge non-relevant arcs */
00375     if (irplib_distortion_purge_arcs(im, &det, label_im, min_arclen,
00376                 max_arc_width, arc_sat) == -1) {
00377         cpl_msg_error(cpl_func, "Cannot purge the arcs") ;
00378         cpl_image_delete(*label_im) ;
00379         *label_im = NULL ;
00380         cpl_apertures_delete(det) ;
00381         return NULL ;
00382     }
00383     if (cpl_apertures_get_size(det) < ARC_MINNBARCS) {
00384         cpl_msg_error(cpl_func, "Not enough valid arcs (%d < %d)", 
00385                 cpl_apertures_get_size(det), ARC_MINNBARCS) ;
00386         cpl_image_delete(*label_im) ;
00387         *label_im = NULL ;
00388         cpl_apertures_delete(det) ;
00389         return NULL ;
00390     }
00391 
00392     /* Return  */
00393     return det ;
00394 }
00395 
00396 static int irplib_distortion_fill_badzones(
00397         cpl_image   *   im,
00398         int             xmin,
00399         int             ymin,
00400         int             xmax,
00401         int             ymax,
00402         double          fillval)
00403 {
00404     float       *   pfi ;
00405     int             nx, ny ;
00406     int             i, j ;
00407 
00408     /* Check entries */
00409     if (im == NULL) return -1 ;
00410     if (cpl_image_get_type(im) != CPL_TYPE_FLOAT) return -1 ;
00411 
00412     /* Get the data */
00413     pfi = cpl_image_get_data_float(im) ;
00414     nx = cpl_image_get_size_x(im) ;
00415     ny = cpl_image_get_size_y(im) ;
00416 
00417     /* Fill the zone */
00418     for (i=0 ; i<nx ; i++) {
00419         for (j=0 ; j<ny ; j++) {
00420             if ((i<xmin-1) || (i>xmax-1) || (j<ymin-1) || (j>ymax-1)) {
00421                 pfi[i+j*nx] = (float)fillval ;
00422             }
00423         }
00424     }
00425     return 0 ;
00426 }
00427 
00428 static int irplib_distortion_threshold1d(
00429         cpl_image   *   im,
00430         double          threshold,
00431         cpl_image   *   im1d,
00432         double          newval)
00433 {
00434     float       *   pim ;
00435     float       *   pim1d ;
00436     int             nx, ny ;
00437     int             i, j ;
00438 
00439     /* Check entries */
00440     if (im == NULL) return -1 ;
00441     if (im1d == NULL) return -1 ;
00442     if (cpl_image_get_type(im) != CPL_TYPE_FLOAT) return -1 ;
00443     if (cpl_image_get_type(im1d) != CPL_TYPE_FLOAT) return -1 ;
00444 
00445     /* Get access to the im / im1d data */
00446     pim = cpl_image_get_data_float(im) ;
00447     pim1d = cpl_image_get_data_float(im1d) ;
00448     nx = cpl_image_get_size_x(im) ;
00449     ny = cpl_image_get_size_y(im) ;
00450 
00451     /* Apply the thresholding */
00452     for (i=0 ; i<nx ; i++)
00453         if (pim1d[i] < threshold) {
00454             for (j=0 ; j<ny ; j++) pim[i+j*nx] = (float)newval ;
00455         }
00456 
00457     /* Return */
00458     return 0 ;
00459 }
00460 
00461 static int irplib_distortion_sub_hor_lowpass(
00462         cpl_image   *   im, 
00463         int             filt_size)
00464 {
00465     cpl_vector  *   linehi ;
00466     cpl_vector  *   linelo ;
00467     cpl_vector  *   avglinehi ;
00468     cpl_vector  *   avglinelo ;
00469     double      *   pavglinehi ;
00470     float       *   pim ;
00471     int             lopos, hipos, nx, ny ;
00472     int             i, j ;
00473 
00474     /* Test entries */
00475     if (im == NULL) return -1 ;
00476     if (filt_size <= 0) return -1 ;
00477     
00478     /* Initialise */
00479     nx = cpl_image_get_size_x(im) ;
00480     ny = cpl_image_get_size_y(im) ;
00481     lopos = (int)(ny/4) ;
00482     hipos = (int)(3*ny/4) ;
00483 
00484     /* Get the vectors out of the image */
00485     if ((linehi = cpl_vector_new_from_image_row(im, hipos)) == NULL) {
00486         return -1 ;
00487     }
00488     if ((linelo = cpl_vector_new_from_image_row(im, lopos)) == NULL) {
00489         cpl_vector_delete(linehi) ;
00490         return -1 ;
00491     }
00492     
00493     /* Filter the vectors */
00494     if ((avglinehi = cpl_vector_filter_median_create(linehi, 
00495                     filt_size)) == NULL) {
00496         cpl_vector_delete(linehi) ;
00497         cpl_vector_delete(linelo) ;
00498         return -1 ;
00499     }
00500     cpl_vector_delete(linehi) ;
00501     
00502     if ((avglinelo = cpl_vector_filter_median_create(linelo, 
00503                     filt_size)) == NULL) {
00504         cpl_vector_delete(linelo) ;
00505         cpl_vector_delete(avglinehi) ;
00506         return -1 ;
00507     }
00508     cpl_vector_delete(linelo) ;
00509 
00510     /* Average the filtered vectors to get the low freq signal */
00511     cpl_vector_add(avglinehi, avglinelo) ;
00512     cpl_vector_delete(avglinelo) ;
00513     cpl_vector_divide_scalar(avglinehi, 2.0) ;
00514 
00515     /* Subtract the low frequency signal */
00516     pavglinehi = cpl_vector_get_data(avglinehi) ;
00517     pim = cpl_image_get_data_float(im) ;
00518     for (i=0 ; i<nx ; i++) {
00519         for (j=0 ; j<ny ; j++) {
00520             pim[i+j*nx] -= pavglinehi[i] ;
00521         }
00522     }
00523     cpl_vector_delete(avglinehi) ;
00524 
00525     return 0 ;
00526 }
00527 
00528 static int irplib_distortion_purge_arcs(
00529         cpl_image       *   im,
00530         cpl_apertures   **  arcs,
00531         cpl_image       **  lab_im,
00532         int                 min_arclen,
00533         int                 max_arcwidth,
00534         double              arc_sat)
00535 {
00536     int             nb_arcs ;
00537     int         *   selection ;
00538     int             arclen, arcwidth, edge ;
00539     double          mean ;
00540     int         *   plabim ;
00541     cpl_mask    *   bin_im ;
00542     int             nx, ny ;
00543     int             i, j ;
00544 
00545     /* Check entries */
00546     if (arcs == NULL) return -1 ;
00547     if (*arcs == NULL) return -1 ;
00548     if (*lab_im == NULL) return -1 ;
00549 
00550     /* Get number of arcs */
00551     nb_arcs = cpl_apertures_get_size(*arcs) ;
00552     nx = cpl_image_get_size_x(*lab_im) ;
00553     ny = cpl_image_get_size_y(*lab_im) ;
00554 
00555     /* Allocate selection array */
00556     selection = cpl_malloc(nb_arcs * sizeof(int)) ;
00557 
00558     /* Loop on the different arcs candidates */
00559     for (i=0 ; i<nb_arcs ; i++) {
00560         arclen = cpl_apertures_get_top(*arcs, i+1) -
00561             cpl_apertures_get_bottom(*arcs, i+1) + 1 ;
00562         arcwidth = cpl_apertures_get_right(*arcs, i+1) -
00563             cpl_apertures_get_left(*arcs, i+1) + 1 ;
00564         edge = cpl_apertures_get_left_y(*arcs, i+1) ;
00565         mean = cpl_apertures_get_mean(*arcs, i+1) ;
00566 
00567         /* Test if the current object is a valid arc */
00568         if ((arclen>min_arclen) && (arcwidth<max_arcwidth)
00569                 && (edge>0) && (mean < arc_sat)) {
00570             selection[i] = 1 ;
00571         } else {
00572             selection[i] = 0 ;
00573         }
00574     }
00575 
00576     /* Update the labelised image by erasing non valid arcs */
00577     for (i=0 ; i<nb_arcs ; i++) {
00578         if (selection[i] == 0) {
00579             plabim = cpl_image_get_data_int(*lab_im) ;
00580             for (j=0 ; j<nx*ny ; j++) {
00581                 if (plabim[j] == i+1) plabim[j] = 0 ;
00582             }
00583         }
00584     }
00585     cpl_free(selection) ;
00586 
00587     /* Reset the labels to have consecutive ones */
00588     bin_im = cpl_mask_threshold_image_create(*lab_im, 0.5, DBL_MAX) ;
00589     cpl_image_delete(*lab_im) ;
00590     *lab_im = cpl_image_labelise_mask_create(bin_im, NULL) ;
00591     cpl_mask_delete(bin_im) ;
00592 
00593     /* Purge the bad arcs */
00594     cpl_apertures_delete(*arcs) ;
00595     *arcs = cpl_apertures_new_from_image(im, *lab_im) ;
00596 
00597     /* Check if there are some valid arcs */
00598     if (cpl_apertures_get_size(*arcs) <= 0) {
00599         cpl_msg_error(cpl_func, "No valid arc found") ;
00600         return -1 ;
00601     }
00602     /* Return  */
00603     return 0 ;
00604 }
00605 
00606 static cpl_bivector ** irplib_distortion_get_arc_positions(
00607         cpl_image       *   in,
00608         cpl_image       *   label_im,
00609         cpl_apertures   *   det,
00610         int                 nb_samples,
00611         double          **  lines_pos)
00612 {
00613     int                 n_arcs ;
00614     cpl_image       *   filt_img ;
00615     cpl_matrix      *   kernel ;
00616     cpl_bivector    **  pos ;
00617     double          *   biv_x ;
00618     double          *   biv_y ;
00619     double              x_finepos ;
00620     int             *   plabel_im ;
00621     int             *   arcs_samples_y ;
00622     int             *   computed ;
00623     double              arclen ;
00624     int                 use_this_arc ;
00625     int                 obj ;
00626     int                 nx, ny ;
00627     int                 i, j, k ;
00628 
00629     /* Check entries */
00630 
00631     /* Initialise */
00632     n_arcs = cpl_apertures_get_size(det) ;
00633     nx = cpl_image_get_size_x(label_im) ;
00634     ny = cpl_image_get_size_y(label_im) ;
00635 
00636     /* Allocate positions (pos. of n_arcs*nb_samples pts on the arcs) */
00637     pos = cpl_calloc(n_arcs, sizeof(cpl_bivector*)) ;
00638     for (i=0 ; i<n_arcs ; i++) pos[i] = cpl_bivector_new(nb_samples) ;
00639 
00640     /* Median filter on input image */
00641     kernel = cpl_matrix_new(3, 3) ;
00642     cpl_matrix_fill(kernel, 1.0) ;
00643     filt_img = cpl_image_filter_median(in, kernel) ;
00644     cpl_matrix_delete(kernel) ;
00645 
00646     /* Measured Arcs coordinates along curvature */
00647     arcs_samples_y = cpl_malloc(n_arcs * nb_samples * sizeof(int)) ;
00648     computed = cpl_calloc(n_arcs*nb_samples, sizeof(int)) ;
00649 
00650     /* Find out the Y coordinates along the arcs  */
00651     for (j=0 ; j<n_arcs ; j++) {
00652         arclen = cpl_apertures_get_top(det,j+1) - 
00653             cpl_apertures_get_bottom(det,j+1) + 1 ;
00654         for (i=0 ; i<nb_samples ; i++) {
00655             arcs_samples_y[i+j*nb_samples] = 
00656                 (int)(cpl_apertures_get_bottom(det, j+1) + 
00657                       (arclen * (i + 0.5)) / (double)nb_samples) ;
00658         }
00659     }
00660 
00661     /* Find out the X coord. at nb_samples Y positions on all arcs */
00662     plabel_im = cpl_image_get_data_int(label_im) ;
00663     for (i=0 ; i<nx ; i++) {
00664         for (j=0 ; j<ny ; j++) {
00665             /* use_this_arc is set to 1 if we are on the arc at a y */
00666             /* coordinate where the x coord should be found */
00667             obj = plabel_im[i + j * nx] ;
00668             /* Handle background */
00669             if (obj==0) continue ;
00670             /* Decrease by one to index the array from 0 */
00671             else obj-- ;
00672 
00673             use_this_arc = 0 ;
00674             for (k=0 ; k<nb_samples ; k++) {
00675                 if (arcs_samples_y[k+obj*nb_samples] == j) {
00676                     use_this_arc = 1 ;
00677                     break ;
00678                 }
00679             }
00680             if ((use_this_arc)  && (computed[k+obj*nb_samples] == 0)) {
00681                 /* Find x coordinate of obj at the Y coord. */
00682                 if ((x_finepos = irplib_distortion_fine_pos(filt_img,
00683                                 label_im, i, j)) < 0.0) {
00684                     cpl_msg_error(cpl_func, "cannot find fine arc position") ;
00685                     cpl_image_delete(filt_img) ;
00686                     cpl_free(arcs_samples_y);
00687                     cpl_free(computed) ;
00688                     for (i=0 ; i<n_arcs ; i++) cpl_bivector_delete(pos[i]); 
00689                     cpl_free(pos) ;
00690                     return NULL ;
00691                 } else {
00692                     biv_x = cpl_bivector_get_x_data(pos[obj]) ;
00693                     biv_y = cpl_bivector_get_y_data(pos[obj]) ;
00694                     biv_x[k] = x_finepos ;
00695                     biv_y[k] = j ;
00696                     (*lines_pos)[obj] = cpl_apertures_get_centroid_x(det,obj+1);
00697                     computed[k+obj*nb_samples] = 1 ;
00698                 }
00699             }
00700         }
00701     }
00702 
00703     /* Free and return */
00704     cpl_image_delete(filt_img) ;
00705     cpl_free(arcs_samples_y) ;
00706     cpl_free(computed) ;
00707     return pos ;
00708 }
00709 
00710 static double irplib_distortion_fine_pos(
00711         cpl_image   *   im,
00712         cpl_image   *   label_im,
00713         int             x,
00714         int             y)
00715 {
00716     float   *   pim ;
00717     int     *   plabel_im ;
00718     int         objnum ;
00719     int         curr_obj ;
00720     int         start_pos ;
00721     double      grav_c ;
00722     double      sum ;
00723     double      max ;
00724     double      val ;
00725     int         maxpos ;
00726     int         im_extrem ;
00727     double      arc_pos ;
00728     int         nx ;
00729 
00730     /* Initialize */
00731     nx = cpl_image_get_size_x(im) ;
00732     grav_c = 0.0 ;
00733     sum    = 0.0 ;
00734     start_pos = x ;
00735     maxpos = start_pos ;
00736     pim = cpl_image_get_data_float(im) ;
00737     max    = (double)pim[start_pos + y * nx] ;
00738     plabel_im = cpl_image_get_data_int(label_im) ;
00739     objnum = plabel_im[start_pos + y * nx] ;
00740     im_extrem = nx ;
00741 
00742     /* While we stay in the same object... */
00743     do {
00744         val = (double)pim[start_pos + y * nx] ;
00745         if (start_pos == 0) grav_c = 0.0 ;
00746         else grav_c += start_pos * val ;
00747         sum += val ;
00748         if (val > max) {
00749             max = val ;
00750             maxpos = start_pos ;
00751         }
00752 
00753         /* Next point */
00754         start_pos++ ;
00755 
00756         curr_obj = plabel_im[start_pos + y * nx] ;
00757     } while (curr_obj == objnum) ;
00758 
00759     /* Returned position is the gravity center or the max in bad cases */
00760     if ((fabs(grav_c) < 1.0e-40) || (fabs(sum) < 1.0e-40)) {
00761         arc_pos = maxpos ;
00762     } else {
00763         arc_pos = grav_c / sum ;
00764         if (fabs(arc_pos) >= start_pos) arc_pos = maxpos ;
00765     }
00766 
00767     /* Return */
00768     return arc_pos ;
00769 }
00770 
00771 /*----------------------------------------------------------------------------*/
00777 /*----------------------------------------------------------------------------*/
00778 #define IS_NB_TESTPOINTS    8
00779 #define IS_MIN_SLOPE        0.01
00780 #define IS_MAX_SLOPE_DIF    0.075
00781 #define IS_MAX_FIT_EDGE_DIF 0.05
00782 #define IS_MIN_RAMP         10.0
00783 #define IS_MAX_MNERR        13.0
00784 #define IS_MAX_MNERR_DIF    8.0
00785 #define IS_MAX_INTER_DIF    20.0
00786 #define IS_SKIPZONE         2.5
00787 #define SQR(x) ((x)*(x))
00788 static cpl_image * irplib_distortion_remove_ramp(const cpl_image * in) 
00789 {
00790     int                 ramp_present ;
00791     int                 nx, ny ;
00792     int                 y, yhi, ylo;
00793     cpl_vector      *   tmp_vector ;
00794     cpl_bivector    *   testpointlo ;
00795     double          *   testpointlo_x ;
00796     double          *   testpointlo_y ;
00797     cpl_bivector    *   testpointhi ;
00798     double          *   testpointhi_x ;
00799     double          *   testpointhi_y ;
00800     int                 spacing;
00801     double              rampdif, fitslope;
00802     double          *   pol_coefhi,
00803                     *   pol_coeflo ;
00804     cpl_vector      *   median ;
00805     double          *   median_data ;
00806     double              medianerrlo, medianerrhi;
00807     double              slope ;
00808     cpl_image       *   out ;
00809     float           *   pout ;
00810     float               val ;
00811     int                 i, j ;
00812 
00813     /* Initialise */
00814     nx = cpl_image_get_size_x(in) ;
00815     ny = cpl_image_get_size_y(in) ;
00816                     
00817     /* Check entries */
00818     if (in==NULL) return NULL ;
00819 
00820     if (ny<IS_SKIPZONE*IS_NB_TESTPOINTS){
00821         cpl_msg_error(cpl_func, "image has %d lines, min=%d ",
00822                 ny, (int)(IS_SKIPZONE*IS_NB_TESTPOINTS*2));
00823         return NULL ;
00824     }
00825     
00826     slope=0.0 ;
00827     spacing= ny / (IS_SKIPZONE*IS_NB_TESTPOINTS) ;
00828     yhi = (int)(ny/2) ;
00829     ylo = yhi - 1 ;
00830     /* Fill the vectors */
00831     testpointhi = cpl_bivector_new(IS_NB_TESTPOINTS) ;
00832     testpointhi_x = cpl_bivector_get_x_data(testpointhi) ;
00833     testpointhi_y = cpl_bivector_get_y_data(testpointhi) ;
00834     testpointlo = cpl_bivector_new(IS_NB_TESTPOINTS) ;
00835     testpointlo_x = cpl_bivector_get_x_data(testpointlo) ;
00836     testpointlo_y = cpl_bivector_get_y_data(testpointlo) ;
00837     for (i=0 ; i<IS_NB_TESTPOINTS ; i++) {
00838         y = yhi + i * spacing;
00839         tmp_vector = cpl_vector_new_from_image_row(in, y+1) ;
00840         testpointhi_x[i] = y - ny / 2;
00841         testpointhi_y[i] = cpl_vector_get_median_const(tmp_vector) ;
00842         cpl_vector_delete(tmp_vector) ;
00843         y = ylo - i * spacing;
00844         tmp_vector = cpl_vector_new_from_image_row(in, y+1) ;
00845         testpointlo_x[IS_NB_TESTPOINTS-i-1] = y ;
00846         testpointlo_y[IS_NB_TESTPOINTS-i-1]=cpl_vector_get_median_const(tmp_vector) ;
00847         cpl_vector_delete(tmp_vector) ;
00848     }
00849 
00850     /* Apply the fit */
00851     pol_coefhi = irplib_flat_fit_slope_robust(testpointhi_x,
00852             testpointhi_y, IS_NB_TESTPOINTS) ; 
00853     pol_coeflo = irplib_flat_fit_slope_robust(testpointlo_x, 
00854             testpointlo_y, IS_NB_TESTPOINTS) ;
00855 
00856     /* Compute the errors */
00857     median = cpl_vector_new(IS_NB_TESTPOINTS) ;
00858     median_data = cpl_vector_get_data(median) ;
00859     for (i=0 ; i<IS_NB_TESTPOINTS ; i++) {
00860         median_data[i]=SQR(testpointhi_y[i]
00861                 - pol_coefhi[0] - pol_coefhi[1] * testpointhi_x[i]);
00862     }
00863     medianerrhi = cpl_vector_get_median_const(median) ;
00864     for (i=0; i<IS_NB_TESTPOINTS; i++) {
00865         median_data[i]=SQR(testpointlo_y[i]
00866                 - pol_coeflo[0] - pol_coeflo[1] * testpointlo_x[i]);
00867     }
00868     medianerrlo = cpl_vector_get_median_const(median) ;
00869     cpl_vector_delete(median) ;
00870     rampdif = testpointlo_y[IS_NB_TESTPOINTS-1] - testpointhi_y[0];
00871     slope = rampdif / (ny/2.0) ;
00872     fitslope = (pol_coefhi[1] + pol_coeflo[1]) / 2.0 ;
00873 
00874     cpl_bivector_delete(testpointlo);
00875     cpl_bivector_delete(testpointhi);
00876 
00877     /* Decide if there is a ramp or not  */
00878     if (fabs(rampdif)<IS_MIN_RAMP ||
00879             fabs(pol_coefhi[1]) < IS_MIN_SLOPE ||
00880             fabs(pol_coeflo[1]) < IS_MIN_SLOPE ||
00881             pol_coefhi[1]/pol_coeflo[1]<0.5 ||
00882             pol_coefhi[1]/pol_coeflo[1]>2.0 ||
00883             fabs(pol_coefhi[1]-pol_coeflo[1])>IS_MAX_SLOPE_DIF ||
00884             fabs(pol_coefhi[0]-pol_coeflo[0]) > IS_MAX_INTER_DIF ||
00885             medianerrlo> IS_MAX_MNERR ||
00886             medianerrhi> IS_MAX_MNERR ||
00887             fabs(medianerrlo-medianerrhi) >IS_MAX_MNERR_DIF ||
00888             fabs(slope-fitslope) > IS_MAX_FIT_EDGE_DIF ||
00889             slope/fitslope<0.5 ||
00890             slope/fitslope>2.0) ramp_present = 0 ;
00891     else ramp_present = 1 ;
00892 
00893     cpl_free(pol_coeflo) ;
00894     cpl_free(pol_coefhi) ;
00895 
00896     /* Correct the ramp if it is there */
00897     out = cpl_image_duplicate(in) ;
00898     pout = cpl_image_get_data_float(out) ;
00899     if (ramp_present == 1) {
00900         for (j=0 ; j<ny/2 ; j++) {
00901             val = slope * (j-ny/2) ;
00902             for (i=0 ; i<nx ; i++)
00903                 pout[i+j*nx] -= val ;
00904         }
00905         for (j=ny/2 ; j<ny ; j++) {
00906             val = slope * (j-ny) ;
00907             for (i=0 ; i<nx ; i++)
00908                 pout[i+j*nx] -= val ;
00909         }
00910 
00911     }
00912 
00913     return out ;
00914 }
00915 

Generated on Mon Apr 21 10:56:54 2008 for UVES Pipeline Reference Manual by  doxygen 1.5.1