00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #ifdef HAVE_CONFIG_H
00035 # include <config.h>
00036 #endif
00037
00038
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
00056
00057
00058
00059
00060
00061 #define HALF_CENTROID_DOMAIN 5
00062
00063
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
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,
00163 int npix
00164 )
00165 {
00166 pixelvalue max ;
00167 double centroid ;
00168 double weights ;
00169 int i, maxpos ;
00170
00171
00172
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
00186
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
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
00255
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
00310 out_sig = sinfo_function1d_new(samples);
00311
00312
00313 kernel = function1d_generate_smooth_kernel(filter_type, hw) ;
00314
00315
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
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
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
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
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
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
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
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
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
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
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
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
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
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;
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
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
00794 for (n = 0, i = 1; i < end; i++, n++) {
00795
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
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
00807 for (n = 0, i = 1; i < end; i++, n++) {
00808
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
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
00821 for (j = 0; j < splLen; j++) {
00822 v = (double)splX[j];
00823 splY[j] = (pixelvalue)0;
00824
00825
00826 if ((v < (double)x[0]) || (v > (double)x[end])) {
00827 continue;
00828 }
00829
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
00876 if ((line==NULL) || (npix<1)) return (pixelvalue)0 ;
00877 if ((pix_low+pix_high)>=npix) return (pixelvalue)0 ;
00878
00879
00880 sorted = cpl_malloc(npix * sizeof(pixelvalue)) ;
00881 memcpy(sorted, line, npix * sizeof(pixelvalue)) ;
00882 sinfo_pixel_qsort(sorted, npix);
00883
00884
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
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 }