diff options
author | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
---|---|---|
committer | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
commit | 40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch) | |
tree | 4464880c571602d54f6ae114729bf62a89518057 /vendor/cfitsio/quantize.c | |
download | iraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz |
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'vendor/cfitsio/quantize.c')
-rw-r--r-- | vendor/cfitsio/quantize.c | 3888 |
1 files changed, 3888 insertions, 0 deletions
diff --git a/vendor/cfitsio/quantize.c b/vendor/cfitsio/quantize.c new file mode 100644 index 00000000..8fe6acca --- /dev/null +++ b/vendor/cfitsio/quantize.c @@ -0,0 +1,3888 @@ +/* + The following code is based on algorithms written by Richard White at STScI and made + available for use in CFITSIO in July 1999 and updated in January 2008. +*/ + +# include <stdio.h> +# include <stdlib.h> +# include <math.h> +# include <limits.h> +# include <float.h> + +#include "fitsio2.h" + +/* nearest integer function */ +# define NINT(x) ((x >= 0.) ? (int) (x + 0.5) : (int) (x - 0.5)) + +#define NULL_VALUE -2147483647 /* value used to represent undefined pixels */ +#define N_RESERVED_VALUES 10 /* number of reserved values, starting with */ + /* and including NULL_VALUE. These values */ + /* may not be used to represent the quantized */ + /* and scaled floating point pixel values */ + /* If lossy Hcompression is used, and the */ + /* array contains null values, then it is also */ + /* possible for the compressed values to slightly */ + /* exceed the range of the actual (lossless) values */ + /* so we must reserve a little more space */ + +/* more than this many standard deviations from the mean is an outlier */ +# define SIGMA_CLIP 5. +# define NITER 3 /* number of sigma-clipping iterations */ + +static int FnMeanSigma_short(short *array, long npix, int nullcheck, + short nullvalue, long *ngoodpix, double *mean, double *sigma, int *status); +static int FnMeanSigma_int(int *array, long npix, int nullcheck, + int nullvalue, long *ngoodpix, double *mean, double *sigma, int *status); +static int FnMeanSigma_float(float *array, long npix, int nullcheck, + float nullvalue, long *ngoodpix, double *mean, double *sigma, int *status); +static int FnMeanSigma_double(double *array, long npix, int nullcheck, + double nullvalue, long *ngoodpix, double *mean, double *sigma, int *status); + +static int FnNoise5_short(short *array, long nx, long ny, int nullcheck, + short nullvalue, long *ngood, short *minval, short *maxval, + double *n2, double *n3, double *n5, int *status); +static int FnNoise5_int(int *array, long nx, long ny, int nullcheck, + int nullvalue, long *ngood, int *minval, int *maxval, + double *n2, double *n3, double *n5, int *status); +static int FnNoise5_float(float *array, long nx, long ny, int nullcheck, + float nullvalue, long *ngood, float *minval, float *maxval, + double *n2, double *n3, double *n5, int *status); +static int FnNoise5_double(double *array, long nx, long ny, int nullcheck, + double nullvalue, long *ngood, double *minval, double *maxval, + double *n2, double *n3, double *n5, int *status); + +static int FnNoise3_short(short *array, long nx, long ny, int nullcheck, + short nullvalue, long *ngood, short *minval, short *maxval, double *noise, int *status); +static int FnNoise3_int(int *array, long nx, long ny, int nullcheck, + int nullvalue, long *ngood, int *minval, int *maxval, double *noise, int *status); +static int FnNoise3_float(float *array, long nx, long ny, int nullcheck, + float nullvalue, long *ngood, float *minval, float *maxval, double *noise, int *status); +static int FnNoise3_double(double *array, long nx, long ny, int nullcheck, + double nullvalue, long *ngood, double *minval, double *maxval, double *noise, int *status); + +static int FnNoise1_short(short *array, long nx, long ny, + int nullcheck, short nullvalue, double *noise, int *status); +static int FnNoise1_int(int *array, long nx, long ny, + int nullcheck, int nullvalue, double *noise, int *status); +static int FnNoise1_float(float *array, long nx, long ny, + int nullcheck, float nullvalue, double *noise, int *status); +static int FnNoise1_double(double *array, long nx, long ny, + int nullcheck, double nullvalue, double *noise, int *status); + +static int FnCompare_short (const void *, const void *); +static int FnCompare_int (const void *, const void *); +static int FnCompare_float (const void *, const void *); +static int FnCompare_double (const void *, const void *); +static float quick_select_float(float arr[], int n); +static short quick_select_short(short arr[], int n); +static int quick_select_int(int arr[], int n); +static LONGLONG quick_select_longlong(LONGLONG arr[], int n); +static double quick_select_double(double arr[], int n); + +/*---------------------------------------------------------------------------*/ +int fits_quantize_float (long row, float fdata[], long nxpix, long nypix, int nullcheck, + float in_null_value, float qlevel, int idata[], double *bscale, + double *bzero, int *iminval, int *imaxval) { + +/* arguments: +long row i: if positive, tile number = row number in the binary table + (this is only used when dithering the quantized values) +float fdata[] i: array of image pixels to be compressed +long nxpix i: number of pixels in each row of fdata +long nypix i: number of rows in fdata +nullcheck i: check for nullvalues in fdata? +float in_null_value i: value used to represent undefined pixels in fdata +float qlevel i: quantization level +int idata[] o: values of fdata after applying bzero and bscale +double bscale o: scale factor +double bzero o: zero offset +int iminval o: minimum quantized value that is returned +int imaxval o: maximum quantized value that is returned + +The function value will be one if the input fdata were copied to idata; +in this case the parameters bscale and bzero can be used to convert back to +nearly the original floating point values: fdata ~= idata * bscale + bzero. +If the function value is zero, the data were not copied to idata. +*/ + + int status, anynulls = 0, iseed; + long i, nx, ngood = 0; + double stdev, noise2, noise3, noise5; /* MAD 2nd, 3rd, and 5th order noise values */ + float minval = 0., maxval = 0.; /* min & max of fdata */ + double delta; /* bscale, 1 in idata = delta in fdata */ + double zeropt; /* bzero */ + double temp; + int nextrand = 0; + extern float *fits_rand_value; /* this is defined in imcompress.c */ + LONGLONG iqfactor; + + nx = nxpix * nypix; + if (nx <= 1) { + *bscale = 1.; + *bzero = 0.; + return (0); + } + + if (qlevel >= 0.) { + + /* estimate background noise using MAD pixel differences */ + FnNoise5_float(fdata, nxpix, nypix, nullcheck, in_null_value, &ngood, + &minval, &maxval, &noise2, &noise3, &noise5, &status); + + if (nullcheck && ngood == 0) { /* special case of an image filled with Nulls */ + /* set parameters to dummy values, which are not used */ + minval = 0.; + maxval = 1.; + stdev = 1; + } else { + + /* use the minimum of noise2, noise3, and noise5 as the best noise value */ + stdev = noise3; + if (noise2 != 0. && noise2 < stdev) stdev = noise2; + if (noise5 != 0. && noise5 < stdev) stdev = noise5; + } + + if (qlevel == 0.) + delta = stdev / 4.; /* default quantization */ + else + delta = stdev / qlevel; + + if (delta == 0.) + return (0); /* don't quantize */ + + } else { + /* negative value represents the absolute quantization level */ + delta = -qlevel; + + /* only nned to calculate the min and max values */ + FnNoise3_float(fdata, nxpix, nypix, nullcheck, in_null_value, &ngood, + &minval, &maxval, 0, &status); + } + + /* check that the range of quantized levels is not > range of int */ + if ((maxval - minval) / delta > 2. * 2147483647. - N_RESERVED_VALUES ) + return (0); /* don't quantize */ + + if (row > 0) { /* we need to dither the quantized values */ + if (!fits_rand_value) + if (fits_init_randoms()) return(MEMORY_ALLOCATION); + + /* initialize the index to the next random number in the list */ + iseed = (int) ((row - 1) % N_RANDOM); + nextrand = (int) (fits_rand_value[iseed] * 500.); + } + + if (ngood == nx) { /* don't have to check for nulls */ + /* return all positive values, if possible since some */ + /* compression algorithms either only work for positive integers, */ + /* or are more efficient. */ + + if ((maxval - minval) / delta < 2147483647. - N_RESERVED_VALUES ) + { + zeropt = minval; + /* fudge the zero point so it is an integer multiple of delta */ + /* This helps to ensure the same scaling will be performed if the */ + /* file undergoes multiple fpack/funpack cycles */ + iqfactor = (LONGLONG) (zeropt/delta + 0.5); + zeropt = iqfactor * delta; + } + else + { + /* center the quantized levels around zero */ + zeropt = (minval + maxval) / 2.; + } + + if (row > 0) { /* dither the values when quantizing */ + for (i = 0; i < nx; i++) { + + idata[i] = NINT((((double) fdata[i] - zeropt) / delta) + fits_rand_value[nextrand] - 0.5); + + nextrand++; + if (nextrand == N_RANDOM) { + iseed++; + if (iseed == N_RANDOM) iseed = 0; + nextrand = (int) (fits_rand_value[iseed] * 500); + } + } + } else { /* do not dither the values */ + + for (i = 0; i < nx; i++) { + idata[i] = NINT ((fdata[i] - zeropt) / delta); + } + } + } + else { + /* data contains null values; shift the range to be */ + /* close to the value used to represent null values */ + zeropt = minval - delta * (NULL_VALUE + N_RESERVED_VALUES); + + if (row > 0) { /* dither the values */ + for (i = 0; i < nx; i++) { + if (fdata[i] != in_null_value) { + idata[i] = NINT((((double) fdata[i] - zeropt) / delta) + fits_rand_value[nextrand] - 0.5); + } else { + idata[i] = NULL_VALUE; + } + + /* increment the random number index, regardless */ + nextrand++; + if (nextrand == N_RANDOM) { + iseed++; + if (iseed == N_RANDOM) iseed = 0; + nextrand = (int) (fits_rand_value[iseed] * 500); + } + } + } else { /* do not dither the values */ + for (i = 0; i < nx; i++) { + if (fdata[i] != in_null_value) + idata[i] = NINT((fdata[i] - zeropt) / delta); + else + idata[i] = NULL_VALUE; + } + } + } + + /* calc min and max values */ + temp = (minval - zeropt) / delta; + *iminval = NINT (temp); + temp = (maxval - zeropt) / delta; + *imaxval = NINT (temp); + + *bscale = delta; + *bzero = zeropt; + return (1); /* yes, data have been quantized */ +} +/*---------------------------------------------------------------------------*/ +int fits_quantize_double (long row, double fdata[], long nxpix, long nypix, int nullcheck, + double in_null_value, float qlevel, int idata[], double *bscale, + double *bzero, int *iminval, int *imaxval) { + +/* arguments: +long row i: tile number = row number in the binary table +double fdata[] i: array of image pixels to be compressed +long nxpix i: number of pixels in each row of fdata +long nypix i: number of rows in fdata +nullcheck i: check for nullvalues in fdata? +double in_null_value i: value used to represent undefined pixels in fdata +int noise_bits i: quantization level (number of bits) +int idata[] o: values of fdata after applying bzero and bscale +double bscale o: scale factor +double bzero o: zero offset +int iminval o: minimum quantized value that is returned +int imaxval o: maximum quantized value that is returned + +The function value will be one if the input fdata were copied to idata; +in this case the parameters bscale and bzero can be used to convert back to +nearly the original floating point values: fdata ~= idata * bscale + bzero. +If the function value is zero, the data were not copied to idata. +*/ + + int status, anynulls = 0, iseed; + long i, nx, ngood = 0; + double stdev, noise2, noise3, noise5; /* MAD 2nd, 3rd, and 5th order noise values */ + double minval = 0., maxval = 0.; /* min & max of fdata */ + double delta; /* bscale, 1 in idata = delta in fdata */ + double zeropt; /* bzero */ + double temp; + int nextrand = 0; + extern float *fits_rand_value; + LONGLONG iqfactor; + + nx = nxpix * nypix; + if (nx <= 1) { + *bscale = 1.; + *bzero = 0.; + return (0); + } + + if (qlevel >= 0.) { + + /* estimate background noise using MAD pixel differences */ + FnNoise5_double(fdata, nxpix, nypix, nullcheck, in_null_value, &ngood, + &minval, &maxval, &noise2, &noise3, &noise5, &status); + + if (nullcheck && ngood == 0) { /* special case of an image filled with Nulls */ + /* set parameters to dummy values, which are not used */ + minval = 0.; + maxval = 1.; + stdev = 1; + } else { + + /* use the minimum of noise2, noise3, and noise5 as the best noise value */ + stdev = noise3; + if (noise2 != 0. && noise2 < stdev) stdev = noise2; + if (noise5 != 0. && noise5 < stdev) stdev = noise5; + } + + if (qlevel == 0.) + delta = stdev / 4.; /* default quantization */ + else + delta = stdev / qlevel; + + if (delta == 0.) + return (0); /* don't quantize */ + + } else { + /* negative value represents the absolute quantization level */ + delta = -qlevel; + + /* only nned to calculate the min and max values */ + FnNoise3_double(fdata, nxpix, nypix, nullcheck, in_null_value, &ngood, + &minval, &maxval, 0, &status); + } + + /* check that the range of quantized levels is not > range of int */ + if ((maxval - minval) / delta > 2. * 2147483647. - N_RESERVED_VALUES ) + return (0); /* don't quantize */ + + if (row > 0) { /* we need to dither the quantized values */ + if (!fits_rand_value) + if (fits_init_randoms()) return(MEMORY_ALLOCATION); + + /* initialize the index to the next random number in the list */ + iseed = (int) ((row - 1) % N_RANDOM); + nextrand = (int) (fits_rand_value[iseed] * 500); + } + + if (ngood == nx) { /* don't have to check for nulls */ + /* return all positive values, if possible since some */ + /* compression algorithms either only work for positive integers, */ + /* or are more efficient. */ + if ((maxval - minval) / delta < 2147483647. - N_RESERVED_VALUES ) + { + zeropt = minval; + /* fudge the zero point so it is an integer multiple of delta */ + /* This helps to ensure the same scaling will be performed if the */ + /* file undergoes multiple fpack/funpack cycles */ + iqfactor = (LONGLONG) (zeropt/delta + 0.5); + zeropt = iqfactor * delta; + } + else + { + /* center the quantized levels around zero */ + zeropt = (minval + maxval) / 2.; + } + + if (row > 0) { /* dither the values when quantizing */ + for (i = 0; i < nx; i++) { + + idata[i] = NINT((((double) fdata[i] - zeropt) / delta) + fits_rand_value[nextrand] - 0.5); + + nextrand++; + if (nextrand == N_RANDOM) { + iseed++; + nextrand = (int) (fits_rand_value[iseed] * 500); + } + } + } else { /* do not dither the values */ + + for (i = 0; i < nx; i++) { + idata[i] = NINT ((fdata[i] - zeropt) / delta); + } + } + } + else { + /* data contains null values; shift the range to be */ + /* close to the value used to represent null values */ + zeropt = minval - delta * (NULL_VALUE + N_RESERVED_VALUES); + + if (row > 0) { /* dither the values */ + for (i = 0; i < nx; i++) { + if (fdata[i] != in_null_value) { + idata[i] = NINT((((double) fdata[i] - zeropt) / delta) + fits_rand_value[nextrand] - 0.5); + } else { + idata[i] = NULL_VALUE; + } + + /* increment the random number index, regardless */ + nextrand++; + if (nextrand == N_RANDOM) { + iseed++; + nextrand = (int) (fits_rand_value[iseed] * 500); + } + } + } else { /* do not dither the values */ + for (i = 0; i < nx; i++) { + if (fdata[i] != in_null_value) + idata[i] = NINT((fdata[i] - zeropt) / delta); + else + idata[i] = NULL_VALUE; + } + } + } + + /* calc min and max values */ + temp = (minval - zeropt) / delta; + *iminval = NINT (temp); + temp = (maxval - zeropt) / delta; + *imaxval = NINT (temp); + + *bscale = delta; + *bzero = zeropt; + + return (1); /* yes, data have been quantized */ +} +/*--------------------------------------------------------------------------*/ +int fits_img_stats_short(short *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + /* (if this is a 3D image, then ny should be the */ + /* product of the no. of rows times the no. of planes) */ + int nullcheck, /* check for null values, if true */ + short nullvalue, /* value of null pixels, if nullcheck is true */ + + /* returned parameters (if the pointer is not null) */ + long *ngoodpix, /* number of non-null pixels in the image */ + short *minvalue, /* returned minimum non-null value in the array */ + short *maxvalue, /* returned maximum non-null value in the array */ + double *mean, /* returned mean value of all non-null pixels */ + double *sigma, /* returned R.M.S. value of all non-null pixels */ + double *noise1, /* 1st order estimate of noise in image background level */ + double *noise2, /* 2nd order estimate of noise in image background level */ + double *noise3, /* 3rd order estimate of noise in image background level */ + double *noise5, /* 5th order estimate of noise in image background level */ + int *status) /* error status */ + +/* + Compute statistics of the input short integer image. +*/ +{ + long ngood; + short minval, maxval; + double xmean = 0., xsigma = 0., xnoise = 0., xnoise2 = 0., xnoise3 = 0., xnoise5 = 0.; + + /* need to calculate mean and/or sigma and/or limits? */ + if (mean || sigma ) { + FnMeanSigma_short(array, nx * ny, nullcheck, nullvalue, + &ngood, &xmean, &xsigma, status); + + if (ngoodpix) *ngoodpix = ngood; + if (mean) *mean = xmean; + if (sigma) *sigma = xsigma; + } + + if (noise1) { + FnNoise1_short(array, nx, ny, nullcheck, nullvalue, + &xnoise, status); + + *noise1 = xnoise; + } + + if (minvalue || maxvalue || noise3) { + FnNoise5_short(array, nx, ny, nullcheck, nullvalue, + &ngood, &minval, &maxval, &xnoise2, &xnoise3, &xnoise5, status); + + if (ngoodpix) *ngoodpix = ngood; + if (minvalue) *minvalue= minval; + if (maxvalue) *maxvalue = maxval; + if (noise2) *noise2 = xnoise2; + if (noise3) *noise3 = xnoise3; + if (noise5) *noise5 = xnoise5; + } + return(*status); +} +/*--------------------------------------------------------------------------*/ +int fits_img_stats_int(int *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + /* (if this is a 3D image, then ny should be the */ + /* product of the no. of rows times the no. of planes) */ + int nullcheck, /* check for null values, if true */ + int nullvalue, /* value of null pixels, if nullcheck is true */ + + /* returned parameters (if the pointer is not null) */ + long *ngoodpix, /* number of non-null pixels in the image */ + int *minvalue, /* returned minimum non-null value in the array */ + int *maxvalue, /* returned maximum non-null value in the array */ + double *mean, /* returned mean value of all non-null pixels */ + double *sigma, /* returned R.M.S. value of all non-null pixels */ + double *noise1, /* 1st order estimate of noise in image background level */ + double *noise2, /* 2nd order estimate of noise in image background level */ + double *noise3, /* 3rd order estimate of noise in image background level */ + double *noise5, /* 5th order estimate of noise in image background level */ + int *status) /* error status */ + +/* + Compute statistics of the input integer image. +*/ +{ + long ngood; + int minval, maxval; + double xmean = 0., xsigma = 0., xnoise = 0., xnoise2 = 0., xnoise3 = 0., xnoise5 = 0.; + + /* need to calculate mean and/or sigma and/or limits? */ + if (mean || sigma ) { + FnMeanSigma_int(array, nx * ny, nullcheck, nullvalue, + &ngood, &xmean, &xsigma, status); + + if (ngoodpix) *ngoodpix = ngood; + if (mean) *mean = xmean; + if (sigma) *sigma = xsigma; + } + + if (noise1) { + FnNoise1_int(array, nx, ny, nullcheck, nullvalue, + &xnoise, status); + + *noise1 = xnoise; + } + + if (minvalue || maxvalue || noise3) { + FnNoise5_int(array, nx, ny, nullcheck, nullvalue, + &ngood, &minval, &maxval, &xnoise2, &xnoise3, &xnoise5, status); + + if (ngoodpix) *ngoodpix = ngood; + if (minvalue) *minvalue= minval; + if (maxvalue) *maxvalue = maxval; + if (noise2) *noise2 = xnoise2; + if (noise3) *noise3 = xnoise3; + if (noise5) *noise5 = xnoise5; + } + return(*status); +} +/*--------------------------------------------------------------------------*/ +int fits_img_stats_float(float *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + /* (if this is a 3D image, then ny should be the */ + /* product of the no. of rows times the no. of planes) */ + int nullcheck, /* check for null values, if true */ + float nullvalue, /* value of null pixels, if nullcheck is true */ + + /* returned parameters (if the pointer is not null) */ + long *ngoodpix, /* number of non-null pixels in the image */ + float *minvalue, /* returned minimum non-null value in the array */ + float *maxvalue, /* returned maximum non-null value in the array */ + double *mean, /* returned mean value of all non-null pixels */ + double *sigma, /* returned R.M.S. value of all non-null pixels */ + double *noise1, /* 1st order estimate of noise in image background level */ + double *noise2, /* 2nd order estimate of noise in image background level */ + double *noise3, /* 3rd order estimate of noise in image background level */ + double *noise5, /* 5th order estimate of noise in image background level */ + int *status) /* error status */ + +/* + Compute statistics of the input float image. +*/ +{ + long ngood; + float minval, maxval; + double xmean = 0., xsigma = 0., xnoise = 0., xnoise2 = 0., xnoise3 = 0., xnoise5 = 0.; + + /* need to calculate mean and/or sigma and/or limits? */ + if (mean || sigma ) { + FnMeanSigma_float(array, nx * ny, nullcheck, nullvalue, + &ngood, &xmean, &xsigma, status); + + if (ngoodpix) *ngoodpix = ngood; + if (mean) *mean = xmean; + if (sigma) *sigma = xsigma; + } + + if (noise1) { + FnNoise1_float(array, nx, ny, nullcheck, nullvalue, + &xnoise, status); + + *noise1 = xnoise; + } + + if (minvalue || maxvalue || noise3) { + FnNoise5_float(array, nx, ny, nullcheck, nullvalue, + &ngood, &minval, &maxval, &xnoise2, &xnoise3, &xnoise5, status); + + if (ngoodpix) *ngoodpix = ngood; + if (minvalue) *minvalue= minval; + if (maxvalue) *maxvalue = maxval; + if (noise2) *noise2 = xnoise2; + if (noise3) *noise3 = xnoise3; + if (noise5) *noise5 = xnoise5; + } + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnMeanSigma_short + (short *array, /* 2 dimensional array of image pixels */ + long npix, /* number of pixels in the image */ + int nullcheck, /* check for null values, if true */ + short nullvalue, /* value of null pixels, if nullcheck is true */ + + /* returned parameters */ + + long *ngoodpix, /* number of non-null pixels in the image */ + double *mean, /* returned mean value of all non-null pixels */ + double *sigma, /* returned R.M.S. value of all non-null pixels */ + int *status) /* error status */ + +/* +Compute mean and RMS sigma of the non-null pixels in the input array. +*/ +{ + long ii, ngood = 0; + short *value; + double sum = 0., sum2 = 0., xtemp; + + value = array; + + if (nullcheck) { + for (ii = 0; ii < npix; ii++, value++) { + if (*value != nullvalue) { + ngood++; + xtemp = (double) *value; + sum += xtemp; + sum2 += (xtemp * xtemp); + } + } + } else { + ngood = npix; + for (ii = 0; ii < npix; ii++, value++) { + xtemp = (double) *value; + sum += xtemp; + sum2 += (xtemp * xtemp); + } + } + + if (ngood > 1) { + if (ngoodpix) *ngoodpix = ngood; + xtemp = sum / ngood; + if (mean) *mean = xtemp; + if (sigma) *sigma = sqrt((sum2 / ngood) - (xtemp * xtemp)); + } else if (ngood == 1){ + if (ngoodpix) *ngoodpix = 1; + if (mean) *mean = sum; + if (sigma) *sigma = 0.0; + } else { + if (ngoodpix) *ngoodpix = 0; + if (mean) *mean = 0.; + if (sigma) *sigma = 0.; + } + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnMeanSigma_int + (int *array, /* 2 dimensional array of image pixels */ + long npix, /* number of pixels in the image */ + int nullcheck, /* check for null values, if true */ + int nullvalue, /* value of null pixels, if nullcheck is true */ + + /* returned parameters */ + + long *ngoodpix, /* number of non-null pixels in the image */ + double *mean, /* returned mean value of all non-null pixels */ + double *sigma, /* returned R.M.S. value of all non-null pixels */ + int *status) /* error status */ + +/* +Compute mean and RMS sigma of the non-null pixels in the input array. +*/ +{ + long ii, ngood = 0; + int *value; + double sum = 0., sum2 = 0., xtemp; + + value = array; + + if (nullcheck) { + for (ii = 0; ii < npix; ii++, value++) { + if (*value != nullvalue) { + ngood++; + xtemp = (double) *value; + sum += xtemp; + sum2 += (xtemp * xtemp); + } + } + } else { + ngood = npix; + for (ii = 0; ii < npix; ii++, value++) { + xtemp = (double) *value; + sum += xtemp; + sum2 += (xtemp * xtemp); + } + } + + if (ngood > 1) { + if (ngoodpix) *ngoodpix = ngood; + xtemp = sum / ngood; + if (mean) *mean = xtemp; + if (sigma) *sigma = sqrt((sum2 / ngood) - (xtemp * xtemp)); + } else if (ngood == 1){ + if (ngoodpix) *ngoodpix = 1; + if (mean) *mean = sum; + if (sigma) *sigma = 0.0; + } else { + if (ngoodpix) *ngoodpix = 0; + if (mean) *mean = 0.; + if (sigma) *sigma = 0.; + } + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnMeanSigma_float + (float *array, /* 2 dimensional array of image pixels */ + long npix, /* number of pixels in the image */ + int nullcheck, /* check for null values, if true */ + float nullvalue, /* value of null pixels, if nullcheck is true */ + + /* returned parameters */ + + long *ngoodpix, /* number of non-null pixels in the image */ + double *mean, /* returned mean value of all non-null pixels */ + double *sigma, /* returned R.M.S. value of all non-null pixels */ + int *status) /* error status */ + +/* +Compute mean and RMS sigma of the non-null pixels in the input array. +*/ +{ + long ii, ngood = 0; + float *value; + double sum = 0., sum2 = 0., xtemp; + + value = array; + + if (nullcheck) { + for (ii = 0; ii < npix; ii++, value++) { + if (*value != nullvalue) { + ngood++; + xtemp = (double) *value; + sum += xtemp; + sum2 += (xtemp * xtemp); + } + } + } else { + ngood = npix; + for (ii = 0; ii < npix; ii++, value++) { + xtemp = (double) *value; + sum += xtemp; + sum2 += (xtemp * xtemp); + } + } + + if (ngood > 1) { + if (ngoodpix) *ngoodpix = ngood; + xtemp = sum / ngood; + if (mean) *mean = xtemp; + if (sigma) *sigma = sqrt((sum2 / ngood) - (xtemp * xtemp)); + } else if (ngood == 1){ + if (ngoodpix) *ngoodpix = 1; + if (mean) *mean = sum; + if (sigma) *sigma = 0.0; + } else { + if (ngoodpix) *ngoodpix = 0; + if (mean) *mean = 0.; + if (sigma) *sigma = 0.; + } + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnMeanSigma_double + (double *array, /* 2 dimensional array of image pixels */ + long npix, /* number of pixels in the image */ + int nullcheck, /* check for null values, if true */ + double nullvalue, /* value of null pixels, if nullcheck is true */ + + /* returned parameters */ + + long *ngoodpix, /* number of non-null pixels in the image */ + double *mean, /* returned mean value of all non-null pixels */ + double *sigma, /* returned R.M.S. value of all non-null pixels */ + int *status) /* error status */ + +/* +Compute mean and RMS sigma of the non-null pixels in the input array. +*/ +{ + long ii, ngood = 0; + double *value; + double sum = 0., sum2 = 0., xtemp; + + value = array; + + if (nullcheck) { + for (ii = 0; ii < npix; ii++, value++) { + if (*value != nullvalue) { + ngood++; + xtemp = *value; + sum += xtemp; + sum2 += (xtemp * xtemp); + } + } + } else { + ngood = npix; + for (ii = 0; ii < npix; ii++, value++) { + xtemp = *value; + sum += xtemp; + sum2 += (xtemp * xtemp); + } + } + + if (ngood > 1) { + if (ngoodpix) *ngoodpix = ngood; + xtemp = sum / ngood; + if (mean) *mean = xtemp; + if (sigma) *sigma = sqrt((sum2 / ngood) - (xtemp * xtemp)); + } else if (ngood == 1){ + if (ngoodpix) *ngoodpix = 1; + if (mean) *mean = sum; + if (sigma) *sigma = 0.0; + } else { + if (ngoodpix) *ngoodpix = 0; + if (mean) *mean = 0.; + if (sigma) *sigma = 0.; + } + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnNoise5_short + (short *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + int nullcheck, /* check for null values, if true */ + short nullvalue, /* value of null pixels, if nullcheck is true */ + /* returned parameters */ + long *ngood, /* number of good, non-null pixels? */ + short *minval, /* minimum non-null value */ + short *maxval, /* maximum non-null value */ + double *noise2, /* returned 2nd order MAD of all non-null pixels */ + double *noise3, /* returned 3rd order MAD of all non-null pixels */ + double *noise5, /* returned 5th order MAD of all non-null pixels */ + int *status) /* error status */ + +/* +Estimate the median and background noise in the input image using 2nd, 3rd and 5th +order Median Absolute Differences. + +The noise in the background of the image is calculated using the MAD algorithms +developed for deriving the signal to noise ratio in spectra +(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/) + +3rd order: noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2))) + +The returned estimates are the median of the values that are computed for each +row of the image. +*/ +{ + long ii, jj, nrows = 0, nrows2 = 0, nvals, nvals2, ngoodpix = 0; + int *differences2, *differences3, *differences5; + short *rowpix, v1, v2, v3, v4, v5, v6, v7, v8, v9; + short xminval = SHRT_MAX, xmaxval = SHRT_MIN; + int do_range = 0; + double *diffs2, *diffs3, *diffs5; + double xnoise2 = 0, xnoise3 = 0, xnoise5 = 0; + + if (nx < 5) { + /* treat entire array as an image with a single row */ + nx = nx * ny; + ny = 1; + } + + /* rows must have at least 9 pixels */ + if (nx < 9) { + + for (ii = 0; ii < nx; ii++) { + if (nullcheck && array[ii] == nullvalue) + continue; + else { + if (array[ii] < xminval) xminval = array[ii]; + if (array[ii] > xmaxval) xmaxval = array[ii]; + ngoodpix++; + } + } + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (ngood) *ngood = ngoodpix; + if (noise2) *noise2 = 0.; + if (noise3) *noise3 = 0.; + if (noise5) *noise5 = 0.; + return(*status); + } + + /* do we need to compute the min and max value? */ + if (minval || maxval) do_range = 1; + + /* allocate arrays used to compute the median and noise estimates */ + differences2 = calloc(nx, sizeof(int)); + if (!differences2) { + *status = MEMORY_ALLOCATION; + return(*status); + } + differences3 = calloc(nx, sizeof(int)); + if (!differences3) { + free(differences2); + *status = MEMORY_ALLOCATION; + return(*status); + } + differences5 = calloc(nx, sizeof(int)); + if (!differences5) { + free(differences2); + free(differences3); + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs2 = calloc(ny, sizeof(double)); + if (!diffs2) { + free(differences2); + free(differences3); + free(differences5); + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs3 = calloc(ny, sizeof(double)); + if (!diffs3) { + free(differences2); + free(differences3); + free(differences5); + free(diffs2); + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs5 = calloc(ny, sizeof(double)); + if (!diffs5) { + free(differences2); + free(differences3); + free(differences5); + free(diffs2); + free(diffs3); + *status = MEMORY_ALLOCATION; + return(*status); + } + + /* loop over each row of the image */ + for (jj=0; jj < ny; jj++) { + + rowpix = array + (jj * nx); /* point to first pixel in the row */ + + /***** find the first valid pixel in row */ + ii = 0; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v1 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v1 < xminval) xminval = v1; + if (v1 > xmaxval) xmaxval = v1; + } + + /***** find the 2nd valid pixel in row (which we will skip over) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v2 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v2 < xminval) xminval = v2; + if (v2 > xmaxval) xmaxval = v2; + } + + /***** find the 3rd valid pixel in row */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v3 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v3 < xminval) xminval = v3; + if (v3 > xmaxval) xmaxval = v3; + } + + /* find the 4nd valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v4 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v4 < xminval) xminval = v4; + if (v4 > xmaxval) xmaxval = v4; + } + + /* find the 5th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v5 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v5 < xminval) xminval = v5; + if (v5 > xmaxval) xmaxval = v5; + } + + /* find the 6th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v6 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v6 < xminval) xminval = v6; + if (v6 > xmaxval) xmaxval = v6; + } + + /* find the 7th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v7 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v7 < xminval) xminval = v7; + if (v7 > xmaxval) xmaxval = v7; + } + + /* find the 8th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v8 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v8 < xminval) xminval = v8; + if (v8 > xmaxval) xmaxval = v8; + } + /* now populate the differences arrays */ + /* for the remaining pixels in the row */ + nvals = 0; + nvals2 = 0; + for (ii++; ii < nx; ii++) { + + /* find the next valid pixel in row */ + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) break; /* hit end of row */ + v9 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v9 < xminval) xminval = v9; + if (v9 > xmaxval) xmaxval = v9; + } + + /* construct array of absolute differences */ + + if (!(v5 == v6 && v6 == v7) ) { + differences2[nvals2] = abs((int) v5 - (int) v7); + nvals2++; + } + + if (!(v3 == v4 && v4 == v5 && v5 == v6 && v6 == v7) ) { + differences3[nvals] = abs((2 * (int) v5) - (int) v3 - (int) v7); + differences5[nvals] = abs((6 * (int) v5) - (4 * (int) v3) - (4 * (int) v7) + (int) v1 + (int) v9); + nvals++; + } else { + /* ignore constant background regions */ + ngoodpix++; + } + + /* shift over 1 pixel */ + v1 = v2; + v2 = v3; + v3 = v4; + v4 = v5; + v5 = v6; + v6 = v7; + v7 = v8; + v8 = v9; + } /* end of loop over pixels in the row */ + + /* compute the median diffs */ + /* Note that there are 8 more pixel values than there are diffs values. */ + ngoodpix += (nvals + 8); + + if (nvals == 0) { + continue; /* cannot compute medians on this row */ + } else if (nvals == 1) { + if (nvals2 == 1) { + diffs2[nrows2] = differences2[0]; + nrows2++; + } + + diffs3[nrows] = differences3[0]; + diffs5[nrows] = differences5[0]; + } else { + /* quick_select returns the median MUCH faster than using qsort */ + if (nvals2 > 1) { + diffs2[nrows2] = quick_select_int(differences2, nvals); + nrows2++; + } + + diffs3[nrows] = quick_select_int(differences3, nvals); + diffs5[nrows] = quick_select_int(differences5, nvals); + } + + nrows++; + } /* end of loop over rows */ + + /* compute median of the values for each row */ + if (nrows == 0) { + xnoise3 = 0; + xnoise5 = 0; + } else if (nrows == 1) { + xnoise3 = diffs3[0]; + xnoise5 = diffs5[0]; + } else { + qsort(diffs3, nrows, sizeof(double), FnCompare_double); + qsort(diffs5, nrows, sizeof(double), FnCompare_double); + xnoise3 = (diffs3[(nrows - 1)/2] + diffs3[nrows/2]) / 2.; + xnoise5 = (diffs5[(nrows - 1)/2] + diffs5[nrows/2]) / 2.; + } + + if (nrows2 == 0) { + xnoise2 = 0; + } else if (nrows2 == 1) { + xnoise2 = diffs2[0]; + } else { + qsort(diffs2, nrows2, sizeof(double), FnCompare_double); + xnoise2 = (diffs2[(nrows2 - 1)/2] + diffs2[nrows2/2]) / 2.; + } + + if (ngood) *ngood = ngoodpix; + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (noise2) *noise2 = 1.0483579 * xnoise2; + if (noise3) *noise3 = 0.6052697 * xnoise3; + if (noise5) *noise5 = 0.1772048 * xnoise5; + + free(diffs5); + free(diffs3); + free(diffs2); + free(differences5); + free(differences3); + free(differences2); + + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnNoise5_int + (int *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + int nullcheck, /* check for null values, if true */ + int nullvalue, /* value of null pixels, if nullcheck is true */ + /* returned parameters */ + long *ngood, /* number of good, non-null pixels? */ + int *minval, /* minimum non-null value */ + int *maxval, /* maximum non-null value */ + double *noise2, /* returned 2nd order MAD of all non-null pixels */ + double *noise3, /* returned 3rd order MAD of all non-null pixels */ + double *noise5, /* returned 5th order MAD of all non-null pixels */ + int *status) /* error status */ + +/* +Estimate the median and background noise in the input image using 2nd, 3rd and 5th +order Median Absolute Differences. + +The noise in the background of the image is calculated using the MAD algorithms +developed for deriving the signal to noise ratio in spectra +(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/) + +3rd order: noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2))) + +The returned estimates are the median of the values that are computed for each +row of the image. +*/ +{ + long ii, jj, nrows = 0, nrows2 = 0, nvals, nvals2, ngoodpix = 0; + LONGLONG *differences2, *differences3, *differences5, tdiff; + int *rowpix, v1, v2, v3, v4, v5, v6, v7, v8, v9; + int xminval = INT_MAX, xmaxval = INT_MIN; + int do_range = 0; + double *diffs2, *diffs3, *diffs5; + double xnoise2 = 0, xnoise3 = 0, xnoise5 = 0; + + if (nx < 5) { + /* treat entire array as an image with a single row */ + nx = nx * ny; + ny = 1; + } + + /* rows must have at least 9 pixels */ + if (nx < 9) { + + for (ii = 0; ii < nx; ii++) { + if (nullcheck && array[ii] == nullvalue) + continue; + else { + if (array[ii] < xminval) xminval = array[ii]; + if (array[ii] > xmaxval) xmaxval = array[ii]; + ngoodpix++; + } + } + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (ngood) *ngood = ngoodpix; + if (noise2) *noise2 = 0.; + if (noise3) *noise3 = 0.; + if (noise5) *noise5 = 0.; + return(*status); + } + + /* do we need to compute the min and max value? */ + if (minval || maxval) do_range = 1; + + /* allocate arrays used to compute the median and noise estimates */ + differences2 = calloc(nx, sizeof(LONGLONG)); + if (!differences2) { + *status = MEMORY_ALLOCATION; + return(*status); + } + differences3 = calloc(nx, sizeof(LONGLONG)); + if (!differences3) { + free(differences2); + *status = MEMORY_ALLOCATION; + return(*status); + } + differences5 = calloc(nx, sizeof(LONGLONG)); + if (!differences5) { + free(differences2); + free(differences3); + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs2 = calloc(ny, sizeof(double)); + if (!diffs2) { + free(differences2); + free(differences3); + free(differences5); + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs3 = calloc(ny, sizeof(double)); + if (!diffs3) { + free(differences2); + free(differences3); + free(differences5); + free(diffs2); + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs5 = calloc(ny, sizeof(double)); + if (!diffs5) { + free(differences2); + free(differences3); + free(differences5); + free(diffs2); + free(diffs3); + *status = MEMORY_ALLOCATION; + return(*status); + } + + /* loop over each row of the image */ + for (jj=0; jj < ny; jj++) { + + rowpix = array + (jj * nx); /* point to first pixel in the row */ + + /***** find the first valid pixel in row */ + ii = 0; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v1 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v1 < xminval) xminval = v1; + if (v1 > xmaxval) xmaxval = v1; + } + + /***** find the 2nd valid pixel in row (which we will skip over) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v2 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v2 < xminval) xminval = v2; + if (v2 > xmaxval) xmaxval = v2; + } + + /***** find the 3rd valid pixel in row */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v3 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v3 < xminval) xminval = v3; + if (v3 > xmaxval) xmaxval = v3; + } + + /* find the 4nd valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v4 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v4 < xminval) xminval = v4; + if (v4 > xmaxval) xmaxval = v4; + } + + /* find the 5th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v5 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v5 < xminval) xminval = v5; + if (v5 > xmaxval) xmaxval = v5; + } + + /* find the 6th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v6 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v6 < xminval) xminval = v6; + if (v6 > xmaxval) xmaxval = v6; + } + + /* find the 7th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v7 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v7 < xminval) xminval = v7; + if (v7 > xmaxval) xmaxval = v7; + } + + /* find the 8th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v8 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v8 < xminval) xminval = v8; + if (v8 > xmaxval) xmaxval = v8; + } + /* now populate the differences arrays */ + /* for the remaining pixels in the row */ + nvals = 0; + nvals2 = 0; + for (ii++; ii < nx; ii++) { + + /* find the next valid pixel in row */ + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) break; /* hit end of row */ + v9 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v9 < xminval) xminval = v9; + if (v9 > xmaxval) xmaxval = v9; + } + + /* construct array of absolute differences */ + + if (!(v5 == v6 && v6 == v7) ) { + tdiff = (LONGLONG) v5 - (LONGLONG) v7; + if (tdiff < 0) + differences2[nvals2] = -1 * tdiff; + else + differences2[nvals2] = tdiff; + + nvals2++; + } + + if (!(v3 == v4 && v4 == v5 && v5 == v6 && v6 == v7) ) { + tdiff = (2 * (LONGLONG) v5) - (LONGLONG) v3 - (LONGLONG) v7; + if (tdiff < 0) + differences3[nvals] = -1 * tdiff; + else + differences3[nvals] = tdiff; + + tdiff = (6 * (LONGLONG) v5) - (4 * (LONGLONG) v3) - (4 * (LONGLONG) v7) + (LONGLONG) v1 + (LONGLONG) v9; + if (tdiff < 0) + differences5[nvals] = -1 * tdiff; + else + differences5[nvals] = tdiff; + + nvals++; + } else { + /* ignore constant background regions */ + ngoodpix++; + } + + /* shift over 1 pixel */ + v1 = v2; + v2 = v3; + v3 = v4; + v4 = v5; + v5 = v6; + v6 = v7; + v7 = v8; + v8 = v9; + } /* end of loop over pixels in the row */ + + /* compute the median diffs */ + /* Note that there are 8 more pixel values than there are diffs values. */ + ngoodpix += (nvals + 8); + + if (nvals == 0) { + continue; /* cannot compute medians on this row */ + } else if (nvals == 1) { + if (nvals2 == 1) { + diffs2[nrows2] = (double) differences2[0]; + nrows2++; + } + + diffs3[nrows] = (double) differences3[0]; + diffs5[nrows] = (double) differences5[0]; + } else { + /* quick_select returns the median MUCH faster than using qsort */ + if (nvals2 > 1) { + diffs2[nrows2] = (double) quick_select_longlong(differences2, nvals); + nrows2++; + } + + diffs3[nrows] = (double) quick_select_longlong(differences3, nvals); + diffs5[nrows] = (double) quick_select_longlong(differences5, nvals); + } + + nrows++; + } /* end of loop over rows */ + + /* compute median of the values for each row */ + if (nrows == 0) { + xnoise3 = 0; + xnoise5 = 0; + } else if (nrows == 1) { + xnoise3 = diffs3[0]; + xnoise5 = diffs5[0]; + } else { + qsort(diffs3, nrows, sizeof(double), FnCompare_double); + qsort(diffs5, nrows, sizeof(double), FnCompare_double); + xnoise3 = (diffs3[(nrows - 1)/2] + diffs3[nrows/2]) / 2.; + xnoise5 = (diffs5[(nrows - 1)/2] + diffs5[nrows/2]) / 2.; + } + + if (nrows2 == 0) { + xnoise2 = 0; + } else if (nrows2 == 1) { + xnoise2 = diffs2[0]; + } else { + qsort(diffs2, nrows2, sizeof(double), FnCompare_double); + xnoise2 = (diffs2[(nrows2 - 1)/2] + diffs2[nrows2/2]) / 2.; + } + + if (ngood) *ngood = ngoodpix; + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (noise2) *noise2 = 1.0483579 * xnoise2; + if (noise3) *noise3 = 0.6052697 * xnoise3; + if (noise5) *noise5 = 0.1772048 * xnoise5; + + free(diffs5); + free(diffs3); + free(diffs2); + free(differences5); + free(differences3); + free(differences2); + + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnNoise5_float + (float *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + int nullcheck, /* check for null values, if true */ + float nullvalue, /* value of null pixels, if nullcheck is true */ + /* returned parameters */ + long *ngood, /* number of good, non-null pixels? */ + float *minval, /* minimum non-null value */ + float *maxval, /* maximum non-null value */ + double *noise2, /* returned 2nd order MAD of all non-null pixels */ + double *noise3, /* returned 3rd order MAD of all non-null pixels */ + double *noise5, /* returned 5th order MAD of all non-null pixels */ + int *status) /* error status */ + +/* +Estimate the median and background noise in the input image using 2nd, 3rd and 5th +order Median Absolute Differences. + +The noise in the background of the image is calculated using the MAD algorithms +developed for deriving the signal to noise ratio in spectra +(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/) + +3rd order: noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2))) + +The returned estimates are the median of the values that are computed for each +row of the image. +*/ +{ + long ii, jj, nrows = 0, nrows2 = 0, nvals, nvals2, ngoodpix = 0; + float *differences2, *differences3, *differences5; + float *rowpix, v1, v2, v3, v4, v5, v6, v7, v8, v9; + float xminval = FLT_MAX, xmaxval = -FLT_MAX; + int do_range = 0; + double *diffs2, *diffs3, *diffs5; + double xnoise2 = 0, xnoise3 = 0, xnoise5 = 0; + + if (nx < 5) { + /* treat entire array as an image with a single row */ + nx = nx * ny; + ny = 1; + } + + /* rows must have at least 9 pixels */ + if (nx < 9) { + + for (ii = 0; ii < nx; ii++) { + if (nullcheck && array[ii] == nullvalue) + continue; + else { + if (array[ii] < xminval) xminval = array[ii]; + if (array[ii] > xmaxval) xmaxval = array[ii]; + ngoodpix++; + } + } + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (ngood) *ngood = ngoodpix; + if (noise2) *noise2 = 0.; + if (noise3) *noise3 = 0.; + if (noise5) *noise5 = 0.; + return(*status); + } + + /* do we need to compute the min and max value? */ + if (minval || maxval) do_range = 1; + + /* allocate arrays used to compute the median and noise estimates */ + differences2 = calloc(nx, sizeof(float)); + if (!differences2) { + *status = MEMORY_ALLOCATION; + return(*status); + } + differences3 = calloc(nx, sizeof(float)); + if (!differences3) { + free(differences2); + *status = MEMORY_ALLOCATION; + return(*status); + } + differences5 = calloc(nx, sizeof(float)); + if (!differences5) { + free(differences2); + free(differences3); + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs2 = calloc(ny, sizeof(double)); + if (!diffs2) { + free(differences2); + free(differences3); + free(differences5); + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs3 = calloc(ny, sizeof(double)); + if (!diffs3) { + free(differences2); + free(differences3); + free(differences5); + free(diffs2); + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs5 = calloc(ny, sizeof(double)); + if (!diffs5) { + free(differences2); + free(differences3); + free(differences5); + free(diffs2); + free(diffs3); + *status = MEMORY_ALLOCATION; + return(*status); + } + + /* loop over each row of the image */ + for (jj=0; jj < ny; jj++) { + + rowpix = array + (jj * nx); /* point to first pixel in the row */ + + /***** find the first valid pixel in row */ + ii = 0; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v1 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v1 < xminval) xminval = v1; + if (v1 > xmaxval) xmaxval = v1; + } + + /***** find the 2nd valid pixel in row (which we will skip over) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v2 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v2 < xminval) xminval = v2; + if (v2 > xmaxval) xmaxval = v2; + } + + /***** find the 3rd valid pixel in row */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v3 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v3 < xminval) xminval = v3; + if (v3 > xmaxval) xmaxval = v3; + } + + /* find the 4nd valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v4 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v4 < xminval) xminval = v4; + if (v4 > xmaxval) xmaxval = v4; + } + + /* find the 5th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v5 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v5 < xminval) xminval = v5; + if (v5 > xmaxval) xmaxval = v5; + } + + /* find the 6th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v6 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v6 < xminval) xminval = v6; + if (v6 > xmaxval) xmaxval = v6; + } + + /* find the 7th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v7 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v7 < xminval) xminval = v7; + if (v7 > xmaxval) xmaxval = v7; + } + + /* find the 8th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v8 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v8 < xminval) xminval = v8; + if (v8 > xmaxval) xmaxval = v8; + } + /* now populate the differences arrays */ + /* for the remaining pixels in the row */ + nvals = 0; + nvals2 = 0; + for (ii++; ii < nx; ii++) { + + /* find the next valid pixel in row */ + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) break; /* hit end of row */ + v9 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v9 < xminval) xminval = v9; + if (v9 > xmaxval) xmaxval = v9; + } + + /* construct array of absolute differences */ + + if (!(v5 == v6 && v6 == v7) ) { + differences2[nvals2] = (float) fabs(v5 - v7); + nvals2++; + } + + if (!(v3 == v4 && v4 == v5 && v5 == v6 && v6 == v7) ) { + differences3[nvals] = (float) fabs((2 * v5) - v3 - v7); + differences5[nvals] = (float) fabs((6 * v5) - (4 * v3) - (4 * v7) + v1 + v9); + nvals++; + } else { + /* ignore constant background regions */ + ngoodpix++; + } + + /* shift over 1 pixel */ + v1 = v2; + v2 = v3; + v3 = v4; + v4 = v5; + v5 = v6; + v6 = v7; + v7 = v8; + v8 = v9; + } /* end of loop over pixels in the row */ + + /* compute the median diffs */ + /* Note that there are 8 more pixel values than there are diffs values. */ + ngoodpix += (nvals + 8); + + if (nvals == 0) { + continue; /* cannot compute medians on this row */ + } else if (nvals == 1) { + if (nvals2 == 1) { + diffs2[nrows2] = differences2[0]; + nrows2++; + } + + diffs3[nrows] = differences3[0]; + diffs5[nrows] = differences5[0]; + } else { + /* quick_select returns the median MUCH faster than using qsort */ + if (nvals2 > 1) { + diffs2[nrows2] = quick_select_float(differences2, nvals); + nrows2++; + } + + diffs3[nrows] = quick_select_float(differences3, nvals); + diffs5[nrows] = quick_select_float(differences5, nvals); + } + + nrows++; + } /* end of loop over rows */ + + /* compute median of the values for each row */ + if (nrows == 0) { + xnoise3 = 0; + xnoise5 = 0; + } else if (nrows == 1) { + xnoise3 = diffs3[0]; + xnoise5 = diffs5[0]; + } else { + qsort(diffs3, nrows, sizeof(double), FnCompare_double); + qsort(diffs5, nrows, sizeof(double), FnCompare_double); + xnoise3 = (diffs3[(nrows - 1)/2] + diffs3[nrows/2]) / 2.; + xnoise5 = (diffs5[(nrows - 1)/2] + diffs5[nrows/2]) / 2.; + } + + if (nrows2 == 0) { + xnoise2 = 0; + } else if (nrows2 == 1) { + xnoise2 = diffs2[0]; + } else { + qsort(diffs2, nrows2, sizeof(double), FnCompare_double); + xnoise2 = (diffs2[(nrows2 - 1)/2] + diffs2[nrows2/2]) / 2.; + } + + if (ngood) *ngood = ngoodpix; + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (noise2) *noise2 = 1.0483579 * xnoise2; + if (noise3) *noise3 = 0.6052697 * xnoise3; + if (noise5) *noise5 = 0.1772048 * xnoise5; + + free(diffs5); + free(diffs3); + free(diffs2); + free(differences5); + free(differences3); + free(differences2); + + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnNoise5_double + (double *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + int nullcheck, /* check for null values, if true */ + double nullvalue, /* value of null pixels, if nullcheck is true */ + /* returned parameters */ + long *ngood, /* number of good, non-null pixels? */ + double *minval, /* minimum non-null value */ + double *maxval, /* maximum non-null value */ + double *noise2, /* returned 2nd order MAD of all non-null pixels */ + double *noise3, /* returned 3rd order MAD of all non-null pixels */ + double *noise5, /* returned 5th order MAD of all non-null pixels */ + int *status) /* error status */ + +/* +Estimate the median and background noise in the input image using 2nd, 3rd and 5th +order Median Absolute Differences. + +The noise in the background of the image is calculated using the MAD algorithms +developed for deriving the signal to noise ratio in spectra +(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/) + +3rd order: noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2))) + +The returned estimates are the median of the values that are computed for each +row of the image. +*/ +{ + long ii, jj, nrows = 0, nrows2 = 0, nvals, nvals2, ngoodpix = 0; + double *differences2, *differences3, *differences5; + double *rowpix, v1, v2, v3, v4, v5, v6, v7, v8, v9; + double xminval = DBL_MAX, xmaxval = -DBL_MAX; + int do_range = 0; + double *diffs2, *diffs3, *diffs5; + double xnoise2 = 0, xnoise3 = 0, xnoise5 = 0; + + if (nx < 5) { + /* treat entire array as an image with a single row */ + nx = nx * ny; + ny = 1; + } + + /* rows must have at least 9 pixels */ + if (nx < 9) { + + for (ii = 0; ii < nx; ii++) { + if (nullcheck && array[ii] == nullvalue) + continue; + else { + if (array[ii] < xminval) xminval = array[ii]; + if (array[ii] > xmaxval) xmaxval = array[ii]; + ngoodpix++; + } + } + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (ngood) *ngood = ngoodpix; + if (noise2) *noise2 = 0.; + if (noise3) *noise3 = 0.; + if (noise5) *noise5 = 0.; + return(*status); + } + + /* do we need to compute the min and max value? */ + if (minval || maxval) do_range = 1; + + /* allocate arrays used to compute the median and noise estimates */ + differences2 = calloc(nx, sizeof(double)); + if (!differences2) { + *status = MEMORY_ALLOCATION; + return(*status); + } + differences3 = calloc(nx, sizeof(double)); + if (!differences3) { + free(differences2); + *status = MEMORY_ALLOCATION; + return(*status); + } + differences5 = calloc(nx, sizeof(double)); + if (!differences5) { + free(differences2); + free(differences3); + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs2 = calloc(ny, sizeof(double)); + if (!diffs2) { + free(differences2); + free(differences3); + free(differences5); + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs3 = calloc(ny, sizeof(double)); + if (!diffs3) { + free(differences2); + free(differences3); + free(differences5); + free(diffs2); + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs5 = calloc(ny, sizeof(double)); + if (!diffs5) { + free(differences2); + free(differences3); + free(differences5); + free(diffs2); + free(diffs3); + *status = MEMORY_ALLOCATION; + return(*status); + } + + /* loop over each row of the image */ + for (jj=0; jj < ny; jj++) { + + rowpix = array + (jj * nx); /* point to first pixel in the row */ + + /***** find the first valid pixel in row */ + ii = 0; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v1 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v1 < xminval) xminval = v1; + if (v1 > xmaxval) xmaxval = v1; + } + + /***** find the 2nd valid pixel in row (which we will skip over) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v2 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v2 < xminval) xminval = v2; + if (v2 > xmaxval) xmaxval = v2; + } + + /***** find the 3rd valid pixel in row */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v3 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v3 < xminval) xminval = v3; + if (v3 > xmaxval) xmaxval = v3; + } + + /* find the 4nd valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v4 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v4 < xminval) xminval = v4; + if (v4 > xmaxval) xmaxval = v4; + } + + /* find the 5th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v5 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v5 < xminval) xminval = v5; + if (v5 > xmaxval) xmaxval = v5; + } + + /* find the 6th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v6 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v6 < xminval) xminval = v6; + if (v6 > xmaxval) xmaxval = v6; + } + + /* find the 7th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v7 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v7 < xminval) xminval = v7; + if (v7 > xmaxval) xmaxval = v7; + } + + /* find the 8th valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v8 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v8 < xminval) xminval = v8; + if (v8 > xmaxval) xmaxval = v8; + } + /* now populate the differences arrays */ + /* for the remaining pixels in the row */ + nvals = 0; + nvals2 = 0; + for (ii++; ii < nx; ii++) { + + /* find the next valid pixel in row */ + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) break; /* hit end of row */ + v9 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v9 < xminval) xminval = v9; + if (v9 > xmaxval) xmaxval = v9; + } + + /* construct array of absolute differences */ + + if (!(v5 == v6 && v6 == v7) ) { + differences2[nvals2] = fabs(v5 - v7); + nvals2++; + } + + if (!(v3 == v4 && v4 == v5 && v5 == v6 && v6 == v7) ) { + differences3[nvals] = fabs((2 * v5) - v3 - v7); + differences5[nvals] = fabs((6 * v5) - (4 * v3) - (4 * v7) + v1 + v9); + nvals++; + } else { + /* ignore constant background regions */ + ngoodpix++; + } + + /* shift over 1 pixel */ + v1 = v2; + v2 = v3; + v3 = v4; + v4 = v5; + v5 = v6; + v6 = v7; + v7 = v8; + v8 = v9; + } /* end of loop over pixels in the row */ + + /* compute the median diffs */ + /* Note that there are 8 more pixel values than there are diffs values. */ + ngoodpix += (nvals + 8); + + if (nvals == 0) { + continue; /* cannot compute medians on this row */ + } else if (nvals == 1) { + if (nvals2 == 1) { + diffs2[nrows2] = differences2[0]; + nrows2++; + } + + diffs3[nrows] = differences3[0]; + diffs5[nrows] = differences5[0]; + } else { + /* quick_select returns the median MUCH faster than using qsort */ + if (nvals2 > 1) { + diffs2[nrows2] = quick_select_double(differences2, nvals); + nrows2++; + } + + diffs3[nrows] = quick_select_double(differences3, nvals); + diffs5[nrows] = quick_select_double(differences5, nvals); + } + + nrows++; + } /* end of loop over rows */ + + /* compute median of the values for each row */ + if (nrows == 0) { + xnoise3 = 0; + xnoise5 = 0; + } else if (nrows == 1) { + xnoise3 = diffs3[0]; + xnoise5 = diffs5[0]; + } else { + qsort(diffs3, nrows, sizeof(double), FnCompare_double); + qsort(diffs5, nrows, sizeof(double), FnCompare_double); + xnoise3 = (diffs3[(nrows - 1)/2] + diffs3[nrows/2]) / 2.; + xnoise5 = (diffs5[(nrows - 1)/2] + diffs5[nrows/2]) / 2.; + } + + if (nrows2 == 0) { + xnoise2 = 0; + } else if (nrows2 == 1) { + xnoise2 = diffs2[0]; + } else { + qsort(diffs2, nrows2, sizeof(double), FnCompare_double); + xnoise2 = (diffs2[(nrows2 - 1)/2] + diffs2[nrows2/2]) / 2.; + } + + if (ngood) *ngood = ngoodpix; + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (noise2) *noise2 = 1.0483579 * xnoise2; + if (noise3) *noise3 = 0.6052697 * xnoise3; + if (noise5) *noise5 = 0.1772048 * xnoise5; + + free(diffs5); + free(diffs3); + free(diffs2); + free(differences5); + free(differences3); + free(differences2); + + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnNoise3_short + (short *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + int nullcheck, /* check for null values, if true */ + short nullvalue, /* value of null pixels, if nullcheck is true */ + /* returned parameters */ + long *ngood, /* number of good, non-null pixels? */ + short *minval, /* minimum non-null value */ + short *maxval, /* maximum non-null value */ + double *noise, /* returned R.M.S. value of all non-null pixels */ + int *status) /* error status */ + +/* +Estimate the median and background noise in the input image using 3rd order differences. + +The noise in the background of the image is calculated using the 3rd order algorithm +developed for deriving the signal to noise ratio in spectra +(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/) + + noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2))) + +The returned estimates are the median of the values that are computed for each +row of the image. +*/ +{ + long ii, jj, nrows = 0, nvals, ngoodpix = 0; + short *differences, *rowpix, v1, v2, v3, v4, v5; + short xminval = SHRT_MAX, xmaxval = SHRT_MIN, do_range = 0; + double *diffs, xnoise = 0, sigma; + + if (nx < 5) { + /* treat entire array as an image with a single row */ + nx = nx * ny; + ny = 1; + } + + /* rows must have at least 5 pixels */ + if (nx < 5) { + + for (ii = 0; ii < nx; ii++) { + if (nullcheck && array[ii] == nullvalue) + continue; + else { + if (array[ii] < xminval) xminval = array[ii]; + if (array[ii] > xmaxval) xmaxval = array[ii]; + ngoodpix++; + } + } + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (ngood) *ngood = ngoodpix; + if (noise) *noise = 0.; + return(*status); + } + + /* do we need to compute the min and max value? */ + if (minval || maxval) do_range = 1; + + /* allocate arrays used to compute the median and noise estimates */ + differences = calloc(nx, sizeof(short)); + if (!differences) { + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs = calloc(ny, sizeof(double)); + if (!diffs) { + free(differences); + *status = MEMORY_ALLOCATION; + return(*status); + } + + /* loop over each row of the image */ + for (jj=0; jj < ny; jj++) { + + rowpix = array + (jj * nx); /* point to first pixel in the row */ + + /***** find the first valid pixel in row */ + ii = 0; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v1 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v1 < xminval) xminval = v1; + if (v1 > xmaxval) xmaxval = v1; + } + + /***** find the 2nd valid pixel in row (which we will skip over) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v2 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v2 < xminval) xminval = v2; + if (v2 > xmaxval) xmaxval = v2; + } + + /***** find the 3rd valid pixel in row */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v3 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v3 < xminval) xminval = v3; + if (v3 > xmaxval) xmaxval = v3; + } + + /* find the 4nd valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v4 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v4 < xminval) xminval = v4; + if (v4 > xmaxval) xmaxval = v4; + } + + /* now populate the differences arrays */ + /* for the remaining pixels in the row */ + nvals = 0; + for (ii++; ii < nx; ii++) { + + /* find the next valid pixel in row */ + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) break; /* hit end of row */ + v5 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v5 < xminval) xminval = v5; + if (v5 > xmaxval) xmaxval = v5; + } + + /* construct array of 3rd order absolute differences */ + if (!(v1 == v2 && v2 == v3 && v3 == v4 && v4 == v5)) { + differences[nvals] = abs((2 * v3) - v1 - v5); + nvals++; + } else { + /* ignore constant background regions */ + ngoodpix++; + } + + + /* shift over 1 pixel */ + v1 = v2; + v2 = v3; + v3 = v4; + v4 = v5; + } /* end of loop over pixels in the row */ + + /* compute the 3rd order diffs */ + /* Note that there are 4 more pixel values than there are diffs values. */ + ngoodpix += (nvals + 4); + + if (nvals == 0) { + continue; /* cannot compute medians on this row */ + } else if (nvals == 1) { + diffs[nrows] = differences[0]; + } else { + /* quick_select returns the median MUCH faster than using qsort */ + diffs[nrows] = quick_select_short(differences, nvals); + } + + nrows++; + } /* end of loop over rows */ + + /* compute median of the values for each row */ + if (nrows == 0) { + xnoise = 0; + } else if (nrows == 1) { + xnoise = diffs[0]; + } else { + + + qsort(diffs, nrows, sizeof(double), FnCompare_double); + xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.; + + FnMeanSigma_double(diffs, nrows, 0, 0.0, 0, &xnoise, &sigma, status); + + /* do a 4.5 sigma rejection of outliers */ + jj = 0; + sigma = 4.5 * sigma; + for (ii = 0; ii < nrows; ii++) { + if ( fabs(diffs[ii] - xnoise) <= sigma) { + if (jj != ii) + diffs[jj] = diffs[ii]; + jj++; + } + } + if (ii != jj) + FnMeanSigma_double(diffs, jj, 0, 0.0, 0, &xnoise, &sigma, status); + } + + if (ngood) *ngood = ngoodpix; + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (noise) *noise = 0.6052697 * xnoise; + + free(diffs); + free(differences); + + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnNoise3_int + (int *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + int nullcheck, /* check for null values, if true */ + int nullvalue, /* value of null pixels, if nullcheck is true */ + /* returned parameters */ + long *ngood, /* number of good, non-null pixels? */ + int *minval, /* minimum non-null value */ + int *maxval, /* maximum non-null value */ + double *noise, /* returned R.M.S. value of all non-null pixels */ + int *status) /* error status */ + +/* +Estimate the background noise in the input image using 3rd order differences. + +The noise in the background of the image is calculated using the 3rd order algorithm +developed for deriving the signal to noise ratio in spectra +(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/) + + noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2))) + +The returned estimates are the median of the values that are computed for each +row of the image. +*/ +{ + long ii, jj, nrows = 0, nvals, ngoodpix = 0; + int *differences, *rowpix, v1, v2, v3, v4, v5; + int xminval = INT_MAX, xmaxval = INT_MIN, do_range = 0; + double *diffs, xnoise = 0, sigma; + + if (nx < 5) { + /* treat entire array as an image with a single row */ + nx = nx * ny; + ny = 1; + } + + /* rows must have at least 5 pixels */ + if (nx < 5) { + + for (ii = 0; ii < nx; ii++) { + if (nullcheck && array[ii] == nullvalue) + continue; + else { + if (array[ii] < xminval) xminval = array[ii]; + if (array[ii] > xmaxval) xmaxval = array[ii]; + ngoodpix++; + } + } + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (ngood) *ngood = ngoodpix; + if (noise) *noise = 0.; + return(*status); + } + + /* do we need to compute the min and max value? */ + if (minval || maxval) do_range = 1; + + /* allocate arrays used to compute the median and noise estimates */ + differences = calloc(nx, sizeof(int)); + if (!differences) { + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs = calloc(ny, sizeof(double)); + if (!diffs) { + free(differences); + *status = MEMORY_ALLOCATION; + return(*status); + } + + /* loop over each row of the image */ + for (jj=0; jj < ny; jj++) { + + rowpix = array + (jj * nx); /* point to first pixel in the row */ + + /***** find the first valid pixel in row */ + ii = 0; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v1 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v1 < xminval) xminval = v1; + if (v1 > xmaxval) xmaxval = v1; + } + + /***** find the 2nd valid pixel in row (which we will skip over) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v2 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v2 < xminval) xminval = v2; + if (v2 > xmaxval) xmaxval = v2; + } + + /***** find the 3rd valid pixel in row */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v3 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v3 < xminval) xminval = v3; + if (v3 > xmaxval) xmaxval = v3; + } + + /* find the 4nd valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v4 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v4 < xminval) xminval = v4; + if (v4 > xmaxval) xmaxval = v4; + } + + /* now populate the differences arrays */ + /* for the remaining pixels in the row */ + nvals = 0; + for (ii++; ii < nx; ii++) { + + /* find the next valid pixel in row */ + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) break; /* hit end of row */ + v5 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v5 < xminval) xminval = v5; + if (v5 > xmaxval) xmaxval = v5; + } + + /* construct array of 3rd order absolute differences */ + if (!(v1 == v2 && v2 == v3 && v3 == v4 && v4 == v5)) { + differences[nvals] = abs((2 * v3) - v1 - v5); + nvals++; + } else { + /* ignore constant background regions */ + ngoodpix++; + } + + /* shift over 1 pixel */ + v1 = v2; + v2 = v3; + v3 = v4; + v4 = v5; + } /* end of loop over pixels in the row */ + + /* compute the 3rd order diffs */ + /* Note that there are 4 more pixel values than there are diffs values. */ + ngoodpix += (nvals + 4); + + if (nvals == 0) { + continue; /* cannot compute medians on this row */ + } else if (nvals == 1) { + diffs[nrows] = differences[0]; + } else { + /* quick_select returns the median MUCH faster than using qsort */ + diffs[nrows] = quick_select_int(differences, nvals); + } + + nrows++; + } /* end of loop over rows */ + + /* compute median of the values for each row */ + if (nrows == 0) { + xnoise = 0; + } else if (nrows == 1) { + xnoise = diffs[0]; + } else { + + qsort(diffs, nrows, sizeof(double), FnCompare_double); + xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.; + + FnMeanSigma_double(diffs, nrows, 0, 0.0, 0, &xnoise, &sigma, status); + + /* do a 4.5 sigma rejection of outliers */ + jj = 0; + sigma = 4.5 * sigma; + for (ii = 0; ii < nrows; ii++) { + if ( fabs(diffs[ii] - xnoise) <= sigma) { + if (jj != ii) + diffs[jj] = diffs[ii]; + jj++; + } + } + if (ii != jj) + FnMeanSigma_double(diffs, jj, 0, 0.0, 0, &xnoise, &sigma, status); + } + + if (ngood) *ngood = ngoodpix; + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (noise) *noise = 0.6052697 * xnoise; + + free(diffs); + free(differences); + + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnNoise3_float + (float *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + int nullcheck, /* check for null values, if true */ + float nullvalue, /* value of null pixels, if nullcheck is true */ + /* returned parameters */ + long *ngood, /* number of good, non-null pixels? */ + float *minval, /* minimum non-null value */ + float *maxval, /* maximum non-null value */ + double *noise, /* returned R.M.S. value of all non-null pixels */ + int *status) /* error status */ + +/* +Estimate the median and background noise in the input image using 3rd order differences. + +The noise in the background of the image is calculated using the 3rd order algorithm +developed for deriving the signal to noise ratio in spectra +(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/) + + noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2))) + +The returned estimates are the median of the values that are computed for each +row of the image. +*/ +{ + long ii, jj, nrows = 0, nvals, ngoodpix = 0; + float *differences, *rowpix, v1, v2, v3, v4, v5; + float xminval = FLT_MAX, xmaxval = -FLT_MAX; + int do_range = 0; + double *diffs, xnoise = 0; + + if (nx < 5) { + /* treat entire array as an image with a single row */ + nx = nx * ny; + ny = 1; + } + + /* rows must have at least 5 pixels to calc noise, so just calc min, max, ngood */ + if (nx < 5) { + + for (ii = 0; ii < nx; ii++) { + if (nullcheck && array[ii] == nullvalue) + continue; + else { + if (array[ii] < xminval) xminval = array[ii]; + if (array[ii] > xmaxval) xmaxval = array[ii]; + ngoodpix++; + } + } + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (ngood) *ngood = ngoodpix; + if (noise) *noise = 0.; + return(*status); + } + + /* do we need to compute the min and max value? */ + if (minval || maxval) do_range = 1; + + /* allocate arrays used to compute the median and noise estimates */ + if (noise) { + differences = calloc(nx, sizeof(float)); + if (!differences) { + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs = calloc(ny, sizeof(double)); + if (!diffs) { + free(differences); + *status = MEMORY_ALLOCATION; + return(*status); + } + } + + /* loop over each row of the image */ + for (jj=0; jj < ny; jj++) { + + rowpix = array + (jj * nx); /* point to first pixel in the row */ + + /***** find the first valid pixel in row */ + ii = 0; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v1 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v1 < xminval) xminval = v1; + if (v1 > xmaxval) xmaxval = v1; + } + + /***** find the 2nd valid pixel in row (which we will skip over) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v2 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v2 < xminval) xminval = v2; + if (v2 > xmaxval) xmaxval = v2; + } + + /***** find the 3rd valid pixel in row */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v3 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v3 < xminval) xminval = v3; + if (v3 > xmaxval) xmaxval = v3; + } + + /* find the 4nd valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v4 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v4 < xminval) xminval = v4; + if (v4 > xmaxval) xmaxval = v4; + } + + /* now populate the differences arrays */ + /* for the remaining pixels in the row */ + nvals = 0; + for (ii++; ii < nx; ii++) { + + /* find the next valid pixel in row */ + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) { + ii++; + } + + if (ii == nx) break; /* hit end of row */ + v5 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v5 < xminval) xminval = v5; + if (v5 > xmaxval) xmaxval = v5; + } + + /* construct array of 3rd order absolute differences */ + if (noise) { + if (!(v1 == v2 && v2 == v3 && v3 == v4 && v4 == v5)) { + + differences[nvals] = (float) fabs((2. * v3) - v1 - v5); + nvals++; + } else { + /* ignore constant background regions */ + ngoodpix++; + } + } else { + /* just increment the number of non-null pixels */ + ngoodpix++; + } + + /* shift over 1 pixel */ + v1 = v2; + v2 = v3; + v3 = v4; + v4 = v5; + } /* end of loop over pixels in the row */ + + /* compute the 3rd order diffs */ + /* Note that there are 4 more pixel values than there are diffs values. */ + ngoodpix += (nvals + 4); + + if (noise) { + if (nvals == 0) { + continue; /* cannot compute medians on this row */ + } else if (nvals == 1) { + diffs[nrows] = differences[0]; + } else { + /* quick_select returns the median MUCH faster than using qsort */ + diffs[nrows] = quick_select_float(differences, nvals); + } + } + nrows++; + } /* end of loop over rows */ + + /* compute median of the values for each row */ + if (noise) { + if (nrows == 0) { + xnoise = 0; + } else if (nrows == 1) { + xnoise = diffs[0]; + } else { + qsort(diffs, nrows, sizeof(double), FnCompare_double); + xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.; + } + } + + if (ngood) *ngood = ngoodpix; + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (noise) { + *noise = 0.6052697 * xnoise; + free(diffs); + free(differences); + } + + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnNoise3_double + (double *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + int nullcheck, /* check for null values, if true */ + double nullvalue, /* value of null pixels, if nullcheck is true */ + /* returned parameters */ + long *ngood, /* number of good, non-null pixels? */ + double *minval, /* minimum non-null value */ + double *maxval, /* maximum non-null value */ + double *noise, /* returned R.M.S. value of all non-null pixels */ + int *status) /* error status */ + +/* +Estimate the median and background noise in the input image using 3rd order differences. + +The noise in the background of the image is calculated using the 3rd order algorithm +developed for deriving the signal to noise ratio in spectra +(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/) + + noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2))) + +The returned estimates are the median of the values that are computed for each +row of the image. +*/ +{ + long ii, jj, nrows = 0, nvals, ngoodpix = 0; + double *differences, *rowpix, v1, v2, v3, v4, v5; + double xminval = DBL_MAX, xmaxval = -DBL_MAX; + int do_range = 0; + double *diffs, xnoise = 0; + + if (nx < 5) { + /* treat entire array as an image with a single row */ + nx = nx * ny; + ny = 1; + } + + /* rows must have at least 5 pixels */ + if (nx < 5) { + + for (ii = 0; ii < nx; ii++) { + if (nullcheck && array[ii] == nullvalue) + continue; + else { + if (array[ii] < xminval) xminval = array[ii]; + if (array[ii] > xmaxval) xmaxval = array[ii]; + ngoodpix++; + } + } + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (ngood) *ngood = ngoodpix; + if (noise) *noise = 0.; + return(*status); + } + + /* do we need to compute the min and max value? */ + if (minval || maxval) do_range = 1; + + /* allocate arrays used to compute the median and noise estimates */ + if (noise) { + differences = calloc(nx, sizeof(double)); + if (!differences) { + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs = calloc(ny, sizeof(double)); + if (!diffs) { + free(differences); + *status = MEMORY_ALLOCATION; + return(*status); + } + } + + /* loop over each row of the image */ + for (jj=0; jj < ny; jj++) { + + rowpix = array + (jj * nx); /* point to first pixel in the row */ + + /***** find the first valid pixel in row */ + ii = 0; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v1 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v1 < xminval) xminval = v1; + if (v1 > xmaxval) xmaxval = v1; + } + + /***** find the 2nd valid pixel in row (which we will skip over) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v2 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v2 < xminval) xminval = v2; + if (v2 > xmaxval) xmaxval = v2; + } + + /***** find the 3rd valid pixel in row */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v3 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v3 < xminval) xminval = v3; + if (v3 > xmaxval) xmaxval = v3; + } + + /* find the 4nd valid pixel in row (to be skipped) */ + ii++; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v4 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v4 < xminval) xminval = v4; + if (v4 > xmaxval) xmaxval = v4; + } + + /* now populate the differences arrays */ + /* for the remaining pixels in the row */ + nvals = 0; + for (ii++; ii < nx; ii++) { + + /* find the next valid pixel in row */ + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) break; /* hit end of row */ + v5 = rowpix[ii]; /* store the good pixel value */ + + if (do_range) { + if (v5 < xminval) xminval = v5; + if (v5 > xmaxval) xmaxval = v5; + } + + /* construct array of 3rd order absolute differences */ + if (noise) { + if (!(v1 == v2 && v2 == v3 && v3 == v4 && v4 == v5)) { + + differences[nvals] = fabs((2. * v3) - v1 - v5); + nvals++; + } else { + /* ignore constant background regions */ + ngoodpix++; + } + } else { + /* just increment the number of non-null pixels */ + ngoodpix++; + } + + /* shift over 1 pixel */ + v1 = v2; + v2 = v3; + v3 = v4; + v4 = v5; + } /* end of loop over pixels in the row */ + + /* compute the 3rd order diffs */ + /* Note that there are 4 more pixel values than there are diffs values. */ + ngoodpix += (nvals + 4); + + if (noise) { + if (nvals == 0) { + continue; /* cannot compute medians on this row */ + } else if (nvals == 1) { + diffs[nrows] = differences[0]; + } else { + /* quick_select returns the median MUCH faster than using qsort */ + diffs[nrows] = quick_select_double(differences, nvals); + } + } + nrows++; + } /* end of loop over rows */ + + /* compute median of the values for each row */ + if (noise) { + if (nrows == 0) { + xnoise = 0; + } else if (nrows == 1) { + xnoise = diffs[0]; + } else { + qsort(diffs, nrows, sizeof(double), FnCompare_double); + xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.; + } + } + + if (ngood) *ngood = ngoodpix; + if (minval) *minval = xminval; + if (maxval) *maxval = xmaxval; + if (noise) { + *noise = 0.6052697 * xnoise; + free(diffs); + free(differences); + } + + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnNoise1_short + (short *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + int nullcheck, /* check for null values, if true */ + short nullvalue, /* value of null pixels, if nullcheck is true */ + /* returned parameters */ + double *noise, /* returned R.M.S. value of all non-null pixels */ + int *status) /* error status */ +/* +Estimate the background noise in the input image using sigma of 1st order differences. + + noise = 1.0 / sqrt(2) * rms of (flux[i] - flux[i-1]) + +The returned estimate is the median of the values that are computed for each +row of the image. +*/ +{ + int iter; + long ii, jj, kk, nrows = 0, nvals; + short *differences, *rowpix, v1; + double *diffs, xnoise, mean, stdev; + + /* rows must have at least 3 pixels to estimate noise */ + if (nx < 3) { + *noise = 0; + return(*status); + } + + /* allocate arrays used to compute the median and noise estimates */ + differences = calloc(nx, sizeof(short)); + if (!differences) { + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs = calloc(ny, sizeof(double)); + if (!diffs) { + free(differences); + *status = MEMORY_ALLOCATION; + return(*status); + } + + /* loop over each row of the image */ + for (jj=0; jj < ny; jj++) { + + rowpix = array + (jj * nx); /* point to first pixel in the row */ + + /***** find the first valid pixel in row */ + ii = 0; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v1 = rowpix[ii]; /* store the good pixel value */ + + /* now continue populating the differences arrays */ + /* for the remaining pixels in the row */ + nvals = 0; + for (ii++; ii < nx; ii++) { + + /* find the next valid pixel in row */ + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) break; /* hit end of row */ + + /* construct array of 1st order differences */ + differences[nvals] = v1 - rowpix[ii]; + + nvals++; + /* shift over 1 pixel */ + v1 = rowpix[ii]; + } /* end of loop over pixels in the row */ + + if (nvals < 2) + continue; + else { + + FnMeanSigma_short(differences, nvals, 0, 0, 0, &mean, &stdev, status); + + if (stdev > 0.) { + for (iter = 0; iter < NITER; iter++) { + kk = 0; + for (ii = 0; ii < nvals; ii++) { + if (fabs (differences[ii] - mean) < SIGMA_CLIP * stdev) { + if (kk < ii) + differences[kk] = differences[ii]; + kk++; + } + } + if (kk == nvals) break; + + nvals = kk; + FnMeanSigma_short(differences, nvals, 0, 0, 0, &mean, &stdev, status); + } + } + + diffs[nrows] = stdev; + nrows++; + } + } /* end of loop over rows */ + + /* compute median of the values for each row */ + if (nrows == 0) { + xnoise = 0; + } else if (nrows == 1) { + xnoise = diffs[0]; + } else { + qsort(diffs, nrows, sizeof(double), FnCompare_double); + xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.; + } + + *noise = .70710678 * xnoise; + + free(diffs); + free(differences); + + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnNoise1_int + (int *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + int nullcheck, /* check for null values, if true */ + int nullvalue, /* value of null pixels, if nullcheck is true */ + /* returned parameters */ + double *noise, /* returned R.M.S. value of all non-null pixels */ + int *status) /* error status */ +/* +Estimate the background noise in the input image using sigma of 1st order differences. + + noise = 1.0 / sqrt(2) * rms of (flux[i] - flux[i-1]) + +The returned estimate is the median of the values that are computed for each +row of the image. +*/ +{ + int iter; + long ii, jj, kk, nrows = 0, nvals; + int *differences, *rowpix, v1; + double *diffs, xnoise, mean, stdev; + + /* rows must have at least 3 pixels to estimate noise */ + if (nx < 3) { + *noise = 0; + return(*status); + } + + /* allocate arrays used to compute the median and noise estimates */ + differences = calloc(nx, sizeof(int)); + if (!differences) { + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs = calloc(ny, sizeof(double)); + if (!diffs) { + free(differences); + *status = MEMORY_ALLOCATION; + return(*status); + } + + /* loop over each row of the image */ + for (jj=0; jj < ny; jj++) { + + rowpix = array + (jj * nx); /* point to first pixel in the row */ + + /***** find the first valid pixel in row */ + ii = 0; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v1 = rowpix[ii]; /* store the good pixel value */ + + /* now continue populating the differences arrays */ + /* for the remaining pixels in the row */ + nvals = 0; + for (ii++; ii < nx; ii++) { + + /* find the next valid pixel in row */ + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) break; /* hit end of row */ + + /* construct array of 1st order differences */ + differences[nvals] = v1 - rowpix[ii]; + + nvals++; + /* shift over 1 pixel */ + v1 = rowpix[ii]; + } /* end of loop over pixels in the row */ + + if (nvals < 2) + continue; + else { + + FnMeanSigma_int(differences, nvals, 0, 0, 0, &mean, &stdev, status); + + if (stdev > 0.) { + for (iter = 0; iter < NITER; iter++) { + kk = 0; + for (ii = 0; ii < nvals; ii++) { + if (fabs (differences[ii] - mean) < SIGMA_CLIP * stdev) { + if (kk < ii) + differences[kk] = differences[ii]; + kk++; + } + } + if (kk == nvals) break; + + nvals = kk; + FnMeanSigma_int(differences, nvals, 0, 0, 0, &mean, &stdev, status); + } + } + + diffs[nrows] = stdev; + nrows++; + } + } /* end of loop over rows */ + + /* compute median of the values for each row */ + if (nrows == 0) { + xnoise = 0; + } else if (nrows == 1) { + xnoise = diffs[0]; + } else { + qsort(diffs, nrows, sizeof(double), FnCompare_double); + xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.; + } + + *noise = .70710678 * xnoise; + + free(diffs); + free(differences); + + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnNoise1_float + (float *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + int nullcheck, /* check for null values, if true */ + float nullvalue, /* value of null pixels, if nullcheck is true */ + /* returned parameters */ + double *noise, /* returned R.M.S. value of all non-null pixels */ + int *status) /* error status */ +/* +Estimate the background noise in the input image using sigma of 1st order differences. + + noise = 1.0 / sqrt(2) * rms of (flux[i] - flux[i-1]) + +The returned estimate is the median of the values that are computed for each +row of the image. +*/ +{ + int iter; + long ii, jj, kk, nrows = 0, nvals; + float *differences, *rowpix, v1; + double *diffs, xnoise, mean, stdev; + + /* rows must have at least 3 pixels to estimate noise */ + if (nx < 3) { + *noise = 0; + return(*status); + } + + /* allocate arrays used to compute the median and noise estimates */ + differences = calloc(nx, sizeof(float)); + if (!differences) { + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs = calloc(ny, sizeof(double)); + if (!diffs) { + free(differences); + *status = MEMORY_ALLOCATION; + return(*status); + } + + /* loop over each row of the image */ + for (jj=0; jj < ny; jj++) { + + rowpix = array + (jj * nx); /* point to first pixel in the row */ + + /***** find the first valid pixel in row */ + ii = 0; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v1 = rowpix[ii]; /* store the good pixel value */ + + /* now continue populating the differences arrays */ + /* for the remaining pixels in the row */ + nvals = 0; + for (ii++; ii < nx; ii++) { + + /* find the next valid pixel in row */ + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) break; /* hit end of row */ + + /* construct array of 1st order differences */ + differences[nvals] = v1 - rowpix[ii]; + + nvals++; + /* shift over 1 pixel */ + v1 = rowpix[ii]; + } /* end of loop over pixels in the row */ + + if (nvals < 2) + continue; + else { + + FnMeanSigma_float(differences, nvals, 0, 0, 0, &mean, &stdev, status); + + if (stdev > 0.) { + for (iter = 0; iter < NITER; iter++) { + kk = 0; + for (ii = 0; ii < nvals; ii++) { + if (fabs (differences[ii] - mean) < SIGMA_CLIP * stdev) { + if (kk < ii) + differences[kk] = differences[ii]; + kk++; + } + } + if (kk == nvals) break; + + nvals = kk; + FnMeanSigma_float(differences, nvals, 0, 0, 0, &mean, &stdev, status); + } + } + + diffs[nrows] = stdev; + nrows++; + } + } /* end of loop over rows */ + + /* compute median of the values for each row */ + if (nrows == 0) { + xnoise = 0; + } else if (nrows == 1) { + xnoise = diffs[0]; + } else { + qsort(diffs, nrows, sizeof(double), FnCompare_double); + xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.; + } + + *noise = .70710678 * xnoise; + + free(diffs); + free(differences); + + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnNoise1_double + (double *array, /* 2 dimensional array of image pixels */ + long nx, /* number of pixels in each row of the image */ + long ny, /* number of rows in the image */ + int nullcheck, /* check for null values, if true */ + double nullvalue, /* value of null pixels, if nullcheck is true */ + /* returned parameters */ + double *noise, /* returned R.M.S. value of all non-null pixels */ + int *status) /* error status */ +/* +Estimate the background noise in the input image using sigma of 1st order differences. + + noise = 1.0 / sqrt(2) * rms of (flux[i] - flux[i-1]) + +The returned estimate is the median of the values that are computed for each +row of the image. +*/ +{ + int iter; + long ii, jj, kk, nrows = 0, nvals; + double *differences, *rowpix, v1; + double *diffs, xnoise, mean, stdev; + + /* rows must have at least 3 pixels to estimate noise */ + if (nx < 3) { + *noise = 0; + return(*status); + } + + /* allocate arrays used to compute the median and noise estimates */ + differences = calloc(nx, sizeof(double)); + if (!differences) { + *status = MEMORY_ALLOCATION; + return(*status); + } + + diffs = calloc(ny, sizeof(double)); + if (!diffs) { + free(differences); + *status = MEMORY_ALLOCATION; + return(*status); + } + + /* loop over each row of the image */ + for (jj=0; jj < ny; jj++) { + + rowpix = array + (jj * nx); /* point to first pixel in the row */ + + /***** find the first valid pixel in row */ + ii = 0; + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) continue; /* hit end of row */ + v1 = rowpix[ii]; /* store the good pixel value */ + + /* now continue populating the differences arrays */ + /* for the remaining pixels in the row */ + nvals = 0; + for (ii++; ii < nx; ii++) { + + /* find the next valid pixel in row */ + if (nullcheck) + while (ii < nx && rowpix[ii] == nullvalue) ii++; + + if (ii == nx) break; /* hit end of row */ + + /* construct array of 1st order differences */ + differences[nvals] = v1 - rowpix[ii]; + + nvals++; + /* shift over 1 pixel */ + v1 = rowpix[ii]; + } /* end of loop over pixels in the row */ + + if (nvals < 2) + continue; + else { + + FnMeanSigma_double(differences, nvals, 0, 0, 0, &mean, &stdev, status); + + if (stdev > 0.) { + for (iter = 0; iter < NITER; iter++) { + kk = 0; + for (ii = 0; ii < nvals; ii++) { + if (fabs (differences[ii] - mean) < SIGMA_CLIP * stdev) { + if (kk < ii) + differences[kk] = differences[ii]; + kk++; + } + } + if (kk == nvals) break; + + nvals = kk; + FnMeanSigma_double(differences, nvals, 0, 0, 0, &mean, &stdev, status); + } + } + + diffs[nrows] = stdev; + nrows++; + } + } /* end of loop over rows */ + + /* compute median of the values for each row */ + if (nrows == 0) { + xnoise = 0; + } else if (nrows == 1) { + xnoise = diffs[0]; + } else { + qsort(diffs, nrows, sizeof(double), FnCompare_double); + xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.; + } + + *noise = .70710678 * xnoise; + + free(diffs); + free(differences); + + return(*status); +} +/*--------------------------------------------------------------------------*/ +static int FnCompare_short(const void *v1, const void *v2) +{ + const short *i1 = v1; + const short *i2 = v2; + + if (*i1 < *i2) + return(-1); + else if (*i1 > *i2) + return(1); + else + return(0); +} +/*--------------------------------------------------------------------------*/ +static int FnCompare_int(const void *v1, const void *v2) +{ + const int *i1 = v1; + const int *i2 = v2; + + if (*i1 < *i2) + return(-1); + else if (*i1 > *i2) + return(1); + else + return(0); +} +/*--------------------------------------------------------------------------*/ +static int FnCompare_float(const void *v1, const void *v2) +{ + const float *i1 = v1; + const float *i2 = v2; + + if (*i1 < *i2) + return(-1); + else if (*i1 > *i2) + return(1); + else + return(0); +} +/*--------------------------------------------------------------------------*/ +static int FnCompare_double(const void *v1, const void *v2) +{ + const double *i1 = v1; + const double *i2 = v2; + + if (*i1 < *i2) + return(-1); + else if (*i1 > *i2) + return(1); + else + return(0); +} +/*--------------------------------------------------------------------------*/ + +/* + * These Quickselect routines are based on the algorithm described in + * "Numerical recipes in C", Second Edition, + * Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5 + * This code by Nicolas Devillard - 1998. Public domain. + */ + +/*--------------------------------------------------------------------------*/ + +#define ELEM_SWAP(a,b) { register float t=(a);(a)=(b);(b)=t; } + +static float quick_select_float(float arr[], int n) +{ + int low, high ; + int median; + int middle, ll, hh; + + low = 0 ; high = n-1 ; median = (low + high) / 2; + for (;;) { + if (high <= low) /* One element only */ + return arr[median] ; + + if (high == low + 1) { /* Two elements only */ + if (arr[low] > arr[high]) + ELEM_SWAP(arr[low], arr[high]) ; + return arr[median] ; + } + + /* Find median of low, middle and high items; swap into position low */ + middle = (low + high) / 2; + if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ; + if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; + if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ; + + /* Swap low item (now in position middle) into position (low+1) */ + ELEM_SWAP(arr[middle], arr[low+1]) ; + + /* Nibble from each end towards middle, swapping items when stuck */ + ll = low + 1; + hh = high; + for (;;) { + do ll++; while (arr[low] > arr[ll]) ; + do hh--; while (arr[hh] > arr[low]) ; + + if (hh < ll) + break; + + ELEM_SWAP(arr[ll], arr[hh]) ; + } + + /* Swap middle item (in position low) back into correct position */ + ELEM_SWAP(arr[low], arr[hh]) ; + + /* Re-set active partition */ + if (hh <= median) + low = ll; + if (hh >= median) + high = hh - 1; + } +} + +#undef ELEM_SWAP + +/*--------------------------------------------------------------------------*/ + +#define ELEM_SWAP(a,b) { register short t=(a);(a)=(b);(b)=t; } + +static short quick_select_short(short arr[], int n) +{ + int low, high ; + int median; + int middle, ll, hh; + + low = 0 ; high = n-1 ; median = (low + high) / 2; + for (;;) { + if (high <= low) /* One element only */ + return arr[median] ; + + if (high == low + 1) { /* Two elements only */ + if (arr[low] > arr[high]) + ELEM_SWAP(arr[low], arr[high]) ; + return arr[median] ; + } + + /* Find median of low, middle and high items; swap into position low */ + middle = (low + high) / 2; + if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ; + if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; + if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ; + + /* Swap low item (now in position middle) into position (low+1) */ + ELEM_SWAP(arr[middle], arr[low+1]) ; + + /* Nibble from each end towards middle, swapping items when stuck */ + ll = low + 1; + hh = high; + for (;;) { + do ll++; while (arr[low] > arr[ll]) ; + do hh--; while (arr[hh] > arr[low]) ; + + if (hh < ll) + break; + + ELEM_SWAP(arr[ll], arr[hh]) ; + } + + /* Swap middle item (in position low) back into correct position */ + ELEM_SWAP(arr[low], arr[hh]) ; + + /* Re-set active partition */ + if (hh <= median) + low = ll; + if (hh >= median) + high = hh - 1; + } +} + +#undef ELEM_SWAP + +/*--------------------------------------------------------------------------*/ + +#define ELEM_SWAP(a,b) { register int t=(a);(a)=(b);(b)=t; } + +static int quick_select_int(int arr[], int n) +{ + int low, high ; + int median; + int middle, ll, hh; + + low = 0 ; high = n-1 ; median = (low + high) / 2; + for (;;) { + if (high <= low) /* One element only */ + return arr[median] ; + + if (high == low + 1) { /* Two elements only */ + if (arr[low] > arr[high]) + ELEM_SWAP(arr[low], arr[high]) ; + return arr[median] ; + } + + /* Find median of low, middle and high items; swap into position low */ + middle = (low + high) / 2; + if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ; + if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; + if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ; + + /* Swap low item (now in position middle) into position (low+1) */ + ELEM_SWAP(arr[middle], arr[low+1]) ; + + /* Nibble from each end towards middle, swapping items when stuck */ + ll = low + 1; + hh = high; + for (;;) { + do ll++; while (arr[low] > arr[ll]) ; + do hh--; while (arr[hh] > arr[low]) ; + + if (hh < ll) + break; + + ELEM_SWAP(arr[ll], arr[hh]) ; + } + + /* Swap middle item (in position low) back into correct position */ + ELEM_SWAP(arr[low], arr[hh]) ; + + /* Re-set active partition */ + if (hh <= median) + low = ll; + if (hh >= median) + high = hh - 1; + } +} + +#undef ELEM_SWAP + +/*--------------------------------------------------------------------------*/ + +#define ELEM_SWAP(a,b) { register LONGLONG t=(a);(a)=(b);(b)=t; } + +static LONGLONG quick_select_longlong(LONGLONG arr[], int n) +{ + int low, high ; + int median; + int middle, ll, hh; + + low = 0 ; high = n-1 ; median = (low + high) / 2; + for (;;) { + if (high <= low) /* One element only */ + return arr[median] ; + + if (high == low + 1) { /* Two elements only */ + if (arr[low] > arr[high]) + ELEM_SWAP(arr[low], arr[high]) ; + return arr[median] ; + } + + /* Find median of low, middle and high items; swap into position low */ + middle = (low + high) / 2; + if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ; + if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; + if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ; + + /* Swap low item (now in position middle) into position (low+1) */ + ELEM_SWAP(arr[middle], arr[low+1]) ; + + /* Nibble from each end towards middle, swapping items when stuck */ + ll = low + 1; + hh = high; + for (;;) { + do ll++; while (arr[low] > arr[ll]) ; + do hh--; while (arr[hh] > arr[low]) ; + + if (hh < ll) + break; + + ELEM_SWAP(arr[ll], arr[hh]) ; + } + + /* Swap middle item (in position low) back into correct position */ + ELEM_SWAP(arr[low], arr[hh]) ; + + /* Re-set active partition */ + if (hh <= median) + low = ll; + if (hh >= median) + high = hh - 1; + } +} + +#undef ELEM_SWAP + +/*--------------------------------------------------------------------------*/ + +#define ELEM_SWAP(a,b) { register double t=(a);(a)=(b);(b)=t; } + +static double quick_select_double(double arr[], int n) +{ + int low, high ; + int median; + int middle, ll, hh; + + low = 0 ; high = n-1 ; median = (low + high) / 2; + for (;;) { + if (high <= low) /* One element only */ + return arr[median] ; + + if (high == low + 1) { /* Two elements only */ + if (arr[low] > arr[high]) + ELEM_SWAP(arr[low], arr[high]) ; + return arr[median] ; + } + + /* Find median of low, middle and high items; swap into position low */ + middle = (low + high) / 2; + if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ; + if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; + if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ; + + /* Swap low item (now in position middle) into position (low+1) */ + ELEM_SWAP(arr[middle], arr[low+1]) ; + + /* Nibble from each end towards middle, swapping items when stuck */ + ll = low + 1; + hh = high; + for (;;) { + do ll++; while (arr[low] > arr[ll]) ; + do hh--; while (arr[hh] > arr[low]) ; + + if (hh < ll) + break; + + ELEM_SWAP(arr[ll], arr[hh]) ; + } + + /* Swap middle item (in position low) back into correct position */ + ELEM_SWAP(arr[low], arr[hh]) ; + + /* Re-set active partition */ + if (hh <= median) + low = ll; + if (hh >= median) + high = hh - 1; + } +} + +#undef ELEM_SWAP + + |