public software.sextractor

[/] [trunk/] [src/] [scan.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
*                               scan.c
3 2 bertin
*
4 233 bertin
* Main image scanning routines.
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        "back.h"
42
#include        "check.h"
43
#include        "clean.h"
44
#include        "extract.h"
45
#include        "filter.h"
46
#include        "image.h"
47
#include        "plist.h"
48 210 bertin
#include        "weight.h"
49 2 bertin
 
50
/****************************** scanimage ************************************
51
PROTO   void scanimage(picstruct *field, picstruct *dfield, picstruct *ffield,
52
        picstruct *wfield, picstruct *dwfield)
53
PURPOSE Scan of the large pixmap(s). Main loop and heart of the program.
54
INPUT   Measurement field pointer,
55
        Detection field pointer,
56
        Flag field pointer,
57
        Measurement weight-map field pointer,
58
        Detection weight-map field pointer,
59
OUTPUT  -.
60
NOTES   -.
61 4 bertin
AUTHOR  E. Bertin (IAP)
62 231 bertin
VERSION 28/09/2010
63 2 bertin
 ***/
64
void    scanimage(picstruct *field, picstruct *dfield, picstruct **pffield,
65
                int nffield, picstruct *wfield, picstruct *dwfield)
66
 
67
  {
68
   static infostruct    curpixinfo, *info, *store,
69
                        initinfo, freeinfo, *victim;
70
   picstruct            *ffield;
71
   checkstruct          *check;
72
   objliststruct        objlist;
73
   objstruct            *cleanobj;
74
   pliststruct          *pixel, *pixt;
75
   picstruct            *cfield, *cdwfield;
76
 
77
   char                 *marker, newmarker, *blankpad, *bpt,*bpt0;
78
   int                  co, i,j, flag, luflag,pstop, xl,xl2,yl, cn,
79
                        nposize, stacksize, w, h, blankh, maxpixnb,
80 194 bertin
                        varthreshflag, ontotal;
81 2 bertin
   short                trunflag;
82 210 bertin
   PIXTYPE              thresh, relthresh, cdnewsymbol, cdvar,cdwthresh,wthresh,
83
                        *scan,*dscan,*cdscan,*dwscan,*dwscanp,*dwscann,
84
                        *cdwscan,*cdwscanp,*cdwscann,*wscand,
85
                        *scant, *wscan,*wscann,*wscanp;
86 2 bertin
   FLAGTYPE             *pfscan[MAXFLAG];
87
   status               cs, ps, *psstack;
88
   int                  *start, *end, ymax;
89
 
90 4 bertin
/* Avoid gcc -Wall warnings */
91 210 bertin
  scan = dscan = cdscan = cdwscan = cdwscann = cdwscanp
92
        = dwscan = dwscann = dwscanp
93
        = wscan = wscann = wscanp = NULL;
94 4 bertin
  victim = NULL;                        /* Avoid gcc -Wall warnings */
95 2 bertin
  blankh = 0;                            /* Avoid gcc -Wall warnings */
96
/*----- Beginning of the main loop: Initialisations  */
97
  thecat.ntotal = thecat.ndetect = 0;
98
 
99
/* cfield is the detection field in any case */
100
  cfield = dfield? dfield:field;
101
 
102
/* cdwfield is the detection weight-field if available */
103
  cdwfield = dwfield? dwfield:(prefs.dweight_flag?wfield:NULL);
104 210 bertin
  cdwthresh = cdwfield ? cdwfield->weight_thresh : 0.0;
105
  if (cdwthresh>BIG*WTHRESH_CONVFAC);
106
    cdwthresh = BIG*WTHRESH_CONVFAC;
107
  wthresh = wfield? wfield->weight_thresh : 0.0;
108 2 bertin
 
109
/* If WEIGHTing and no absolute thresholding, activate threshold scaling */
110
  varthreshflag = (cdwfield && prefs.thresh_type[0]!=THRESH_ABSOLUTE);
111
  relthresh = varthreshflag ? prefs.dthresh[0] : 0.0;/* To avoid gcc warnings*/
112
  w = cfield->width;
113
  h = cfield->height;
114
  objlist.dthresh = cfield->dthresh;
115 231 bertin
  objlist.thresh = field->thresh;
116 2 bertin
  cfield->yblank = 1;
117
  field->y = field->stripy = 0;
118
  field->ymin = field->stripylim = 0;
119
  field->stripysclim = 0;
120
  if (dfield)
121
    {
122
    dfield->y = dfield->stripy = 0;
123
    dfield->ymin = dfield->stripylim = 0;
124
    dfield->stripysclim = 0;
125
    }
126
  if (nffield)
127
    for (i=0; i<nffield; i++)
128
      {
129
      ffield = pffield[i];
130
      ffield->y = ffield->stripy = 0;
131
      ffield->ymin = ffield->stripylim = 0;
132
      ffield->stripysclim = 0;
133
      }
134
  if (wfield)
135
    {
136
    wfield->y = wfield->stripy = 0;
137
    wfield->ymin = wfield->stripylim = 0;
138
    wfield->stripysclim = 0;
139
    }
140
  if (dwfield)
141
    {
142
    dwfield->y = dwfield->stripy = 0;
143
    dwfield->ymin = dwfield->stripylim = 0;
144
    dwfield->stripysclim = 0;
145
    }
146
 
147
/*Allocate memory for buffers */
148
  stacksize = w+1;
149
  QMALLOC(info, infostruct, stacksize);
150 173 bertin
  QCALLOC(store, infostruct, stacksize);
151 2 bertin
  QMALLOC(marker, char, stacksize);
152
  QMALLOC(dumscan, PIXTYPE, stacksize);
153
  QMALLOC(psstack, status, stacksize);
154 173 bertin
  QCALLOC(start, int, stacksize);
155 2 bertin
  QMALLOC(end, int, stacksize);
156
  blankpad = bpt = NULL;
157
  lutzalloc(w,h);
158
  allocparcelout();
159
 
160
/* Some initializations */
161
 
162
  thresh = objlist.dthresh;
163
  initinfo.pixnb = 0;
164
  initinfo.flag = 0;
165
  initinfo.firstpix = initinfo.lastpix = -1;
166
 
167
  for (xl=0; xl<stacksize; xl++)
168
    {
169
    marker[xl]  = 0 ;
170
    dumscan[xl] = -BIG ;
171
    }
172
 
173
  co = pstop = 0;
174
  objlist.nobj = 1;
175
  curpixinfo.pixnb = 1;
176
 
177
/* Init cleaning procedure */
178
  initclean();
179
 
180
/*----- Allocate memory for the pixel list */
181
  init_plist();
182
 
183
  if (!(pixel = objlist.plist = malloc(nposize=prefs.mem_pixstack*plistsize)))
184
    error(EXIT_FAILURE, "Not enough memory to store the pixel stack:\n",
185
        "           Try to decrease MEMORY_PIXSTACK");
186
 
187
/*----- at the beginning, "free" object fills the whole pixel list */
188
  freeinfo.firstpix = 0;
189
  freeinfo.lastpix = nposize-plistsize;
190
  pixt = pixel;
191
  for (i=plistsize; i<nposize; i += plistsize, pixt += plistsize)
192
    PLIST(pixt, nextpix) = i;
193
  PLIST(pixt, nextpix) = -1;
194
 
195 210 bertin
/* Allocate memory for other buffers */
196
  if (prefs.filter_flag)
197
    {
198
    QMALLOC(cdscan, PIXTYPE, stacksize);
199
    if (cdwfield)
200
      {
201
      QCALLOC(cdwscan, PIXTYPE, stacksize);
202
      if (PLISTEXIST(wflag))
203
        {
204
        QCALLOC(cdwscanp, PIXTYPE, stacksize);
205
        QCALLOC(cdwscann, PIXTYPE, stacksize);
206
        }
207
      }
208
/*-- One needs a buffer to protect filtering if source-blanking applies */
209
    if (prefs.blank_flag)
210
      {
211
      blankh = thefilter->convh/2+1;
212
      QMALLOC(blankpad, char, w*blankh);
213
      cfield->yblank -= blankh;
214
      if (dfield)
215
        field->yblank = cfield->yblank;
216
      bpt = blankpad;
217
      }
218
    }
219
 
220 2 bertin
/*----- Here we go */
221
  for (yl=0; yl<=h;)
222
    {
223
    ps = COMPLETE;
224
    cs = NONOBJECT;
225
    if (yl==h)
226
      {
227
/*---- Need an empty line for Lutz' algorithm to end gracely */
228
      if (prefs.filter_flag)
229
        {
230
        free(cdscan);
231
        if (cdwfield)
232 4 bertin
          {
233
          if (PLISTEXIST(wflag))
234 210 bertin
            {
235 4 bertin
            free(cdwscanp);
236 210 bertin
            free(cdwscann);
237
            cdwscanp = cdwscan;
238
            }
239
          else
240
            free(cdwscan);
241 4 bertin
          }
242 2 bertin
        }
243 210 bertin
      cdwscan = cdwscann = cdscan = dumscan;
244 2 bertin
      }
245
    else
246
      {
247
      if (nffield)
248
        for (i=0; i<nffield; i++)
249
          {
250
          ffield = pffield[i];
251
          pfscan[i] = (ffield->stripy==ffield->stripysclim)?
252
                  (FLAGTYPE *)loadstrip(ffield, (picstruct *)NULL)
253
                : &ffield->fstrip[ffield->stripy*ffield->width];
254
          }
255
      if (wfield)
256 4 bertin
        {
257
/*------ Copy the previous weight line to track bad pixel limits */
258 2 bertin
        wscan = (wfield->stripy==wfield->stripysclim)?
259
                  (PIXTYPE *)loadstrip(wfield, (picstruct *)NULL)
260
                : &wfield->strip[wfield->stripy*wfield->width];
261 210 bertin
        if (PLISTEXIST(wflag))
262
          {
263
          if (yl>0)
264
            wscanp = &wfield->strip[((yl-1)%wfield->stripheight)*wfield->width];
265
          if (yl<h-1)
266
            wscann = &wfield->strip[((yl+1)%wfield->stripheight)*wfield->width];
267
          }
268 4 bertin
        }
269 2 bertin
      scan = (field->stripy==field->stripysclim)?
270
                  (PIXTYPE *)loadstrip(field, wfield)
271
                : &field->strip[field->stripy*field->width];
272
      if (dwfield)
273 210 bertin
        {
274 2 bertin
        dwscan = (dwfield->stripy==dwfield->stripysclim)?
275
                  (PIXTYPE *)loadstrip(dwfield,
276
                                dfield?(picstruct *)NULL:dwfield)
277
                : &dwfield->strip[dwfield->stripy*dwfield->width];
278 210 bertin
        if (PLISTEXIST(wflag))
279
          {
280
          if (yl>0)
281
            dwscanp = &dwfield->strip[((yl-1)%dwfield->stripheight)
282
                        *dwfield->width];
283
          if (yl<h-1)
284
            dwscann = &dwfield->strip[((yl+1)%dwfield->stripheight)
285
                        *dwfield->width];
286
          }
287
        }
288 2 bertin
      else
289 210 bertin
        {
290 2 bertin
        dwscan = wscan;
291 210 bertin
        if (PLISTEXIST(wflag))
292
          {
293
          dwscanp = wscanp;
294
          dwscann = wscann;
295
          }
296
        }
297 2 bertin
      if (dfield)
298
        dscan = (dfield->stripy==dfield->stripysclim)?
299
                  (PIXTYPE *)loadstrip(dfield, dwfield)
300
                : &dfield->strip[dfield->stripy*dfield->width];
301
      else
302
        dscan = scan;
303
 
304
      if (prefs.filter_flag)
305
        {
306 210 bertin
        filter(cfield, cdscan, cfield->y);
307 2 bertin
        if (cdwfield)
308 217 bertin
          {
309 210 bertin
          if (PLISTEXIST(wflag))
310
            {
311
            if (yl==0)
312
              filter(cdwfield, cdwscann, yl);
313
            wscand = cdwscanp;
314
            cdwscanp = cdwscan;
315
            cdwscan = cdwscann;
316
            cdwscann = wscand;
317
            if (yl < h-1)
318
              filter(cdwfield, cdwscann, yl + 1);
319
            }
320
          else
321
            filter(cdwfield, cdwscan, yl);
322 217 bertin
          }
323 2 bertin
        }
324
      else
325
        {
326
        cdscan = dscan;
327
        cdwscan = dwscan;
328 210 bertin
        if (PLISTEXIST(wflag))
329
          {
330
          cdwscanp = dwscanp;
331
          cdwscann = dwscann;
332
          }
333 2 bertin
        }
334
 
335
      if ((check=prefs.check[CHECK_FILTERED]))
336
        writecheck(check, cdscan, w);
337
      }
338
 
339
    trunflag = (yl==0 || yl==h-1)? OBJ_TRUNC:0;
340
 
341
    for (xl=0; xl<=w; xl++)
342
      {
343
      if (xl == w)
344
        cdnewsymbol = -BIG;
345
      else
346
        cdnewsymbol = cdscan[xl];
347
 
348
      newmarker = marker[xl];
349
      marker[xl] = 0;
350
 
351
      curpixinfo.flag = trunflag;
352
      if (varthreshflag)
353
        thresh = relthresh*sqrt(cdvar = ((xl==w || yl==h)? 0.0:cdwscan[xl]));
354
      luflag = cdnewsymbol > thresh?1:0;
355
 
356
      if (luflag)
357
        {
358
        if (xl==0 || xl==w-1)
359
          curpixinfo.flag |= OBJ_TRUNC;
360
        pixt = pixel + (cn=freeinfo.firstpix);
361
        freeinfo.firstpix = PLIST(pixt, nextpix);
362
 
363
/*------- Running out of pixels, the largest object becomes a "victim" ------*/
364
 
365
        if (freeinfo.firstpix==freeinfo.lastpix)
366
          {
367
          sprintf(gstr, "%d,%d", xl+1, yl+1);
368
          warning("Pixel stack overflow at position ", gstr);
369
          maxpixnb = 0;
370
          for (i=0; i<=w; i++)
371
            if (store[i].pixnb>maxpixnb)
372
              if (marker[i]=='S' || (newmarker=='S' && i==xl))
373
                {
374
                flag = 0;
375
                if (i<xl)
376
                  for (j=0; j<=co; j++)
377
                    flag |= (start[j]==i);
378
                if (!flag)
379
                  maxpixnb = (victim = &store[i])->pixnb;
380
                }
381
          for (j=1; j<=co; j++)
382
            if (info[j].pixnb>maxpixnb)
383
              maxpixnb = (victim = &info[j])->pixnb;
384
 
385
          if (!maxpixnb)
386
            error(EXIT_FAILURE, "*Fatal Error*: something is badly bugged in ",
387
                "scanimage()!");
388
          if (maxpixnb <= 1)
389
            error(EXIT_FAILURE, "Pixel stack overflow in ", "scanimage()");
390
          freeinfo.firstpix = PLIST(pixel+victim->firstpix, nextpix);
391
          PLIST(pixel+victim->lastpix, nextpix) = freeinfo.lastpix;
392
          PLIST(pixel+(victim->lastpix=victim->firstpix), nextpix) = -1;
393
          victim->pixnb = 1;
394
          victim->flag |= OBJ_OVERFLOW;
395
          }
396
 
397
/*---------------------------------------------------------------------------*/
398
        curpixinfo.lastpix = curpixinfo.firstpix = cn;
399
        PLIST(pixt, nextpix) = -1;
400
        PLIST(pixt, x) = xl;
401
        PLIST(pixt, y) = yl;
402
        PLIST(pixt, value) = scan[xl];
403
        if (PLISTEXIST(dvalue))
404
          PLISTPIX(pixt, dvalue) = dscan[xl];
405
        if (PLISTEXIST(cdvalue))
406
          PLISTPIX(pixt, cdvalue) = cdnewsymbol;
407
        if (PLISTEXIST(flag))
408
          for (i=0; i<nffield; i++)
409
            PLISTFLAG(pixt, flag[i]) = pfscan[i][xl];
410 210 bertin
/*--------------------- Detect pixels with a low weight ---------------------*/
411 4 bertin
        if (PLISTEXIST(wflag) && wscan)
412
          {
413
          PLISTFLAG(pixt, wflag) = 0;
414 210 bertin
          if (wscan[xl] >= wthresh)
415
            PLISTFLAG(pixt, wflag) |= OBJ_LOWWEIGHT;
416
          if (cdwscan[xl] >= cdwthresh)
417
            PLISTFLAG(pixt, wflag) |= OBJ_LOWDWEIGHT;
418
 
419
          if (yl>0)
420 4 bertin
            {
421 210 bertin
            if (cdwscanp[xl] >= cdwthresh)
422
              PLISTFLAG(pixt, wflag) |= OBJ_LOWDWEIGHT;
423
            if (xl>0 && cdwscanp[xl-1]>=cdwthresh)
424
              PLISTFLAG(pixt, wflag) |= OBJ_LOWDWEIGHT;
425
            if (xl<w-1 && cdwscanp[xl+1]>=cdwthresh)
426
              PLISTFLAG(pixt, wflag) |= OBJ_LOWDWEIGHT;
427 4 bertin
            }
428 210 bertin
          if (xl>0 && cdwscan[xl-1]>=cdwthresh)
429
              PLISTFLAG(pixt, wflag) |= OBJ_LOWDWEIGHT;
430
          if (xl<w-1 && cdwscan[xl+1]>=cdwthresh)
431
            PLISTFLAG(pixt, wflag) |= OBJ_LOWDWEIGHT;
432
          if (yl<h-1)
433 4 bertin
            {
434 210 bertin
            if (cdwscann[xl] >= cdwthresh)
435
              PLISTFLAG(pixt, wflag) |= OBJ_LOWDWEIGHT;
436
            if (xl>0 && cdwscann[xl-1]>=cdwthresh)
437
              PLISTFLAG(pixt, wflag) |= OBJ_LOWDWEIGHT;
438
            if (xl<w-1 && cdwscann[xl+1]>=cdwthresh)
439
              PLISTFLAG(pixt, wflag) |= OBJ_LOWDWEIGHT;
440 4 bertin
            }
441
          }
442 2 bertin
        if (PLISTEXIST(dthresh))
443
          PLISTPIX(pixt, dthresh) = thresh;
444
        if (PLISTEXIST(var))
445
          PLISTPIX(pixt, var) = wscan[xl];
446
 
447
        if (cs != OBJECT)
448
/*------------------------------- Start Segment -----------------------------*/
449
 
450
          {
451
          cs = OBJECT;
452
          if (ps == OBJECT)
453
            {
454
            if (start[co] == UNKNOWN)
455
              {
456
              marker[xl] = 'S';
457
              start[co] = xl;
458
              }
459
            else
460
              marker[xl] = 's';
461
            }
462
          else
463
            {
464
            psstack[pstop++] = ps;
465
            marker[xl] = 'S';
466
            start[++co] = xl;
467
            ps = COMPLETE;
468
            info[co] = initinfo;
469
            }
470
          }
471
 
472
/*---------------------------------------------------------------------------*/
473
        }
474
 
475
      if (newmarker)
476
 
477
/*---------------------------- Process New Marker ---------------------------*/
478
 
479
        {
480
        if (newmarker == 'S')
481
          {
482
          psstack[pstop++] = ps;
483
          if (cs == NONOBJECT)
484
            {
485
            psstack[pstop++] = COMPLETE;
486
            info[++co] = store[xl];
487
            start[co] = UNKNOWN;
488
            }
489
          else
490
            update (&info[co],&store[xl], pixel);
491
          ps = OBJECT;
492
          }
493
        else if (newmarker == 's')
494
          {
495
          if ((cs == OBJECT) && (ps == COMPLETE))
496
            {
497
            pstop--;
498
            xl2 = start[co];
499
            update (&info[co-1],&info[co], pixel);
500
            if (start[--co] == UNKNOWN)
501
              start[co] = xl2;
502
            else
503
              marker[xl2] = 's';
504
            }
505
          ps = OBJECT;
506
          }
507
        else if (newmarker == 'f')
508
          ps = INCOMPLETE;
509
        else if (newmarker == 'F')
510
          {
511
          ps = psstack[--pstop];
512
          if ((cs == NONOBJECT) && (ps == COMPLETE))
513
            {
514
            if (start[co] == UNKNOWN)
515
              {
516
              if ((int)info[co].pixnb >= prefs.ext_minarea)
517 4 bertin
                {
518
                sortit(field, dfield, wfield, cdwfield, &info[co], &objlist,
519
                       cdwscan, wscan);
520
                }
521 2 bertin
/* ------------------------------------ free the chain-list */
522
 
523
              PLIST(pixel+info[co].lastpix, nextpix) = freeinfo.firstpix;
524
              freeinfo.firstpix = info[co].firstpix;
525
              }
526
            else
527
              {
528
              marker[end[co]] = 'F';
529
              store[start[co]] = info[co];
530
              }
531
            co--;
532
            ps = psstack[--pstop];
533
            }
534
          }
535
        }
536
/*---------------------------------------------------------------------------*/
537
 
538
      if (luflag)
539
        update (&info[co],&curpixinfo, pixel);
540
      else
541
        {
542
        if (cs == OBJECT)
543
/*-------------------------------- End Segment ------------------------------*/
544
          {
545
          cs = NONOBJECT;
546
          if (ps != COMPLETE)
547
            {
548
            marker[xl] = 'f';
549
            end[co] = xl;
550
            }
551
          else
552
            {
553
            ps = psstack[--pstop];
554
            marker[xl] = 'F';
555
            store[start[co]] = info[co];
556
            co--;
557
            }
558
          }
559
        }
560
 
561
      if (prefs.blank_flag && xl<w)
562
        {
563
        if (prefs.filter_flag)
564
          *(bpt++) = (luflag)?1:0;
565
        else if (luflag)
566
          dscan[xl] = -BIG;
567
        if (dfield && luflag)
568
          scan[xl] = -BIG;
569
        }
570
/*--------------------- End of the loop over the x's -----------------------*/
571
      }
572
 
573
/* Detected pixel removal at the end of each line */
574
    if (prefs.blank_flag && yl<h)
575
      {
576
      if (prefs.filter_flag)
577
        {
578
        bpt = bpt0 = blankpad + w*((yl+1)%blankh);
579
        if (cfield->yblank >= 0)
580
          {
581
          scant = &PIX(cfield, 0, cfield->yblank);
582
          for (i=w; i--; scant++)
583
            if (*(bpt++))
584
              *scant = -BIG;
585
          if (dfield)
586
            {
587
            bpt = bpt0;
588
            scant = &PIX(field, 0, cfield->yblank);
589
            for (i=w; i--; scant++)
590
              if (*(bpt++))
591
                *scant = -BIG;
592
            }
593
          bpt = bpt0;
594
          }
595
        }
596
      cfield->yblank++;
597
      if (dfield)
598
        field->yblank = cfield->yblank;
599
      }
600
 
601
/*-- Prepare markers for the next line */
602
    yl++;
603
    field->stripy = (field->y=yl)%field->stripheight;
604
    if (dfield)
605
      dfield->stripy = (dfield->y=yl)%dfield->stripheight;
606
    if (nffield)
607
      for (i=0; i<nffield; i++)
608
        {
609
        ffield = pffield[i];
610
        ffield->stripy = (ffield->y=yl)%ffield->stripheight;
611
        }
612
    if (wfield)
613
      wfield->stripy = (wfield->y=yl)%wfield->stripheight;
614
    if (dwfield)
615
      dwfield->stripy = (dwfield->y=yl)%dwfield->stripheight;
616
 
617
/*-- Remove objects close to the ymin limit if ymin is ready to increase */
618
    if (cfield->stripy==cfield->stripysclim)
619
      {
620
      cleanobj = cleanobjlist->obj+cleanobjlist->nobj-1;
621 194 bertin
      ontotal = 0;
622 2 bertin
      for (i=cleanobjlist->nobj; i--; cleanobj--)
623
        {
624
        if (cleanobj->ycmin <= cfield->ymin)
625
          {
626
/*-------- Warn if there is a possibility for any aperture to be truncated */
627
          if ((ymax=cleanobj->ycmax) > cfield->ymax)
628
            {
629
            sprintf(gstr, "Object at position %.0f,%.0f ",
630
                cleanobj->mx+1, cleanobj->my+1);
631
            QWARNING(gstr, "may have some apertures truncated:\n"
632
                "          You might want to increase MEMORY_BUFSIZE");
633
            }
634
          else if (ymax>cfield->yblank && prefs.blank_flag)
635
            {
636
            sprintf(gstr, "Object at position %.0f,%.0f ",
637
                cleanobj->mx+1, cleanobj->my+1);
638
            QWARNING(gstr, "may have some unBLANKed neighbours:\n"
639
                "          You might want to increase MEMORY_PIXSTACK");
640
            }
641 194 bertin
          if ((prefs.prof_flag && !(thecat.ntotal%10)
642
                && thecat.ntotal != ontotal)
643
                || !(thecat.ntotal%400))
644
            NPRINTF(OUTPUT, "\33[1M> Line:%5d  "
645
                "Objects: %8d detected / %8d sextracted\n\33[1A",
646 234 bertin
                yl>h? h:yl, thecat.ndetect, thecat.ntotal);
647 194 bertin
          ontotal = thecat.ntotal;
648 2 bertin
          endobject(field, dfield, wfield, cdwfield, i, cleanobjlist);
649
          subcleanobj(i);
650
          cleanobj = cleanobjlist->obj+i;       /* realloc in subcleanobj() */
651
          }
652
        }
653
      }
654
 
655 234 bertin
    if ((prefs.prof_flag && !(thecat.ntotal%10)) || !(yl%25))
656 2 bertin
      NPRINTF(OUTPUT, "\33[1M> Line:%5d  "
657
                "Objects: %8d detected / %8d sextracted\n\33[1A",
658 234 bertin
        yl>h?h:yl, thecat.ndetect, thecat.ntotal);
659 2 bertin
/*--------------------- End of the loop over the y's -----------------------*/
660
    }
661
 
662
/* Removal or the remaining pixels */
663
  if (prefs.blank_flag && prefs.filter_flag && (cfield->yblank >= 0))
664
    for (j=blankh-1; j--; yl++)
665
      {
666
      bpt = bpt0 = blankpad + w*(yl%blankh);
667
      scant = &PIX(cfield, 0, cfield->yblank);
668
      for (i=w; i--; scant++)
669
        if (*(bpt++))
670
          *scant = -BIG;
671
      if (dfield)
672
        {
673
        bpt = bpt0;
674
        scant = &PIX(field, 0, cfield->yblank);
675
        for (i=w; i--; scant++)
676
          if (*(bpt++))
677
            *scant = -BIG;
678
        }
679
      cfield->yblank++;
680
      if (dfield)
681
        field->yblank = cfield->yblank;
682
      }
683
 
684
/* Now that all "detected" pixels have been removed, analyse detections */
685 194 bertin
  ontotal = 0;
686 2 bertin
  for (j=cleanobjlist->nobj; j--;)
687
    {
688 194 bertin
    if ((prefs.prof_flag && !(thecat.ntotal%10) && thecat.ntotal != ontotal)
689
                || !(thecat.ntotal%400))
690
      NPRINTF(OUTPUT, "\33[1M> Line:%5d  "
691
                "Objects: %8d detected / %8d sextracted\n\33[1A",
692
        h, thecat.ndetect, thecat.ntotal);
693
    ontotal = thecat.ntotal;
694 2 bertin
    endobject(field, dfield, wfield, cdwfield, 0, cleanobjlist);
695
    subcleanobj(0);
696
    }
697
 
698
  endclean();
699
 
700
/*Free memory */
701 210 bertin
  if (prefs.filter_flag && cdwfield && PLISTEXIST(wflag))
702
    free(cdwscanp);
703 2 bertin
  freeparcelout();
704
  free(pixel);
705
  lutzfree();
706
  free(info);
707
  free(store);
708
  free(marker);
709
  free(dumscan);
710
  free(psstack);
711
  free(start);
712
  free(end);
713
  if (prefs.blank_flag && prefs.filter_flag)
714
    free(blankpad);
715
 
716
  return;
717
  }
718
 
719
 
720
/********************************* update ************************************/
721
/*
722
update object's properties each time one of its pixels is scanned by lutz()
723
*/
724
void  update(infostruct *infoptr1, infostruct *infoptr2, pliststruct *pixel)
725
 
726
  {
727
  infoptr1->pixnb += infoptr2->pixnb;
728
  infoptr1->flag |= infoptr2->flag;
729
  if (infoptr1->firstpix == -1)
730
    {
731
    infoptr1->firstpix = infoptr2->firstpix;
732
    infoptr1->lastpix = infoptr2->lastpix;
733
    }
734
  else if (infoptr2->lastpix != -1)
735
    {
736
    PLIST(pixel+infoptr1->lastpix, nextpix) = infoptr2->firstpix;
737
    infoptr1->lastpix = infoptr2->lastpix;
738
    }
739
 
740
  return;
741
  }
742
 
743
/********************************* sortit ************************************/
744
/*
745
build the object structure.
746
*/
747
void  sortit(picstruct *field, picstruct *dfield, picstruct *wfield,
748 4 bertin
        picstruct *dwfield, infostruct *info, objliststruct *objlist,
749
             PIXTYPE *cdwscan, PIXTYPE *wscan)
750 2 bertin
 
751
  {
752
   picstruct            *cfield;
753
   objliststruct        objlistout, *objlist2;
754
   static objstruct     obj;
755
   objstruct            *cobj;
756
   pliststruct          *pixel;
757
   int                  i,j,n;
758
 
759
  cfield = dfield? dfield: field;
760
 
761
  pixel = objlist->plist;
762
  objlistout.obj = NULL;
763
  objlistout.plist = NULL;
764
  objlistout.nobj = objlistout.npix = 0;
765
 
766
/*----- Allocate memory to store object data */
767
 
768
  objlist->obj = &obj;
769
  objlist->nobj = 1;
770
 
771
  memset(&obj, 0, (size_t)sizeof(objstruct));
772
  objlist->npix = info->pixnb;
773
  obj.firstpix = info->firstpix;
774
  obj.lastpix = info->lastpix;
775
  obj.flag = info->flag;
776
  obj.dthresh = objlist->dthresh;
777
  obj.thresh = objlist->thresh;
778
 
779
  preanalyse(0, objlist, ANALYSE_FAST);
780
 
781
/*----- Check if the current strip contains the lower isophote... */
782
  if ((int)obj.ymin < cfield->ymin)
783
    obj.flag |= OBJ_ISO_PB;
784
 
785
  if (!(obj.flag & OBJ_OVERFLOW) && (createsubmap(objlist, 0) == RETURN_OK))
786
    {
787
    if (parcelout(objlist, &objlistout) == RETURN_OK)
788
      objlist2 = &objlistout;
789
    else
790
      {
791
      objlist2 = objlist;
792
      for (i=0; i<objlist2->nobj; i++)
793
        objlist2->obj[i].flag |= OBJ_DOVERFLOW;
794
      sprintf(gstr, "%.0f,%.0f", obj.mx+1, obj.my+1);
795
      warning("Deblending overflow for detection at ", gstr);
796
      }
797
    free(obj.submap);
798
    }
799
  else
800
    objlist2 = objlist;
801
 
802
  for (i=0; i<objlist2->nobj; i++)
803
    {
804
    preanalyse(i, objlist2, ANALYSE_FULL|ANALYSE_ROBUST);
805 219 bertin
    if (prefs.ext_maxarea && objlist2->obj[i].fdnpix > prefs.ext_maxarea)
806
      continue;
807 2 bertin
    analyse(field, dfield, i, objlist2);
808
    cobj = objlist2->obj + i;
809
    if (prefs.blank_flag)
810
      {
811
      if (createblank(objlist2,i) != RETURN_OK)
812
        {
813
/*------ Not enough mem. for the BLANK vignet: flag the object now */
814
        cobj->flag |= OBJ_OVERFLOW;
815
        cobj->blank = cobj->dblank = NULL;
816
        sprintf(gstr, "%.0f,%.0f", cobj->mx+1, cobj->my+1);
817
        warning("Memory overflow during masking for detection at ", gstr);
818
        }
819
      }
820
 
821
    if ((n=cleanobjlist->nobj) >= prefs.clean_stacksize)
822
      {
823
       objstruct        *cleanobj;
824
       int              ymin, ymax, victim=0;
825
 
826
      ymin = 2000000000;        /* No image is expected to be that tall ! */
827
      cleanobj = cleanobjlist->obj;
828
      for (j=0; j<n; j++, cleanobj++)
829
        if (cleanobj->ycmax < ymin)
830
          {
831
          victim = j;
832
          ymin = cleanobj->ycmax;
833
          }
834
 
835
/*---- Warn if there is a possibility for any aperture to be truncated */
836
      if (field->ymax < field->height)
837
        {
838
        cleanobj = &cleanobjlist->obj[victim];
839
        if ((ymax=cleanobj->ycmax) > field->ymax)
840
          {
841
          sprintf(gstr, "Object at position %.0f,%.0f ",
842
                cleanobj->mx+1, cleanobj->my+1);
843
          QWARNING(gstr, "may have some apertures truncated:\n"
844
                "          You might want to increase MEMORY_OBJSTACK");
845
          }
846
        else if (ymax>field->yblank && prefs.blank_flag)
847
          {
848
          sprintf(gstr, "Object at position %.0f,%.0f ",
849
                cleanobj->mx+1, cleanobj->my+1);
850
          QWARNING(gstr, "may have some unBLANKed neighbours\n"
851
                "          You might want to increase MEMORY_OBJSTACK");
852
          }
853
        }
854
 
855
      endobject(field, dfield, wfield, dwfield, victim, cleanobjlist);
856
      subcleanobj(victim);
857
      }
858
 
859
/* Only add the object if it is not swallowed by cleaning */
860
    if (!prefs.clean_flag || clean(field, dfield, i, objlist2))
861
      addcleanobj(cobj);
862
    }
863
 
864
  free(objlistout.plist);
865
  free(objlistout.obj);
866
 
867
  return;
868
  }
869
 
870
 
871
/******************************** preanalyse *********************************
872
PROTO   void preanalyse(int no, objliststruct *objlist, int analyse_type)
873
PURPOSE Compute basic image parameters from the pixel-list for each detection.
874
INPUT   objlist number,
875
        objlist pointer,
876
        analysis switch flag.
877
OUTPUT  -.
878
NOTES   -.
879
AUTHOR  E. Bertin (IAP & Leiden & ESO)
880
VERSION 28/11/2003
881
 ***/
882
void  preanalyse(int no, objliststruct *objlist, int analyse_type)
883
 
884
  {
885
   objstruct    *obj = &objlist->obj[no];
886
   pliststruct  *pixel = objlist->plist, *pixt;
887
   PIXTYPE      peak, cpeak, val, cval, minthresh, thresht;
888
   double       thresh,thresh2, t1t2,darea,
889
                mx,my, mx2,my2,mxy, rv, tv,
890
                xm,ym, xm2,ym2,xym,
891
                temp,temp2, theta,pmx2,pmy2;
892
   int          x, y, xmin,xmax, ymin,ymax,area2, fdnpix, dnpix;
893
 
894
 
895
/*-----  initialize stacks and bounds */
896
  thresh = obj->dthresh;
897
  if (PLISTEXIST(dthresh))
898
    minthresh = BIG;
899
  else
900
    minthresh = 0.0;
901
  fdnpix = dnpix = 0;
902
  rv = 0.0;
903
  peak = cpeak = -BIG;
904
  ymin = xmin = 2*MAXPICSIZE;    /* to be really sure!! */
905
  ymax = xmax = 0;
906
 
907
/*-----  integrate results */
908
  for (pixt=pixel+obj->firstpix; pixt>=pixel; pixt=pixel+PLIST(pixt,nextpix))
909
    {
910
    x = PLIST(pixt, x);
911
    y = PLIST(pixt, y);
912
    val=PLISTPIX(pixt, dvalue);
913
    if (cpeak < (cval=PLISTPIX(pixt, cdvalue)))
914
      cpeak = cval;
915
    if (PLISTEXIST(dthresh) && (thresht=PLISTPIX(pixt, dthresh))<minthresh)
916
      minthresh = thresht;
917
    if (peak < val)
918
      peak = val;
919
    rv += cval;
920
    if (xmin > x)
921
      xmin = x;
922
    if (xmax < x)
923
      xmax = x;
924
    if (ymin > y)
925
      ymin = y;
926
    if (ymax < y)
927
      ymax = y;
928
    fdnpix++;
929
    }
930
 
931
  if (PLISTEXIST(dthresh))
932
    obj->dthresh = thresh = minthresh;
933
 
934
/* copy some data to "obj" structure */
935
 
936
  obj->fdnpix = (LONG)fdnpix;
937
  obj->fdflux = (float)rv;
938
  obj->fdpeak = cpeak;
939
  obj->dpeak = peak;
940
  obj->xmin = xmin;
941
  obj->xmax = xmax;
942
  obj->ymin = ymin;
943
  obj->ymax = ymax;
944
 
945
  if (analyse_type & ANALYSE_FULL)
946
    {
947
    mx = my = tv = 0.0;
948
    mx2 = my2 = mxy = 0.0;
949
    thresh2 = (thresh + peak)/2.0;
950
    area2 = 0;
951
    for (pixt=pixel+obj->firstpix; pixt>=pixel; pixt=pixel+PLIST(pixt,nextpix))
952
      {
953
      x = PLIST(pixt,x)-xmin;   /* avoid roundoff errors on big images */
954
      y = PLIST(pixt,y)-ymin;   /* avoid roundoff errors on big images */
955
      cval = PLISTPIX(pixt, cdvalue);
956
      tv += (val = PLISTPIX(pixt, dvalue));
957
      if (val>thresh)
958
        dnpix++;
959
      if (val > thresh2)
960
        area2++;
961
      mx += cval * x;
962
      my += cval * y;
963
      mx2 += cval * x*x;
964
      my2 += cval * y*y;
965
      mxy += cval * x*y;
966
      }
967
 
968
/*----- compute object's properties */
969
    xm = mx / rv;                       /* mean x */
970
    ym = my / rv;                       /* mean y */
971
 
972
/*-- In case of blending, use previous barycenters */
973
    if ((analyse_type&ANALYSE_ROBUST) && (obj->flag&OBJ_MERGED))
974
      {
975
       double   xn,yn;
976
 
977
      xn = obj->mx-xmin;
978
      yn = obj->my-ymin;
979
      xm2 = mx2 / rv + xn*xn - 2*xm*xn;
980
      ym2 = my2 / rv + yn*yn - 2*ym*yn;
981
      xym = mxy / rv + xn*yn - xm*yn - xn*ym;
982
      xm = xn;
983
      ym = yn;
984
      }
985
    else
986
      {
987
      xm2 = mx2 / rv - xm * xm; /* variance of x */
988
      ym2 = my2 / rv - ym * ym; /* variance of y */
989
      xym = mxy / rv - xm * ym; /* covariance */
990
      }
991
 
992
/* Handle fully correlated x/y (which cause a singularity...) */
993
    if ((temp2=xm2*ym2-xym*xym)<0.00694)
994
      {
995
      xm2 += 0.0833333;
996
      ym2 += 0.0833333;
997
      temp2 = xm2*ym2-xym*xym;
998
      obj->singuflag = 1;
999
      }
1000
    else
1001
      obj->singuflag = 0;
1002
 
1003
    if ((fabs(temp=xm2-ym2)) > 0.0)
1004
      theta = atan2(2.0 * xym,temp) / 2.0;
1005
    else
1006
      theta = PI/4.0;
1007
 
1008
    temp = sqrt(0.25*temp*temp+xym*xym);
1009
    pmy2 = pmx2 = 0.5*(xm2+ym2);
1010
    pmx2+=temp;
1011
    pmy2-=temp;
1012
 
1013
    obj->dnpix = (obj->flag & OBJ_OVERFLOW)? obj->fdnpix:(LONG)dnpix;
1014
    obj->dflux = tv;
1015
    obj->mx = xm+xmin;  /* add back xmin */
1016
    obj->my = ym+ymin;  /* add back ymin */
1017
    obj->mx2 = xm2;
1018
    obj->my2 = ym2;
1019
    obj->mxy = xym;
1020
    obj->a = (float)sqrt(pmx2);
1021
    obj->b = (float)sqrt(pmy2);
1022
    obj->theta = theta*180.0/PI;
1023
 
1024
    obj->cxx = (float)(ym2/temp2);
1025
    obj->cyy = (float)(xm2/temp2);
1026
    obj->cxy = (float)(-2*xym/temp2);
1027
 
1028
    darea = (double)area2 - dnpix;
1029
    t1t2 = thresh/thresh2;
1030
    if (t1t2>0.0 && !prefs.dweight_flag)
1031
      {
1032
      obj->abcor = (darea<0.0?darea:-1.0)/(2*PI*log(t1t2<1.0?t1t2:0.99)
1033
        *obj->a*obj->b);
1034
      if (obj->abcor>1.0)
1035
        obj->abcor = 1.0;
1036
      }
1037
    else
1038
      obj->abcor = 1.0;
1039
    }
1040
 
1041
  return;
1042
  }
1043