sinfo_function_1d.c

00001 /*
00002  * This file is part of the ESO SINFONI Pipeline
00003  * Copyright (C) 2004,2005 European Southern Observatory
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
00018  */
00019 /*----------------------------------------------------------------------------
00020    
00021    File name     :    function_1d.c
00022    Author         :    Nicolas Devillard
00023    Created on    :    Tue, Sept 23 1997    
00024    Description    :    1d signal processing related routines    
00025 
00026  ---------------------------------------------------------------------------*/
00027 /*
00028  $Id: sinfo_function_1d.c,v 1.7 2012/03/02 08:42:20 amodigli Exp $
00029  $Author: amodigli $
00030  $Date: 2012/03/02 08:42:20 $
00031  $Revision: 1.7 $
00032  */
00033 
00034 #ifdef HAVE_CONFIG_H
00035 #  include <config.h>
00036 #endif
00037 /*----------------------------------------------------------------------------
00038                                    Includes
00039  ---------------------------------------------------------------------------*/
00040 #include <math.h>
00041 #include <string.h>
00042 #include "sinfo_function_1d.h"
00043 #include "sinfo_fit_curve.h"
00044 #include "sinfo_median.h"
00045 
00054 /*----------------------------------------------------------------------------
00055                                    Defines
00056  ---------------------------------------------------------------------------*/
00057 /*
00058  * This parameter sets up the half size of the domain around which a
00059  * centroid position will be computed.
00060  */
00061 #define HALF_CENTROID_DOMAIN    5
00062 /*----------------------------------------------------------------------------
00063                         Private function prototypes
00064  ---------------------------------------------------------------------------*/
00065 static double * function1d_generate_smooth_kernel(int filt_type, int hw);
00066 
00067 static int
00068 function1d_search_value(
00069     pixelvalue  *   x,
00070     int             len,
00071     pixelvalue      key,
00072     int         *   foundPtr
00073 ) ;
00074 
00075 /*----------------------------------------------------------------------------
00076                               Function codes
00077  ---------------------------------------------------------------------------*/
00094 pixelvalue *
00095 sinfo_function1d_new(int nsamples)
00096 {
00097     if (nsamples<1) return NULL ;
00098     return cpl_calloc(nsamples, sizeof(pixelvalue)) ;
00099 }
00100 
00101 
00111 void 
00112 sinfo_function1d_del(pixelvalue * s)
00113 {
00114     if (s)
00115         cpl_free(s);
00116     return ;
00117 }
00118 
00135 pixelvalue * 
00136 sinfo_function1d_dup(pixelvalue * arr, int ns)
00137 {
00138     pixelvalue    *    n_arr ;
00139 
00140     n_arr = sinfo_function1d_new(ns);
00141     memcpy(n_arr, arr, ns * sizeof(pixelvalue));
00142     return n_arr ;
00143 }
00144 
00160 double
00161 sinfo_function1d_find_centroid(
00162     pixelvalue    *    line,    /*    the input line    */
00163     int    npix    /*     number of pixels in this line    */
00164 )
00165 {
00166     pixelvalue    max ;
00167     double        centroid ;
00168     double        weights ;
00169     int            i, maxpos ;
00170 
00171     /*
00172      * Search for the maximum pixel value on the line
00173      */
00174 
00175     max = line[0] ;
00176     maxpos = 0 ;
00177     for (i=1 ; i<npix ; i++) {
00178         if (line[i]>max) {
00179             max = line[i] ;
00180             maxpos = i ;
00181         }
00182     }
00183 
00184     /*
00185      * The centroid position is the weighted average over the maximum 
00186      * pixel neighborhood.
00187      */
00188 
00189     centroid = 0.0 ;
00190     weights  = 0.0 ;
00191     for (i=maxpos-HALF_CENTROID_DOMAIN; 
00192             i<=maxpos+HALF_CENTROID_DOMAIN; i++) {
00193         centroid += (double)line[i] * (double)i ;
00194         weights  += (double)line[i] ;
00195     }
00196 
00197     centroid /= weights ;
00198     return centroid ;    
00199 }
00200 
00223 double
00224 sinfo_function1d_find_locmax(
00225     pixelvalue    *    line,
00226     int                npix,
00227     int                where,
00228     int                hs
00229 )
00230 {
00231     pixelvalue    max ;
00232     double        centroid ;
00233     double        weights ;
00234     int            i, maxpos ;
00235 
00236 
00237     if ((where<hs) || (where>(npix-hs-1))) {
00238         return (double)-1.0 ;
00239     }
00240     
00241     /*
00242      * Search for the closest local maximal around the requested range.
00243      */
00244     max = line[where] ;
00245     maxpos = where ;
00246     for (i=-hs ; i<=hs ; i++) {
00247         if (line[where+i]>max) {
00248             max = line[where+i] ;
00249             maxpos = where+i ;
00250         }
00251     }
00252 
00253     /*
00254      * The centroid position is the weighted average over the maximum 
00255      * pixel neighborhood.
00256      */
00257 
00258     centroid = 0.0 ;
00259     weights  = 0.0 ;
00260     for (i=maxpos-hs; i<=maxpos+hs; i++) {
00261         centroid += (double)line[i] * (double)i ;
00262         weights  += (double)line[i] ;
00263     }
00264     if (fabs(weights)>1e-6) {
00265         centroid /= weights ;
00266     } else {
00267         centroid = -1.0 ;
00268     }
00269     return centroid ;    
00270 }
00271 
00296 pixelvalue *
00297 sinfo_function1d_filter_lowpass(
00298     pixelvalue    *    input_sig,
00299     int                samples,
00300     int                filter_type,
00301     int                hw
00302 )
00303 {
00304     pixelvalue    *    out_sig ;
00305     int                i, j ;
00306     double            replace ;
00307     double        *    kernel ;
00308 
00309     /* allocate output signal */
00310     out_sig = sinfo_function1d_new(samples);
00311 
00312     /* generate low-pass filter kernel */
00313     kernel = function1d_generate_smooth_kernel(filter_type, hw) ;
00314 
00315     /* compute sinfo_edge effects for the first hw elements */
00316     for (i=0 ; i<hw ; i++) {
00317         replace = 0.0 ;
00318         for (j=-hw ; j<=hw ; j++) {
00319             if (i+j<0) {
00320                 replace += kernel[hw+j] * (double)input_sig[0] ;
00321             } else {
00322                 replace += kernel[hw+j] * (double)input_sig[i+j] ;
00323             }
00324         }
00325         out_sig[i] = (pixelvalue)replace ;
00326     }
00327 
00328     /* compute sinfo_edge effects for the last hw elements */
00329     for (i=samples-hw ; i<samples ; i++) {
00330         replace = 0.0 ;
00331         for (j=-hw ; j<=hw ; j++) {
00332             if (i+j>samples-1) {
00333                 replace += kernel[hw+j] * (double)input_sig[samples-1] ;
00334             } else {
00335                 replace += kernel[hw+j] * (double)input_sig[i+j] ;
00336             }
00337         }
00338         out_sig[i] = (pixelvalue)replace ;
00339     }
00340 
00341     /* compute all other elements */
00342     for (i=hw ; i<samples-hw ; i++) {
00343         replace = 0.0 ;
00344         for (j=-hw ; j<=hw ; j++) {
00345             replace += kernel[hw+j] * (double)input_sig[i+j] ;
00346         }
00347         out_sig[i] = (pixelvalue)replace ;
00348     }
00349 
00350     cpl_free(kernel) ;
00351     return out_sig ;
00352 
00353 }
00354 
00371 static double * 
00372 function1d_generate_smooth_kernel(int filt_type, int hw)
00373 {
00374     double  *   kernel ;
00375     double      norm ;
00376     int         i ;
00377 
00378     kernel = (double*)cpl_calloc(2*hw+1, sizeof(double)) ;
00379 
00380     switch(filt_type) {
00381 
00382         case LOW_PASS_LINEAR:
00383         for (i=-hw ; i<=hw ; i++) {
00384             /* flat kernel */
00385             kernel[hw+i] = 1.0 / (double)(2*hw+1) ;
00386         }
00387         break ;
00388 
00389         case LOW_PASS_GAUSSIAN:
00390         norm = 0.00 ;
00391         for (i=-hw ; i<=hw ; i++) {
00392             /* sinfo_gaussian kernel */
00393             kernel[hw+i] = exp(-(double)(i*i)) ;
00394             norm += kernel[hw+i] ;
00395         }
00396         for (i=0 ; i<2*hw+1 ; i++) {
00397             kernel[i] /= norm ;
00398         }
00399         break ;
00400 
00401         default:
00402         sinfo_msg_error("unrecognized low pass filter: "
00403                                 "cannot generate kernel") ;
00404         return (double*)NULL ;
00405         break ;
00406     }
00407 
00408     return kernel ;
00409 }
00410 
00429 pixelvalue * 
00430 sinfo_function1d_median_smooth(
00431     pixelvalue * list,
00432     int          np,
00433     int             hw)
00434 {
00435     int             i,j ;
00436     pixelvalue    *    row ;
00437     pixelvalue    *     smoothed ;
00438 
00439     /* simply copy first 3 and last 3 items */
00440     smoothed = sinfo_function1d_new(np);
00441     for (i=0 ; i<hw ; i++) {
00442         smoothed[i] = list[i] ;
00443     }
00444     for (i=np-hw ; i<np ; i++) {
00445         smoothed[i] = list[i] ;
00446     }
00447 
00448     /* sinfo_median filter on all central items */
00449     row = sinfo_function1d_new(2*hw+1);
00450     for (i=hw ; i<np-hw ; i++) {
00451         for (j=-hw ; j<=hw ; j++) {
00452             row[j+hw] = list[i+j] ;
00453         }
00454         smoothed[i] = sinfo_median_pixelvalue(row, 2*hw+1) ; 
00455     }
00456     sinfo_function1d_del(row) ;
00457     return smoothed ;
00458 }
00459 
00476 #define LOWFREQ_PASSES        5
00477 
00478 pixelvalue * 
00479 sinfo_function1d_remove_lowfreq(
00480     pixelvalue * pixel_signal,
00481     int             ns)
00482 {
00483     pixelvalue    *    sig_in ;
00484     pixelvalue    *    smooth ;
00485     int                i ;
00486     
00487     
00488     /* Apply severe low-pass filter several times */
00489     sig_in = sinfo_function1d_dup(pixel_signal, ns);
00490     for (i=0 ; i<LOWFREQ_PASSES ; i++) {
00491         smooth = sinfo_function1d_filter_lowpass( sig_in, ns, 
00492                          LOW_PASS_LINEAR, 5);
00493         cpl_free(sig_in);
00494         sig_in = smooth ;
00495     }
00496 
00497     /* Subtract smoothed signal from input signal */
00498     for (i=0 ; i<ns ; i++) {
00499         smooth[i] = pixel_signal[i] - smooth[i];
00500     }
00501     return smooth ;
00502 }
00503 
00504 #undef LOWFREQ_PASSES
00505 
00527 #define SAMPLE_BORDER    10
00528 
00529 pixelvalue * 
00530 sinfo_function1d_remove_thermalbg(
00531     pixelvalue * pixel_signal,
00532     int             ns)
00533 {
00534     pixelvalue    *    smooth ;
00535     int                i ;
00536     
00537     int                nmin ;
00538     pixelvalue        lef[2], rig[2];
00539 
00540     pixelvalue    *    x,
00541                 *    y,
00542                 *    spl_x,
00543                 *    spl_y ;
00544     double            med_y ;
00545     double            avg2med ;
00546     double            dist ;
00547 
00548     
00549     /* Detect all local minima */
00550     nmin = 0 ;
00551     x = sinfo_function1d_new(ns);
00552     y = sinfo_function1d_new(ns);
00553 
00554     for (i=SAMPLE_BORDER ; i<(ns-SAMPLE_BORDER) ; i++) {
00555         lef[0] = pixel_signal[i-2];
00556         lef[1] = pixel_signal[i-1];
00557         rig[0] = pixel_signal[i+1];
00558         rig[1] = pixel_signal[i+2];
00559 
00560         if ( (pixel_signal[i] < lef[0]) &&
00561              (pixel_signal[i] < lef[1]) &&
00562              (pixel_signal[i] < rig[0]) &&
00563              (pixel_signal[i] < rig[1])) {
00564             x[nmin] = (pixelvalue)i ;
00565             y[nmin] = pixel_signal[i];
00566             nmin ++ ;
00567         }
00568     }
00569 
00570 
00571     /* Interpolate linearly missing values */
00572     spl_x = sinfo_function1d_new(ns);
00573     spl_y = sinfo_function1d_new(ns);
00574     for (i=0 ; i<ns ; i++) {
00575         spl_x[i] = (pixelvalue)i ;
00576     }
00577     sinfo_function1d_interpolate_linear(x, y, nmin, spl_x, spl_y, ns);
00578 
00579     sinfo_function1d_del(x) ;
00580     sinfo_function1d_del(y) ;
00581     sinfo_function1d_del(spl_x);
00582 
00583     /* Compute sinfo_median and average distance to the sinfo_median */
00584     med_y = (double)sinfo_median_pixelvalue(pixel_signal, ns);
00585     avg2med = 0.0 ;
00586     for (i=0 ; i<ns ; i++) {
00587         avg2med += fabs((double)pixel_signal[i] - med_y) ;
00588     }
00589     avg2med /= (double)ns ;
00590 
00591     /* Reset all pixels out of sinfo_median + 2 * avg2med to zero. */
00592     for (i=0 ; i<ns ; i++) {
00593         dist = fabs((double)pixel_signal[i] - med_y);
00594         if (dist > (2.0*avg2med)) {
00595             spl_y[i] = (pixelvalue)0 ;
00596         }
00597     }
00598 
00599 
00600     smooth = sinfo_function1d_new(ns);
00601     for (i=0 ; i<ns ; i++) {
00602         if (spl_y[i]>1e-4) {
00603             smooth[i] = pixel_signal[i] - spl_y[i];
00604         } else {
00605             smooth[i] = 0.0 ;
00606         }
00607     }
00608     sinfo_function1d_del(spl_y);
00609     return smooth ;
00610 }
00611 
00612 #undef LOWFREQ_PASSES
00613 
00635 void 
00636 sinfo_function1d_interpolate_linear(
00637     pixelvalue    *    x,
00638     pixelvalue    *    y,
00639     int                len,
00640     pixelvalue    *    spl_x,
00641     pixelvalue    *    spl_y,
00642     int                spl_len
00643 )
00644 {
00645     double        a, b ;
00646     int            i, j ;
00647     int            found ;
00648 
00649     for (i=0 ; i<spl_len ; i++) {
00650         /* Find (x1,y1) on the left of the current point */
00651         found = 0 ;
00652         for (j=0 ; j<(len-1) ; j++) {
00653             if ((spl_x[i]>=x[j]) && (spl_x[i]<=x[j+1])) {
00654                 found++ ;
00655                 break ;
00656             }
00657         }
00658         if (!found) {
00659             spl_y[i] = 0.0;
00660         } else {
00661             a = ((double)y[j+1]-(double)y[j]) /
00662                 ((double)x[j+1]-(double)x[j]);
00663             b = (double)y[j] - a * (double)x[j] ;
00664             spl_y[i] = (pixelvalue)(a * (double)spl_x[i] + b) ;
00665         }
00666     }
00667     return ;
00668 }
00669 
00686 static int
00687 function1d_search_value(
00688     pixelvalue    *    x,
00689     int             len,
00690     pixelvalue         key,
00691     int         *    foundPtr
00692 )
00693 {
00694     int    high,
00695         low,
00696         middle;
00697 
00698     low  = 0;
00699     high = len - 1;
00700 
00701     while (high >= low) {
00702         middle = (high + low) / 2;
00703         if (key > x[middle]) {
00704             low = middle + 1;
00705         } else if (key < x[middle]) {
00706             high = middle - 1;
00707         } else {
00708             *foundPtr = 1;
00709             return (middle);
00710         }
00711     }
00712     *foundPtr = 0;
00713     return (low);
00714 }
00715 
00741 int
00742 sinfo_function1d_natural_spline(
00743     pixelvalue    *     x,
00744     pixelvalue    *     y,
00745     int             len,
00746     pixelvalue    *     splX,
00747     pixelvalue    *     splY,
00748     int             splLen
00749 )
00750 {
00751     int             end;
00752     int             loc,
00753                     found;
00754     register int     i,
00755                     j,
00756                     n;
00757     double         *    h; /* sinfo_vector of deltas in x */
00758     double         *    alpha;
00759     double         *    l,
00760                 *    mu,
00761                 *    z,
00762                 *    a,
00763                 *    b,
00764                 *    c,
00765                 *    d,
00766                     v;
00767 
00768     end = len - 1;
00769 
00770     a = cpl_malloc(sizeof(double) * splLen * 9) ;
00771     b = a + len;
00772     c = b + len;
00773     d = c + len;
00774     h = d + len;
00775     l = h + len;
00776     z = l + len;
00777     mu = z + len;
00778     alpha = mu + len;
00779 
00780     for (i = 0; i < len; i++) {
00781         a[i] = (double)y[i];
00782     }
00783 
00784     /* Calculate sinfo_vector of differences */
00785     for (i = 0; i < end; i++) {
00786         h[i] = (double)x[i + 1] - (double)x[i];
00787         if (h[i] < 0.0) {
00788             cpl_free(a) ;
00789             return -1;
00790         }
00791     }
00792 
00793     /* Calculate alpha sinfo_vector */
00794     for (n = 0, i = 1; i < end; i++, n++) {
00795         /* n = i - 1 */
00796         alpha[i] = 3.0 * ((a[i+1] / h[i]) - (a[i] / h[n]) - (a[i] / h[i]) +
00797                   (a[n] / h[n]));
00798     }
00799 
00800     /* Vectors to solve the tridiagonal sinfo_matrix */
00801     l[0] = l[end] = 1.0;
00802     mu[0] = mu[end] = 0.0;
00803     z[0] = z[end] = 0.0;
00804     c[0] = c[end] = 0.0;
00805 
00806     /* Calculate the intermediate results */
00807     for (n = 0, i = 1; i < end; i++, n++) {
00808         /* n = i-1 */
00809         l[i] = 2 * (h[i] + h[n]) - h[n] * mu[n];
00810         mu[i] = h[i] / l[i];
00811         z[i] = (alpha[i] - h[n] * z[n]) / l[i];
00812     }
00813     for (n = end, j = end - 1; j >= 0; j--, n--) {
00814         /* n = j + 1 */
00815         c[j] = z[j] - mu[j] * c[n];
00816         b[j] = (a[n] - a[j]) / h[j] - h[j] * (c[n] + 2.0 * c[j]) / 3.0;
00817         d[j] = (c[n] - c[j]) / (3.0 * h[j]);
00818     }
00819 
00820     /* Now calculate the new values */
00821     for (j = 0; j < splLen; j++) {
00822          v = (double)splX[j];
00823      splY[j] = (pixelvalue)0;
00824 
00825      /* Is it outside the interval? */
00826      if ((v < (double)x[0]) || (v > (double)x[end])) {
00827         continue;
00828      }
00829      /* Search for the interval containing v in the x sinfo_vector */
00830      loc = function1d_search_value(x, len, (pixelvalue)v, &found);
00831      if (found) {
00832         splY[j] = y[loc];
00833      } else {
00834         loc--;
00835         v -= (double)x[loc];
00836         splY[j] = (pixelvalue)(    a[loc] +
00837                         v * (b[loc] +
00838                    v * (c[loc] +
00839                     v * d[loc])));
00840         }
00841     }
00842     cpl_free(a) ;
00843     return 0;
00844 }
00845 
00864 pixelvalue
00865 sinfo_function1d_average_reject(
00866     pixelvalue    *    line,
00867     int                npix,
00868     int                pix_low,
00869     int                pix_high)
00870 {
00871     pixelvalue    *    sorted ;
00872     int                i ;
00873     double            avg ;
00874 
00875     /* Sanity tests */
00876     if ((line==NULL) || (npix<1)) return (pixelvalue)0 ;
00877     if ((pix_low+pix_high)>=npix) return (pixelvalue)0 ;
00878 
00879     /* Copy input line and sort it */
00880     sorted = cpl_malloc(npix * sizeof(pixelvalue)) ;
00881     memcpy(sorted, line, npix * sizeof(pixelvalue)) ;
00882     sinfo_pixel_qsort(sorted, npix);
00883 
00884     /* Find out average of remaining values */
00885     avg = 0.00 ;
00886     for (i=pix_low+1 ; i<(npix-pix_high) ; i++) {
00887         avg += (double)sorted[i] ;
00888     }
00889     cpl_free(sorted);
00890     avg /= (double)(npix - pix_high - pix_low) ;
00891 
00892     return (pixelvalue)avg ;
00893 }
00894 
00920 #define STEP_MIN    (-half_search)
00921 #define STEP_MAX    (half_search)
00922 
00923 double 
00924 sinfo_function1d_xcorrelate(
00925     pixelvalue *    line_i,
00926     int             width_i,
00927     pixelvalue *    line_t,
00928     int             width_t,
00929     int                half_search,
00930     double     *    delta
00931 )
00932 {
00933     double * xcorr ;
00934     double   xcorr_max ;
00935     double   mean_i, mean_t ;
00936     double   rms_i, rms_t ;
00937     double   sum, sqsum ;
00938     double   norm ;
00939     int      maxpos ;
00940     int      nsteps ;
00941     int      i ;
00942     int      step ;
00943     int      nval ;
00944 
00945 
00946     /* Compute normalization factors */
00947     sum = sqsum = 0.00 ;
00948     for (i=0 ; i<width_i ; i++) {
00949         sum += (double)line_i[i] ;
00950         sqsum += (double)line_i[i] * (double)line_i[i];
00951     }
00952     mean_i = sum / (double)width_i ;
00953     sqsum /= (double)width_i ;
00954     rms_i = sqsum - mean_i*mean_i ;
00955 
00956     sum = sqsum = 0.00 ;
00957     for (i=0 ; i<width_t ; i++) {
00958         sum += (double)line_t[i] ;
00959         sqsum += (double)line_t[i] * (double)line_t[i];
00960     }
00961     mean_t = sum / (double)width_t ;
00962     sqsum /= (double)width_t ;
00963     rms_t = sqsum - mean_t*mean_t ;
00964 
00965     norm = 1.00 / sqrt(rms_i * rms_t);
00966 
00967     nsteps = (STEP_MAX - STEP_MIN) +1 ;
00968     xcorr = cpl_malloc(nsteps * sizeof(double));
00969     for (step=STEP_MIN ; step<=STEP_MAX ; step++) {
00970         xcorr[step-STEP_MIN] = 0.00 ;
00971         nval = 0 ;
00972         for (i=0 ; i<width_t ; i++) {
00973             if ((i+step > 0) &&
00974                 (i+step < width_i)) {
00975             xcorr[step-STEP_MIN] += ((double)line_t[i] - mean_t) *
00976                                     ((double)line_i[i+step] - mean_i) *
00977                                     norm ;
00978                 nval++ ;
00979             }
00980         }
00981         xcorr[step-STEP_MIN] /= (double)nval ;
00982     }
00983     xcorr_max = xcorr[0] ;
00984     maxpos    = 0 ;
00985     for (i=0 ; i<nsteps ; i++) {
00986         if (xcorr[i]>xcorr_max) {
00987             maxpos = i ;
00988             xcorr_max = xcorr[i];
00989         }
00990     }
00991     cpl_free(xcorr);
00992     (*delta) = + ((double)STEP_MIN + (double)maxpos);
00993     return xcorr_max ;
00994 }

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