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 }