public software.sextractor

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

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

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