irplib_distortion.c

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

Generated on Tue Jun 19 14:39:14 2007 for UVES Pipeline Reference Manual by  doxygen 1.4.6