Ejemplo n.º 1
0
Archivo: extract.c Proyecto: cdeil/sep
/****************************** extract **************************************/
int sep_extract(PIXTYPE *im, PIXTYPE *var, int w, int h,
	        PIXTYPE thresh, int minarea,
	        float *conv, int convw, int convh,
		int deblend_nthresh, double deblend_mincont,
		int clean_flag, double clean_param,
		int *nobj, sepobj **objects)
{
  static infostruct	curpixinfo, *info, *store, initinfo, freeinfo, *victim;
  objliststruct       	objlist, *finalobjlist;
  pliststruct		*pixel, *pixt; 
  char			*marker, newmarker;
  int			co, i, j, flag, luflag, pstop, xl, xl2, yl, cn,
			nposize, stacksize, maxpixnb, convn, status;
  short	       	        trunflag;
  PIXTYPE		relthresh, cdnewsymbol;
  PIXTYPE               *scan,*cdscan,*cdwscan,*wscan,*dumscan;
  float                 sum, *convnorm;
  pixstatus		cs, ps, *psstack;
  int			*start, *end, *survives;

  status = RETURN_OK;
  char errtext[80];  /* 80 should be more than enough */
  
  pixel = NULL;
  convnorm = NULL;
  scan = wscan = cdscan = cdwscan = dumscan = NULL;
  victim = NULL;
  info = NULL;
  store = NULL;
  marker = NULL;
  psstack = NULL;
  start = end = NULL;
  finalobjlist = NULL; /* final return value */
  convn = 0;
  sum = 0.0;

  /* var is the image variance to use for thresholding, if available */
  relthresh = var? thresh : 0.0;/* To avoid gcc warnings*/

  objlist.dthresh = thresh;
  objlist.thresh = thresh;

  /*Allocate memory for buffers */
  stacksize = w+1;
  QMALLOC(info, infostruct, stacksize, status);
  QCALLOC(store, infostruct, stacksize, status);
  QMALLOC(marker, char, stacksize, status);
  QMALLOC(dumscan, PIXTYPE, stacksize, status);
  QMALLOC(psstack, pixstatus, stacksize, status);
  QCALLOC(start, int, stacksize, status);
  QMALLOC(end, int, stacksize, status);
  if ((status = lutzalloc(w, h)) != RETURN_OK)
    goto exit;
  if ((status = allocdeblend(deblend_nthresh)) != RETURN_OK)
    goto exit;

  /* More initializations */
  initinfo.pixnb = 0;
  initinfo.flag = 0;
  initinfo.firstpix = initinfo.lastpix = -1;

  for (xl=0; xl<stacksize; xl++)
    {
    marker[xl]  = 0 ;
    dumscan[xl] = -BIG ;
    }

  co = pstop = 0;
  objlist.nobj = 1;
  curpixinfo.pixnb = 1;

  /* Init finalobjlist (the return catalog) */
  QMALLOC(finalobjlist, objliststruct, 1, status);
  finalobjlist->obj = NULL;
  finalobjlist->plist = NULL;
  finalobjlist->nobj = finalobjlist->npix = 0;


  /* Allocate memory for the pixel list */
  plistinit(conv, var);
  if (!(pixel = objlist.plist = malloc(nposize=MEMORY_PIXSTACK*plistsize)))
    {
      status = MEMORY_ALLOC_ERROR;
      goto exit;
    }

  /*----- at the beginning, "free" object fills the whole pixel list */
  freeinfo.firstpix = 0;
  freeinfo.lastpix = nposize-plistsize;
  pixt = pixel;
  for (i=plistsize; i<nposize; i += plistsize, pixt += plistsize)
    PLIST(pixt, nextpix) = i;
  PLIST(pixt, nextpix) = -1;

  if (conv)
    {
      /* allocate memory for convolved buffers */
      QMALLOC(cdscan, PIXTYPE, stacksize, status);
      if (var)
	QCALLOC(cdwscan, PIXTYPE, stacksize, status);

      /* normalize the filter */
      convn = convw * convh;
      QMALLOC(convnorm, PIXTYPE, convn, status);
      for (i=0; i<convn; i++)
	sum += fabs(conv[i]);
      for (i=0; i<convn; i++)
	convnorm[i] = conv[i] / sum;
    }

  /*----- MAIN LOOP ------ */
  for (yl=0; yl<=h; yl++)
    {

      ps = COMPLETE;
      cs = NONOBJECT;
    
      /* Need an empty line for Lutz' algorithm to end gracely */
      if (yl==h)
	{
	  if (conv)
	    {
	      free(cdscan);
	      cdscan = NULL;
	      if (var)
		{
		  free(cdwscan);
		  cdwscan = NULL;
		}
	    }
	  cdwscan = cdscan = dumscan;
	}

      else
	{
	  scan = im + yl*w;
	  if (var)
	    wscan = var + yl*w;

	  /* filter the lines */
	  if (conv)
	    {
	      convolve(im, w, h, yl, convnorm, convw, convh, cdscan);
	      if (var)
		convolve(var, w, h, yl, convnorm, convw, convh, cdwscan);
	    }
	  else
	    {
	      cdscan = scan;
	      cdwscan = wscan;
	    }	  
	}
      
      trunflag = (yl==0 || yl==h-1)? SEP_OBJ_TRUNC:0;
      
      for (xl=0; xl<=w; xl++)
	{
	  if (xl == w)
	    cdnewsymbol = -BIG;
	  else
	    cdnewsymbol = cdscan[xl];

	  newmarker = marker[xl];  /* marker at this pixel */
	  marker[xl] = 0;

	  curpixinfo.flag = trunflag;
	  if (var)
	    thresh = relthresh * sqrt((xl==w || yl==h)? 0.0:cdwscan[xl]);
	  luflag = cdnewsymbol > thresh? 1: 0;  /* is pixel above thresh? */

	  if (luflag)
	    {
	      /* flag the current object if we're near the image bounds */
	      if (xl==0 || xl==w-1)
		curpixinfo.flag |= SEP_OBJ_TRUNC;
	      
	      /* point pixt to first free pixel in pixel list */
	      /* and increment the "first free pixel" */
	      pixt = pixel + (cn=freeinfo.firstpix);
	      freeinfo.firstpix = PLIST(pixt, nextpix);
	      curpixinfo.lastpix = curpixinfo.firstpix = cn;

	      /* set values for the new pixel */ 
	      PLIST(pixt, nextpix) = -1;
	      PLIST(pixt, x) = xl;
	      PLIST(pixt, y) = yl;
	      PLIST(pixt, value) = scan[xl];
	      if (PLISTEXIST(cdvalue))
		PLISTPIX(pixt, cdvalue) = cdnewsymbol;
	      if (PLISTEXIST(var))
		PLISTPIX(pixt, var) = wscan[xl];

	      /* Check if we are running out of free pixels in objlist.plist */
	      /* (previously, the largest object became a "victim") */
	      if (freeinfo.firstpix==freeinfo.lastpix)
		{
		  status = SEP_INTERNAL_ERROR;
		  sprintf(errtext, "Pixel stack overflow at position %d,%d.",
			  xl+1, yl+1);
		  put_errdetail(errtext);
		  goto exit;
		  
		  /* NOTE: The above error was originally just a warning.
		     with the change to an error, the following code in this
		     if block is never executed.
		     TODO: should this just be a warning (or nothing?)
		  */

		  /* loop over pixels in row to find largest object */
		  maxpixnb = 0;
		  for (i=0; i<=w; i++)
		    if (store[i].pixnb>maxpixnb)
		      if (marker[i]=='S' || (newmarker=='S' && i==xl))
			{
			  flag = 0;
			  if (i<xl)
			    for (j=0; j<=co; j++)
			      flag |= (start[j]==i);
			  if (!flag)
			    maxpixnb = (victim = &store[i])->pixnb;
			}
		  for (j=1; j<=co; j++)
		    if (info[j].pixnb>maxpixnb)
		      maxpixnb = (victim = &info[j])->pixnb;
		  
		  if ((!maxpixnb) || (maxpixnb <= 1))
		    {
		      status = SEP_INTERNAL_ERROR;
		      goto exit;
		    }
		  freeinfo.firstpix = PLIST(pixel+victim->firstpix, nextpix);
		  PLIST(pixel+victim->lastpix, nextpix) = freeinfo.lastpix;
		  PLIST(pixel+(victim->lastpix=victim->firstpix), nextpix) = -1;
		  victim->pixnb = 1;
		  victim->flag |= SEP_OBJ_OVERFLOW;
		}
	      /*------------------------------------------------------------*/

	      /* if the current status on this line is not already OBJECT... */
	      /* start segment */
	      if (cs != OBJECT)
		{
		  cs = OBJECT;
		  if (ps == OBJECT)
		    {
		      if (start[co] == UNKNOWN)
			{
			  marker[xl] = 'S';
			  start[co] = xl;
			}
		      else
			marker[xl] = 's';
		    }
		  else
		    {
		      psstack[pstop++] = ps;
		      marker[xl] = 'S';
		      start[++co] = xl;
		      ps = COMPLETE;
		      info[co] = initinfo;
		    }
		}

	    } /* closes if pixel above threshold */

	  /* process new marker ---------------------------------------------*/
	  /* newmarker is marker[ ] at this pixel position before we got to
	     it. We'll only enter this if marker[ ] was set on a previous
	     loop iteration.   */
	  if (newmarker)
	    {
	      if (newmarker == 'S')
		{
		  psstack[pstop++] = ps;
		  if (cs == NONOBJECT)
		    {
		      psstack[pstop++] = COMPLETE;
		      info[++co] = store[xl];
		      start[co] = UNKNOWN;
		    }
		  else
		    update(&info[co], &store[xl], pixel);
		  ps = OBJECT;
		}

	      else if (newmarker == 's')
		{
		  if ((cs == OBJECT) && (ps == COMPLETE))
		    {
		      pstop--;
		      xl2 = start[co];
		      update (&info[co-1],&info[co], pixel);
		      if (start[--co] == UNKNOWN)
			start[co] = xl2;
		      else
			marker[xl2] = 's';
		    }
		  ps = OBJECT;
		}

	      else if (newmarker == 'f')
		ps = INCOMPLETE;

	      else if (newmarker == 'F')
		{
		  ps = psstack[--pstop];
		  if ((cs == NONOBJECT) && (ps == COMPLETE))
		    {
		      if (start[co] == UNKNOWN)
			{
			  if ((int)info[co].pixnb >= minarea)
			    {
			      status = sortit(&info[co], &objlist, minarea,
					      finalobjlist,
					      deblend_nthresh,deblend_mincont);
			      if (status != RETURN_OK)
				goto exit;
			    }

			  /* free the chain-list */
			  PLIST(pixel+info[co].lastpix, nextpix) =
			    freeinfo.firstpix;
			  freeinfo.firstpix = info[co].firstpix;
			}
		      else
			{
			  marker[end[co]] = 'F';
			  store[start[co]] = info[co];
			}
		      co--;
		      ps = psstack[--pstop];
		    }
		}
	    }
	  /* end of if (newmarker) ------------------------------------------*/

	  /* update the info or end segment */
	  if (luflag)
	    {
	      update(&info[co], &curpixinfo, pixel);
	    }
	  else if (cs == OBJECT)
	    {
	      cs = NONOBJECT;
	      if (ps != COMPLETE)
		{
		  marker[xl] = 'f';
		  end[co] = xl;
		}
	      else
		{
		  ps = psstack[--pstop];
		  marker[xl] = 'F';
		  store[start[co]] = info[co];
		  co--;
		}
	    }

	} /*------------ End of the loop over the x's -----------------------*/
    } /*---------------- End of the loop over the y's -----------------------*/

  /* convert `finalobjlist` to an array of `sepobj` structs */
  if (clean_flag)
    {
      /* Calculate mthresh for all objects in the list (needed for cleaning) */
      for (i=0; i<finalobjlist->nobj; i++)
	{
	  status = analysemthresh(i, finalobjlist, minarea, thresh);
	  if (status != RETURN_OK)
	    goto exit;
	}

      QMALLOC(survives, int, finalobjlist->nobj, status);
      clean(finalobjlist, clean_param, survives);

      /* count surviving objects and allocate space accordingly*/
      *nobj = 0;
      for (i=0; i<finalobjlist->nobj; i++)
	*nobj += survives[i];
      QMALLOC(*objects, sepobj, *nobj, status);

      /* fill */
      j=0;
      for (i=0; i<finalobjlist->nobj; i++)
	if (survives[i])
	    convertobj(i, finalobjlist, (*objects) + j++, w);
    }
  else
    {
Ejemplo n.º 2
0
/*
Divide a list of isophotal detections in several parts (deblending).
NOTE: Even if the object is not deblended, the output objlist threshold is
      recomputed if a variable threshold is used.

This can return two error codes: DEBLEND_OVERFLOW or MEMORY_ALLOC_ERROR
*/
int deblend(objliststruct *objlistin, int l, objliststruct *objlistout,
	    int deblend_nthresh, double deblend_mincont, int minarea)
{
  objstruct		*obj;
  static objliststruct	debobjlist, debobjlist2;
  double		thresh, thresh0, value0;
  int			h,i,j,k,m,subx,suby,subh,subw,
                        xn,
			nbm = NBRANCH,
			status;
  int                   *submap;

  submap = NULL;
  status = RETURN_OK;
  xn = deblend_nthresh;

  /* reset global static objlist for deblending */
  memset(objlist, 0, (size_t)xn*sizeof(objliststruct));

  /* initialize local object lists */
  debobjlist.obj = debobjlist2.obj =  NULL;
  debobjlist.plist = debobjlist2.plist = NULL;
  debobjlist.nobj = debobjlist2.nobj = 0;
  debobjlist.npix = debobjlist2.npix = 0;

  /* Create the submap for the object. 
   * The submap is used in lutz(). We create it here because we may call
   * lutz multiple times below, and we only want to create it once.
   */
  submap = createsubmap(objlistin, l, &subx, &suby, &subw, &subh);
  if (!submap)
    {
      status = MEMORY_ALLOC_ERROR;
      goto exit;
    }

  /* set thresholds of object lists based on object threshold */
  thresh0 = objlistin->obj[l].thresh;
  objlistout->thresh = debobjlist2.thresh = thresh0;

  /* add input object to global deblending objlist and one local objlist */
  if ((status = addobjdeep(l, objlistin, &objlist[0])) != RETURN_OK)
    goto exit;
  if ((status = addobjdeep(l, objlistin, &debobjlist2)) != RETURN_OK)
    goto exit;

  value0 = objlist[0].obj[0].fdflux*deblend_mincont;
  ok[0] = (short)1;
  for (k=1; k<xn; k++)
    {
      /*------ Calculate threshold */
      thresh = objlistin->obj[l].fdpeak;
      debobjlist.thresh = thresh > 0.0? 
	thresh0*pow(thresh/thresh0,(double)k/xn) : thresh0;
      
      /*--------- Build tree (bottom->up) */
      if (objlist[k-1].nobj>=NSONMAX)
	{
	  status = DEBLEND_OVERFLOW;
	  goto exit;
	}
      
      for (i=0; i<objlist[k-1].nobj; i++)
	{
	  status = lutz(objlistin->plist, submap, subx, suby, subw,
			&objlist[k-1].obj[i], &debobjlist, minarea);
	  if (status != RETURN_OK)
	    goto exit;
	  
	  for (j=h=0; j<debobjlist.nobj; j++)
	    if (belong(j, &debobjlist, i, &objlist[k-1]))
	      {
		debobjlist.obj[j].thresh = debobjlist.thresh;
		if ((status = addobjdeep(j, &debobjlist, &objlist[k]))
		    != RETURN_OK)
		  goto exit;
		m = objlist[k].nobj - 1;
		if (m>=NSONMAX)
		  {
		    status = DEBLEND_OVERFLOW;
		    goto exit;
		  }
		if (h>=nbm-1)
		  if (!(son = (short *)
			realloc(son,xn*NSONMAX*(nbm+=16)*sizeof(short))))
		    {
		      status = MEMORY_ALLOC_ERROR;
		      goto exit;
		    }
		son[k-1+xn*(i+NSONMAX*(h++))] = (short)m;
		ok[k+xn*m] = (short)1;
	      }
	  son[k-1+xn*(i+NSONMAX*h)] = (short)-1;
	}
    }
  
  /*------- cut the right branches (top->down) */
  for (k = xn-2; k>=0; k--)
    {
      obj = objlist[k+1].obj;
      for (i=0; i<objlist[k].nobj; i++)
	{
	  for (m=h=0; (j=(int)son[k+xn*(i+NSONMAX*h)])!=-1; h++)
	    {
	      if (obj[j].fdflux - obj[j].thresh * obj[j].fdnpix > value0)
		m++;
	      ok[k+xn*i] &= ok[k+1+xn*j];
	    }
	  if (m>1)	
	    {
	      for (h=0; (j=(int)son[k+xn*(i+NSONMAX*h)])!=-1; h++)
		if (ok[k+1+xn*j] &&
		    obj[j].fdflux - obj[j].thresh * obj[j].fdnpix > value0)
		  {
		    objlist[k+1].obj[j].flag |= SEP_OBJ_MERGED;
		    status = addobjdeep(j, &objlist[k+1], &debobjlist2);
		    if (status != RETURN_OK)
		      goto exit;
		  }
	      ok[k+xn*i] = (short)0;
	    }
	}
    }
  
  if (ok[0])
    status = addobjdeep(0, &debobjlist2, objlistout);
  else
    status = gatherup(&debobjlist2, objlistout);
  
 exit:
  if (status == DEBLEND_OVERFLOW)
    put_errdetail("limit of " NSONMAX_STR " sub-objects reached while "
		  "deblending. Decrease number of deblending thresholds "
		  "or increase the detection threshold.");

  free(submap);
  submap = NULL;
  free(debobjlist2.obj);
  free(debobjlist2.plist);
  
  for (k=0; k<xn; k++)
    {
      free(objlist[k].obj);
      free(objlist[k].plist);
    }

  free(debobjlist.obj);
  free(debobjlist.plist);
  
  return status;
}