/* * back.c * * Functions dealing with the image background. * *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% * * This file part of: SExtractor * * Copyright: (C) 1993-2014 Emmanuel Bertin -- IAP/CNRS/UPMC * * License: GNU General Public License * * SExtractor is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * SExtractor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with SExtractor. If not, see . * * Last modified: 17/06/2014 * *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "define.h" #include "globals.h" #include "prefs.h" #include "fits/fitscat.h" #include "back.h" #include "field.h" #include "weight.h" /******************************** makeback ***********************************/ /* Background maps are established from the images themselves; thus we need to make at least one first pass through the data. */ void makeback(picstruct *field, picstruct *wfield, int wscale_flag) { backstruct *backmesh,*wbackmesh, *bm,*wbm; tabstruct *tab, *wtab; PIXTYPE *buf,*wbuf, *buft,*wbuft; OFF_T2 fcurpos,wfcurpos, wfcurpos2,fcurpos2, bufshift, jumpsize; OFF_T2 currentElement, wcurrentElement, currentElement2, wcurrentElement2; size_t bufsize, bufsize2, size,meshsize; int i,j,k,m,n, step, nlines, w,bw, bh, nx,ny,nb, lflag, nr; float *ratio,*ratiop, *weight, *sigma, sratio, sigfac; /* If the weight-map is not an external one, no stats are needed for it */ if (wfield && wfield->flags&(INTERP_FIELD|BACKRMS_FIELD)) wfield= NULL; tab = field->tab; if (wfield) wtab = wfield->tab; else wtab = NULL; /* to avoid gcc -Wall warnings */ w = field->width; bw = field->backw; bh = field->backh; nx = field->nbackx; ny = field->nbacky; nb = field->nback; NFPRINTF(OUTPUT, "Setting up background maps"); /* Decide if it is worth displaying progress each 16 lines */ lflag = (field->width*field->backh >= (size_t)65536); /* Save current positions in files */ wfcurpos = wfcurpos2 = 0; /* to avoid gcc -Wall warnings */ QFTELL(field->file, fcurpos, field->filename); currentElement = (tab->currentElement == 0) ? 1 : tab->currentElement; // CFITSIO if (wfield) { QFTELL(wfield->file, wfcurpos, wfield->filename); wcurrentElement = (wtab->currentElement == 0) ? 1 : wtab->currentElement; // CFITSIO } /* Allocate a correct amount of memory to store pixels */ bufsize = (OFF_T2)w*bh; meshsize = (size_t)bufsize; nlines = 0; if (bufsize > (size_t)BACK_BUFSIZE) { nlines = BACK_BUFSIZE/w; step = (field->backh-1)/nlines+1; bufsize = (size_t)(nlines = field->backh/step)*w; bufshift = (step/2)*(OFF_T2)w; jumpsize = (step-1)*(OFF_T2)w; } else bufshift = jumpsize = 0; /* to avoid gcc -Wall warnings */ /* Allocate some memory */ QMALLOC(backmesh, backstruct, nx); /* background information */ QMALLOC(buf, PIXTYPE, bufsize); /* pixel buffer */ free(field->back); QMALLOC(field->back, float, nb); /* background map */ free(field->backline); QMALLOC(field->backline, PIXTYPE, w); /* current background line */ free(field->sigma); QMALLOC(field->sigma, float, nb); /* sigma map */ if (wfield) { QMALLOC(wbackmesh, backstruct, nx); /* background information */ QMALLOC(wbuf, PIXTYPE, bufsize); /* pixel buffer */ free(wfield->back); QMALLOC(wfield->back, float, nb); /* background map */ free(wfield->backline); QMALLOC(wfield->backline, PIXTYPE, w); /* current background line */ free(wfield->sigma); QMALLOC(wfield->sigma, float, nb); /* sigma map */ wfield->sigfac = 1.0; } else { wbackmesh = NULL; wbuf = NULL; } /* Loop over the data packets */ for (j=0; j Setting up background map at line:%5d\n\33[1A", j*bh); if (!nlines) { /*---- The image is small enough so that we can make exhaustive stats */ if (j == ny-1 && field->npix%bufsize) bufsize = field->npix%bufsize; read_body(field->tab, buf, bufsize); if (wfield) { read_body(wfield->tab, wbuf, bufsize); weight_to_var(wfield, wbuf, bufsize); } /*---- Build the histograms */ backstat(backmesh, wbackmesh, buf, wbuf, bufsize,nx, w, bw, wfield?wfield->weight_thresh:0.0); bm = backmesh; for (m=nx; m--; bm++) if (bm->mean <= -BIG) bm->histo=NULL; else QCALLOC(bm->histo, LONG, bm->nlevels); if (wfield) { wbm = wbackmesh; for (m=nx; m--; wbm++) if (wbm->mean <= -BIG) wbm->histo=NULL; else QCALLOC(wbm->histo, LONG, wbm->nlevels); } backhisto(backmesh, wbackmesh, buf, wbuf, bufsize,nx, w, bw, wfield?wfield->weight_thresh:0.0); } else { /*---- Image size too big, we have to skip a few data !*/ QFTELL(field->file, fcurpos2, field->filename); currentElement2 = (tab->currentElement == 0) ? 1 : tab->currentElement; // CFITSIO if (wfield){ QFTELL(wfield->file, wfcurpos2, wfield->filename); wcurrentElement2 = (wtab->currentElement == 0) ? 1 : wtab->currentElement; // CFITSIO } if (j == ny-1 && (n=field->height%field->backh)) { meshsize = n*(size_t)w; nlines = BACK_BUFSIZE/w; step = (n-1)/nlines+1; bufsize = (nlines = n/step)*(size_t)w; bufshift = (step/2)*(OFF_T2)w; jumpsize = (step-1)*(OFF_T2)w; free(buf); QMALLOC(buf, PIXTYPE, bufsize); /* pixel buffer */ if (wfield) { free(wbuf); QMALLOC(wbuf, PIXTYPE, bufsize); /* pixel buffer */ } } /*---- Read and skip, read and skip, etc... */ QFSEEK(field->file, bufshift*(OFF_T2)field->bytepix, SEEK_CUR, field->filename); tab->currentElement += bufshift; // CFITSIO buft = buf; for (i=nlines; i--; buft += w) { read_body(field->tab, buft, w); if (i) { QFSEEK(field->file, jumpsize*(OFF_T2)field->bytepix, SEEK_CUR, field->filename); tab->currentElement += jumpsize; // CFITSIO } } if (wfield) { /*------ Read and skip, read and skip, etc... now on the weight-map */ QFSEEK(wfield->file, bufshift*(OFF_T2)wfield->bytepix, SEEK_CUR, wfield->filename); wtab->currentElement += bufshift; // CFITSIO wbuft = wbuf; for (i=nlines; i--; wbuft += w) { read_body(wfield->tab, wbuft, w); weight_to_var(wfield, wbuft, w); if (i){ QFSEEK(wfield->file, jumpsize*(OFF_T2)wfield->bytepix, SEEK_CUR, wfield->filename); wtab->currentElement += jumpsize; // CFITSIO } } } backstat(backmesh, wbackmesh, buf, wbuf, bufsize, nx, w, bw, wfield?wfield->weight_thresh:0.0); QFSEEK(field->file, fcurpos2, SEEK_SET, field->filename); tab->currentElement = currentElement2; // CFITSIO bm = backmesh; for (m=nx; m--; bm++) if (bm->mean <= -BIG) bm->histo=NULL; else QCALLOC(bm->histo, LONG, bm->nlevels); if (wfield) { QFSEEK(wfield->file, wfcurpos2, SEEK_SET, wfield->filename); wtab->currentElement = wcurrentElement2; // CFITSIO wbm = wbackmesh; for (m=nx; m--; wbm++) if (wbm->mean <= -BIG) wbm->histo=NULL; else QCALLOC(wbm->histo, LONG, wbm->nlevels); } /*---- Build (progressively this time) the histograms */ for(size=meshsize, bufsize2=bufsize; size>0; size -= bufsize2) { if (bufsize2>size) bufsize2 = size; read_body(field->tab, buf, bufsize2); if (wfield) { read_body(wfield->tab, wbuf, bufsize2); weight_to_var(wfield, wbuf, bufsize2); } backhisto(backmesh, wbackmesh, buf, wbuf, bufsize2, nx, w, bw, wfield?wfield->weight_thresh:0.0); } } /*-- Compute background statistics from the histograms */ bm = backmesh; for (m=0; mback+k, field->sigma+k); free(bm->histo); } if (wfield) { wbm = wbackmesh; for (m=0; mback+k, wfield->sigma+k); free(wbm->histo); } } } /* Free memory */ free(buf); free(backmesh); if (wfield) { free(wbackmesh); free(wbuf); } /* Go back to the original position */ QFSEEK(field->file, fcurpos, SEEK_SET, field->filename); tab->currentElement = currentElement; // CFITSIO if (wfield) { QFSEEK(wfield->file, wfcurpos, SEEK_SET, wfield->filename); wfield->tab->currentElement = wcurrentElement; // CFITSIO } /* Median-filter and check suitability of the background map */ NFPRINTF(OUTPUT, "Filtering background map(s)"); filterback(field); if (wfield) filterback(wfield); /* Compute normalization for variance- or weight-maps*/ if (wfield && wfield->flags&(VAR_FIELD|WEIGHT_FIELD)) { nr = 0; QMALLOC(ratio, float, wfield->nback); ratiop = ratio; weight = wfield->back; sigma = field->sigma; for (i=wfield->nback; i--; sigma++) if ((sratio=*(weight++)) > 0.0 && (sratio = *sigma/sqrt(sratio)) > 0.0) { *(ratiop++) = sratio; nr++; } sigfac = fqmedian(ratio, nr); for (i=0; isigfac = sigfac; else { wfield->sigfac = 1.0; field->backsig /= sigfac; } } /* Compute 2nd derivatives along the y-direction */ NFPRINTF(OUTPUT, "Computing background d-map"); free(field->dback); field->dback = makebackspline(field, field->back); NFPRINTF(OUTPUT, "Computing background-noise d-map"); free(field->dsigma); field->dsigma = makebackspline(field, field->sigma); /* If asked for, force the backmean parameter to the supplied value */ if (field->back_type == BACK_ABSOLUTE) field->backmean = (float)prefs.back_val[(field->flags&DETECT_FIELD)?0:1]; /* Set detection/measurement threshold */ if (prefs.ndthresh > 1) { double dval; if (fabs(dval=prefs.dthresh[0] - prefs.dthresh[1])> 70.0) error(EXIT_FAILURE, "*Error*: I cannot deal with such extreme thresholds!", ""); field->dthresh = field->pixscale*field->pixscale*pow(10.0, -0.4*dval); } else if (prefs.thresh_type[0]==THRESH_ABSOLUTE) field->dthresh = prefs.dthresh[0]; else field->dthresh = prefs.dthresh[0]*field->backsig; if (prefs.nthresh > 1) { double dval; if (fabs(dval=prefs.thresh[0] - prefs.thresh[1]) > 70.0) error(EXIT_FAILURE, "*Error*: I cannot deal with such extreme thresholds!", ""); field->thresh = field->pixscale*field->pixscale*pow(10.0, -0.4*dval); } else if (prefs.thresh_type[1]==THRESH_ABSOLUTE) field->thresh = prefs.thresh[0]; else field->thresh = prefs.thresh[0]*field->backsig; #ifdef QUALITY_CHECK printf("%-10g %-10g %-10g\n", field->backmean, field->backsig, (field->flags & DETECT_FIELD)? field->dthresh : field->thresh); #endif if (field->dthresh<=0.0 || field->thresh<=0.0) error(EXIT_FAILURE, "*Error*: I cannot deal with zero or negative thresholds!", ""); if (prefs.detect_type == PHOTO && field->backmean+3*field->backsig > 50*field->ngamma) error(EXIT_FAILURE, "*Error*: The density range of this image is too large for ", "PHOTO mode"); return; } /******************************** backstat **********************************/ /* Compute robust statistical estimators in a row of meshes. */ void backstat(backstruct *backmesh, backstruct *wbackmesh, PIXTYPE *buf, PIXTYPE *wbuf, size_t bufsize, int n, int w, int bw, PIXTYPE wthresh) { backstruct *bm, *wbm; double pix,wpix, sig, mean,wmean, sigma,wsigma, step; PIXTYPE *buft,*wbuft, lcut,wlcut, hcut,whcut; int m,h,x,y, npix,wnpix, offset, lastbite; h = bufsize/w; bm = backmesh; wbm = wbackmesh; offset = w - bw; step = sqrt(2/PI)*QUANTIF_NSIGMA/QUANTIF_AMIN; wmean = wsigma = wlcut = whcut = 0.0; /* to avoid gcc -Wall warnings */ for (m = n; m--; bm++,buf+=bw) { if (!m && (lastbite=w%bw)) { bw = lastbite; offset = w-bw; } mean = sigma = 0.0; buft=buf; /*-- We separate the weighted case at this level to avoid penalty in CPU */ npix = 0; if (wbackmesh) { wmean = wsigma = 0.0; wbuft = wbuf; for (y=h; y--; buft+=offset,wbuft+=offset) for (x=bw; x--;) { pix = *(buft++); if ((wpix = *(wbuft++)) < wthresh && pix > -BIG) { wmean += wpix; wsigma += wpix*wpix; mean += pix; sigma += pix*pix; npix++; } } } else for (y=h; y--; buft+=offset) for (x=bw; x--;) if ((pix = *(buft++)) > -BIG) { mean += pix; sigma += pix*pix; npix++; } /*-- If not enough valid pixels, discard this mesh */ if ((float)npix < (float)(bw*h*BACK_MINGOODFRAC)) { bm->mean = bm->sigma = -BIG; if (wbackmesh) { wbm->mean = wbm->sigma = -BIG; wbm++; wbuf += bw; } continue; } if (wbackmesh) { wmean /= (double)npix; wsigma = (sig = wsigma/npix - wmean*wmean)>0.0? sqrt(sig):0.0; wlcut = wbm->lcut = (PIXTYPE)(wmean - 2.0*wsigma); whcut = wbm->hcut = (PIXTYPE)(wmean + 2.0*wsigma); } mean /= (double)npix; sigma = (sig = sigma/npix - mean*mean)>0.0? sqrt(sig):0.0; lcut = bm->lcut = (PIXTYPE)(mean - 2.0*sigma); hcut = bm->hcut = (PIXTYPE)(mean + 2.0*sigma); mean = sigma = 0.0; npix = wnpix = 0; buft = buf; if (wbackmesh) { wmean = wsigma = 0.0; wbuft=wbuf; for (y=h; y--; buft+=offset, wbuft+=offset) for (x=bw; x--;) { pix = *(buft++); if ((wpix = *(wbuft++))=lcut) { mean += pix; sigma += pix*pix; npix++; if (wpix<=whcut && wpix>=wlcut) { wmean += wpix; wsigma += wpix*wpix; wnpix++; } } } } else for (y=h; y--; buft+=offset) for (x=bw; x--;) { pix = *(buft++); if (pix<=hcut && pix>=lcut) { mean += pix; sigma += pix*pix; npix++; } } bm->npix = npix; mean /= (double)npix; sig = sigma/npix - mean*mean; sigma = sig>0.0 ? sqrt(sig):0.0; bm->mean = mean; bm->sigma = sigma; if ((bm->nlevels = (int)(step*npix+1)) > QUANTIF_NMAXLEVELS) bm->nlevels = QUANTIF_NMAXLEVELS; bm->qscale = sigma>0.0? 2*QUANTIF_NSIGMA*sigma/bm->nlevels : 1.0; bm->qzero = mean - QUANTIF_NSIGMA*sigma; if (wbackmesh) { wbm->npix = wnpix; wmean /= (double)wnpix; sig = wsigma/wnpix - wmean*wmean; wsigma = sig>0.0 ? sqrt(sig):0.0; wbm->mean = wmean; wbm->sigma = wsigma; if ((wbm->nlevels = (int)(step*wnpix+1)) > QUANTIF_NMAXLEVELS) wbm->nlevels = QUANTIF_NMAXLEVELS; wbm->qscale = wsigma>0.0? 2*QUANTIF_NSIGMA*wsigma/wbm->nlevels : 1.0; wbm->qzero = wmean - QUANTIF_NSIGMA*wsigma; wbm++; wbuf += bw; } } return; } /******************************** backhisto *********************************/ /* Compute robust statistical estimators in a row of meshes. */ void backhisto(backstruct *backmesh, backstruct *wbackmesh, PIXTYPE *buf, PIXTYPE *wbuf, size_t bufsize, int n, int w, int bw, PIXTYPE wthresh) { backstruct *bm,*wbm; PIXTYPE *buft,*wbuft; float qscale,wqscale, cste,wcste, wpix; LONG *histo,*whisto; int h,m,x,y, nlevels,wnlevels, lastbite, offset, bin; h = bufsize/w; bm = backmesh; wbm = wbackmesh; offset = w - bw; for (m=0; m++mean <= -BIG) { if (wbackmesh) { wbm++; wbuf += bw; } continue; } nlevels = bm->nlevels; histo = bm->histo; qscale = bm->qscale; cste = 0.499999 - bm->qzero/qscale; buft = buf; if (wbackmesh) { wnlevels = wbm->nlevels; whisto = wbm->histo; wqscale = wbm->qscale; wcste = 0.499999 - wbm->qzero/wqscale; wbuft = wbuf; for (y=h; y--; buft+=offset, wbuft+=offset) for (x=bw; x--;) { bin = (int)(*(buft++)/qscale + cste); if ((wpix = *(wbuft++))=0) { (*(histo+bin))++; bin = (int)(wpix/wqscale + wcste); if (bin>=0 && bin=0 && binmean<=-BIG) { *mean = *sigma = -BIG; return -BIG; } histo = bkg->histo; hcut = nlevelsm1 = bkg->nlevels-1; lcut = 0; sig = 10.0*nlevelsm1; sig1 = 1.0; mea = med = bkg->mean; for (n=100; n-- && (sig>=0.1) && (fabs(sig/sig1-1.0)>EPS);) { sig1 = sig; sum = mea = sig = 0.0; lowsum = highsum = 0; histot = hilow = histo+lcut; hihigh = histo+hcut; for (i=lcut; i<=hcut; i++) { if (lowsum=histo? ((hihigh-histo)+0.5+((double)highsum-lowsum)/(2.0*(*hilow>*hihigh? *hilow:*hihigh))) : 0.0; if (sum) { mea /= (double)sum; sig = sig/sum - mea*mea; } sig = sig>0.0?sqrt(sig):0.0; lcut = (ftemp=med-3.0*sig)>0.0 ?(int)(ftemp>0.0?ftemp+0.5:ftemp-0.5):0; hcut = (ftemp=med+3.0*sig)0.0?ftemp+0.5:ftemp-0.5) : nlevelsm1; } *mean = fabs(sig)>0.0? (fabs(bkg->sigma/(sig*bkg->qscale)-1) < 0.0 ? bkg->qzero+mea*bkg->qscale :(fabs((mea-med)/sig)< 0.3 ? bkg->qzero+(2.5*med-1.5*mea)*bkg->qscale :bkg->qzero+med*bkg->qscale)) :bkg->qzero+mea*bkg->qscale; *sigma = sig*bkg->qscale; return *mean; } /******************************* filterback *********************************/ /* Median filtering of the background map to remove the contribution from bright sources. */ void filterback(picstruct *field) { float *back,*sigma, *back2,*sigma2, *bmask,*smask, *sigmat, d2,d2min, fthresh, med, val,sval; int i,j,px,py, np, nx,ny, npx,npx2, npy,npy2, dpx,dpy, x,y, nmin; fthresh = prefs.backfthresh; nx = field->nbackx; ny = field->nbacky; np = field->nback; npx = field->nbackfx/2; npy = field->nbackfy/2; npy *= nx; QMALLOC(bmask, float, (2*npx+1)*(2*npy+1)); QMALLOC(smask, float, (2*npx+1)*(2*npy+1)); QMALLOC(back2, float, np); QMALLOC(sigma2, float, np); back = field->back; sigma = field->sigma; val = sval = 0.0; /* to avoid gcc -Wall warnings */ /* Look for `bad' meshes and interpolate them if necessary */ for (i=0,py=0; py-BIG) { d2 = (float)(x-px)*(x-px)+(y-py)*(y-py); if (d2npy) npy2 = npy; if (npy2>py) npy2 = py; for (px=0; pxnpx) npx2 = npx; if (npx2>px) npx2 = px; i=0; for (dpy = -npy2; dpy<=npy2; dpy+=nx) { y = py+dpy; for (dpx = -npx2; dpx <= npx2; dpx++) { x = px+dpx; bmask[i] = back[x+y]; smask[i++] = sigma[x+y]; } } if (fabs((med=fqmedian(bmask, i))-back[px+py])>=fthresh) { back2[px+py] = med; sigma2[px+py] = fqmedian(smask, i); } else { back2[px+py] = back[px+py]; sigma2[px+py] = sigma[px+py]; } } } free(bmask); free(smask); memcpy(back, back2, np*sizeof(float)); field->backmean = fqmedian(back2, np); free(back2); memcpy(sigma, sigma2, np*sizeof(float)); field->backsig = fqmedian(sigma2, np); if (field->backsig<=0.0) { sigmat = sigma2+np; for (i=np; i-- && *(--sigmat)>0.0;); if (i>=0 && i<(np-1)) field->backsig = fqmedian(sigmat+1, np-1-i); else { if (field->flags&(DETECT_FIELD|MEASURE_FIELD)) warning("Image contains mainly constant data; ", "I'll try to cope with that..."); field->backsig = 1.0; } } free(sigma2); return; } /******************************** localback *********************************/ /* Compute Local background if possible. */ float localback(picstruct *field, objstruct *obj) { static backstruct backmesh; int bxmin,bxmax, bymin,bymax, ixmin,ixmax, iymin,iymax, bxnml,bynml, oxsize,oysize, npix, i, x,y, bin, w,sh, bmn, pbs; float bkg, bqs,cste; LONG *bmh; PIXTYPE *backpix, *bp, *strip, *st, pix; strip = field->strip; w = field->width; sh = field->stripheight; pbs = prefs.pback_size; /* Estimate background in a 'rectangular annulus' around the object */ oxsize = obj->xmax - obj->xmin + 1; oysize = obj->ymax - obj->ymin + 1; bxnml = oxsizeheight/2? oysize/4 : (field->height-oysize)/4; bxmin = (ixmin = obj->xmin - bxnml) - pbs; bxmax = (ixmax = obj->xmax+1 + bxnml) + pbs; bymin = (iymin = obj->ymin - bynml) - pbs; bymax = (iymax = obj->ymax+1 + bynml) + pbs; if (bymin>=field->ymin && bymaxymax && bxmin>=0 && bxmax-BIG) { *(bp++) = pix; npix++; } st += ixmax-ixmin; for (x=pbs; x--;) if ((pix=*(st++))>-BIG) { *(bp++) = pix; npix++; } } for (y=bymin; y-BIG) { *(bp++) = pix; npix++; } } for (y=iymax; y-BIG) { *(bp++) = pix; npix++; } } if (npix) { backstat(&backmesh, NULL, backpix, NULL, npix, 1, 1, 1, 0.0); QCALLOC(backmesh.histo, LONG, backmesh.nlevels); bmh = backmesh.histo; bmn = backmesh.nlevels; cste = 0.499999 - backmesh.qzero/(bqs = backmesh.qscale); bp = backpix; for (i=npix; i--;) { bin = (int)(*(bp++)/bqs + cste); if (bin>=0 && binsigbkg); obj->bkg += (obj->dbkg = bkg); free(backmesh.histo); } else { obj->dbkg = 0.0; obj->sigbkg = field->backsig; } free(backpix); } else { obj->dbkg = bkg = 0.0; obj->sigbkg = field->backsig; } return bkg; } /************************************ back ***********************************/ /* return background at position x,y (linear interpolation between background map vertices). */ PIXTYPE back(picstruct *field, int x, int y) { int nx,ny, xl,yl, pos; double dx,dy, cdx; float *b, b0,b1,b2,b3; b = field->back; nx = field->nbackx; ny = field->nbacky; dx = (double)x/field->backw - 0.5; dy = (double)y/field->backh - 0.5; dx -= (xl = (int)dx); dy -= (yl = (int)dy); if (xl<0) { xl = 0; dx -= 1.0; } else if (xl>=nx-1) { xl = nx<2 ? 0 : nx-2; dx += 1.0; } if (yl<0) { yl = 0; dy -= 1.0; } else if (yl>=ny-1) { yl = ny<2 ? 0 : ny-2; dy += 1.0; } pos = yl*nx + xl; cdx = 1 - dx; b0 = *(b+=pos); /* consider when nbackx or nbacky = 1 */ b1 = nx<2? b0:*(++b); b2 = ny<2? *b:*(b+=nx); b3 = nx<2? *b:*(--b); return (PIXTYPE)((1-dy)*(cdx*b0 + dx*b1) + dy*(dx*b2 + cdx*b3)); } /******************************* makebackspline ******************************/ /* Pre-compute 2nd derivatives along the y direction at background nodes. */ float *makebackspline(picstruct *field, float *map) { int x,y, nbx,nby,nbym1; float *dmap,*dmapt,*mapt, *u, temp; nbx = field->nbackx; nby = field->nbacky; nbym1 = nby - 1; QMALLOC(dmap, float, field->nback); for (x=0; x1) { QMALLOC(u, float, nbym1); /* temporary array */ *dmapt = *u = 0.0; /* "natural" lower boundary condition */ mapt += nbx; for (y=1; ywidth; backline = field->backline; if (field->back_type==BACK_ABSOLUTE) { /*-- In absolute background mode, just subtract a cste */ bval = field->backmean; for (i=width; i--;) *(line++) -= ((*backline++)=bval); return; } nbx = field->nbackx; nbxm1 = nbx - 1; nby = field->nbacky; if (nby > 1) { dy = (float)y/field->backh - 0.5; dy -= (yl = (int)dy); if (yl<0) { yl = 0; dy -= 1.0; } else if (yl>=nby-1) { yl = nby<2 ? 0 : nby-2; dy += 1.0; } /*-- Interpolation along y for each node */ cdy = 1 - dy; dy3 = (dy*dy*dy-dy); cdy3 = (cdy*cdy*cdy-cdy); ystep = nbx*yl; blo = field->back + ystep; bhi = blo + nbx; dblo = field->dback + ystep; dbhi = dblo + nbx; QMALLOC(node, float, nbx); /* Interpolated background */ nodep = node; for (x=nbx; x--;) *(nodep++) = cdy**(blo++) + dy**(bhi++) + cdy3**(dblo++) + dy3**(dbhi++); /*-- Computation of 2nd derivatives along x */ QMALLOC(dnode, float, nbx); /* 2nd derivative along x */ if (nbx>1) { QMALLOC(u, float, nbxm1); /* temporary array */ *dnode = *u = 0.0; /* "natural" lower boundary condition */ nodep = node+1; for (x=nbxm1; --x; nodep++) { temp = -1/(*(dnode++)+4); *dnode = temp; temp *= *(u++) - 6*(*(nodep+1)+*(nodep-1)-2**nodep); *u = temp; } *(++dnode) = 0.0; /* "natural" upper boundary condition */ for (x=nbx-2; x--;) { temp = *(dnode--); *dnode = (*dnode*temp+*(u--))/6.0; } free(u); dnode--; } } else { /*-- No interpolation and no new 2nd derivatives needed along y */ node = field->back; dnode = field->dback; } /*-- Interpolation along x */ if (nbx>1) { nx = field->backw; if (nx==1) /* special handling of 1-pixel mesh sizes */ { blo = node; for (j=width; j--;) *(line++) -= (*(backline++) = (PIXTYPE)*(blo++)); } else { xstep = 1.0/nx; changepoint = nx/2; dx = (xstep - 1)/2; /* dx of the first pixel in the row */ dx0 = ((nx+1)%2)*xstep/2; /* dx of the 1st pixel right to a bkgnd node */ blo = node; bhi = node + 1; dblo = dnode; dbhi = dnode + 1; for (x=i=0,j=width; j--; i++, dx += xstep) { if (i==changepoint && x>0 && x1) { free(node); free(dnode); } return; } /******************************* backrmsline ******************************** PROTO void backrmsline(picstruct *field, int y, PIXTYPE *line) PURPOSE Bicubic-spline interpolation of the background noise along the current scanline (y). INPUT Measurement or detection field pointer, Current line position. Where to put the data. OUTPUT -. NOTES Most of the code is a copy of subbackline(), for optimization reasons. AUTHOR E. Bertin (IAP & Leiden & ESO) VERSION 02/02/98 ***/ void backrmsline(picstruct *field, int y, PIXTYPE *line) { int i,j,x,yl, nbx,nbxm1,nby, nx,width, ystep, changepoint; float dx,dx0,dy,dy3, cdx,cdy,cdy3, temp, xstep, *node,*nodep,*dnode, *blo,*bhi,*dblo,*dbhi, *u; nbx = field->nbackx; nbxm1 = nbx - 1; nby = field->nbacky; if (nby > 1) { dy = (float)y/field->backh - 0.5; dy -= (yl = (int)dy); if (yl<0) { yl = 0; dy -= 1.0; } else if (yl>=nby-1) { yl = nby<2 ? 0 : nby-2; dy += 1.0; } /*-- Interpolation along y for each node */ cdy = 1 - dy; dy3 = (dy*dy*dy-dy); cdy3 = (cdy*cdy*cdy-cdy); ystep = nbx*yl; blo = field->sigma + ystep; bhi = blo + nbx; dblo = field->dsigma + ystep; dbhi = dblo + nbx; QMALLOC(node, float, nbx); /* Interpolated background */ nodep = node; for (x=nbx; x--;) *(nodep++) = cdy**(blo++) + dy**(bhi++) + cdy3**(dblo++) + dy3**(dbhi++); /*-- Computation of 2nd derivatives along x */ QMALLOC(dnode, float, nbx); /* 2nd derivative along x */ if (nbx>1) { QMALLOC(u, float, nbxm1); /* temporary array */ *dnode = *u = 0.0; /* "natural" lower boundary condition */ nodep = node+1; for (x=nbxm1; --x; nodep++) { temp = -1/(*(dnode++)+4); *dnode = temp; temp *= *(u++) - 6*(*(nodep+1)+*(nodep-1)-2**nodep); *u = temp; } *(++dnode) = 0.0; /* "natural" upper boundary condition */ for (x=nbx-2; x--;) { temp = *(dnode--); *dnode = (*dnode*temp+*(u--))/6.0; } free(u); dnode--; } } else { /*-- No interpolation and no new 2nd derivatives needed along y */ node = field->sigma; dnode = field->dsigma; } /*-- Interpolation along x */ width = field->width; if (nbx>1) { nx = field->backw; xstep = 1.0/nx; changepoint = nx/2; dx = (xstep - 1)/2; /* dx of the first pixel in the row */ dx0 = ((nx+1)%2)*xstep/2; /* dx of the 1st pixel right to a bkgnd node */ blo = node; bhi = node + 1; dblo = dnode; dbhi = dnode + 1; for (x=i=0,j=width; j--; i++, dx += xstep) { if (i==changepoint && x>0 && x1) { free(node); free(dnode); } return; } /********************************* copyback **********************************/ /* Copy sub-structures related to background procedures (mainly freeing memory). */ void copyback(picstruct *infield, picstruct *outfield) { QMEMCPY(infield->back, outfield->back, float, infield->nback); QMEMCPY(infield->dback, outfield->dback, float, infield->nback); QMEMCPY(infield->sigma, outfield->sigma, float, infield->nback); QMEMCPY(infield->dsigma, outfield->dsigma, float, infield->nback); QMEMCPY(infield->backline, outfield->backline, PIXTYPE, infield->width); return; } /********************************* endback ***********************************/ /* Terminate background procedures (mainly freeing memory). */ void endback(picstruct *field) { free(field->back); free(field->dback); free(field->sigma); free(field->dsigma); free(field->backline); return; }