public software.sextractor

[/] [trunk/] [src/] [back.c] - Blame information for rev 235

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 233 bertin
/*
2
*                               back.c
3 2 bertin
*
4 233 bertin
* Functions dealing with the image background.
5 2 bertin
*
6 233 bertin
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7 2 bertin
*
8 233 bertin
*       This file part of:      SExtractor
9 2 bertin
*
10 235 bertin
*       Copyright:              (C) 1993-2010 Emmanuel Bertin -- IAP/CNRS/UPMC
11 2 bertin
*
12 233 bertin
*       License:                GNU General Public License
13
*
14
*       SExtractor is free software: you can redistribute it and/or modify
15
*       it under the terms of the GNU General Public License as published by
16
*       the Free Software Foundation, either version 3 of the License, or
17
*       (at your option) any later version.
18
*       SExtractor is distributed in the hope that it will be useful,
19
*       but WITHOUT ANY WARRANTY; without even the implied warranty of
20
*       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
*       GNU General Public License for more details.
22
*       You should have received a copy of the GNU General Public License
23
*       along with SExtractor. If not, see <http://www.gnu.org/licenses/>.
24
*
25
*       Last modified:          11/10/2010
26
*
27
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
28 2 bertin
 
29
#ifdef HAVE_CONFIG_H
30
#include        "config.h"
31
#endif
32
 
33
#include        <math.h>
34
#include        <stdio.h>
35
#include        <stdlib.h>
36
#include        <string.h>
37
 
38
#include        "define.h"
39
#include        "globals.h"
40
#include        "prefs.h"
41
#include        "fits/fitscat.h"
42
#include        "back.h"
43
#include        "field.h"
44
#include        "weight.h"
45
 
46
/******************************** makeback ***********************************/
47
/*
48
Background maps are established from the images themselves; thus we need to
49
make at least one first pass through the data.
50
*/
51
void    makeback(picstruct *field, picstruct *wfield)
52
 
53
  {
54
   backstruct   *backmesh,*wbackmesh, *bm,*wbm;
55
   PIXTYPE      *buf,*wbuf, *buft,*wbuft;
56
   OFF_T        fcurpos,wfcurpos, wfcurpos2,fcurpos2, bufshift, jumpsize;
57
   size_t       bufsize, bufsize2,
58
                size,meshsize;
59
   int          i,j,k,m,n, step, nlines,
60
                w,bw, bh, nx,ny,nb,
61
                lflag, nr;
62
   float        *ratio,*ratiop, *weight, *sigma,
63
                sratio;
64
 
65
/* If the weight-map is not an external one, no stats are needed for it */
66
  if (wfield && wfield->flags&(INTERP_FIELD|BACKRMS_FIELD))
67
    wfield= NULL;
68
 
69
  w = field->width;
70
  bw = field->backw;
71
  bh = field->backh;
72
  nx = field->nbackx;
73
  ny = field->nbacky;
74
  nb = field->nback;
75
 
76
  NFPRINTF(OUTPUT, "Setting up background maps");
77
 
78
/* Decide if it is worth displaying progress each 16 lines */
79
 
80
  lflag = (field->width*field->backh >= (size_t)65536);
81
 
82
/* Save current positions in files */
83
 
84
  wfcurpos = wfcurpos2 = 0;              /* to avoid gcc -Wall warnings */
85
  QFTELL(field->file, fcurpos, field->filename);
86
  if (wfield)
87
    QFTELL(wfield->file, wfcurpos, wfield->filename);
88
 
89
/* Allocate a correct amount of memory to store pixels */
90
 
91
  bufsize = (OFF_T)w*bh;
92
  meshsize = (size_t)bufsize;
93
  nlines = 0;
94
  if (bufsize > (size_t)BACK_BUFSIZE)
95
    {
96
    nlines = BACK_BUFSIZE/w;
97
    step = (field->backh-1)/nlines+1;
98
    bufsize = (size_t)(nlines = field->backh/step)*w;
99
    bufshift = (step/2)*(OFF_T)w;
100
    jumpsize = (step-1)*(OFF_T)w;
101
    }
102
  else
103
    bufshift = jumpsize = 0;             /* to avoid gcc -Wall warnings */
104
 
105
/* Allocate some memory */
106
  QMALLOC(backmesh, backstruct, nx);            /* background information */
107
  QMALLOC(buf, PIXTYPE, bufsize);               /* pixel buffer */
108
  free(field->back);
109
  QMALLOC(field->back, float, nb);              /* background map */
110
  free(field->backline);
111
  QMALLOC(field->backline, PIXTYPE, w);         /* current background line */
112
  free(field->sigma);
113
  QMALLOC(field->sigma, float, nb);             /* sigma map */
114
  if (wfield)
115
    {
116
    QMALLOC(wbackmesh, backstruct, nx);         /* background information */
117
    QMALLOC(wbuf, PIXTYPE, bufsize);            /* pixel buffer */
118
    free(wfield->back);
119
    QMALLOC(wfield->back, float, nb);           /* background map */
120
    free(wfield->backline);
121
    QMALLOC(wfield->backline, PIXTYPE, w);      /* current background line */
122
    free(wfield->sigma);
123
    QMALLOC(wfield->sigma, float, nb);          /* sigma map */
124
    wfield->sigfac = 1.0;
125
    }
126
  else
127
    {
128
    wbackmesh = NULL;
129
    wbuf = NULL;
130
    }
131
 
132
/* Loop over the data packets */
133
 
134
  for (j=0; j<ny; j++)
135
    {
136
    if (lflag && j)
137
      NPRINTF(OUTPUT, "\33[1M> Setting up background map at line:%5d\n\33[1A",
138
              j*bh);
139
    if (!nlines)
140
      {
141
/*---- The image is small enough so that we can make exhaustive stats */
142
      if (j == ny-1 && field->npix%bufsize)
143
        bufsize = field->npix%bufsize;
144 173 bertin
      read_body(field->tab, buf, bufsize);
145 2 bertin
      if (wfield)
146
        {
147 173 bertin
        read_body(wfield->tab, wbuf, bufsize);
148 2 bertin
        weight_to_var(wfield, wbuf, bufsize);
149
        }
150
/*---- Build the histograms */
151
      backstat(backmesh, wbackmesh, buf, wbuf, bufsize,nx, w, bw,
152
        wfield?wfield->weight_thresh:0.0);
153
      bm = backmesh;
154
      for (m=nx; m--; bm++)
155
        if (bm->mean <= -BIG)
156
          bm->histo=NULL;
157
        else
158
          QCALLOC(bm->histo, LONG, bm->nlevels);
159
      if (wfield)
160
        {
161
        wbm = wbackmesh;
162
        for (m=nx; m--; wbm++)
163
          if (wbm->mean <= -BIG)
164
            wbm->histo=NULL;
165
          else
166
            QCALLOC(wbm->histo, LONG, wbm->nlevels);
167
        }
168
      backhisto(backmesh, wbackmesh, buf, wbuf, bufsize,nx, w, bw,
169
        wfield?wfield->weight_thresh:0.0);
170
      }
171
    else
172
      {
173
/*---- Image size too big, we have to skip a few data !*/
174
      QFTELL(field->file, fcurpos2, field->filename);
175
      if (wfield)
176
        QFTELL(wfield->file, wfcurpos2, wfield->filename);
177
      if (j == ny-1 && (n=field->height%field->backh))
178
        {
179
        meshsize = n*(size_t)w;
180
        nlines = BACK_BUFSIZE/w;
181
        step = (n-1)/nlines+1;
182
        bufsize = (nlines = n/step)*(size_t)w;
183
        bufshift = (step/2)*(OFF_T)w;
184
        jumpsize = (step-1)*(OFF_T)w;
185
        free(buf);
186
        QMALLOC(buf, PIXTYPE, bufsize);         /* pixel buffer */
187
        if (wfield)
188
          {
189
          free(wbuf);
190
          QMALLOC(wbuf, PIXTYPE, bufsize);      /* pixel buffer */
191
          }
192
        }
193
 
194
/*---- Read and skip, read and skip, etc... */
195
      QFSEEK(field->file, bufshift*(OFF_T)field->bytepix, SEEK_CUR,
196
                field->filename);
197
      buft = buf;
198
      for (i=nlines; i--; buft += w)
199
        {
200 173 bertin
        read_body(field->tab, buft, w);
201 2 bertin
        if (i)
202
          QFSEEK(field->file, jumpsize*(OFF_T)field->bytepix, SEEK_CUR,
203
                field->filename);
204
        }
205
 
206
      if (wfield)
207
        {
208
/*------ Read and skip, read and skip, etc... now on the weight-map */
209
        QFSEEK(wfield->file, bufshift*(OFF_T)wfield->bytepix, SEEK_CUR,
210
                wfield->filename);
211
        wbuft = wbuf;
212
        for (i=nlines; i--; wbuft += w)
213
          {
214 173 bertin
          read_body(wfield->tab, wbuft, w);
215 2 bertin
          weight_to_var(wfield, wbuft, w);
216
          if (i)
217
            QFSEEK(wfield->file, jumpsize*(OFF_T)wfield->bytepix, SEEK_CUR,
218
                wfield->filename);
219
          }
220
        }
221
      backstat(backmesh, wbackmesh, buf, wbuf, bufsize, nx, w, bw,
222
        wfield?wfield->weight_thresh:0.0);
223
      QFSEEK(field->file, fcurpos2, SEEK_SET, field->filename);
224
      bm = backmesh;
225
      for (m=nx; m--; bm++)
226
        if (bm->mean <= -BIG)
227
          bm->histo=NULL;
228
        else
229
          QCALLOC(bm->histo, LONG, bm->nlevels);
230
      if (wfield)
231
        {
232
        QFSEEK(wfield->file, wfcurpos2, SEEK_SET, wfield->filename);
233
        wbm = wbackmesh;
234
        for (m=nx; m--; wbm++)
235
          if (wbm->mean <= -BIG)
236
            wbm->histo=NULL;
237
          else
238
            QCALLOC(wbm->histo, LONG, wbm->nlevels);
239
        }
240
/*---- Build (progressively this time) the histograms */
241
      for(size=meshsize, bufsize2=bufsize; size>0; size -= bufsize2)
242
        {
243
        if (bufsize2>size)
244
          bufsize2 = size;
245 173 bertin
        read_body(field->tab, buf, bufsize2);
246 2 bertin
        if (wfield)
247
          {
248 173 bertin
          read_body(wfield->tab, wbuf, bufsize2);
249 2 bertin
          weight_to_var(wfield, wbuf, bufsize2);
250
          }
251
        backhisto(backmesh, wbackmesh, buf, wbuf, bufsize2, nx, w, bw,
252
                wfield?wfield->weight_thresh:0.0);
253
        }
254
      }
255
 
256
    /*-- Compute background statistics from the histograms */
257
    bm = backmesh;
258
    for (m=0; m<nx; m++, bm++)
259
      {
260
      k = m+nx*j;
261
      backguess(bm, field->back+k, field->sigma+k);
262
      free(bm->histo);
263
      }
264
    if (wfield)
265
      {
266
      wbm = wbackmesh;
267
      for (m=0; m<nx; m++, wbm++)
268
        {
269
        k = m+nx*j;
270
        backguess(wbm, wfield->back+k, wfield->sigma+k);
271
        free(wbm->histo);
272
        }
273
      }
274
    }
275
 
276
/* Free memory */
277
  free(buf);
278
  free(backmesh);
279
  if (wfield)
280
    {
281
    free(wbackmesh);
282
    free(wbuf);
283
    }
284
 
285
/* Go back to the original position */
286
  QFSEEK(field->file, fcurpos, SEEK_SET, field->filename);
287
  if (wfield)
288
    QFSEEK(wfield->file, wfcurpos, SEEK_SET, wfield->filename);
289
 
290
/* Median-filter and check suitability of the background map */
291
  NFPRINTF(OUTPUT, "Filtering background map(s)");
292
  filterback(field);
293
  if (wfield)
294
    filterback(wfield);
295
 
296
/* Compute normalization for variance- or weight-maps*/
297
  if (wfield && wfield->flags&(VAR_FIELD|WEIGHT_FIELD))
298
    {
299
    nr = 0;
300
    QMALLOC(ratio, float, wfield->nback);
301
    ratiop = ratio;
302
    weight = wfield->back;
303
    sigma = field->sigma;
304
    for (i=wfield->nback; i--; sigma++)
305
      if ((sratio=*(weight++)) > 0.0
306
                && (sratio = *sigma/sqrt(sratio)) > 0.0)
307
        {
308
        *(ratiop++) = sratio;
309
        nr++;
310
        }
311 233 bertin
    wfield->sigfac = fqmedian(ratio, nr);
312 2 bertin
    for (i=0; i<nr && ratio[i]<=0.0; i++);
313
    if (i<nr)
314 233 bertin
      wfield->sigfac = fqmedian(ratio+i, nr-i);
315 2 bertin
    else
316
      {
317
      warning("Null or negative global weighting factor:","defaulted to 1");
318
      wfield->sigfac = 1.0;
319
      }
320
    free(ratio);
321
    }
322
 
323
/* Compute 2nd derivatives along the y-direction */
324
  NFPRINTF(OUTPUT, "Computing background d-map");
325
  free(field->dback);
326
  field->dback = makebackspline(field, field->back);
327
  NFPRINTF(OUTPUT, "Computing background-noise d-map");
328
  free(field->dsigma);
329
  field->dsigma = makebackspline(field, field->sigma);
330
/* If asked for, force the backmean parameter to the supplied value */
331
  if (field->back_type == BACK_ABSOLUTE)
332
    field->backmean = (float)prefs.back_val[(field->flags&DETECT_FIELD)?0:1];
333
 
334
/* Set detection/measurement threshold */
335
  if (prefs.ndthresh > 1)
336
    {
337
     double     dval;
338
 
339
    if (fabs(dval=prefs.dthresh[0] - prefs.dthresh[1])> 70.0)
340
      error(EXIT_FAILURE,
341
        "*Error*: I cannot deal with such extreme thresholds!", "");
342
 
343
    field->dthresh = field->pixscale*field->pixscale*pow(10.0, -0.4*dval);
344
    }
345
  else if (prefs.thresh_type[0]==THRESH_ABSOLUTE)
346
    field->dthresh = prefs.dthresh[0];
347
  else
348
    field->dthresh = prefs.dthresh[0]*field->backsig;
349
  if (prefs.nthresh > 1)
350
    {
351
     double     dval;
352
 
353
    if (fabs(dval=prefs.thresh[0] - prefs.thresh[1]) > 70.0)
354
      error(EXIT_FAILURE,
355
        "*Error*: I cannot deal with such extreme thresholds!", "");
356
 
357
    field->thresh = field->pixscale*field->pixscale*pow(10.0, -0.4*dval);
358
    }
359
  else if (prefs.thresh_type[1]==THRESH_ABSOLUTE)
360
    field->thresh = prefs.thresh[0];
361
  else
362
    field->thresh = prefs.thresh[0]*field->backsig;
363
 
364
#ifdef  QUALITY_CHECK
365
  printf("%-10g %-10g %-10g\n", field->backmean, field->backsig,
366
        (field->flags & DETECT_FIELD)? field->dthresh : field->thresh);
367
#endif
368
  if (field->dthresh<=0.0 || field->thresh<=0.0)
369
    error(EXIT_FAILURE,
370
        "*Error*: I cannot deal with zero or negative thresholds!", "");
371
 
372
  if (prefs.detect_type == PHOTO
373
        && field->backmean+3*field->backsig > 50*field->ngamma)
374
    error(EXIT_FAILURE,
375
        "*Error*: The density range of this image is too large for ",
376
        "PHOTO mode");
377
 
378
  return;
379
  }
380
 
381
 
382
/******************************** backstat **********************************/
383
/*
384
Compute robust statistical estimators in a row of meshes.
385
*/
386
void    backstat(backstruct *backmesh, backstruct *wbackmesh,
387
                PIXTYPE *buf, PIXTYPE *wbuf, size_t bufsize,
388
                        int n, int w, int bw, PIXTYPE wthresh)
389
 
390
  {
391
   backstruct   *bm, *wbm;
392
   double       pix,wpix, sig, mean,wmean, sigma,wsigma, step;
393
   PIXTYPE      *buft,*wbuft,
394
                lcut,wlcut, hcut,whcut;
395 21 bertin
   int          m,h,x,y, npix,wnpix, offset, lastbite;
396 2 bertin
 
397
  h = bufsize/w;
398
  bm = backmesh;
399
  wbm = wbackmesh;
400
  offset = w - bw;
401
  step = sqrt(2/PI)*QUANTIF_NSIGMA/QUANTIF_AMIN;
402
  wmean = wsigma = wlcut = whcut = 0.0; /* to avoid gcc -Wall warnings */
403
  for (m = n; m--; bm++,buf+=bw)
404
    {
405
    if (!m && (lastbite=w%bw))
406
      {
407
      bw = lastbite;
408
      offset = w-bw;
409
      }
410
    mean = sigma = 0.0;
411
    buft=buf;
412
/*-- We separate the weighted case at this level to avoid penalty in CPU */
413 21 bertin
    npix = 0;
414 2 bertin
    if (wbackmesh)
415
      {
416
      wmean = wsigma = 0.0;
417
      wbuft = wbuf;
418
      for (y=h; y--; buft+=offset,wbuft+=offset)
419
        for (x=bw; x--;)
420
          {
421
          pix = *(buft++);
422 21 bertin
          if ((wpix = *(wbuft++)) < wthresh && pix > -BIG)
423 2 bertin
            {
424
            wmean += wpix;
425
            wsigma += wpix*wpix;
426
            mean += pix;
427
            sigma += pix*pix;
428 21 bertin
            npix++;
429 2 bertin
            }
430
          }
431
      }
432
    else
433
      for (y=h; y--; buft+=offset)
434
        for (x=bw; x--;)
435 21 bertin
          if ((pix = *(buft++)) > -BIG)
436
            {
437
            mean += pix;
438
            sigma += pix*pix;
439
            npix++;
440
            }
441
/*-- If not enough valid pixels, discard this mesh */
442
    if ((float)npix < (float)(bw*h*BACK_MINGOODFRAC))
443 2 bertin
      {
444 21 bertin
      bm->mean = bm->sigma = -BIG;
445
      if (wbackmesh)
446 2 bertin
        {
447 21 bertin
        wbm->mean = wbm->sigma = -BIG;
448
        wbm++;
449
        wbuf += bw;
450 2 bertin
        }
451 21 bertin
      continue;
452
      }
453
    if (wbackmesh)
454
      {
455 2 bertin
      wmean /= (double)npix;
456
      wsigma = (sig = wsigma/npix - wmean*wmean)>0.0? sqrt(sig):0.0;
457
      wlcut = wbm->lcut = (PIXTYPE)(wmean - 2.0*wsigma);
458
      whcut = wbm->hcut = (PIXTYPE)(wmean + 2.0*wsigma);
459
      }
460
    mean /= (double)npix;
461
    sigma = (sig = sigma/npix - mean*mean)>0.0? sqrt(sig):0.0;
462
    lcut = bm->lcut = (PIXTYPE)(mean - 2.0*sigma);
463
    hcut = bm->hcut = (PIXTYPE)(mean + 2.0*sigma);
464
    mean = sigma = 0.0;
465
    npix = wnpix = 0;
466
    buft = buf;
467
    if (wbackmesh)
468
      {
469
      wmean = wsigma = 0.0;
470
      wbuft=wbuf;
471
      for (y=h; y--; buft+=offset, wbuft+=offset)
472
        for (x=bw; x--;)
473
          {
474
          pix = *(buft++);
475
          if ((wpix = *(wbuft++))<wthresh && pix<=hcut && pix>=lcut)
476
            {
477
            mean += pix;
478
            sigma += pix*pix;
479
            npix++;
480
            if (wpix<=whcut && wpix>=wlcut)
481
              {
482
              wmean += wpix;
483
              wsigma += wpix*wpix;
484
              wnpix++;
485
              }
486
            }
487
          }
488
      }
489
    else
490
      for (y=h; y--; buft+=offset)
491
        for (x=bw; x--;)
492
          {
493
          pix = *(buft++);
494
          if (pix<=hcut && pix>=lcut)
495
            {
496
            mean += pix;
497
            sigma += pix*pix;
498
            npix++;
499
            }
500
          }
501
 
502
    bm->npix = npix;
503
    mean /= (double)npix;
504
    sig = sigma/npix - mean*mean;
505
    sigma = sig>0.0 ? sqrt(sig):0.0;
506
    bm->mean = mean;
507
    bm->sigma = sigma;
508
    if ((bm->nlevels = (int)(step*npix+1)) > QUANTIF_NMAXLEVELS)
509
      bm->nlevels = QUANTIF_NMAXLEVELS;
510
    bm->qscale = sigma>0.0? 2*QUANTIF_NSIGMA*sigma/bm->nlevels : 1.0;
511
    bm->qzero = mean - QUANTIF_NSIGMA*sigma;
512
    if (wbackmesh)
513
      {
514
      wbm->npix = wnpix;
515
      wmean /= (double)wnpix;
516
      sig = wsigma/wnpix - wmean*wmean;
517
      wsigma = sig>0.0 ? sqrt(sig):0.0;
518
      wbm->mean = wmean;
519
      wbm->sigma = wsigma;
520
      if ((wbm->nlevels = (int)(step*wnpix+1)) > QUANTIF_NMAXLEVELS)
521
        wbm->nlevels = QUANTIF_NMAXLEVELS;
522
      wbm->qscale = wsigma>0.0? 2*QUANTIF_NSIGMA*wsigma/wbm->nlevels : 1.0;
523
      wbm->qzero = wmean - QUANTIF_NSIGMA*wsigma;
524
      wbm++;
525
      wbuf += bw;
526
      }
527
    }
528
 
529
  return;
530
  }
531
 
532
 
533
/******************************** backhisto *********************************/
534
/*
535
Compute robust statistical estimators in a row of meshes.
536
*/
537
void    backhisto(backstruct *backmesh, backstruct *wbackmesh,
538
                PIXTYPE *buf, PIXTYPE *wbuf, size_t bufsize,
539
                        int n, int w, int bw, PIXTYPE wthresh)
540
  {
541
   backstruct   *bm,*wbm;
542
   PIXTYPE      *buft,*wbuft;
543
   float        qscale,wqscale, cste,wcste, wpix;
544
   LONG         *histo,*whisto;
545
   int          h,m,x,y, nlevels,wnlevels, lastbite, offset, bin;
546
 
547
  h = bufsize/w;
548
  bm = backmesh;
549
  wbm = wbackmesh;
550
  offset = w - bw;
551
  for (m=0; m++<n; bm++ , buf+=bw)
552
    {
553
    if (m==n && (lastbite=w%bw))
554
      {
555
      bw = lastbite;
556
      offset = w-bw;
557
      }
558
/*-- Skip bad meshes */
559
    if (bm->mean <= -BIG)
560
      {
561
      if (wbackmesh)
562
        {
563
        wbm++;
564
        wbuf += bw;
565
        }
566
      continue;
567
      }
568
    nlevels = bm->nlevels;
569
    histo = bm->histo;
570
    qscale = bm->qscale;
571
    cste = 0.499999 - bm->qzero/qscale;
572
    buft = buf;
573
    if (wbackmesh)
574
      {
575
      wnlevels = wbm->nlevels;
576
      whisto = wbm->histo;
577
      wqscale = wbm->qscale;
578
      wcste = 0.499999 - wbm->qzero/wqscale;
579
      wbuft = wbuf;
580
      for (y=h; y--; buft+=offset, wbuft+=offset)
581
        for (x=bw; x--;)
582
          {
583
          bin = (int)(*(buft++)/qscale + cste);
584
          if ((wpix = *(wbuft++))<wthresh && bin<nlevels && bin>=0)
585
            {
586
            (*(histo+bin))++;
587
            bin = (int)(wpix/wqscale + wcste);
588
            if (bin>=0 && bin<wnlevels)
589
              (*(whisto+bin))++;
590
            }
591
          }
592
      wbm++;
593
      wbuf += bw;
594
      }
595
    else
596
      for (y=h; y--; buft += offset)
597
        for (x=bw; x--;)
598
          {
599
          bin = (int)(*(buft++)/qscale + cste);
600
          if (bin>=0 && bin<nlevels)
601
            (*(histo+bin))++;
602
          }
603
    }
604
 
605
  return;
606
  }
607
 
608
/******************************* backguess **********************************/
609
/*
610
Estimate the background from a histogram;
611
*/
612
float   backguess(backstruct *bkg, float *mean, float *sigma)
613
 
614
#define EPS     (1e-4)  /* a small number */
615
 
616
  {
617
   LONG         *histo, *hilow, *hihigh, *histot;
618
   unsigned long lowsum, highsum, sum;
619
   double       ftemp, mea, sig, sig1, med, dpix;
620
   int          i, n, lcut,hcut, nlevelsm1, pix;
621
 
622
/* Leave here if the mesh is already classified as `bad' */
623
  if (bkg->mean<=-BIG)
624
    {
625
    *mean = *sigma = -BIG;
626
    return -BIG;
627
    }
628
 
629
  histo = bkg->histo;
630
  hcut = nlevelsm1 = bkg->nlevels-1;
631
  lcut = 0;
632
 
633
  sig = 10.0*nlevelsm1;
634
  sig1 = 1.0;
635
  mea = med = bkg->mean;
636
  for (n=100; n-- && (sig>=0.1) && (fabs(sig/sig1-1.0)>EPS);)
637
    {
638
    sig1 = sig;
639
    sum = mea = sig = 0.0;
640
    lowsum = highsum = 0;
641
    histot = hilow = histo+lcut;
642
    hihigh = histo+hcut;
643
    for (i=lcut; i<=hcut; i++)
644
      {
645
      if (lowsum<highsum)
646
        lowsum += *(hilow++);
647
      else
648
        highsum +=  *(hihigh--);
649
      sum += (pix = *(histot++));
650
      mea += (dpix = (double)pix*i);
651
      sig += dpix*i;
652
      }
653
 
654
    med = hihigh>=histo?
655
        ((hihigh-histo)+0.5+((double)highsum-lowsum)/(2.0*(*hilow>*hihigh?
656
                                                *hilow:*hihigh)))
657
       : 0.0;
658
    if (sum)
659
      {
660
      mea /= (double)sum;
661
      sig = sig/sum - mea*mea;
662
      }
663
    sig = sig>0.0?sqrt(sig):0.0;
664
    lcut = (ftemp=med-3.0*sig)>0.0 ?(int)(ftemp>0.0?ftemp+0.5:ftemp-0.5):0;
665
    hcut = (ftemp=med+3.0*sig)<nlevelsm1 ?(int)(ftemp>0.0?ftemp+0.5:ftemp-0.5)
666
                                                                : nlevelsm1;
667
    }
668
  *mean = fabs(sig)>0.0? (fabs(bkg->sigma/(sig*bkg->qscale)-1) < 0.0 ?
669
                            bkg->qzero+mea*bkg->qscale
670
                            :(fabs((mea-med)/sig)< 0.3 ?
671
                              bkg->qzero+(2.5*med-1.5*mea)*bkg->qscale
672
                             :bkg->qzero+med*bkg->qscale))
673
                       :bkg->qzero+mea*bkg->qscale;
674
 
675
  *sigma = sig*bkg->qscale;
676
 
677
  return *mean;
678
  }
679
 
680
 
681
/******************************* filterback *********************************/
682
/*
683
Median filtering of the background map to remove the contribution from bright
684
sources.
685
*/
686
void    filterback(picstruct *field)
687
 
688
  {
689
   float        *back,*sigma, *back2,*sigma2, *bmask,*smask, *sigmat,
690
                d2,d2min, fthresh, med, val,sval;
691 173 bertin
   int          i,j,px,py, np, nx,ny, npx,npx2, npy,npy2, dpx,dpy, x,y, nmin;
692 2 bertin
 
693
  fthresh = prefs.backfthresh;
694
  nx = field->nbackx;
695
  ny = field->nbacky;
696
  np = field->nback;
697 173 bertin
  npx = field->nbackfx/2;
698
  npy = field->nbackfy/2;
699
  npy *= nx;
700 2 bertin
 
701 173 bertin
  QMALLOC(bmask, float, (2*npx+1)*(2*npy+1));
702
  QMALLOC(smask, float, (2*npx+1)*(2*npy+1));
703 2 bertin
  QMALLOC(back2, float, np);
704
  QMALLOC(sigma2, float, np);
705
 
706
  back = field->back;
707
  sigma = field->sigma;
708
  val = sval = 0.0;                     /* to avoid gcc -Wall warnings */
709
 
710
/* Look for `bad' meshes and interpolate them if necessary */
711
  for (i=0,py=0; py<ny; py++)
712
    for (px=0; px<nx; px++,i++)
713
      if ((back2[i]=back[i])<=-BIG)
714
        {
715
/*------ Seek the closest valid mesh */
716
        d2min = BIG;
717
        nmin = 0.0;
718
        for (j=0,y=0; y<ny; y++)
719
          for (x=0; x<nx; x++,j++)
720
            if (back[j]>-BIG)
721
              {
722
              d2 = (float)(x-px)*(x-px)+(y-py)*(y-py);
723
              if (d2<d2min)
724
                {
725
                val = back[j];
726
                sval = sigma[j];
727
                nmin = 1;
728
                d2min = d2;
729
                }
730
              else if (d2==d2min)
731
                {
732
                val += back[j];
733
                sval += sigma[j];
734
                nmin++;
735
                }
736
              }
737
        back2[i] = nmin? val/nmin: 0.0;
738
        sigma[i] = nmin? sval/nmin: 1.0;
739
        }
740
  memcpy(back, back2, (size_t)np*sizeof(float));
741
 
742
/* Do the actual filtering */
743
  for (py=0; py<np; py+=nx)
744 173 bertin
    {
745
    npy2 = np - py - nx;
746
    if (npy2>npy)
747
      npy2 = npy;
748
    if (npy2>py)
749
      npy2 = py;
750 2 bertin
    for (px=0; px<nx; px++)
751
      {
752 173 bertin
      npx2 = nx - px - 1;
753
      if (npx2>npx)
754
        npx2 = npx;
755
      if (npx2>px)
756
        npx2 = px;
757 2 bertin
      i=0;
758 173 bertin
      for (dpy = -npy2; dpy<=npy2; dpy+=nx)
759
        {
760
        y = py+dpy;
761
        for (dpx = -npx2; dpx <= npx2; dpx++)
762 2 bertin
          {
763
          x = px+dpx;
764 173 bertin
          bmask[i] = back[x+y];
765
          smask[i++] = sigma[x+y];
766 2 bertin
          }
767 173 bertin
        }
768 233 bertin
      if (fabs((med=fqmedian(bmask, i))-back[px+py])>=fthresh)
769 2 bertin
        {
770
        back2[px+py] = med;
771 233 bertin
        sigma2[px+py] = fqmedian(smask, i);
772 2 bertin
        }
773
      else
774
        {
775
        back2[px+py] = back[px+py];
776
        sigma2[px+py] = sigma[px+py];
777
        }
778
      }
779 173 bertin
    }
780 2 bertin
 
781
  free(bmask);
782
  free(smask);
783
  memcpy(back, back2, np*sizeof(float));
784 233 bertin
  field->backmean = fqmedian(back2, np);
785 2 bertin
  free(back2);
786
  memcpy(sigma, sigma2, np*sizeof(float));
787 233 bertin
  field->backsig = fqmedian(sigma2, np);
788 2 bertin
 
789
  if (field->backsig<=0.0)
790
    {
791
    sigmat = sigma2+np;
792
    for (i=np; i-- && *(--sigmat)>0.0;);
793
    if (i>=0 && i<(np-1))
794 233 bertin
      field->backsig = fqmedian(sigmat+1, np-1-i);
795 2 bertin
    else
796
      {
797
      if (field->flags&(DETECT_FIELD|MEASURE_FIELD))
798
        warning("Image contains mainly constant data; ",
799
                "I'll try to cope with that...");
800
      field->backsig = 1.0;
801
      }
802
    }
803
 
804
  free(sigma2);
805
 
806
 
807
  return;
808
  }
809
 
810
 
811
/******************************** localback *********************************/
812
/*
813
Compute Local background if possible.
814
*/
815
float   localback(picstruct *field, objstruct *obj)
816
 
817
  {
818
   static backstruct    backmesh;
819
   int                  bxmin,bxmax, bymin,bymax, ixmin,ixmax, iymin,iymax,
820
                        bxnml,bynml, oxsize,oysize, npix,
821
                        i, x,y, bin, w,sh, bmn, pbs;
822
   float                bkg, bqs,cste;
823
   LONG                 *bmh;
824
   PIXTYPE              *backpix, *bp, *strip, *st,
825
                        pix;
826
 
827
  strip = field->strip;
828
  w = field->width;
829
  sh = field->stripheight;
830
  pbs = prefs.pback_size;
831
 
832
/* Estimate background in a 'rectangular annulus' around the object */
833
  oxsize = obj->xmax - obj->xmin + 1;
834
  oysize = obj->ymax - obj->ymin + 1;
835
  bxnml = oxsize<w/2? oxsize/4 : (w-oxsize)/4;
836
  bynml = oysize<field->height/2? oysize/4 : (field->height-oysize)/4;
837
  bxmin = (ixmin = obj->xmin - bxnml) - pbs;
838
  bxmax = (ixmax = obj->xmax+1 + bxnml) + pbs;
839
  bymin = (iymin = obj->ymin - bynml) - pbs;
840
  bymax = (iymax = obj->ymax+1 + bynml) + pbs;
841
 
842
  if (bymin>=field->ymin && bymax<field->ymax
843
        && bxmin>=0 && bxmax<w)
844
    {
845
    npix = (bxmax-bxmin)*(bymax-bymin) - (ixmax-ixmin)*(iymax-iymin);
846
 
847
    QMALLOC(backpix, PIXTYPE, npix);
848
    bp = backpix;
849
 
850
/*--store all the pixels*/
851
    npix = 0;
852
    for (y=bymin; y<bymax; y++)
853
      {
854
      st = strip + (y%sh)*w + bxmin;
855
      for (x=pbs; x--;)
856
        if ((pix=*(st++))>-BIG)
857
          {
858
          *(bp++) = pix;
859
          npix++;
860
          }
861
      st += ixmax-ixmin;
862
      for (x=pbs; x--;)
863
        if ((pix=*(st++))>-BIG)
864
          {
865
          *(bp++) = pix;
866
          npix++;
867
          }
868
      }
869
 
870
    for (y=bymin; y<iymin; y++)
871
      {
872
      st = strip + (y%sh)*w + ixmin;
873
      for (x=ixmax-ixmin; x--;)
874
        if ((pix=*(st++))>-BIG)
875
          {
876
          *(bp++) = pix;
877
          npix++;
878
          }
879
      }
880
    for (y=iymax; y<bymax; y++)
881
      {
882
      st = strip + (y%sh)*w + ixmin;
883
      for (x=ixmax-ixmin; x--;)
884
        if ((pix=*(st++))>-BIG)
885
          {
886
          *(bp++) = pix;
887
          npix++;
888
          }
889
      }
890
 
891
    if (npix)
892
      {
893
      backstat(&backmesh, NULL, backpix, NULL, npix, 1, 1, 1, 0.0);
894
      QCALLOC(backmesh.histo, LONG, backmesh.nlevels);
895
      bmh = backmesh.histo;
896
      bmn = backmesh.nlevels;
897
      cste = 0.499999 - backmesh.qzero/(bqs = backmesh.qscale);
898
      bp = backpix;
899
      for (i=npix; i--;)
900
        {
901
        bin = (int)(*(bp++)/bqs + cste);
902
        if (bin>=0 && bin<bmn)
903
          (*(bmh+bin))++;
904
        }
905
      backguess(&backmesh, &bkg, &obj->sigbkg);
906
      obj->bkg += (obj->dbkg = bkg);
907
      free(backmesh.histo);
908
      }
909
    else
910
      {
911
      obj->dbkg = 0.0;
912
      obj->sigbkg = field->backsig;
913
      }
914
    free(backpix);
915
    }
916
  else
917
    {
918
    obj->dbkg = bkg = 0.0;
919
    obj->sigbkg = field->backsig;
920
    }
921
 
922
  return bkg;
923
  }
924
 
925
 
926
/************************************ back ***********************************/
927
/*
928
return background at position x,y (linear interpolation between background
929
map vertices).
930
*/
931
PIXTYPE back(picstruct *field, int x, int y)
932
 
933
  {
934
   int          nx,ny, xl,yl, pos;
935
   double       dx,dy, cdx;
936
   float        *b, b0,b1,b2,b3;
937
 
938
  b = field->back;
939
  nx = field->nbackx;
940
  ny = field->nbacky;
941
 
942
  dx = (double)x/field->backw - 0.5;
943
  dy = (double)y/field->backh - 0.5;
944
  dx -= (xl = (int)dx);
945
  dy -= (yl = (int)dy);
946
 
947
  if (xl<0)
948
    {
949
    xl = 0;
950
    dx -= 1.0;
951
    }
952
  else if (xl>=nx-1)
953
    {
954
    xl = nx<2 ? 0 : nx-2;
955
    dx += 1.0;
956
    }
957
 
958
  if (yl<0)
959
    {
960
    yl = 0;
961
    dy -= 1.0;
962
    }
963
  else if (yl>=ny-1)
964
    {
965
    yl = ny<2 ? 0 : ny-2;
966
    dy += 1.0;
967
    }
968
 
969
  pos = yl*nx + xl;
970
  cdx = 1 - dx;
971
 
972
  b0 = *(b+=pos);               /* consider when nbackx or nbacky = 1 */
973
  b1 = nx<2? b0:*(++b);
974
  b2 = ny<2? *b:*(b+=nx);
975
  b3 = nx<2? *b:*(--b);
976
 
977
  return (PIXTYPE)((1-dy)*(cdx*b0 + dx*b1) + dy*(dx*b2 + cdx*b3));
978
  }
979
 
980
 
981
/******************************* makebackspline ******************************/
982
/*
983
Pre-compute 2nd derivatives along the y direction at background nodes.
984
*/
985
float *makebackspline(picstruct *field, float *map)
986
 
987
  {
988
   int          x,y, nbx,nby,nbym1;
989
   float        *dmap,*dmapt,*mapt, *u, temp;
990
 
991
  nbx = field->nbackx;
992
  nby = field->nbacky;
993
  nbym1 = nby - 1;
994
  QMALLOC(dmap, float, field->nback);
995
  for (x=0; x<nbx; x++)
996
    {
997
    mapt = map+x;
998
    dmapt = dmap+x;
999
    if (nby>1)
1000
      {
1001
      QMALLOC(u, float, nbym1); /* temporary array */
1002
      *dmapt = *u = 0.0;        /* "natural" lower boundary condition */
1003
      mapt += nbx;
1004
      for (y=1; y<nbym1; y++, mapt+=nbx)
1005
        {
1006
        temp = -1/(*dmapt+4);
1007
        *(dmapt += nbx) = temp;
1008
        temp *= *(u++) - 6*(*(mapt+nbx)+*(mapt-nbx)-2**mapt);
1009
        *u = temp;
1010
        }
1011
      *(dmapt+=nbx) = 0.0;      /* "natural" upper boundary condition */
1012
      for (y=nby-2; y--;)
1013
        {
1014
        temp = *dmapt;
1015
        dmapt -= nbx;
1016
        *dmapt = (*dmapt*temp+*(u--))/6.0;
1017
        }
1018
      free(u);
1019
      }
1020
    else
1021
      *dmapt = 0.0;
1022
    }
1023
 
1024
  return dmap;
1025
  }
1026
 
1027
 
1028
/******************************* subbackline *********************************/
1029
/*
1030
Interpolate background at line y (bicubic spline interpolation between
1031
background map vertices) and subtract it from the current line.
1032
*/
1033
void    subbackline(picstruct *field, int y, PIXTYPE *line)
1034
 
1035
  {
1036
   int          i,j,x,yl, nbx,nbxm1,nby, nx,width, ystep, changepoint;
1037
   float        dx,dx0,dy,dy3, cdx,cdy,cdy3, temp, xstep,
1038
                *node,*nodep,*dnode, *blo,*bhi,*dblo,*dbhi, *u;
1039
   PIXTYPE      *backline, bval;
1040
 
1041
  width = field->width;
1042
  backline = field->backline;
1043
 
1044
  if (field->back_type==BACK_ABSOLUTE)
1045
    {
1046
/*-- In absolute background mode, just subtract a cste */
1047
    bval = field->backmean;
1048
    for (i=width; i--;)
1049
      *(line++) -= ((*backline++)=bval);
1050
    return;
1051
    }
1052
 
1053
  nbx = field->nbackx;
1054
  nbxm1 = nbx - 1;
1055
  nby = field->nbacky;
1056
  if (nby > 1)
1057
    {
1058
    dy = (float)y/field->backh - 0.5;
1059
    dy -= (yl = (int)dy);
1060
    if (yl<0)
1061
      {
1062
      yl = 0;
1063
      dy -= 1.0;
1064
      }
1065
    else if (yl>=nby-1)
1066
      {
1067
      yl = nby<2 ? 0 : nby-2;
1068
      dy += 1.0;
1069
      }
1070
/*-- Interpolation along y for each node */
1071
    cdy = 1 - dy;
1072
    dy3 = (dy*dy*dy-dy);
1073
    cdy3 = (cdy*cdy*cdy-cdy);
1074
    ystep = nbx*yl;
1075
    blo = field->back + ystep;
1076
    bhi = blo + nbx;
1077
    dblo = field->dback + ystep;
1078
    dbhi = dblo + nbx;
1079
    QMALLOC(node, float, nbx);  /* Interpolated background */
1080
    nodep = node;
1081
    for (x=nbx; x--;)
1082
      *(nodep++) = cdy**(blo++) + dy**(bhi++) + cdy3**(dblo++) + dy3**(dbhi++);
1083
 
1084
/*-- Computation of 2nd derivatives along x */
1085
    QMALLOC(dnode, float, nbx); /* 2nd derivative along x */
1086
    if (nbx>1)
1087
      {
1088
      QMALLOC(u, float, nbxm1); /* temporary array */
1089
      *dnode = *u = 0.0;        /* "natural" lower boundary condition */
1090
      nodep = node+1;
1091
      for (x=nbxm1; --x; nodep++)
1092
        {
1093
        temp = -1/(*(dnode++)+4);
1094
        *dnode = temp;
1095
        temp *= *(u++) - 6*(*(nodep+1)+*(nodep-1)-2**nodep);
1096
        *u = temp;
1097
        }
1098
      *(++dnode) = 0.0; /* "natural" upper boundary condition */
1099
      for (x=nbx-2; x--;)
1100
        {
1101
        temp = *(dnode--);
1102
        *dnode = (*dnode*temp+*(u--))/6.0;
1103
        }
1104
      free(u);
1105
      dnode--;
1106
      }
1107
    }
1108
  else
1109
    {
1110
/*-- No interpolation and no new 2nd derivatives needed along y */
1111
    node = field->back;
1112
    dnode = field->dback;
1113
    }
1114
 
1115
/*-- Interpolation along x */
1116
  if (nbx>1)
1117
    {
1118
    nx = field->backw;
1119
    xstep = 1.0/nx;
1120
    changepoint = nx/2;
1121
    dx  = (xstep - 1)/2;        /* dx of the first pixel in the row */
1122
    dx0 = ((nx+1)%2)*xstep/2;   /* dx of the 1st pixel right to a bkgnd node */
1123
    blo = node;
1124
    bhi = node + 1;
1125
    dblo = dnode;
1126
    dbhi = dnode + 1;
1127
    for (x=i=0,j=width; j--; i++, dx += xstep)
1128
      {
1129
      if (i==changepoint && x>0 && x<nbxm1)
1130
        {
1131
        blo++;
1132
        bhi++;
1133
        dblo++;
1134
        dbhi++;
1135
        dx = dx0;
1136
        }
1137
      cdx = 1 - dx;
1138
      *(line++) -= (*(backline++) = (PIXTYPE)(cdx*(*blo+(cdx*cdx-1)**dblo)
1139
                        + dx*(*bhi+(dx*dx-1)**dbhi)));
1140
      if (i==nx)
1141
        {
1142
        x++;
1143
        i = 0;
1144
        }
1145
      }
1146
    }
1147
  else
1148
    for (j=width; j--;)
1149
      *(line++) -= (*(backline++) = (PIXTYPE)*node);
1150
 
1151
  if (nby>1)
1152
    {
1153
    free(node);
1154
    free(dnode);
1155
    }
1156
 
1157
  return;
1158
  }
1159
 
1160
 
1161
/******************************* backrmsline ********************************
1162
PROTO   void backrmsline(picstruct *field, int y, PIXTYPE *line)
1163
PURPOSE Bicubic-spline interpolation of the background noise along the current
1164
        scanline (y).
1165
INPUT   Measurement or detection field pointer,
1166
        Current line position.
1167
        Where to put the data.
1168
OUTPUT  -.
1169
NOTES   Most of the code is a copy of subbackline(), for optimization reasons.
1170
AUTHOR  E. Bertin (IAP & Leiden & ESO)
1171
VERSION 02/02/98
1172
 ***/
1173
void    backrmsline(picstruct *field, int y, PIXTYPE *line)
1174
 
1175
  {
1176
   int          i,j,x,yl, nbx,nbxm1,nby, nx,width, ystep, changepoint;
1177
   float        dx,dx0,dy,dy3, cdx,cdy,cdy3, temp, xstep,
1178
                *node,*nodep,*dnode, *blo,*bhi,*dblo,*dbhi, *u;
1179
 
1180
  nbx = field->nbackx;
1181
  nbxm1 = nbx - 1;
1182
  nby = field->nbacky;
1183
  if (nby > 1)
1184
    {
1185
    dy = (float)y/field->backh - 0.5;
1186
    dy -= (yl = (int)dy);
1187
    if (yl<0)
1188
      {
1189
      yl = 0;
1190
      dy -= 1.0;
1191
      }
1192
    else if (yl>=nby-1)
1193
      {
1194
      yl = nby<2 ? 0 : nby-2;
1195
      dy += 1.0;
1196
      }
1197
/*-- Interpolation along y for each node */
1198
    cdy = 1 - dy;
1199
    dy3 = (dy*dy*dy-dy);
1200
    cdy3 = (cdy*cdy*cdy-cdy);
1201
    ystep = nbx*yl;
1202
    blo = field->sigma + ystep;
1203
    bhi = blo + nbx;
1204
    dblo = field->dsigma + ystep;
1205
    dbhi = dblo + nbx;
1206
    QMALLOC(node, float, nbx);  /* Interpolated background */
1207
    nodep = node;
1208
    for (x=nbx; x--;)
1209
      *(nodep++) = cdy**(blo++) + dy**(bhi++) + cdy3**(dblo++) + dy3**(dbhi++);
1210
 
1211
/*-- Computation of 2nd derivatives along x */
1212
    QMALLOC(dnode, float, nbx); /* 2nd derivative along x */
1213
    if (nbx>1)
1214
      {
1215
      QMALLOC(u, float, nbxm1); /* temporary array */
1216
      *dnode = *u = 0.0;        /* "natural" lower boundary condition */
1217
      nodep = node+1;
1218
      for (x=nbxm1; --x; nodep++)
1219
        {
1220
        temp = -1/(*(dnode++)+4);
1221
        *dnode = temp;
1222
        temp *= *(u++) - 6*(*(nodep+1)+*(nodep-1)-2**nodep);
1223
        *u = temp;
1224
        }
1225
      *(++dnode) = 0.0; /* "natural" upper boundary condition */
1226
      for (x=nbx-2; x--;)
1227
        {
1228
        temp = *(dnode--);
1229
        *dnode = (*dnode*temp+*(u--))/6.0;
1230
        }
1231
      free(u);
1232
      dnode--;
1233
      }
1234
    }
1235
  else
1236
    {
1237
/*-- No interpolation and no new 2nd derivatives needed along y */
1238
    node = field->sigma;
1239
    dnode = field->dsigma;
1240
    }
1241
 
1242
/*-- Interpolation along x */
1243
  width = field->width;
1244
  if (nbx>1)
1245
    {
1246
    nx = field->backw;
1247
    xstep = 1.0/nx;
1248
    changepoint = nx/2;
1249
    dx  = (xstep - 1)/2;        /* dx of the first pixel in the row */
1250
    dx0 = ((nx+1)%2)*xstep/2;   /* dx of the 1st pixel right to a bkgnd node */
1251
    blo = node;
1252
    bhi = node + 1;
1253
    dblo = dnode;
1254
    dbhi = dnode + 1;
1255
    for (x=i=0,j=width; j--; i++, dx += xstep)
1256
      {
1257
      if (i==changepoint && x>0 && x<nbxm1)
1258
        {
1259
        blo++;
1260
        bhi++;
1261
        dblo++;
1262
        dbhi++;
1263
        dx = dx0;
1264
        }
1265
      cdx = 1 - dx;
1266
      *(line++) = (PIXTYPE)(cdx*(*blo+(cdx*cdx-1)**dblo)
1267
                        + dx*(*bhi+(dx*dx-1)**dbhi));
1268
      if (i==nx)
1269
        {
1270
        x++;
1271
        i = 0;
1272
        }
1273
      }
1274
    }
1275
  else
1276
    for (j=width; j--;)
1277
      *(line++) = (PIXTYPE)*node;
1278
 
1279
  if (nby>1)
1280
    {
1281
    free(node);
1282
    free(dnode);
1283
    }
1284
 
1285
  return;
1286
  }
1287
 
1288
 
1289
/********************************* copyback **********************************/
1290
/*
1291
Copy sub-structures related to background procedures (mainly freeing memory).
1292
*/
1293
void    copyback(picstruct *infield, picstruct *outfield)
1294
 
1295
  {
1296
  QMEMCPY(infield->back, outfield->back, float, infield->nback);
1297
  QMEMCPY(infield->dback, outfield->dback, float, infield->nback);
1298
  QMEMCPY(infield->sigma, outfield->sigma, float, infield->nback);
1299
  QMEMCPY(infield->dsigma, outfield->dsigma, float, infield->nback);
1300
  QMEMCPY(infield->backline, outfield->backline, PIXTYPE, infield->width);
1301
 
1302
  return;
1303
  }
1304
 
1305
 
1306
/********************************* endback ***********************************/
1307
/*
1308
Terminate background procedures (mainly freeing memory).
1309
*/
1310
void    endback(picstruct *field)
1311
 
1312
  {
1313
  free(field->back);
1314
  free(field->dback);
1315
  free(field->sigma);
1316
  free(field->dsigma);
1317
  free(field->backline);
1318
 
1319
  return;
1320
  }
1321