File indexing completed on 2024-04-28 15:10:10

0001 /*
0002     This file is part of SEP
0003 
0004     SPDX-FileCopyrightText: 1993-2011 Emmanuel Bertin -- IAP /CNRS/UPMC
0005     SPDX-FileCopyrightText: 2014 SEP developers
0006 
0007     SPDX-License-Identifier: LGPL-3.0-or-later
0008 */
0009 
0010 #include <math.h>
0011 #include <stdio.h>
0012 #include <stdlib.h>
0013 #include <string.h>
0014 #include "sep.h"
0015 #include "sepcore.h"
0016 
0017 #define BACK_MINGOODFRAC   0.5   /* min frac with good weights*/
0018 #define QUANTIF_NSIGMA     5     /* histogram limits */
0019 #define QUANTIF_NMAXLEVELS 4096  /* max nb of quantif. levels */
0020 #define QUANTIF_AMIN       4     /* min nb of "mode pixels" */
0021 
0022 /* Background info in a single mesh*/
0023 typedef struct {
0024   float  mode, mean, sigma; /* Background mode, mean and sigma */
0025   LONG   *histo;            /* Pointer to a histogram */
0026   int    nlevels;       /* Nb of histogram bins */
0027   float  qzero, qscale;     /* Position of histogram */
0028   float  lcut, hcut;        /* Histogram cuts */
0029   int    npix;          /* Number of pixels involved */
0030 } backstruct;
0031 
0032 /* internal helper functions */
0033 void backhisto(backstruct *backmesh,
0034            PIXTYPE *buf, PIXTYPE *wbuf, int bufsize,
0035            int n, int w, int bw, PIXTYPE maskthresh);
0036 void backstat(backstruct *backmesh,
0037           PIXTYPE *buf, PIXTYPE *wbuf, int bufsize,
0038           int n, int w, int bw, PIXTYPE maskthresh);
0039 int filterback(sep_bkg *bkg, int fw, int fh, double fthresh);
0040 float backguess(backstruct *bkg, float *mean, float *sigma);
0041 int makebackspline(sep_bkg *bkg, float *map, float *dmap);
0042 
0043 
0044 int sep_background(sep_image* image, int bw, int bh, int fw, int fh,
0045                    double fthresh, sep_bkg **bkg)
0046 {
0047   BYTE *imt, *maskt;
0048   int npix;                   /* size of image */
0049   int nx, ny, nb;             /* number of background boxes in x, y, total */
0050   int bufsize;                /* size of a "row" of boxes in pixels (w*bh) */
0051   int elsize;                 /* size (in bytes) of an image array element */
0052   int melsize;                /* size (in bytes) of a mask array element */
0053   PIXTYPE *buf, *buft, *mbuf, *mbuft;
0054   PIXTYPE maskthresh;
0055   array_converter convert, mconvert;
0056   backstruct *backmesh, *bm;  /* info about each background "box" */
0057   sep_bkg *bkgout;          /* output */
0058   int j,k,m, status;
0059 
0060   status = RETURN_OK;
0061   npix = image->w * image->h;
0062   bufsize = image->w * bh;
0063   maskthresh = image->maskthresh;
0064   if (image->mask == NULL) maskthresh = 0.0;
0065 
0066   backmesh = bm = NULL;
0067   bkgout = NULL;
0068   buf = mbuf = buft = mbuft = NULL;
0069   convert = mconvert = NULL;
0070 
0071   /* determine number of background boxes */
0072   if ((nx = (image->w - 1) / bw + 1) < 1)
0073     nx = 1;
0074   if ((ny = (image->h - 1) / bh + 1) < 1)
0075     ny = 1;
0076   nb = nx*ny;
0077 
0078   /* Allocate temp memory & initialize */
0079   QMALLOC(backmesh, backstruct, nx, status);
0080   bm = backmesh;
0081   for (m=nx; m--; bm++)
0082     bm->histo=NULL;
0083 
0084   /* Allocate the returned struct */
0085   QMALLOC(bkgout, sep_bkg, 1, status);
0086   bkgout->w = image->w;
0087   bkgout->h = image->h;
0088   bkgout->nx = nx;
0089   bkgout->ny = ny;
0090   bkgout->n = nb;
0091   bkgout->bw = bw;
0092   bkgout->bh = bh;
0093   bkgout->back = NULL;
0094   bkgout->sigma = NULL;
0095   bkgout->dback = NULL;
0096   bkgout->dsigma = NULL;
0097   QMALLOC(bkgout->back, float, nb, status);
0098   QMALLOC(bkgout->sigma, float, nb, status);
0099   QMALLOC(bkgout->dback, float, nb, status);
0100   QMALLOC(bkgout->dsigma, float, nb, status);
0101 
0102   /* cast input array pointers. These are used to step through the arrays. */
0103   imt = (BYTE *)image->data;
0104   maskt = (BYTE *)image->mask;
0105 
0106   /* get the correct array converter and element size, based on dtype code */
0107   status = get_array_converter(image->dtype, &convert, &elsize);
0108   if (status != RETURN_OK)
0109     goto exit;
0110   if (image->mask)
0111     {
0112       status = get_array_converter(image->mdtype, &mconvert, &melsize);
0113       if (status != RETURN_OK)
0114     goto exit;
0115     }
0116 
0117   /* If the input array type is not PIXTYPE, allocate a buffer to hold
0118      converted values */
0119   if (image->dtype != PIXDTYPE)
0120     {
0121       QMALLOC(buf, PIXTYPE, bufsize, status);
0122       buft = buf;
0123       if (status != RETURN_OK)
0124     goto exit;
0125     }
0126   if (image->mask && (image->mdtype != PIXDTYPE))
0127     {
0128       QMALLOC(mbuf, PIXTYPE, bufsize, status);
0129       mbuft = mbuf;
0130       if (status != RETURN_OK)
0131     goto exit;
0132     }
0133 
0134   /* loop over rows of background boxes.
0135    * (here, we could loop over individual boxes rather than entire
0136    * rows, but this is convenient for converting the image and mask
0137    * arrays.  This is also how it is originally done in SExtractor,
0138    * because the pixel buffers are only read in from disk in
0139    * increments of a row of background boxes at a time.)
0140    */
0141   for (j=0; j<ny; j++)
0142     {
0143       /* if the last row, modify the width appropriately*/
0144       if (j == ny-1 && npix%bufsize)
0145         bufsize = npix%bufsize;
0146 
0147       /* convert this row to PIXTYPE and store in buffer(s)*/
0148       if (image->dtype != PIXDTYPE)
0149     convert(imt, bufsize, buft);
0150       else
0151     buft = (PIXTYPE *)imt;
0152 
0153       if (image->mask)
0154     {
0155       if (image->mdtype != PIXDTYPE)
0156         mconvert(maskt, bufsize, mbuft);
0157       else
0158         mbuft = (PIXTYPE *)maskt;
0159     }
0160 
0161       /* Get clipped mean, sigma for all boxes in the row */
0162       backstat(backmesh, buft, mbuft, bufsize, nx, image->w, bw, maskthresh);
0163 
0164       /* Allocate histograms in each box in this row. */
0165       bm = backmesh;
0166       for (m=nx; m--; bm++)
0167     if (bm->mean <= -BIG)
0168       bm->histo=NULL;
0169     else
0170       QCALLOC(bm->histo, LONG, bm->nlevels, status);
0171       backhisto(backmesh, buft, mbuft, bufsize, nx, image->w, bw, maskthresh);
0172 
0173       /* Compute background statistics from the histograms */
0174       bm = backmesh;
0175       for (m=0; m<nx; m++, bm++)
0176     {
0177       k = m+nx*j;
0178       backguess(bm, bkgout->back+k, bkgout->sigma+k);
0179       free(bm->histo);
0180       bm->histo = NULL;
0181     }
0182 
0183       /* increment array pointers to next row of background boxes */
0184       imt += elsize * bufsize;
0185       if (image->mask)
0186     maskt += melsize * bufsize;
0187     }
0188 
0189   /* free memory */
0190   free(buf);
0191   buf = NULL;
0192   free(mbuf);
0193   mbuf = NULL;
0194   free(backmesh);
0195   backmesh = NULL;
0196 
0197   /* Median-filter and check suitability of the background map */
0198   if ((status = filterback(bkgout, fw, fh, fthresh)) != RETURN_OK)
0199     goto exit;
0200 
0201   /* Compute 2nd derivatives along the y-direction */
0202   if ((status = makebackspline(bkgout, bkgout->back, bkgout->dback)) !=
0203       RETURN_OK)
0204     goto exit;
0205   if ((status = makebackspline(bkgout, bkgout->sigma, bkgout->dsigma)) !=
0206       RETURN_OK)
0207     goto exit;
0208 
0209   *bkg = bkgout;
0210   return status;
0211 
0212   /* If we encountered a problem, clean up any allocated memory */
0213  exit:
0214   free(buf);
0215   free(mbuf);
0216   if (backmesh)
0217     {
0218       bm = backmesh;
0219       for (m=0; m<nx; m++, bm++)
0220     free(bm->histo);
0221     }
0222   free(backmesh);
0223   sep_bkg_free(bkgout);
0224   *bkg = NULL;
0225   return status;
0226 }
0227 
0228 /******************************** backstat **********************************/
0229 /*
0230 Compute robust statistical estimators in a row of meshes.
0231 */
0232 void backstat(backstruct *backmesh,
0233           PIXTYPE *buf, PIXTYPE *wbuf, int bufsize,
0234           int n, int w, int bw, PIXTYPE maskthresh)
0235 {
0236   backstruct    *bm;
0237   double    pix, wpix, sig, mean, sigma, step;
0238   PIXTYPE   *buft,*wbuft;
0239   PIXTYPE       lcut,hcut;
0240   int       m,h,x,y, npix,wnpix, offset, lastbite;
0241   
0242   h = bufsize/w;  /* height of background boxes in this row */
0243   bm = backmesh;
0244   offset = w - bw;
0245   step = sqrt(2/PI)*QUANTIF_NSIGMA/QUANTIF_AMIN;
0246 
0247   for (m = n; m--; bm++,buf+=bw)
0248     {
0249       if (!m && (lastbite=w%bw))
0250     {
0251       bw = lastbite;
0252       offset = w-bw;
0253     }
0254 
0255       mean = sigma = 0.0;
0256       buft=buf;
0257       npix = 0;
0258 
0259       /* We separate the weighted case at this level to avoid penalty in CPU */
0260       if (wbuf)
0261     {
0262       wbuft = wbuf;
0263       for (y=h; y--; buft+=offset,wbuft+=offset)
0264         for (x=bw; x--;)
0265           {
0266         pix = *(buft++);
0267         if ((wpix = *(wbuft++)) <= maskthresh && pix > -BIG)
0268           {
0269             mean += pix;
0270             sigma += pix*pix;
0271             npix++;
0272           }
0273           }
0274     }
0275       else
0276     for (y=h; y--; buft+=offset)
0277       for (x=bw; x--;)
0278         if ((pix = *(buft++)) > -BIG)
0279           {
0280         mean += pix;
0281         sigma += pix*pix;
0282         npix++;
0283           }
0284 
0285       /*-- If not enough valid pixels, discard this mesh */
0286       if ((float)npix < (float)(bw*h*BACK_MINGOODFRAC))
0287     {
0288       bm->mean = bm->sigma = -BIG;
0289       if (wbuf)
0290         wbuf += bw;
0291       continue;
0292     }
0293 
0294       mean /= (double)npix;
0295       sigma = (sig = sigma/npix - mean*mean)>0.0? sqrt(sig):0.0;
0296       lcut = bm->lcut = (PIXTYPE)(mean - 2.0*sigma);
0297       hcut = bm->hcut = (PIXTYPE)(mean + 2.0*sigma);
0298       mean = sigma = 0.0;
0299       npix = wnpix = 0;
0300       buft = buf;
0301       
0302       /* do statistics for this mesh again, with cuts */
0303       if (wbuf)
0304     {
0305       wbuft=wbuf;
0306       for (y=h; y--; buft+=offset, wbuft+=offset)
0307         for (x=bw; x--;)
0308           {
0309         pix = *(buft++);
0310         if ((wpix = *(wbuft++))<=maskthresh && pix<=hcut && pix>=lcut)
0311           {
0312             mean += pix;
0313             sigma += pix*pix;
0314             npix++;
0315           }
0316           }
0317     }
0318       else
0319     for (y=h; y--; buft+=offset)
0320       for (x=bw; x--;)
0321         {
0322           pix = *(buft++);
0323           if (pix<=hcut && pix>=lcut)
0324         {
0325           mean += pix;
0326           sigma += pix*pix;
0327           npix++;
0328         }
0329         }
0330 
0331       bm->npix = npix;
0332       mean /= (double)npix;
0333       sig = sigma/npix - mean*mean;
0334       sigma = sig>0.0 ? sqrt(sig):0.0;
0335       bm->mean = mean;
0336       bm->sigma = sigma;
0337       if ((bm->nlevels = (int)(step*npix+1)) > QUANTIF_NMAXLEVELS)
0338     bm->nlevels = QUANTIF_NMAXLEVELS;
0339       bm->qscale = sigma>0.0? 2*QUANTIF_NSIGMA*sigma/bm->nlevels : 1.0;
0340       bm->qzero = mean - QUANTIF_NSIGMA*sigma;
0341 
0342       if (wbuf)
0343     wbuf += bw;
0344     }
0345 
0346   return;
0347 
0348 }
0349 
0350 /******************************** backhisto *********************************/
0351 /*
0352 Fill histograms in a row of meshes.
0353 */
0354 void backhisto(backstruct *backmesh,
0355            PIXTYPE *buf, PIXTYPE *wbuf, int bufsize,
0356            int n, int w, int bw, PIXTYPE maskthresh)
0357 {
0358   backstruct    *bm;
0359   PIXTYPE   *buft,*wbuft;
0360   float         qscale, cste, wpix;
0361   LONG      *histo;
0362   int       h,m,x,y, nlevels, lastbite, offset, bin;
0363 
0364   h = bufsize/w;
0365   bm = backmesh;
0366   offset = w - bw;
0367   for (m=0; m++<n; bm++ , buf+=bw)
0368     {
0369       if (m==n && (lastbite=w%bw))
0370     {
0371       bw = lastbite;
0372       offset = w-bw;
0373     }
0374 
0375       /*-- Skip bad meshes */
0376       if (bm->mean <= -BIG)
0377     {
0378       if (wbuf)
0379         wbuf += bw;
0380       continue;
0381     }
0382 
0383       nlevels = bm->nlevels;
0384       histo = bm->histo;
0385       qscale = bm->qscale;
0386       cste = 0.499999 - bm->qzero/qscale;
0387       buft = buf;
0388 
0389       if (wbuf)
0390     {
0391       wbuft = wbuf;
0392       for (y=h; y--; buft+=offset, wbuft+=offset)
0393         for (x=bw; x--;)
0394           {
0395         bin = (int)(*(buft++)/qscale + cste);
0396         if ((wpix = *(wbuft++))<=maskthresh && bin<nlevels && bin>=0)
0397           (*(histo+bin))++;
0398           }
0399       wbuf += bw;
0400     }
0401       else
0402     for (y=h; y--; buft += offset)
0403       for (x=bw; x--;)
0404         {
0405           bin = (int)(*(buft++)/qscale + cste);
0406           
0407           if (bin>=0 && bin<nlevels)
0408         (*(histo+bin))++;
0409         }
0410     }
0411   return;
0412 }
0413 
0414 /******************************* backguess **********************************/
0415 /*
0416 Estimate the background from a histogram;
0417 */
0418 float backguess(backstruct *bkg, float *mean, float *sigma)
0419 
0420 #define EPS (1e-4)  /* a small number */
0421 
0422 {
0423   LONG      *histo, *hilow, *hihigh, *histot;
0424   unsigned long lowsum, highsum, sum;
0425   double    ftemp, mea, sig, sig1, med, dpix;
0426   int       i, n, lcut,hcut, nlevelsm1, pix;
0427 
0428   /* Leave here if the mesh is already classified as `bad' */
0429   if (bkg->mean<=-BIG)
0430     {
0431       *mean = *sigma = -BIG;
0432       return -BIG;
0433     }
0434 
0435   histo = bkg->histo;
0436   hcut = nlevelsm1 = bkg->nlevels-1;
0437   lcut = 0;
0438 
0439   sig = 10.0*nlevelsm1;
0440   sig1 = 1.0;
0441   mea = med = bkg->mean;
0442 
0443   /* iterate until sigma converges or drops below 0.1 (up to 100 iterations) */
0444   for (n=100; n-- && (sig>=0.1) && (fabs(sig/sig1-1.0)>EPS);)
0445     {
0446       sig1 = sig;
0447       sum = mea = sig = 0.0;
0448       lowsum = highsum = 0;
0449       histot = hilow = histo+lcut;
0450       hihigh = histo+hcut;
0451 
0452       for (i=lcut; i<=hcut; i++)
0453     {
0454       if (lowsum<highsum)
0455         lowsum += *(hilow++);
0456       else
0457         highsum +=  *(hihigh--);
0458       sum += (pix = *(histot++));
0459       mea += (dpix = (double)pix*i);
0460       sig += dpix*i;
0461     }
0462 
0463       med = hihigh>=histo?((hihigh-histo) + 0.5 +
0464                ((double)highsum-lowsum)/(2.0*(*hilow>*hihigh?
0465                                *hilow:*hihigh)))
0466     : 0.0;
0467       if (sum)
0468     {
0469       mea /= (double)sum;
0470       sig = sig/sum - mea*mea;
0471     }
0472 
0473       sig = sig>0.0?sqrt(sig):0.0;
0474       lcut = (ftemp=med-3.0*sig)>0.0 ?(int)(ftemp>0.0?ftemp+0.5:ftemp-0.5):0;
0475       hcut = (ftemp=med+3.0*sig)<nlevelsm1 ?(int)(ftemp>0.0?ftemp+0.5:ftemp-0.5)
0476     : nlevelsm1;
0477 
0478     }
0479   *mean = fabs(sig)>0.0? (fabs(bkg->sigma/(sig*bkg->qscale)-1) < 0.0 ?
0480               bkg->qzero+mea*bkg->qscale
0481               :(fabs((mea-med)/sig)< 0.3 ?
0482                 bkg->qzero+(2.5*med-1.5*mea)*bkg->qscale
0483                 :bkg->qzero+med*bkg->qscale))
0484     :bkg->qzero+mea*bkg->qscale;
0485   
0486   *sigma = sig*bkg->qscale;
0487 
0488   return *mean;
0489 }
0490 
0491 /****************************************************************************/
0492 
0493 int filterback(sep_bkg *bkg, int fw, int fh, double fthresh)
0494 /* Median filterthe background map to remove the contribution
0495  * from bright sources. */
0496 {
0497   float *back, *sigma, *back2, *sigma2, *bmask, *smask, *sigmat;
0498   float d2, d2min, med, val, sval;
0499   int i, j, px, py, np, nx, ny, npx, npx2, npy, npy2, dpx, dpy, x, y, nmin;
0500   int status;
0501   
0502   status = RETURN_OK;
0503   bmask = smask = back2 = sigma2 = NULL;
0504 
0505   nx = bkg->nx;
0506   ny = bkg->ny;
0507   np = bkg->n;
0508   npx = fw/2;
0509   npy = fh/2;
0510   npy *= nx;
0511 
0512   QMALLOC(bmask, float, (2*npx+1)*(2*npy+1), status);
0513   QMALLOC(smask, float, (2*npx+1)*(2*npy+1), status);
0514   QMALLOC(back2, float, np, status);
0515   QMALLOC(sigma2, float, np, status);
0516 
0517   back = bkg->back;
0518   sigma = bkg->sigma;
0519   val = sval = 0.0;  /* to avoid gcc -Wall warnings */
0520 
0521 /* Look for `bad' meshes and interpolate them if necessary */
0522   for (i=0,py=0; py<ny; py++)
0523     for (px=0; px<nx; px++,i++)
0524       if ((back2[i]=back[i])<=-BIG)
0525         {
0526 /*------ Seek the closest valid mesh */
0527         d2min = BIG;
0528         nmin = 0.0;
0529         for (j=0,y=0; y<ny; y++)
0530           for (x=0; x<nx; x++,j++)
0531             if (back[j]>-BIG)
0532               {
0533               d2 = (float)(x-px)*(x-px)+(y-py)*(y-py);
0534               if (d2<d2min)
0535                 {
0536                 val = back[j];
0537                 sval = sigma[j];
0538                 nmin = 1;
0539                 d2min = d2;
0540                 }
0541               else if (d2==d2min)
0542                 {
0543                 val += back[j];
0544                 sval += sigma[j];
0545                 nmin++;
0546                 }
0547               }
0548         back2[i] = nmin? val/nmin: 0.0;
0549         sigma[i] = nmin? sval/nmin: 1.0;
0550         }
0551   memcpy(back, back2, (size_t)np*sizeof(float));
0552 
0553 /* Do the actual filtering */
0554   for (py=0; py<np; py+=nx)
0555     {
0556     npy2 = np - py - nx;
0557     if (npy2>npy)
0558       npy2 = npy;
0559     if (npy2>py)
0560       npy2 = py;
0561     for (px=0; px<nx; px++)
0562       {
0563       npx2 = nx - px - 1;
0564       if (npx2>npx)
0565         npx2 = npx;
0566       if (npx2>px)
0567         npx2 = px;
0568       i=0;
0569       for (dpy = -npy2; dpy<=npy2; dpy+=nx)
0570         {
0571         y = py+dpy;
0572         for (dpx = -npx2; dpx <= npx2; dpx++)
0573           {
0574           x = px+dpx;
0575           bmask[i] = back[x+y];
0576           smask[i++] = sigma[x+y];
0577           }
0578         }
0579       if (fabs((med=fqmedian(bmask, i))-back[px+py])>=fthresh)
0580         {
0581         back2[px+py] = med;
0582         sigma2[px+py] = fqmedian(smask, i);
0583         }
0584       else
0585         {
0586         back2[px+py] = back[px+py];
0587         sigma2[px+py] = sigma[px+py];
0588         }
0589       }
0590     }
0591 
0592   free(bmask);
0593   free(smask);
0594   bmask = smask = NULL;
0595   memcpy(back, back2, np*sizeof(float));
0596   bkg->global = fqmedian(back2, np);
0597   free(back2);
0598   back2 = NULL;
0599   memcpy(sigma, sigma2, np*sizeof(float));
0600   bkg->globalrms = fqmedian(sigma2, np);
0601 
0602   if (bkg->globalrms <= 0.0)
0603     {
0604     sigmat = sigma2+np;
0605     for (i=np; i-- && *(--sigmat)>0.0;);
0606     if (i>=0 && i<(np-1))
0607       bkg->globalrms = fqmedian(sigmat+1, np-1-i);
0608     else
0609       bkg->globalrms = 1.0;
0610     }
0611 
0612   free(sigma2);
0613   sigma2 = NULL;
0614 
0615   return status;
0616 
0617  exit:
0618   if (bmask) free(bmask);
0619   if (smask) free(smask);
0620   if (back2) free(back2);
0621   if (sigma2) free(sigma2);
0622   return status;
0623 }
0624 
0625 
0626 /******************************* makebackspline ******************************/
0627 /*
0628  * Pre-compute 2nd derivatives along the y direction at background nodes.
0629  */
0630 int makebackspline(sep_bkg *bkg, float *map, float *dmap)
0631 {
0632   int   x, y, nbx, nby, nbym1, status;
0633   float *dmapt, *mapt, *u, temp;
0634   u = NULL;
0635   status = RETURN_OK;
0636 
0637   nbx = bkg->nx;
0638   nby = bkg->ny;
0639   nbym1 = nby - 1;
0640   for (x=0; x<nbx; x++)
0641     {
0642       mapt = map+x;
0643       dmapt = dmap+x;
0644       if (nby>1)
0645     {
0646       QMALLOC(u, float, nbym1, status); /* temporary array */
0647       *dmapt = *u = 0.0;    /* "natural" lower boundary condition */
0648       mapt += nbx;
0649       for (y=1; y<nbym1; y++, mapt+=nbx)
0650         {
0651           temp = -1/(*dmapt+4);
0652           *(dmapt += nbx) = temp;
0653           temp *= *(u++) - 6*(*(mapt+nbx)+*(mapt-nbx)-2**mapt);
0654           *u = temp;
0655         }
0656       *(dmapt+=nbx) = 0.0;  /* "natural" upper boundary condition */
0657       for (y=nby-2; y--;)
0658         {
0659           temp = *dmapt;
0660           dmapt -= nbx;
0661           *dmapt = (*dmapt*temp+*(u--))/6.0;
0662         }
0663       free(u);
0664       u = NULL;
0665     }
0666       else
0667     *dmapt = 0.0;
0668     }
0669 
0670   return status;
0671 
0672  exit: 
0673   if (u) free(u);
0674   return status;
0675 }
0676 
0677 /*****************************************************************************/
0678 
0679 float sep_bkg_global(sep_bkg *bkg)
0680 {
0681   return bkg->global;
0682 }
0683 
0684 float sep_bkg_globalrms(sep_bkg *bkg)
0685 {
0686   return bkg->globalrms;
0687 }
0688 
0689 
0690 /*****************************************************************************/
0691 
0692 float sep_bkg_pix(sep_bkg *bkg, int x, int y)
0693 /*
0694  * return background at position x,y.
0695  * (linear interpolation between background map vertices).
0696  */
0697 {
0698   int    nx, ny, xl, yl, pos;
0699   double dx, dy, cdx;
0700   float  *b;
0701   float  b0, b1, b2, b3;
0702 
0703   b = bkg->back;
0704   nx = bkg->nx;
0705   ny = bkg->ny;
0706 
0707   dx = (double)x/bkg->bw - 0.5;
0708   dy = (double)y/bkg->bh - 0.5;
0709   dx -= (xl = (int)dx);
0710   dy -= (yl = (int)dy);
0711 
0712   if (xl<0)
0713     {
0714     xl = 0;
0715     dx -= 1.0;
0716     }
0717   else if (xl>=nx-1)
0718     {
0719     xl = nx<2 ? 0 : nx-2;
0720     dx += 1.0;
0721     }
0722 
0723   if (yl<0)
0724     {
0725     yl = 0;
0726     dy -= 1.0;
0727     }
0728   else if (yl>=ny-1)
0729     {
0730     yl = ny<2 ? 0 : ny-2;
0731     dy += 1.0;
0732     }
0733 
0734   pos = yl*nx + xl;
0735   cdx = 1 - dx;
0736 
0737   b0 = *(b+=pos);       /* consider when nbackx or nbacky = 1 */
0738   b1 = nx<2? b0:*(++b);
0739   b2 = ny<2? *b:*(b+=nx);
0740   b3 = nx<2? *b:*(--b);
0741 
0742   return (float)((1-dy)*(cdx*b0 + dx*b1) + dy*(dx*b2 + cdx*b3));
0743 }
0744 
0745 
0746 /*****************************************************************************/
0747 
0748 int bkg_line_flt_internal(sep_bkg *bkg, float *values, float *dvalues, int y,
0749                           float *line)
0750 /* Interpolate background at line y (bicubic spline interpolation between
0751  * background map vertices) and save to line.
0752  * (values, dvalues) is either (bkg->back, bkg->dback) or
0753  * (bkg->sigma, bkg->dsigma) depending on whether the background value or rms
0754  * is being evaluated. */
0755 {
0756   int i,j,x,yl, nbx,nbxm1,nby, nx,width, ystep, changepoint, status;
0757   float dx,dx0,dy,dy3, cdx,cdy,cdy3, temp, xstep;
0758   float *nodebuf, *dnodebuf, *u;
0759   float *node, *nodep, *dnode, *blo, *bhi, *dblo, *dbhi;
0760 
0761   status = RETURN_OK;
0762   nodebuf = node = NULL;
0763   dnodebuf = dnode = NULL;
0764   u = NULL;
0765 
0766   width = bkg->w;
0767   nbx = bkg->nx;
0768   nbxm1 = nbx - 1;
0769   nby = bkg->ny;
0770   if (nby > 1)
0771     {
0772       dy = (float)y/bkg->bh - 0.5;
0773       dy -= (yl = (int)dy);
0774       if (yl<0)
0775     {
0776       yl = 0;
0777       dy -= 1.0;
0778     }
0779       else if (yl>=nby-1)
0780     {
0781       yl = nby<2 ? 0 : nby-2;
0782       dy += 1.0;
0783     }
0784       /*-- Interpolation along y for each node */
0785       cdy = 1 - dy;
0786       dy3 = (dy*dy*dy-dy);
0787       cdy3 = (cdy*cdy*cdy-cdy);
0788       ystep = nbx*yl;
0789       blo = values + ystep;
0790       bhi = blo + nbx;
0791       dblo = dvalues + ystep;
0792       dbhi = dblo + nbx;
0793       QMALLOC(nodebuf, float, nbx, status);  /* Interpolated background */
0794       nodep = node = nodebuf;
0795       for (x=nbx; x--;)
0796     *(nodep++) = cdy**(blo++) + dy**(bhi++) + cdy3**(dblo++) +
0797       dy3**(dbhi++);
0798 
0799       /*-- Computation of 2nd derivatives along x */
0800       QMALLOC(dnodebuf, float, nbx, status);  /* 2nd derivative along x */
0801       dnode = dnodebuf;
0802       if (nbx>1)
0803     {
0804       QMALLOC(u, float, nbxm1, status);  /* temporary array */
0805       *dnode = *u = 0.0;    /* "natural" lower boundary condition */
0806       nodep = node+1;
0807       for (x=nbxm1; --x; nodep++)
0808         {
0809           temp = -1/(*(dnode++)+4);
0810           *dnode = temp;
0811           temp *= *(u++) - 6*(*(nodep+1)+*(nodep-1)-2**nodep);
0812           *u = temp;
0813         }
0814       *(++dnode) = 0.0; /* "natural" upper boundary condition */
0815       for (x=nbx-2; x--;)
0816         {
0817           temp = *(dnode--);
0818           *dnode = (*dnode*temp+*(u--))/6.0;
0819         }
0820       free(u);
0821       u = NULL;
0822       dnode--;
0823     }
0824     }
0825   else
0826     {
0827       /*-- No interpolation and no new 2nd derivatives needed along y */
0828       node = values;
0829       dnode = dvalues;
0830     }
0831 
0832   /*-- Interpolation along x */
0833   if (nbx>1)
0834     {
0835       nx = bkg->bw;
0836       xstep = 1.0/nx;
0837       changepoint = nx/2;
0838       dx  = (xstep - 1)/2;  /* dx of the first pixel in the row */
0839       dx0 = ((nx+1)%2)*xstep/2; /* dx of the 1st pixel right to a bkgnd node */
0840       blo = node;
0841       bhi = node + 1;
0842       dblo = dnode;
0843       dbhi = dnode + 1;
0844       for (x=i=0,j=width; j--; i++, dx += xstep)
0845     {
0846       if (i==changepoint && x>0 && x<nbxm1)
0847         {
0848           blo++;
0849           bhi++;
0850           dblo++;
0851           dbhi++;
0852           dx = dx0;
0853         }
0854       cdx = 1 - dx;
0855 
0856       *(line++) = (float)(cdx*(*blo+(cdx*cdx-1)**dblo) 
0857                   + dx*(*bhi+(dx*dx-1)**dbhi));
0858 
0859       if (i==nx)
0860         {
0861           x++;
0862           i = 0;
0863         }
0864     }
0865     }
0866   else
0867     for (j=width; j--;)
0868       {
0869     *(line++) = (float)*node;
0870       }
0871 
0872  exit:
0873   if (nodebuf) free(nodebuf);
0874   if (dnodebuf) free(dnodebuf);
0875   if (u) free(u);
0876   return status;
0877 }
0878 
0879 int sep_bkg_line_flt(sep_bkg *bkg, int y, float *line) 
0880 /* Interpolate background at line y (bicubic spline interpolation between
0881  * background map vertices) and save to line */
0882 {
0883   return bkg_line_flt_internal(bkg, bkg->back, bkg->dback, y, line);
0884 }
0885 
0886 /*****************************************************************************/
0887 
0888 int sep_bkg_rmsline_flt(sep_bkg *bkg, int y, float *line)
0889 /* Interpolate background rms at line y (bicubic spline interpolation between
0890  * background map vertices) and save to line */
0891 {
0892   return bkg_line_flt_internal(bkg, bkg->sigma, bkg->dsigma, y, line);
0893 }
0894 
0895 /*****************************************************************************/
0896 /* Multiple dtype functions and convenience functions.
0897  * These mostly wrap the two "line" functions above. */
0898 
0899 int sep_bkg_line(sep_bkg *bkg, int y, void *line, int dtype)
0900 {
0901   array_writer write_array;
0902   int size, status;
0903   float *tmpline; 
0904 
0905   if (dtype == SEP_TFLOAT)
0906     return sep_bkg_line_flt(bkg, y, (float *)line);
0907    
0908   tmpline = NULL;
0909 
0910   status = get_array_writer(dtype, &write_array, &size);
0911   if (status != RETURN_OK)
0912     goto exit;
0913 
0914   QMALLOC(tmpline, float, bkg->w, status);
0915   status = sep_bkg_line_flt(bkg, y, tmpline);
0916   if (status != RETURN_OK)
0917     goto exit;
0918 
0919   /* write to desired output type */
0920   write_array(tmpline, bkg->w, line);
0921 
0922  exit:
0923   free(tmpline);
0924   return status;
0925 }
0926 
0927 int sep_bkg_rmsline(sep_bkg *bkg, int y, void *line, int dtype)
0928 {
0929   array_writer write_array;
0930   int size, status;
0931   float *tmpline; 
0932 
0933   if (dtype == SEP_TFLOAT)
0934     return sep_bkg_rmsline_flt(bkg, y, (float *)line);
0935    
0936   tmpline = NULL;
0937 
0938   status = get_array_writer(dtype, &write_array, &size);
0939   if (status != RETURN_OK)
0940     goto exit;
0941 
0942   QMALLOC(tmpline, float, bkg->w, status);
0943   status = sep_bkg_rmsline_flt(bkg, y, tmpline);
0944   if (status != RETURN_OK)
0945     goto exit;
0946 
0947   /* write to desired output type */
0948   write_array(tmpline, bkg->w, line);
0949 
0950  exit:
0951   free(tmpline);
0952   return status;
0953 }
0954 
0955 int sep_bkg_array(sep_bkg *bkg, void *arr, int dtype)
0956 {
0957   int y, width, size, status;
0958   array_writer write_array;
0959   float *tmpline;
0960   BYTE *line;
0961 
0962   tmpline = NULL;
0963   status = RETURN_OK;
0964   width = bkg->w;
0965 
0966   if (dtype == SEP_TFLOAT)
0967     {
0968       tmpline = (float *)arr;
0969       for (y=0; y<bkg->h; y++, tmpline+=width)
0970     if ((status = sep_bkg_line_flt(bkg, y, tmpline)) != RETURN_OK)
0971       return status;
0972       return status;
0973     }
0974   
0975   if ((status = get_array_writer(dtype, &write_array, &size)) != RETURN_OK)
0976     goto exit;
0977 
0978   QMALLOC(tmpline, float, width, status);
0979 
0980   line = (BYTE *)arr;
0981   for (y=0; y<bkg->h; y++, line += size*width)
0982     {
0983       if ((status = sep_bkg_line_flt(bkg, y, tmpline)) != RETURN_OK)
0984     goto exit;
0985       write_array(tmpline, width, line);
0986     }
0987 
0988  exit:
0989   free(tmpline);
0990   return status;
0991 }
0992 
0993 int sep_bkg_rmsarray(sep_bkg *bkg, void *arr, int dtype)
0994 {
0995   int y, width, size, status;
0996   array_writer write_array;
0997   float *tmpline;
0998   BYTE *line;
0999 
1000   tmpline = NULL;
1001   status = RETURN_OK;
1002   width = bkg->w;
1003 
1004   if (dtype == SEP_TFLOAT)
1005     {
1006       tmpline = (float *)arr;
1007       for (y=0; y<bkg->h; y++, tmpline+=width)
1008     if ((status = sep_bkg_rmsline_flt(bkg, y, tmpline)) != RETURN_OK)
1009       return status;
1010       return status;
1011     }
1012   
1013   if ((status = get_array_writer(dtype, &write_array, &size)) != RETURN_OK)
1014     goto exit;
1015 
1016   QMALLOC(tmpline, float, width, status);
1017 
1018   line = (BYTE *)arr;
1019   for (y=0; y<bkg->h; y++, line += size*width)
1020     {
1021       if ((status = sep_bkg_rmsline_flt(bkg, y, tmpline)) != RETURN_OK)
1022     goto exit;
1023       write_array(tmpline, width, line);
1024     }
1025 
1026  exit:
1027   free(tmpline);
1028   return status;
1029 }
1030 
1031 int sep_bkg_subline(sep_bkg *bkg, int y, void *line, int dtype)
1032 {
1033   array_writer subtract_array;
1034   int status, size;
1035   PIXTYPE *tmpline;
1036 
1037   tmpline = NULL;
1038   status = RETURN_OK;
1039 
1040   QMALLOC(tmpline, PIXTYPE, bkg->w, status);
1041 
1042   status = sep_bkg_line_flt(bkg, y, tmpline);
1043   if (status != RETURN_OK)
1044     goto exit;
1045 
1046   status = get_array_subtractor(dtype, &subtract_array, &size);
1047   if (status != RETURN_OK)
1048     goto exit;
1049 
1050   subtract_array(tmpline, bkg->w, line);
1051 
1052  exit:
1053   free(tmpline);
1054   return status;
1055 }
1056 
1057 int sep_bkg_subarray(sep_bkg *bkg, void *arr, int dtype)
1058 {
1059   array_writer subtract_array;
1060   int y, status, size, width;
1061   PIXTYPE *tmpline;
1062   BYTE *arrt;
1063 
1064   tmpline = NULL;
1065   status = RETURN_OK;
1066   width = bkg->w;
1067   arrt = (BYTE *)arr;
1068 
1069   QMALLOC(tmpline, PIXTYPE, width, status);
1070 
1071   status = get_array_subtractor(dtype, &subtract_array, &size);
1072   if (status != RETURN_OK)
1073     goto exit;
1074 
1075   for (y=0; y<bkg->h; y++, arrt+=(width*size))
1076     { 
1077       if ((status = sep_bkg_line_flt(bkg, y, tmpline)) != RETURN_OK)
1078     goto exit;
1079       subtract_array(tmpline, width, arrt);
1080     }
1081 
1082  exit:
1083   free(tmpline);
1084   return status;
1085 }
1086 
1087 /*****************************************************************************/
1088 
1089 void sep_bkg_free(sep_bkg *bkg)
1090 {
1091   if (bkg)
1092     {
1093       free(bkg->back);
1094       free(bkg->dback);
1095       free(bkg->sigma);
1096       free(bkg->dsigma);
1097     }
1098   free(bkg);
1099   
1100   return;
1101 }