VIRCAM Pipeline  1.3.3
imcore_overlp.c
1 /* $Id: imcore_overlp.c,v 1.9 2010-10-05 09:11:33 jim Exp $
2  *
3  * This file is part of the VIRCAM Pipeline
4  * Copyright (C) 2005 Cambridge Astronomy Survey Unit
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: jim $
23  * $Date: 2010-10-05 09:11:33 $
24  * $Revision: 1.9 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <math.h>
31 
32 #include <cpl.h>
33 
34 #include "ap.h"
35 #include "util.h"
36 #include "imcore.h"
37 #include "floatmath.h"
38 
39 #define NITER 6
40 
41 static void moments_thr(ap_t *, float [], int []);
42 static void sort_on_zsm_rev(int, plstruct *);
43 static void update_ov(float [], float, float, float, float);
44 static void check_term(ap_t *, int *, float [IMNUM][NPAR+1], int [IMNUM][2],
45  int *);
46 
47 static float oldthr;
48 static float curthr;
49 static float nexthr;
50 static float lasthr;
51 static float xbar_start;
52 static float ybar_start;
53 
56 /*---------------------------------------------------------------------------*/
96 /*---------------------------------------------------------------------------*/
97 
98 extern void overlp(ap_t *ap, float parm[IMNUM][NPAR], int *nbit, float xbar,
99  float ybar, float total, int npix, float tmax) {
100  plstruct *pl;
101  int npl,ipix,ipixo2,npl2,nbitprev,nobj,toomany,i,isnew,k,kk,j,ibitx[IMNUM];
102  int ibity[IMNUM],ibitl[IMNUM],iwas,iupdate[IMNUM],npl3,iter,lastone,ic,jj;
103  int ii,conv,ipks[IMNUM][2];
104  float fconst,offset,tmul,smul,xintmn,itmaxlim,algthr,radmax,xb,yb,radius2;
105  float results[IMNUM][NPAR+1],distmax,dx,dy,parmnew[IMNUM][NPAR],sumint;
106  float xlevol,radold,slope,xx,xlevel,radius,xdat[NAREAL+1],xcor[NAREAL+1];
107  float dlbydr,wt,dist,xeff,polycf[3],ttt,radthr,delb,deli,ratio;
108  float bitx[IMNUM],bitl[IMNUM],sxx,syy;
109  ap_t ap2;
110 
111  /* Initialise a few variables */
112 
113  pl = ap->plarray;
114  npl = ap->npl_pix;
115  ipix = ap->ipnop;
116  oldthr = ap->thresh;
117  fconst = ap->fconst;
118  offset = ap->areal_offset;
119  xbar_start = xbar;
120  ybar_start = ybar;
121 
122  /* Initialise some constants that you might need later */
123 
124  tmul = 1.2589678; /* 1/4 mag deblending contour increment */
125  smul = 2.5; /* starting contour increment */
126  ipixo2 = MAX(2,(ipix + 1)/2); /* ipix is the minimum image pixel size */
127  xintmn = oldthr*ipixo2; /* minimum intensity for fragments */
128  itmaxlim = 0.9*tmax; /* upper limit deblending 90% of peak */
129  lasthr = itmaxlim;
130  algthr = logf(oldthr); /* Convenient bit of shorthand */
131  radmax = sqrtf(((float)npix)/CPL_MATH_PI); /* Isophotal size of input data array */
132 
133  /* Get a maximum of IDBLIM points brighter than the new detection threshold
134  by reverse sorting the input array. If there are still more than IDBLIM
135  above the threshold, then revise the thresold until there aren't. Then
136  use the variable npl2 to stop the rest of the routine accessing any of
137  the fainter pixels in the list. This is to restrict processing time
138  for large extended objects */
139 
140  curthr = smul*oldthr;
141  sort_on_zsm_rev(npl,pl);
142  while (1) {
143  npl2 = 0;
144  while (pl[npl2].zsm > curthr && npl2 < npl-1)
145  npl2++;
146  if (npl2 > IDBLIM)
147  curthr += oldthr;
148  else
149  break;
150  }
151 
152  /* If there are fewer pixels above the new threshold than the minimum
153  specified in the input parameters, then you have no reason to be here */
154 
155  if (npl2 < ipix) {
156  *nbit = 1;
157  return;
158  }
159 
160  /* Get a new ap structure */
161 
162  ap2.lsiz = ap->lsiz;
163  ap2.csiz = ap->csiz;
164  ap2.multiply = 1;
165  ap2.ipnop = ipixo2;
166  ap2.areal_offset = offset;
167  ap2.fconst = fconst;
168  ap2.mflag = cpl_calloc((ap2.lsiz)*(ap2.csiz),sizeof(unsigned char*));
169 
170  /* Main analysis loop at new thresholds */
171 
172  *nbit = 0;
173  nbitprev = 0;
174  apinit(&ap2);
175  while (1) {
176  nexthr = MAX(curthr+oldthr,curthr*tmul);
177 
178  /* Locate objects in this cluster */
179 
180  ap2.thresh = curthr;
181  apclust(&ap2,npl2,pl);
182  check_term(&ap2,&nobj,results,ipks,&toomany);
183  apreinit(&ap2);
184  if (nobj == 0)
185  break;
186 
187  /* For each image check the number of points above the next threshold
188  and flag. Do a moments analysis of each object */
189 
190  for (i = 0; i < nobj; i++) {
191 
192  /* Ok, has this object already been detected? If so, then
193  load the new results into the parmnew array. We'll check
194  whether it's worthwhile updating the master parameters
195  list later */
196 
197  isnew = 1;
198  xb = results[i][1];
199  yb = results[i][2];
200  sxx = MAX(1.0,results[i][4]);
201  syy = MAX(1.0,results[i][6]);
202  for (k = 0; k < nbitprev; k++) {
203  dx = xb - parm[k][1];
204  dy = yb - parm[k][2];
205  radius2 = dx*dx/sxx + dy*dy/syy;
206  if ((ibitx[k] == ipks[i][0] && ibity[k] == ipks[i][1]) ||
207  radius2 < 1.0) {
208  isnew = 0;
209  for (kk = 0; kk < NPAR; kk++)
210  parmnew[k][kk] = results[i][kk];
211  ibitl[k] = (int)results[i][NPAR];
212  break;
213  }
214  }
215 
216  /* If this is a new one and it's above the minimum threshold
217  then check to make sure you don't already have too many.
218  If you do, then flag this and break out to the next iteration.
219  If there is room for another, then store the moments analysis
220  profile */
221 
222  if (isnew && results[i][0] > xintmn) {
223  if (*nbit >= IMNUM) {
224  *nbit = IMNUM;
225  toomany = 1;
226  break;
227  }
228  ibitx[*nbit] = ipks[i][0];
229  ibity[*nbit] = ipks[i][1];
230  for (kk = 0; kk < NPAR; kk++)
231  parm[*nbit][kk] = results[i][kk];
232  ibitl[*nbit] = (int)results[i][NPAR];
233  (*nbit)++;
234  }
235  } /* End of object loop */
236 
237  /* If too many objects were found, then skip the next bit...otherwise
238  go through and update parameters if necessary. This block of
239  code is a bit of a place holder waiting for something better to
240  be worked out...*/
241 
242  if (! toomany) {
243  if (*nbit > nbitprev && nbitprev > 0) {
244  for (i = 0; i < nbitprev; i++)
245  iupdate[i] = 0;
246  for (j = nbitprev; j < *nbit; j++) {
247  distmax = 0.0;
248  iwas = 0;
249  for (i = 0; i < nbitprev; i++) {
250  if (parmnew[i][0] > 0.0) {
251  dx = parmnew[i][1] - parm[i][1];
252  dy = parmnew[i][2] - parm[i][2];
253  radius2 = dx*dx + dy*dy;
254  if (radius2 > distmax) {
255  iwas = i;
256  distmax = radius2;
257  }
258  }
259  }
260  iupdate[iwas] = 1;
261  }
262  for (i = 0; i < nbitprev; i++)
263  if (iupdate[i] == 1 && parmnew[i][0] > 0.0)
264  for (j = 0; j < NPAR; j++)
265  parm[i][j] = parmnew[i][j];
266  }
267 
268  /* Reset the update flag and prepare for next iteration*/
269 
270  for (i = 0; i <= *nbit; i++)
271  parmnew[i][0] = -1.0;
272  nbitprev = *nbit;
273  }
274 
275  /* Where do we cut in the list now? */
276 
277 
278  npl3 = 0;
279  while (pl[npl3].zsm > nexthr && npl3 < npl2-1)
280  npl3++;
281  npl2 = npl3;
282 
283  /* Now, do we need to move onto the next threshold? */
284 
285  if (npl2 == 0 || toomany || nexthr >= itmaxlim)
286  break;
287 
288  /* If so, then reset some variables and continue */
289 
290  curthr = nexthr;
291 
292  } /* End of main analysis loop */
293 
294  /* Free up some workspace */
295 
296  free(ap2.mflag);
297  apclose(&ap2);
298 
299  /* If there is only one then we can exit now */
300 
301  if (*nbit == 1)
302  return;
303 
304  /* Find out which images terminated properly and remove those that didn't */
305  j = -1;
306  for (k = 0; k < *nbit; k++) {
307  /* Commented this out as checking for terminations seems to miss some
308  if the total flux above the threshold for an object is negative */
309 
310 /* if (ibitl[k] == 1 && parm[k][0] > xintmn) { */
311  if (parm[k][0] > xintmn) {
312  j++;
313  if (j != k)
314  for (i = 0; i < NPAR; i++)
315  parm[j][i] = parm[k][i];
316  }
317  }
318  *nbit = j + 1;
319  for (j = 0; j < *nbit; j++) {
320  bitx[j] = 0.0;
321  bitl[j] = 0.0;
322  }
323 
324  /* For each image find true areal profile levels and iterate to find
325  local continuum */
326 
327  iter = 0;
328  sumint = 0.0;
329  lastone = 0;
330  while (iter < NITER) {
331  iter++;
332 
333  /* Loop for each of the objects and create a level vs radius array */
334 
335  for (k = 0; k < *nbit; k++) {
336  if (parm[k][0] < 0.0)
337  continue;
338  xlevol = logf(parm[k][7] + parm[k][3] - bitl[k]); /* Pk + newthresh - cont */
339  xlevel = xlevol;
340  radold = 0.0;
341  radius = radold;
342  slope = 1.0;
343  ic = 0;
344  for (i = 1; i <= NAREAL; i++) {
345  jj = NPAR - i;
346  ii = NAREAL - i;
347  xx = (float)ii + offset;
348  if (parm[k][jj] > 0.5) {
349  if (ii == 0)
350  xlevel = logf(parm[k][3] - bitl[k] + 0.5);
351  else
352  xlevel = logf(powf(2.0,xx) - oldthr + parm[k][3] -
353  bitl[k] - 0.5);
354  radius = sqrt(parm[k][jj]/CPL_MATH_PI);
355  xdat[ic] = xlevel;
356  xcor[ic++] = radius;
357  dlbydr = (xlevol - xlevel)/MAX(0.01,radius-radold);
358  wt = MIN(1.0,MAX((radius-radold)*5.0,0.1));
359  slope = (1.0 - 0.5*wt)*slope + 0.5*wt*MIN(5.0,dlbydr);
360  radold = radius;
361  xlevol = xlevel;
362  }
363  }
364 
365  /* If this is not the last iteration then work out the effect
366  on the local continuum from each image */
367 
368  if (! lastone) {
369  for (i = 0; i < *nbit; i++) {
370  if (parm[i][0] >= 0.0 && i != k) {
371  dx = parm[k][1] - parm[i][1];
372  dy = parm[k][2] - parm[i][2];
373  dist = sqrtf(dx*dx + dy*dy);
374  xeff = xlevel - MAX(0.0,MIN(50.0,slope*(dist-radius)));
375  bitx[i] += expf(xeff);
376  }
377  }
378 
379  /* If this is the last iteration loop, then update the parameters
380  before exiting*/
381 
382  } else {
383  if (ic > 2) {
384  polynm(xdat,xcor,ic,polycf,3,0);
385  ttt = polycf[1] + 2.0*polycf[2]*radius;
386  } else
387  ttt = 0.0;
388  slope = MAX(0.1,MAX(-ttt,slope));
389  radthr = radius + (xlevel - algthr)/slope;
390  if (radthr > radmax) {
391  slope = 1.0;
392  radthr = radmax;
393  }
394 
395  /* Pixel area */
396 
397  delb = parm[k][8]*(parm[k][3] - bitl[k]);
398  parm[k][8] = CPL_MATH_PI*radthr*radthr;
399 
400  /* Peak height */
401 
402  parm[k][7] += (parm[k][3] - bitl[k]);
403 
404  /* Intensity */
405 
406  deli = 2.0*CPL_MATH_PI*((parm[k][3] - bitl[k])*(1.0 + slope*radius) -
407  oldthr*(1.0 + slope*radthr))/(slope*slope);
408  parm[k][0] += delb + MAX(0.0,deli);
409  for (i = 0; i < 7; i++)
410  parm[k][i+9] = -1.0;
411  if (parm[k][0] > xintmn)
412  sumint += parm[k][0];
413  }
414  }
415 
416  /* If this is not the last iteration then check and see how the
417  continuum estimates are converging. If they appear to be converging
418  then let the next iteration be the last one. */
419 
420  if (! lastone) {
421  conv = 1;
422  for (i = 0; i < *nbit; i++) {
423  if (parm[i][0] >= 0.0) {
424  if (abs(bitx[i] - bitl[i]) > 3.0)
425  conv = 0;
426  bitl[i] = bitx[i];
427  bitx[i] = 0;
428  bitl[i] = MIN(bitl[i],NINT(parm[i][3]-oldthr));
429  }
430  }
431  lastone = (conv || (iter == NITER-1));
432  } else {
433  break;
434  }
435  }
436 
437  /* Find the scaling if needed */
438 
439  if (sumint == 0.0) {
440  *nbit = 1;
441  return;
442  } else
443  ratio = total/sumint;
444  for (i = 0; i < *nbit; i++)
445  parm[i][0] = ratio*parm[i][0];
446 }
447 
448 /*---------------------------------------------------------------------------*/
468 /*---------------------------------------------------------------------------*/
469 
470 static void sort_on_zsm_rev(int npts, plstruct *pts) {
471  int i,j,ii,jj,ifin;
472  plstruct tmp;
473 
474  jj = 4;
475  while (jj < npts)
476  jj = 2*jj;
477  jj = MIN(npts,(3*jj)/4-1);
478  while (jj > 1) {
479  jj = jj/2;
480  ifin = npts - jj;
481  for (ii = 0; ii < ifin; ii++) {
482  i = ii;
483  j = i + jj;
484  if (pts[i].zsm > pts[j].zsm)
485  continue;
486  tmp = pts[j];
487  do {
488  pts[j] = pts[i];
489  j = i;
490  i = i - jj;
491  if (i < 0)
492  break;
493  } while (pts[i].zsm <= tmp.zsm);
494  pts[j] = tmp;
495  }
496  }
497 }
498 
499 /*---------------------------------------------------------------------------*/
521 /*---------------------------------------------------------------------------*/
522 
523 static void moments_thr(ap_t *ap, float results[NPAR+1], int ipk[2]) {
524  int i,np,nnext;
525  float x,y,xoff,yoff,xsum,ysum,xsumsq,ysumsq,tsum,xysum,t,tmax,twelfth;
526  float xbar,ybar,sxx,syy,sxy,fconst,offset,xsum_w,ysum_w,wsum,w;
527  plstruct *plarray;
528 
529  /* Copy some stuff to local variables */
530 
531  fconst = ap->fconst;
532  offset = ap->areal_offset;
533  plarray = ap->plarray;
534  np = ap->npl_pix;
535 
536  /* Initialise a few things */
537 
538  xoff = xbar_start;
539  yoff = ybar_start;
540  xsum = 0.0;
541  ysum = 0.0;
542  xsum_w = 0.0;
543  ysum_w = 0.0;
544  wsum = 0.0;
545  xsumsq = 0.0;
546  ysumsq = 0.0;
547  tsum = 0.0;
548  xysum = 0.0;
549  tmax = plarray[0].z - curthr;
550  ipk[0] = plarray[0].x;
551  ipk[1] = plarray[0].y;
552  twelfth = 1.0/12.0;
553  for (i = 8; i < NPAR; i++)
554  results[i] = 0.0;
555 
556  /* Do a moments analysis on an object */
557 
558  nnext = 0;
559  for (i = 0; i < np; i++) {
560  x = (float)plarray[i].x - xoff;
561  y = (float)plarray[i].y - yoff;
562  t = plarray[i].z - curthr;
563  w = plarray[i].zsm - curthr;
564  if (w > nexthr)
565  nnext++;
566  xsum += t*x;
567  ysum += t*y;
568  tsum += t;
569  xsum_w += w*t*x;
570  ysum_w += w*t*y;
571  wsum += w*t;
572  xsumsq += (x*x + twelfth)*t;
573  ysumsq += (y*y + twelfth)*t;
574  xysum += x*y*t;
575  update_ov(results+8,t,oldthr,fconst,offset);
576  if (t > tmax) {
577  ipk[0] = plarray[i].x;
578  ipk[1] = plarray[i].y;
579  tmax = t;
580  }
581  }
582 
583  /* Check that the total intensity is enough and if it is, then do
584  the final results. Use negative total counts to signal an error */
585 
586  if (tsum > 0.0) {
587  results[0] = tsum;
588  } else {
589  results[0] = -1.0;
590  tsum = 1.0;
591  }
592  xbar = xsum/tsum;
593  ybar = ysum/tsum;
594  sxx = MAX(0.0,(xsumsq/tsum-xbar*xbar));
595  syy = MAX(0.0,(ysumsq/tsum-ybar*ybar));
596  sxy = xysum/tsum - xbar*ybar;
597  wsum = MAX(1.0,wsum);
598  xbar = xsum_w/wsum;
599  ybar = ysum_w/wsum;
600  xbar += xoff;
601  ybar += yoff;
602  xbar = MAX(1.0,MIN(xbar,ap->lsiz));
603  ybar = MAX(1.0,MIN(ybar,ap->csiz));
604 
605  /* Store the results now */
606 
607  results[1] = xbar;
608  results[2] = ybar;
609  results[3] = curthr;
610  results[4] = sxx;
611  results[5] = sxy;
612  results[6] = syy;
613  results[7] = tmax;
614  results[NPAR] = ((nnext > ap->ipnop && nexthr < lasthr) ? 0 : 1);
615 }
616 
617 /*---------------------------------------------------------------------------*/
642 /*---------------------------------------------------------------------------*/
643 
644 static void update_ov(float iap[NAREAL], float t, float thresh, float fconst,
645  float offset) {
646  int nup,i;
647 
648  /* Get out of here if the intensity is too small */
649 
650  if (t <= 0.0)
651  return;
652 
653  /* Otherwise update the relevant profile counts */
654 
655  nup = MAX(1,MIN(NAREAL,(int)(logf(t+thresh)*fconst-offset)+1));
656  for (i = 0; i < nup; i++)
657  iap[i] += 1.0;
658 }
659 
660 /*---------------------------------------------------------------------------*/
686 /*---------------------------------------------------------------------------*/
687 
688 static void check_term(ap_t *ap, int *nobj, float parm[IMNUM][NPAR+1],
689  int peaks[IMNUM][2], int *toomany) {
690  int ip,i,ipks[2];
691  float momresults[NPAR+1];
692 
693  /* Search through all possible parents */
694 
695  *nobj = 0;
696  *toomany = 0;
697  for (ip = 1; ip <= ap->maxip; ip++) {
698  if (ap->parent[ip].pnop != -1) {
699 /* if (ap->parent[ip].pnop == ap->parent[ip].growing) { */
700 
701  /* That's a termination: */
702 
703  if ((ap->parent[ip].pnop >= ap->ipnop &&
704  ap->parent[ip].touch == 0)) {
705  extract_data(ap,ip);
706  moments_thr(ap,momresults,ipks);
707  if (momresults[0] > 0.0) {
708  if (*nobj == IMNUM-1) {
709  *toomany = 1;
710  break;
711  }
712  for (i = 0; i <= NPAR; i++)
713  parm[*nobj][i] = momresults[i];
714  for (i = 0; i < 2; i++)
715  peaks[*nobj][i] = ipks[i];
716  (*nobj)++;
717  }
718  }
719  restack(ap,ip);
720 /* } else { */
721 
722 /* /\* This parent still active: *\/ */
723 
724 /* ap->parent[ip].growing = ap->parent[ip].pnop; */
725 /* } */
726  }
727  }
728 }
729 
732 /*
733 
734 $Log: not supported by cvs2svn $
735 Revision 1.8 2010/09/09 12:09:57 jim
736 Added docs
737 
738 Revision 1.7 2009/09/09 09:42:25 jim
739 modified to use CPL defined macros for constants
740 
741 Revision 1.6 2009/01/23 12:24:33 jim
742 Fixed bugs in pixel flagging
743 
744 Revision 1.5 2007/12/19 13:17:16 jim
745 Fixed small bug affecting how parameters get updated
746 
747 Revision 1.4 2006/08/21 09:07:29 jim
748 Modified centring algorithm
749 
750 Revision 1.3 2006/06/29 13:43:05 jim
751 Modified to take some stuff out of integer arithmetic
752 
753 Revision 1.2 2006/04/20 11:15:19 jim
754 A few minor bugs fixed
755 
756 Revision 1.1 2005/09/13 13:25:29 jim
757 Initial entry after modifications to make cpl compliant
758 
759 
760 */