public software.sextractor

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

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 244 bertin
*       Copyright:              (C) 1993-2011 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 244 bertin
*       Last modified:          23/03/2011
26 233 bertin
*
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 243 bertin
void    makeback(picstruct *field, picstruct *wfield, int wscale_flag)
52 2 bertin
 
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 244 bertin
                sratio, sigfac;
64 2 bertin
 
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 244 bertin
  if (wfield && wfield->flags&(VAR_FIELD|WEIGHT_FIELD))
298 2 bertin
    {
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 244 bertin
    sigfac = fqmedian(ratio, nr);
312 2 bertin
    for (i=0; i<nr && ratio[i]<=0.0; i++);
313
    if (i<nr)
314 244 bertin
      sigfac = fqmedian(ratio+i, nr-i);
315 2 bertin
    else
316
      {
317
      warning("Null or negative global weighting factor:","defaulted to 1");
318 244 bertin
      sigfac = 1.0;
319 2 bertin
      }
320
    free(ratio);
321 244 bertin
 
322
    if (wscale_flag)
323
      wfield->sigfac = sigfac;
324
    else
325
      {
326
      wfield->sigfac = 1.0;
327
      field->backsig /= sigfac;
328
      }
329 2 bertin
    }
330
 
331 244 bertin
 
332 2 bertin
/* Compute 2nd derivatives along the y-direction */
333
  NFPRINTF(OUTPUT, "Computing background d-map");
334
  free(field->dback);
335
  field->dback = makebackspline(field, field->back);
336
  NFPRINTF(OUTPUT, "Computing background-noise d-map");
337
  free(field->dsigma);
338
  field->dsigma = makebackspline(field, field->sigma);
339
/* If asked for, force the backmean parameter to the supplied value */
340
  if (field->back_type == BACK_ABSOLUTE)
341
    field->backmean = (float)prefs.back_val[(field->flags&DETECT_FIELD)?0:1];
342
 
343
/* Set detection/measurement threshold */
344
  if (prefs.ndthresh > 1)
345
    {
346
     double     dval;
347
 
348
    if (fabs(dval=prefs.dthresh[0] - prefs.dthresh[1])> 70.0)
349
      error(EXIT_FAILURE,
350
        "*Error*: I cannot deal with such extreme thresholds!", "");
351
 
352
    field->dthresh = field->pixscale*field->pixscale*pow(10.0, -0.4*dval);
353
    }
354
  else if (prefs.thresh_type[0]==THRESH_ABSOLUTE)
355
    field->dthresh = prefs.dthresh[0];
356
  else
357
    field->dthresh = prefs.dthresh[0]*field->backsig;
358
  if (prefs.nthresh > 1)
359
    {
360
     double     dval;
361
 
362
    if (fabs(dval=prefs.thresh[0] - prefs.thresh[1]) > 70.0)
363
      error(EXIT_FAILURE,
364
        "*Error*: I cannot deal with such extreme thresholds!", "");
365
 
366
    field->thresh = field->pixscale*field->pixscale*pow(10.0, -0.4*dval);
367
    }
368
  else if (prefs.thresh_type[1]==THRESH_ABSOLUTE)
369
    field->thresh = prefs.thresh[0];
370
  else
371
    field->thresh = prefs.thresh[0]*field->backsig;
372
 
373
#ifdef  QUALITY_CHECK
374
  printf("%-10g %-10g %-10g\n", field->backmean, field->backsig,
375
        (field->flags & DETECT_FIELD)? field->dthresh : field->thresh);
376
#endif
377
  if (field->dthresh<=0.0 || field->thresh<=0.0)
378
    error(EXIT_FAILURE,
379
        "*Error*: I cannot deal with zero or negative thresholds!", "");
380
 
381
  if (prefs.detect_type == PHOTO
382
        && field->backmean+3*field->backsig > 50*field->ngamma)
383
    error(EXIT_FAILURE,
384
        "*Error*: The density range of this image is too large for ",
385
        "PHOTO mode");
386
 
387
  return;
388
  }
389
 
390
 
391
/******************************** backstat **********************************/
392
/*
393
Compute robust statistical estimators in a row of meshes.
394
*/
395
void    backstat(backstruct *backmesh, backstruct *wbackmesh,
396
                PIXTYPE *buf, PIXTYPE *wbuf, size_t bufsize,
397
                        int n, int w, int bw, PIXTYPE wthresh)
398
 
399
  {
400
   backstruct   *bm, *wbm;
401
   double       pix,wpix, sig, mean,wmean, sigma,wsigma, step;
402
   PIXTYPE      *buft,*wbuft,
403
                lcut,wlcut, hcut,whcut;
404 21 bertin
   int          m,h,x,y, npix,wnpix, offset, lastbite;
405 2 bertin
 
406
  h = bufsize/w;
407
  bm = backmesh;
408
  wbm = wbackmesh;
409
  offset = w - bw;
410
  step = sqrt(2/PI)*QUANTIF_NSIGMA/QUANTIF_AMIN;
411
  wmean = wsigma = wlcut = whcut = 0.0; /* to avoid gcc -Wall warnings */
412
  for (m = n; m--; bm++,buf+=bw)
413
    {
414
    if (!m && (lastbite=w%bw))
415
      {
416
      bw = lastbite;
417
      offset = w-bw;
418
      }
419
    mean = sigma = 0.0;
420
    buft=buf;
421
/*-- We separate the weighted case at this level to avoid penalty in CPU */
422 21 bertin
    npix = 0;
423 2 bertin
    if (wbackmesh)
424
      {
425
      wmean = wsigma = 0.0;
426
      wbuft = wbuf;
427
      for (y=h; y--; buft+=offset,wbuft+=offset)
428
        for (x=bw; x--;)
429
          {
430
          pix = *(buft++);
431 21 bertin
          if ((wpix = *(wbuft++)) < wthresh && pix > -BIG)
432 2 bertin
            {
433
            wmean += wpix;
434
            wsigma += wpix*wpix;
435
            mean += pix;
436
            sigma += pix*pix;
437 21 bertin
            npix++;
438 2 bertin
            }
439
          }
440
      }
441
    else
442
      for (y=h; y--; buft+=offset)
443
        for (x=bw; x--;)
444 21 bertin
          if ((pix = *(buft++)) > -BIG)
445
            {
446
            mean += pix;
447
            sigma += pix*pix;
448
            npix++;
449
            }
450
/*-- If not enough valid pixels, discard this mesh */
451
    if ((float)npix < (float)(bw*h*BACK_MINGOODFRAC))
452 2 bertin
      {
453 21 bertin
      bm->mean = bm->sigma = -BIG;
454
      if (wbackmesh)
455 2 bertin
        {
456 21 bertin
        wbm->mean = wbm->sigma = -BIG;
457
        wbm++;
458
        wbuf += bw;
459 2 bertin
        }
460 21 bertin
      continue;
461
      }
462
    if (wbackmesh)
463
      {
464 2 bertin
      wmean /= (double)npix;
465
      wsigma = (sig = wsigma/npix - wmean*wmean)>0.0? sqrt(sig):0.0;
466
      wlcut = wbm->lcut = (PIXTYPE)(wmean - 2.0*wsigma);
467
      whcut = wbm->hcut = (PIXTYPE)(wmean + 2.0*wsigma);
468
      }
469
    mean /= (double)npix;
470
    sigma = (sig = sigma/npix - mean*mean)>0.0? sqrt(sig):0.0;
471
    lcut = bm->lcut = (PIXTYPE)(mean - 2.0*sigma);
472
    hcut = bm->hcut = (PIXTYPE)(mean + 2.0*sigma);
473
    mean = sigma = 0.0;
474
    npix = wnpix = 0;
475
    buft = buf;
476
    if (wbackmesh)
477
      {
478
      wmean = wsigma = 0.0;
479
      wbuft=wbuf;
480
      for (y=h; y--; buft+=offset, wbuft+=offset)
481
        for (x=bw; x--;)
482
          {
483
          pix = *(buft++);
484
          if ((wpix = *(wbuft++))<wthresh && pix<=hcut && pix>=lcut)
485
            {
486
            mean += pix;
487
            sigma += pix*pix;
488
            npix++;
489
            if (wpix<=whcut && wpix>=wlcut)
490
              {
491
              wmean += wpix;
492
              wsigma += wpix*wpix;
493
              wnpix++;
494
              }
495
            }
496
          }
497
      }
498
    else
499
      for (y=h; y--; buft+=offset)
500
        for (x=bw; x--;)
501
          {
502
          pix = *(buft++);
503
          if (pix<=hcut && pix>=lcut)
504
            {
505
            mean += pix;
506
            sigma += pix*pix;
507
            npix++;
508
            }
509
          }
510
 
511
    bm->npix = npix;
512
    mean /= (double)npix;
513
    sig = sigma/npix - mean*mean;
514
    sigma = sig>0.0 ? sqrt(sig):0.0;
515
    bm->mean = mean;
516
    bm->sigma = sigma;
517
    if ((bm->nlevels = (int)(step*npix+1)) > QUANTIF_NMAXLEVELS)
518
      bm->nlevels = QUANTIF_NMAXLEVELS;
519
    bm->qscale = sigma>0.0? 2*QUANTIF_NSIGMA*sigma/bm->nlevels : 1.0;
520
    bm->qzero = mean - QUANTIF_NSIGMA*sigma;
521
    if (wbackmesh)
522
      {
523
      wbm->npix = wnpix;
524
      wmean /= (double)wnpix;
525
      sig = wsigma/wnpix - wmean*wmean;
526
      wsigma = sig>0.0 ? sqrt(sig):0.0;
527
      wbm->mean = wmean;
528
      wbm->sigma = wsigma;
529
      if ((wbm->nlevels = (int)(step*wnpix+1)) > QUANTIF_NMAXLEVELS)
530
        wbm->nlevels = QUANTIF_NMAXLEVELS;
531
      wbm->qscale = wsigma>0.0? 2*QUANTIF_NSIGMA*wsigma/wbm->nlevels : 1.0;
532
      wbm->qzero = wmean - QUANTIF_NSIGMA*wsigma;
533
      wbm++;
534
      wbuf += bw;
535
      }
536
    }
537
 
538
  return;
539
  }
540
 
541
 
542
/******************************** backhisto *********************************/
543
/*
544
Compute robust statistical estimators in a row of meshes.
545
*/
546
void    backhisto(backstruct *backmesh, backstruct *wbackmesh,
547
                PIXTYPE *buf, PIXTYPE *wbuf, size_t bufsize,
548
                        int n, int w, int bw, PIXTYPE wthresh)
549
  {
550
   backstruct   *bm,*wbm;
551
   PIXTYPE      *buft,*wbuft;
552
   float        qscale,wqscale, cste,wcste, wpix;
553
   LONG         *histo,*whisto;
554
   int          h,m,x,y, nlevels,wnlevels, lastbite, offset, bin;
555
 
556
  h = bufsize/w;
557
  bm = backmesh;
558
  wbm = wbackmesh;
559
  offset = w - bw;
560
  for (m=0; m++<n; bm++ , buf+=bw)
561
    {
562
    if (m==n && (lastbite=w%bw))
563
      {
564
      bw = lastbite;
565
      offset = w-bw;
566
      }
567
/*-- Skip bad meshes */
568
    if (bm->mean <= -BIG)
569
      {
570
      if (wbackmesh)
571
        {
572
        wbm++;
573
        wbuf += bw;
574
        }
575
      continue;
576
      }
577
    nlevels = bm->nlevels;
578
    histo = bm->histo;
579
    qscale = bm->qscale;
580
    cste = 0.499999 - bm->qzero/qscale;
581
    buft = buf;
582
    if (wbackmesh)
583
      {
584
      wnlevels = wbm->nlevels;
585
      whisto = wbm->histo;
586
      wqscale = wbm->qscale;
587
      wcste = 0.499999 - wbm->qzero/wqscale;
588
      wbuft = wbuf;
589
      for (y=h; y--; buft+=offset, wbuft+=offset)
590
        for (x=bw; x--;)
591
          {
592
          bin = (int)(*(buft++)/qscale + cste);
593
          if ((wpix = *(wbuft++))<wthresh && bin<nlevels && bin>=0)
594
            {
595
            (*(histo+bin))++;
596
            bin = (int)(wpix/wqscale + wcste);
597
            if (bin>=0 && bin<wnlevels)
598
              (*(whisto+bin))++;
599
            }
600
          }
601
      wbm++;
602
      wbuf += bw;
603
      }
604
    else
605
      for (y=h; y--; buft += offset)
606
        for (x=bw; x--;)
607
          {
608
          bin = (int)(*(buft++)/qscale + cste);
609
          if (bin>=0 && bin<nlevels)
610
            (*(histo+bin))++;
611
          }
612
    }
613
 
614
  return;
615
  }
616
 
617
/******************************* backguess **********************************/
618
/*
619
Estimate the background from a histogram;
620
*/
621
float   backguess(backstruct *bkg, float *mean, float *sigma)
622
 
623
#define EPS     (1e-4)  /* a small number */
624
 
625
  {
626
   LONG         *histo, *hilow, *hihigh, *histot;
627
   unsigned long lowsum, highsum, sum;
628
   double       ftemp, mea, sig, sig1, med, dpix;
629
   int          i, n, lcut,hcut, nlevelsm1, pix;
630
 
631
/* Leave here if the mesh is already classified as `bad' */
632
  if (bkg->mean<=-BIG)
633
    {
634
    *mean = *sigma = -BIG;
635
    return -BIG;
636
    }
637
 
638
  histo = bkg->histo;
639
  hcut = nlevelsm1 = bkg->nlevels-1;
640
  lcut = 0;
641
 
642
  sig = 10.0*nlevelsm1;
643
  sig1 = 1.0;
644
  mea = med = bkg->mean;
645
  for (n=100; n-- && (sig>=0.1) && (fabs(sig/sig1-1.0)>EPS);)
646
    {
647
    sig1 = sig;
648
    sum = mea = sig = 0.0;
649
    lowsum = highsum = 0;
650
    histot = hilow = histo+lcut;
651
    hihigh = histo+hcut;
652
    for (i=lcut; i<=hcut; i++)
653
      {
654
      if (lowsum<highsum)
655
        lowsum += *(hilow++);
656
      else
657
        highsum +=  *(hihigh--);
658
      sum += (pix = *(histot++));
659
      mea += (dpix = (double)pix*i);
660
      sig += dpix*i;
661
      }
662
 
663
    med = hihigh>=histo?
664
        ((hihigh-histo)+0.5+((double)highsum-lowsum)/(2.0*(*hilow>*hihigh?
665
                                                *hilow:*hihigh)))
666
       : 0.0;
667
    if (sum)
668
      {
669
      mea /= (double)sum;
670
      sig = sig/sum - mea*mea;
671
      }
672
    sig = sig>0.0?sqrt(sig):0.0;
673
    lcut = (ftemp=med-3.0*sig)>0.0 ?(int)(ftemp>0.0?ftemp+0.5:ftemp-0.5):0;
674
    hcut = (ftemp=med+3.0*sig)<nlevelsm1 ?(int)(ftemp>0.0?ftemp+0.5:ftemp-0.5)
675
                                                                : nlevelsm1;
676
    }
677
  *mean = fabs(sig)>0.0? (fabs(bkg->sigma/(sig*bkg->qscale)-1) < 0.0 ?
678
                            bkg->qzero+mea*bkg->qscale
679
                            :(fabs((mea-med)/sig)< 0.3 ?
680
                              bkg->qzero+(2.5*med-1.5*mea)*bkg->qscale
681
                             :bkg->qzero+med*bkg->qscale))
682
                       :bkg->qzero+mea*bkg->qscale;
683
 
684
  *sigma = sig*bkg->qscale;
685
 
686
  return *mean;
687
  }
688
 
689
 
690
/******************************* filterback *********************************/
691
/*
692
Median filtering of the background map to remove the contribution from bright
693
sources.
694
*/
695
void    filterback(picstruct *field)
696
 
697
  {
698
   float        *back,*sigma, *back2,*sigma2, *bmask,*smask, *sigmat,
699
                d2,d2min, fthresh, med, val,sval;
700 173 bertin
   int          i,j,px,py, np, nx,ny, npx,npx2, npy,npy2, dpx,dpy, x,y, nmin;
701 2 bertin
 
702
  fthresh = prefs.backfthresh;
703
  nx = field->nbackx;
704
  ny = field->nbacky;
705
  np = field->nback;
706 173 bertin
  npx = field->nbackfx/2;
707
  npy = field->nbackfy/2;
708
  npy *= nx;
709 2 bertin
 
710 173 bertin
  QMALLOC(bmask, float, (2*npx+1)*(2*npy+1));
711
  QMALLOC(smask, float, (2*npx+1)*(2*npy+1));
712 2 bertin
  QMALLOC(back2, float, np);
713
  QMALLOC(sigma2, float, np);
714
 
715
  back = field->back;
716
  sigma = field->sigma;
717
  val = sval = 0.0;                     /* to avoid gcc -Wall warnings */
718
 
719
/* Look for `bad' meshes and interpolate them if necessary */
720
  for (i=0,py=0; py<ny; py++)
721
    for (px=0; px<nx; px++,i++)
722
      if ((back2[i]=back[i])<=-BIG)
723
        {
724
/*------ Seek the closest valid mesh */
725
        d2min = BIG;
726
        nmin = 0.0;
727
        for (j=0,y=0; y<ny; y++)
728
          for (x=0; x<nx; x++,j++)
729
            if (back[j]>-BIG)
730
              {
731
              d2 = (float)(x-px)*(x-px)+(y-py)*(y-py);
732
              if (d2<d2min)
733
                {
734
                val = back[j];
735
                sval = sigma[j];
736
                nmin = 1;
737
                d2min = d2;
738
                }
739
              else if (d2==d2min)
740
                {
741
                val += back[j];
742
                sval += sigma[j];
743
                nmin++;
744
                }
745
              }
746
        back2[i] = nmin? val/nmin: 0.0;
747
        sigma[i] = nmin? sval/nmin: 1.0;
748
        }
749
  memcpy(back, back2, (size_t)np*sizeof(float));
750
 
751
/* Do the actual filtering */
752
  for (py=0; py<np; py+=nx)
753 173 bertin
    {
754
    npy2 = np - py - nx;
755
    if (npy2>npy)
756
      npy2 = npy;
757
    if (npy2>py)
758
      npy2 = py;
759 2 bertin
    for (px=0; px<nx; px++)
760
      {
761 173 bertin
      npx2 = nx - px - 1;
762
      if (npx2>npx)
763
        npx2 = npx;
764
      if (npx2>px)
765
        npx2 = px;
766 2 bertin
      i=0;
767 173 bertin
      for (dpy = -npy2; dpy<=npy2; dpy+=nx)
768
        {
769
        y = py+dpy;
770
        for (dpx = -npx2; dpx <= npx2; dpx++)
771 2 bertin
          {
772
          x = px+dpx;
773 173 bertin
          bmask[i] = back[x+y];
774
          smask[i++] = sigma[x+y];
775 2 bertin
          }
776 173 bertin
        }
777 233 bertin
      if (fabs((med=fqmedian(bmask, i))-back[px+py])>=fthresh)
778 2 bertin
        {
779
        back2[px+py] = med;
780 233 bertin
        sigma2[px+py] = fqmedian(smask, i);
781 2 bertin
        }
782
      else
783
        {
784
        back2[px+py] = back[px+py];
785
        sigma2[px+py] = sigma[px+py];
786
        }
787
      }
788 173 bertin
    }
789 2 bertin
 
790
  free(bmask);
791
  free(smask);
792
  memcpy(back, back2, np*sizeof(float));
793 233 bertin
  field->backmean = fqmedian(back2, np);
794 2 bertin
  free(back2);
795
  memcpy(sigma, sigma2, np*sizeof(float));
796 233 bertin
  field->backsig = fqmedian(sigma2, np);
797 2 bertin
 
798
  if (field->backsig<=0.0)
799
    {
800
    sigmat = sigma2+np;
801
    for (i=np; i-- && *(--sigmat)>0.0;);
802
    if (i>=0 && i<(np-1))
803 233 bertin
      field->backsig = fqmedian(sigmat+1, np-1-i);
804 2 bertin
    else
805
      {
806
      if (field->flags&(DETECT_FIELD|MEASURE_FIELD))
807
        warning("Image contains mainly constant data; ",
808
                "I'll try to cope with that...");
809
      field->backsig = 1.0;
810
      }
811
    }
812
 
813
  free(sigma2);
814
 
815
 
816
  return;
817
  }
818
 
819
 
820
/******************************** localback *********************************/
821
/*
822
Compute Local background if possible.
823
*/
824
float   localback(picstruct *field, objstruct *obj)
825
 
826
  {
827
   static backstruct    backmesh;
828
   int                  bxmin,bxmax, bymin,bymax, ixmin,ixmax, iymin,iymax,
829
                        bxnml,bynml, oxsize,oysize, npix,
830
                        i, x,y, bin, w,sh, bmn, pbs;
831
   float                bkg, bqs,cste;
832
   LONG                 *bmh;
833
   PIXTYPE              *backpix, *bp, *strip, *st,
834
                        pix;
835
 
836
  strip = field->strip;
837
  w = field->width;
838
  sh = field->stripheight;
839
  pbs = prefs.pback_size;
840
 
841
/* Estimate background in a 'rectangular annulus' around the object */
842
  oxsize = obj->xmax - obj->xmin + 1;
843
  oysize = obj->ymax - obj->ymin + 1;
844
  bxnml = oxsize<w/2? oxsize/4 : (w-oxsize)/4;
845
  bynml = oysize<field->height/2? oysize/4 : (field->height-oysize)/4;
846
  bxmin = (ixmin = obj->xmin - bxnml) - pbs;
847
  bxmax = (ixmax = obj->xmax+1 + bxnml) + pbs;
848
  bymin = (iymin = obj->ymin - bynml) - pbs;
849
  bymax = (iymax = obj->ymax+1 + bynml) + pbs;
850
 
851
  if (bymin>=field->ymin && bymax<field->ymax
852
        && bxmin>=0 && bxmax<w)
853
    {
854
    npix = (bxmax-bxmin)*(bymax-bymin) - (ixmax-ixmin)*(iymax-iymin);
855
 
856
    QMALLOC(backpix, PIXTYPE, npix);
857
    bp = backpix;
858
 
859
/*--store all the pixels*/
860
    npix = 0;
861
    for (y=bymin; y<bymax; y++)
862
      {
863
      st = strip + (y%sh)*w + bxmin;
864
      for (x=pbs; x--;)
865
        if ((pix=*(st++))>-BIG)
866
          {
867
          *(bp++) = pix;
868
          npix++;
869
          }
870
      st += ixmax-ixmin;
871
      for (x=pbs; x--;)
872
        if ((pix=*(st++))>-BIG)
873
          {
874
          *(bp++) = pix;
875
          npix++;
876
          }
877
      }
878
 
879
    for (y=bymin; y<iymin; y++)
880
      {
881
      st = strip + (y%sh)*w + ixmin;
882
      for (x=ixmax-ixmin; x--;)
883
        if ((pix=*(st++))>-BIG)
884
          {
885
          *(bp++) = pix;
886
          npix++;
887
          }
888
      }
889
    for (y=iymax; y<bymax; y++)
890
      {
891
      st = strip + (y%sh)*w + ixmin;
892
      for (x=ixmax-ixmin; x--;)
893
        if ((pix=*(st++))>-BIG)
894
          {
895
          *(bp++) = pix;
896
          npix++;
897
          }
898
      }
899
 
900
    if (npix)
901
      {
902
      backstat(&backmesh, NULL, backpix, NULL, npix, 1, 1, 1, 0.0);
903
      QCALLOC(backmesh.histo, LONG, backmesh.nlevels);
904
      bmh = backmesh.histo;
905
      bmn = backmesh.nlevels;
906
      cste = 0.499999 - backmesh.qzero/(bqs = backmesh.qscale);
907
      bp = backpix;
908
      for (i=npix; i--;)
909
        {
910
        bin = (int)(*(bp++)/bqs + cste);
911
        if (bin>=0 && bin<bmn)
912
          (*(bmh+bin))++;
913
        }
914
      backguess(&backmesh, &bkg, &obj->sigbkg);
915
      obj->bkg += (obj->dbkg = bkg);
916
      free(backmesh.histo);
917
      }
918
    else
919
      {
920
      obj->dbkg = 0.0;
921
      obj->sigbkg = field->backsig;
922
      }
923
    free(backpix);
924
    }
925
  else
926
    {
927
    obj->dbkg = bkg = 0.0;
928
    obj->sigbkg = field->backsig;
929
    }
930
 
931
  return bkg;
932
  }
933
 
934
 
935
/************************************ back ***********************************/
936
/*
937
return background at position x,y (linear interpolation between background
938
map vertices).
939
*/
940
PIXTYPE back(picstruct *field, int x, int y)
941
 
942
  {
943
   int          nx,ny, xl,yl, pos;
944
   double       dx,dy, cdx;
945
   float        *b, b0,b1,b2,b3;
946
 
947
  b = field->back;
948
  nx = field->nbackx;
949
  ny = field->nbacky;
950
 
951
  dx = (double)x/field->backw - 0.5;
952
  dy = (double)y/field->backh - 0.5;
953
  dx -= (xl = (int)dx);
954
  dy -= (yl = (int)dy);
955
 
956
  if (xl<0)
957
    {
958
    xl = 0;
959
    dx -= 1.0;
960
    }
961
  else if (xl>=nx-1)
962
    {
963
    xl = nx<2 ? 0 : nx-2;
964
    dx += 1.0;
965
    }
966
 
967
  if (yl<0)
968
    {
969
    yl = 0;
970
    dy -= 1.0;
971
    }
972
  else if (yl>=ny-1)
973
    {
974
    yl = ny<2 ? 0 : ny-2;
975
    dy += 1.0;
976
    }
977
 
978
  pos = yl*nx + xl;
979
  cdx = 1 - dx;
980
 
981
  b0 = *(b+=pos);               /* consider when nbackx or nbacky = 1 */
982
  b1 = nx<2? b0:*(++b);
983
  b2 = ny<2? *b:*(b+=nx);
984
  b3 = nx<2? *b:*(--b);
985
 
986
  return (PIXTYPE)((1-dy)*(cdx*b0 + dx*b1) + dy*(dx*b2 + cdx*b3));
987
  }
988
 
989
 
990
/******************************* makebackspline ******************************/
991
/*
992
Pre-compute 2nd derivatives along the y direction at background nodes.
993
*/
994
float *makebackspline(picstruct *field, float *map)
995
 
996
  {
997
   int          x,y, nbx,nby,nbym1;
998
   float        *dmap,*dmapt,*mapt, *u, temp;
999
 
1000
  nbx = field->nbackx;
1001
  nby = field->nbacky;
1002
  nbym1 = nby - 1;
1003
  QMALLOC(dmap, float, field->nback);
1004
  for (x=0; x<nbx; x++)
1005
    {
1006
    mapt = map+x;
1007
    dmapt = dmap+x;
1008
    if (nby>1)
1009
      {
1010
      QMALLOC(u, float, nbym1); /* temporary array */
1011
      *dmapt = *u = 0.0;        /* "natural" lower boundary condition */
1012
      mapt += nbx;
1013
      for (y=1; y<nbym1; y++, mapt+=nbx)
1014
        {
1015
        temp = -1/(*dmapt+4);
1016
        *(dmapt += nbx) = temp;
1017
        temp *= *(u++) - 6*(*(mapt+nbx)+*(mapt-nbx)-2**mapt);
1018
        *u = temp;
1019
        }
1020
      *(dmapt+=nbx) = 0.0;      /* "natural" upper boundary condition */
1021
      for (y=nby-2; y--;)
1022
        {
1023
        temp = *dmapt;
1024
        dmapt -= nbx;
1025
        *dmapt = (*dmapt*temp+*(u--))/6.0;
1026
        }
1027
      free(u);
1028
      }
1029
    else
1030
      *dmapt = 0.0;
1031
    }
1032
 
1033
  return dmap;
1034
  }
1035
 
1036
 
1037
/******************************* subbackline *********************************/
1038
/*
1039
Interpolate background at line y (bicubic spline interpolation between
1040
background map vertices) and subtract it from the current line.
1041
*/
1042
void    subbackline(picstruct *field, int y, PIXTYPE *line)
1043
 
1044
  {
1045
   int          i,j,x,yl, nbx,nbxm1,nby, nx,width, ystep, changepoint;
1046
   float        dx,dx0,dy,dy3, cdx,cdy,cdy3, temp, xstep,
1047
                *node,*nodep,*dnode, *blo,*bhi,*dblo,*dbhi, *u;
1048
   PIXTYPE      *backline, bval;
1049
 
1050
  width = field->width;
1051
  backline = field->backline;
1052
 
1053
  if (field->back_type==BACK_ABSOLUTE)
1054
    {
1055
/*-- In absolute background mode, just subtract a cste */
1056
    bval = field->backmean;
1057
    for (i=width; i--;)
1058
      *(line++) -= ((*backline++)=bval);
1059
    return;
1060
    }
1061
 
1062
  nbx = field->nbackx;
1063
  nbxm1 = nbx - 1;
1064
  nby = field->nbacky;
1065
  if (nby > 1)
1066
    {
1067
    dy = (float)y/field->backh - 0.5;
1068
    dy -= (yl = (int)dy);
1069
    if (yl<0)
1070
      {
1071
      yl = 0;
1072
      dy -= 1.0;
1073
      }
1074
    else if (yl>=nby-1)
1075
      {
1076
      yl = nby<2 ? 0 : nby-2;
1077
      dy += 1.0;
1078
      }
1079
/*-- Interpolation along y for each node */
1080
    cdy = 1 - dy;
1081
    dy3 = (dy*dy*dy-dy);
1082
    cdy3 = (cdy*cdy*cdy-cdy);
1083
    ystep = nbx*yl;
1084
    blo = field->back + ystep;
1085
    bhi = blo + nbx;
1086
    dblo = field->dback + ystep;
1087
    dbhi = dblo + nbx;
1088
    QMALLOC(node, float, nbx);  /* Interpolated background */
1089
    nodep = node;
1090
    for (x=nbx; x--;)
1091
      *(nodep++) = cdy**(blo++) + dy**(bhi++) + cdy3**(dblo++) + dy3**(dbhi++);
1092
 
1093
/*-- Computation of 2nd derivatives along x */
1094
    QMALLOC(dnode, float, nbx); /* 2nd derivative along x */
1095
    if (nbx>1)
1096
      {
1097
      QMALLOC(u, float, nbxm1); /* temporary array */
1098
      *dnode = *u = 0.0;        /* "natural" lower boundary condition */
1099
      nodep = node+1;
1100
      for (x=nbxm1; --x; nodep++)
1101
        {
1102
        temp = -1/(*(dnode++)+4);
1103
        *dnode = temp;
1104
        temp *= *(u++) - 6*(*(nodep+1)+*(nodep-1)-2**nodep);
1105
        *u = temp;
1106
        }
1107
      *(++dnode) = 0.0; /* "natural" upper boundary condition */
1108
      for (x=nbx-2; x--;)
1109
        {
1110
        temp = *(dnode--);
1111
        *dnode = (*dnode*temp+*(u--))/6.0;
1112
        }
1113
      free(u);
1114
      dnode--;
1115
      }
1116
    }
1117
  else
1118
    {
1119
/*-- No interpolation and no new 2nd derivatives needed along y */
1120
    node = field->back;
1121
    dnode = field->dback;
1122
    }
1123
 
1124
/*-- Interpolation along x */
1125
  if (nbx>1)
1126
    {
1127
    nx = field->backw;
1128
    xstep = 1.0/nx;
1129
    changepoint = nx/2;
1130
    dx  = (xstep - 1)/2;        /* dx of the first pixel in the row */
1131
    dx0 = ((nx+1)%2)*xstep/2;   /* dx of the 1st pixel right to a bkgnd node */
1132
    blo = node;
1133
    bhi = node + 1;
1134
    dblo = dnode;
1135
    dbhi = dnode + 1;
1136
    for (x=i=0,j=width; j--; i++, dx += xstep)
1137
      {
1138
      if (i==changepoint && x>0 && x<nbxm1)
1139
        {
1140
        blo++;
1141
        bhi++;
1142
        dblo++;
1143
        dbhi++;
1144
        dx = dx0;
1145
        }
1146
      cdx = 1 - dx;
1147
      *(line++) -= (*(backline++) = (PIXTYPE)(cdx*(*blo+(cdx*cdx-1)**dblo)
1148
                        + dx*(*bhi+(dx*dx-1)**dbhi)));
1149
      if (i==nx)
1150
        {
1151
        x++;
1152
        i = 0;
1153
        }
1154
      }
1155
    }
1156
  else
1157
    for (j=width; j--;)
1158
      *(line++) -= (*(backline++) = (PIXTYPE)*node);
1159
 
1160
  if (nby>1)
1161
    {
1162
    free(node);
1163
    free(dnode);
1164
    }
1165
 
1166
  return;
1167
  }
1168
 
1169
 
1170
/******************************* backrmsline ********************************
1171
PROTO   void backrmsline(picstruct *field, int y, PIXTYPE *line)
1172
PURPOSE Bicubic-spline interpolation of the background noise along the current
1173
        scanline (y).
1174
INPUT   Measurement or detection field pointer,
1175
        Current line position.
1176
        Where to put the data.
1177
OUTPUT  -.
1178
NOTES   Most of the code is a copy of subbackline(), for optimization reasons.
1179
AUTHOR  E. Bertin (IAP & Leiden & ESO)
1180
VERSION 02/02/98
1181
 ***/
1182
void    backrmsline(picstruct *field, int y, PIXTYPE *line)
1183
 
1184
  {
1185
   int          i,j,x,yl, nbx,nbxm1,nby, nx,width, ystep, changepoint;
1186
   float        dx,dx0,dy,dy3, cdx,cdy,cdy3, temp, xstep,
1187
                *node,*nodep,*dnode, *blo,*bhi,*dblo,*dbhi, *u;
1188
 
1189
  nbx = field->nbackx;
1190
  nbxm1 = nbx - 1;
1191
  nby = field->nbacky;
1192
  if (nby > 1)
1193
    {
1194
    dy = (float)y/field->backh - 0.5;
1195
    dy -= (yl = (int)dy);
1196
    if (yl<0)
1197
      {
1198
      yl = 0;
1199
      dy -= 1.0;
1200
      }
1201
    else if (yl>=nby-1)
1202
      {
1203
      yl = nby<2 ? 0 : nby-2;
1204
      dy += 1.0;
1205
      }
1206
/*-- Interpolation along y for each node */
1207
    cdy = 1 - dy;
1208
    dy3 = (dy*dy*dy-dy);
1209
    cdy3 = (cdy*cdy*cdy-cdy);
1210
    ystep = nbx*yl;
1211
    blo = field->sigma + ystep;
1212
    bhi = blo + nbx;
1213
    dblo = field->dsigma + ystep;
1214
    dbhi = dblo + nbx;
1215
    QMALLOC(node, float, nbx);  /* Interpolated background */
1216
    nodep = node;
1217
    for (x=nbx; x--;)
1218
      *(nodep++) = cdy**(blo++) + dy**(bhi++) + cdy3**(dblo++) + dy3**(dbhi++);
1219
 
1220
/*-- Computation of 2nd derivatives along x */
1221
    QMALLOC(dnode, float, nbx); /* 2nd derivative along x */
1222
    if (nbx>1)
1223
      {
1224
      QMALLOC(u, float, nbxm1); /* temporary array */
1225
      *dnode = *u = 0.0;        /* "natural" lower boundary condition */
1226
      nodep = node+1;
1227
      for (x=nbxm1; --x; nodep++)
1228
        {
1229
        temp = -1/(*(dnode++)+4);
1230
        *dnode = temp;
1231
        temp *= *(u++) - 6*(*(nodep+1)+*(nodep-1)-2**nodep);
1232
        *u = temp;
1233
        }
1234
      *(++dnode) = 0.0; /* "natural" upper boundary condition */
1235
      for (x=nbx-2; x--;)
1236
        {
1237
        temp = *(dnode--);
1238
        *dnode = (*dnode*temp+*(u--))/6.0;
1239
        }
1240
      free(u);
1241
      dnode--;
1242
      }
1243
    }
1244
  else
1245
    {
1246
/*-- No interpolation and no new 2nd derivatives needed along y */
1247
    node = field->sigma;
1248
    dnode = field->dsigma;
1249
    }
1250
 
1251
/*-- Interpolation along x */
1252
  width = field->width;
1253
  if (nbx>1)
1254
    {
1255
    nx = field->backw;
1256
    xstep = 1.0/nx;
1257
    changepoint = nx/2;
1258
    dx  = (xstep - 1)/2;        /* dx of the first pixel in the row */
1259
    dx0 = ((nx+1)%2)*xstep/2;   /* dx of the 1st pixel right to a bkgnd node */
1260
    blo = node;
1261
    bhi = node + 1;
1262
    dblo = dnode;
1263
    dbhi = dnode + 1;
1264
    for (x=i=0,j=width; j--; i++, dx += xstep)
1265
      {
1266
      if (i==changepoint && x>0 && x<nbxm1)
1267
        {
1268
        blo++;
1269
        bhi++;
1270
        dblo++;
1271
        dbhi++;
1272
        dx = dx0;
1273
        }
1274
      cdx = 1 - dx;
1275
      *(line++) = (PIXTYPE)(cdx*(*blo+(cdx*cdx-1)**dblo)
1276
                        + dx*(*bhi+(dx*dx-1)**dbhi));
1277
      if (i==nx)
1278
        {
1279
        x++;
1280
        i = 0;
1281
        }
1282
      }
1283
    }
1284
  else
1285
    for (j=width; j--;)
1286
      *(line++) = (PIXTYPE)*node;
1287
 
1288
  if (nby>1)
1289
    {
1290
    free(node);
1291
    free(dnode);
1292
    }
1293
 
1294
  return;
1295
  }
1296
 
1297
 
1298
/********************************* copyback **********************************/
1299
/*
1300
Copy sub-structures related to background procedures (mainly freeing memory).
1301
*/
1302
void    copyback(picstruct *infield, picstruct *outfield)
1303
 
1304
  {
1305
  QMEMCPY(infield->back, outfield->back, float, infield->nback);
1306
  QMEMCPY(infield->dback, outfield->dback, float, infield->nback);
1307
  QMEMCPY(infield->sigma, outfield->sigma, float, infield->nback);
1308
  QMEMCPY(infield->dsigma, outfield->dsigma, float, infield->nback);
1309
  QMEMCPY(infield->backline, outfield->backline, PIXTYPE, infield->width);
1310
 
1311
  return;
1312
  }
1313
 
1314
 
1315
/********************************* endback ***********************************/
1316
/*
1317
Terminate background procedures (mainly freeing memory).
1318
*/
1319
void    endback(picstruct *field)
1320
 
1321
  {
1322
  free(field->back);
1323
  free(field->dback);
1324
  free(field->sigma);
1325
  free(field->dsigma);
1326
  free(field->backline);
1327
 
1328
  return;
1329
  }
1330