Ejemplo n.º 1
0
/*!
* \return	Object with domain equal to the set difference between the
*		first and second object, with valuetable from the first
*		object.
* \ingroup	WlzDomainOps
* \brief	Calculates the domain difference between two objects.
* \param	obj1			First object.
* \param	obj2			Second object.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzObject *WlzDiffDomain(
  WlzObject *obj1,
  WlzObject *obj2,
  WlzErrorNum	*dstErr)
{
  WlzIntervalWSpace	iwsp2, iwsp1;
  WlzInterval		*intp;
  WlzInterval 		*jntp;
  WlzDomain 		diffdom;
  WlzValues		values;
  WlzIntervalDomain 	*idom1;
  int 			k1, dfinished, intervalcount;
  WlzObject 		*diff=NULL;
  WlzErrorNum		errNum=WLZ_ERR_NONE;

  diffdom.core = NULL;
  /* check object 1 */
  if( obj1 == NULL ){
    errNum = WLZ_ERR_OBJECT_NULL;
  }

  if( errNum == WLZ_ERR_NONE ){
    switch( obj1->type ){

    case WLZ_2D_DOMAINOBJ:
    case WLZ_3D_DOMAINOBJ:
      if( obj1->domain.core == NULL ){
	errNum = WLZ_ERR_DOMAIN_NULL;
      }
      break;

    case WLZ_EMPTY_OBJ:
      diffdom.i = NULL;
      values.v = NULL;
      return WlzMakeMain(WLZ_EMPTY_OBJ, diffdom, values, NULL,
			 NULL, dstErr);

    default:
      errNum = WLZ_ERR_OBJECT_TYPE;
      break;

    }
  }

  /* check object 2 - obj2 == NULL is now an error */
  if( (errNum == WLZ_ERR_NONE) && (obj2 == NULL) ){
    errNum = WLZ_ERR_OBJECT_NULL;
  }

  if( errNum == WLZ_ERR_NONE ){
    switch( obj2->type ){

    case WLZ_2D_DOMAINOBJ:
    case WLZ_3D_DOMAINOBJ:
      if( obj2->type != obj1->type ){
	errNum = WLZ_ERR_OBJECT_TYPE;
	break;
      }
      if( obj2->domain.core == NULL ){
	errNum = WLZ_ERR_OBJECT_NULL;
	break;
      }
      break;

    case WLZ_EMPTY_OBJ:
      return WlzMakeMain(obj1->type, obj1->domain, obj1->values,
			 NULL, NULL, dstErr);

    default:
      errNum = WLZ_ERR_OBJECT_TYPE;
      break;

    }
  }

  /* switch for 3D objects */
  if( (errNum == WLZ_ERR_NONE) && (obj1->type == WLZ_3D_DOMAINOBJ) ){
    return WlzDiffDomain3d( obj1, obj2, dstErr );
  }

  /*
   * make a new interval table that is big enough
   */
  if( errNum == WLZ_ERR_NONE ){
    idom1 = obj1->domain.i;
    k1 = idom1->kol1;
    if( (intp = (WlzInterval *)
	 AlcCalloc(WlzIntervalCount(idom1, NULL) +
		   WlzIntervalCount(obj2->domain.i, NULL),
		   sizeof(WlzInterval))) == NULL ){
      errNum = WLZ_ERR_MEM_ALLOC;
    }
    jntp = intp;
  }

  if( errNum == WLZ_ERR_NONE ){
    if( (diffdom.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL,
					   idom1->line1, idom1->lastln,
					   k1, idom1->lastkl,
					   &errNum)) == NULL ){
      AlcFree((void *) intp);
    }
    else {
      diffdom.i->freeptr = AlcFreeStackPush(diffdom.i->freeptr, (void *)intp,
					    NULL);
    }
  }

  if( errNum == WLZ_ERR_NONE ){
    if( (diff = WlzMakeMain(WLZ_2D_DOMAINOBJ, diffdom, obj1->values,
			    NULL, NULL, &errNum)) == NULL ){
      WlzFreeIntervalDomain(diffdom.i);
    }
  }

  /*
   * initialise interval scanning
   */
  if( errNum == WLZ_ERR_NONE ){
    errNum = WlzInitRasterScan(obj1, &iwsp1, WLZ_RASTERDIR_ILIC);
  }
  if( errNum == WLZ_ERR_NONE ){
    errNum = WlzInitRasterScan(obj2, &iwsp2, WLZ_RASTERDIR_ILIC);
    dfinished = 0;
    intervalcount = 0;
  }

  /*
   * scan object constructing intervals after subtraction of obj2
   */
  if( (errNum == WLZ_ERR_NONE) &&
     ((errNum = WlzNextInterval(&iwsp2)) == WLZ_ERR_NONE) ){

    while( (errNum = WlzNextInterval(&iwsp1)) == WLZ_ERR_NONE ){
      /*
       * case 1 - interval in obj1 succedes interval in obj2 -
       *	    get next interval of obj2
       */
      while( (errNum == WLZ_ERR_NONE) && (dfinished == 0) &&
	     (iwsp1.linpos > iwsp2.linpos ||
	      (iwsp1.linpos == iwsp2.linpos &&
	       iwsp1.lftpos > iwsp2.rgtpos))){
	switch( errNum = WlzNextInterval(&iwsp2) ){
	case WLZ_ERR_NONE:
	  dfinished = 0;
	  break;
	case WLZ_ERR_EOO:
	  errNum = WLZ_ERR_NONE;
	  dfinished = 1;
	  break;
	default:
	  break;
	}
      }
      if( errNum != WLZ_ERR_NONE ){
	break;
      }
      /*
     * case 2 - interval in obj1 precedes interval in obj2
     *	    or obj2 finished - just copy interval
     */
      if( (dfinished != 0) ||
	 (iwsp1.linpos < iwsp2.linpos ||
	  ((iwsp1.linpos == iwsp2.linpos) &&
	   (iwsp1.rgtpos < iwsp2.lftpos))
	   )
	){
	jntp->ileft = iwsp1.lftpos - k1;
	jntp->iright = iwsp1.rgtpos - k1;
	intervalcount++;
	jntp++;
      }
      /*
     * case 3 - intervals overlap.
     * there may be more than one obj2 interval.
     */
      else {
	/*
	 * test left end of obj1 interval < left
	 * end of obj2 interval, when complete
	 * interval can be constructed immediately
	 */
	if (iwsp2.lftpos > iwsp1.lftpos) {
	  jntp->ileft = iwsp1.lftpos - k1;
	  jntp->iright = iwsp2.lftpos -1 - k1;
	  intervalcount++;
	  jntp++;
	}
	do {
	  /*
	   * if right end of obj2 interval <
	   * right end of obj1 interval can
	   * plant left end of new interval
	   */
	  if (iwsp2.rgtpos < iwsp1.rgtpos) {
	    jntp->ileft = iwsp2.rgtpos +1 - k1;
	    switch( errNum = WlzNextInterval(&iwsp2) ){
	    case WLZ_ERR_NONE:
	      dfinished = 0;
	      break;
	    case WLZ_ERR_EOO:
	      errNum = WLZ_ERR_NONE;
	      dfinished = 1;
	      break;
	    default:
	      break;
	    }
	    if( errNum != WLZ_ERR_NONE ){
	      break;
	    }
	    
	    /*
	     * check if next obj2 interval
	     * still overlaps this obj1 interval
	     */
	    if( (dfinished == 0) &&
	       (iwsp1.linpos == iwsp2.linpos) &&
	       (iwsp1.rgtpos >= iwsp2.lftpos))
	      jntp->iright = iwsp2.lftpos -1 -k1;
	    else
	      jntp->iright = iwsp1.rgtpos - k1;
	    intervalcount++;
	    jntp++;
	  }
	} while( (dfinished == 0) && 
		(iwsp1.linpos == iwsp2.linpos) &&
		(iwsp1.rgtpos > iwsp2.rgtpos) );
      }
      if( errNum != WLZ_ERR_NONE ){
	break;
      }

      /*
     * is this obj1 interval the last in the line ?
     * if so, load up the new intervals into the
     * diff domain.
     */
      if (iwsp1.intrmn == 0) {
	errNum = WlzMakeInterval(iwsp1.linpos, diffdom.i,
				 intervalcount, intp);
	intervalcount = 0;
	intp = jntp;
      }
      if( errNum != WLZ_ERR_NONE ){
	break;
      }
    }
  }
  if(errNum == WLZ_ERR_EOO) 	        /* Reset error from end of intervals */ 
  {
    errNum = WLZ_ERR_NONE;
  }

  /* this checks the area and returns NULL if zero
     in principle it should return an "empty object" */
  if(errNum == WLZ_ERR_NONE) {
    if(WlzIntervalCount(diffdom.i, NULL) == 0){
      WlzFreeObj(diff);
      diffdom.i = NULL;
      values.v = NULL;
      diff = WlzMakeEmpty(&errNum);
    }
    else {
      WlzStandardIntervalDomain(diff->domain.i);
    }
  }
  else {
    WlzFreeObj(diff);
    diff = NULL;
  }

  if( dstErr ){
    *dstErr = errNum;
  }
  return diff;
}
Ejemplo n.º 2
0
/*!
* \return	New Woolz interval domain or NULL on error.
* \ingroup	WlzTransform
* \brief	Creates a new 2D Woolz interval domain with a single line
* 		which is the profile from the given start position to the
* 		given end position for the given spatial domain object.
* \param	gObj		Given Woolz object.
* \param	sPos		Start position.
* \param	ePos		End position.
* \param	dstErr		Destination error pointer, may be NULL.
*/
WlzIntervalDomain *WlzProfileLineIDom(
  WlzObject *gObj,
  WlzIVertex3 sPos,
  WlzIVertex3 ePos,
  WlzErrorNum *dstErr)
{
  WlzIntervalDomain *iDom = NULL;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  /* Check given object. */
  if(gObj == NULL)
  {
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else
  {
    switch(gObj->type)
    {
      case WLZ_2D_DOMAINOBJ:
      case WLZ_3D_DOMAINOBJ:
	if(gObj->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
        break;
      default:
	errNum = WLZ_ERR_OBJECT_TYPE;
        break;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    int		len;
    WlzIVertex3	dPos;
    WlzProfileWalkWSp pWSp = {0};
    WlzInterval *rItv = NULL;

    WLZ_VTX_3_SUB(dPos, ePos, sPos);
    len = (int )ceil(WLZ_VTX_3_LENGTH(dPos));
    /* Create return object. */
    iDom = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL,
                                 0, 0, 0, len - 1, &errNum);
    if(errNum == WLZ_ERR_NONE)
    {
      if((rItv = (WlzInterval *)
		 AlcCalloc((len / 2) + 1, sizeof(WlzInterval))) == NULL)
      {
	errNum = WLZ_ERR_MEM_ALLOC;
	(void )WlzFreeIntervalDomain(iDom);
	iDom = NULL;
      }
    }
    if(errNum == WLZ_ERR_NONE)
    {
      WlzIntervalLine *itvLn;

      iDom->freeptr = AlcFreeStackPush(iDom->freeptr, (void *)rItv, NULL);
      pWSp.start = sPos;
      pWSp.end = ePos;
      pWSp.domain.i = iDom;
      itvLn = pWSp.domain.i->intvlines + 0;
      itvLn->intvs = rItv;
      itvLn->nintvs = 0;
      errNum = WlzProfileWalk(gObj, WlzProfileSetIDom, &pWSp);
    }
  }
  if(errNum != WLZ_ERR_NONE)
  {
    iDom = NULL;
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(iDom);
}
Ejemplo n.º 3
0
WlzObject *WlzCbThreshold(
  WlzObject	*obj,
  WlzThreshCbFn	threshCb,
  void		*clientData,
  WlzErrorNum	*dstErr)
{
  WlzObject		*nobj=NULL;
  WlzIntervalDomain	*idom = NULL;
  WlzGreyP		g;
  WlzThreshCbStr	callData;
  int			colno, nints;
  int			over;
  int			nl1,nll,nk1,nkl;
  WlzIntervalWSpace	iwsp;
  WlzGreyWSpace		gwsp;
  WlzInterval		*itvl = NULL, *jtvl = NULL;
  WlzDomain		domain;
  WlzValues		values;
  WlzErrorNum		errNum=WLZ_ERR_NONE;

  /* check the object */
  if( obj == NULL ){
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else {
    switch( obj->type ){

    case WLZ_2D_DOMAINOBJ:
      /* check object 2D domain and valuetable */
      if( obj->domain.core == NULL ){
	errNum = WLZ_ERR_DOMAIN_NULL;
	break;
      }
      if( obj->values.core == NULL ){
	errNum = WLZ_ERR_VALUES_NULL;
	break;
      }
      break;

    case WLZ_3D_DOMAINOBJ:
      return WlzCbThreshold3d(obj, threshCb, clientData, dstErr);

    case WLZ_TRANS_OBJ:
      if((nobj = WlzCbThreshold(obj->values.obj, threshCb, clientData,
				&errNum)) != NULL){
	values.obj = nobj;
	return WlzMakeMain(obj->type, obj->domain, values,
			   NULL, obj, dstErr);
      }
      break;

    case WLZ_EMPTY_OBJ:
      return WlzMakeEmpty(dstErr);

    default:
      errNum = WLZ_ERR_OBJECT_TYPE;
    }
  }

  /*
   * first pass - find line and column bounds of thresholded
   * object and number of intervals.
   */
  if( errNum == WLZ_ERR_NONE ){
    idom = obj->domain.i;
    nl1 = idom->lastln;
    nll = idom->line1;
    nk1 = idom->lastkl;
    nkl = idom->kol1;
    callData.pix.type = gwsp.pixeltype;
    (void) WlzInitGreyScan(obj, &iwsp, &gwsp);
  }
  if( errNum == WLZ_ERR_NONE ){
    nints = 0;
    while( (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE ){
      callData.pos.vtY = iwsp.linpos;
      g = gwsp.u_grintptr;
      over = 0;

      for (colno = iwsp.lftpos; colno <= iwsp.rgtpos; colno++) {
	callData.pix.p = g;
	callData.pos.vtX = colno;
	if((*threshCb)(obj, clientData, &callData) ){
	  if (over == 0) {
	    over = 1;
	    if (iwsp.linpos < nl1)
	      nl1 = iwsp.linpos;
	    if (iwsp.linpos > nll)
	      nll = iwsp.linpos;
	    if (colno < nk1)
	      nk1 = colno;
	  }
	} else {
	  if (over == 1) {
	    if (colno > nkl)
	      nkl = colno;
	    over = 0;
	    nints++;
	  }
	}

	switch( gwsp.pixeltype ){
	case WLZ_GREY_INT:
	  g.inp++;
	  break;
	case WLZ_GREY_SHORT:
	  g.shp++;
	  break;
	case WLZ_GREY_UBYTE:
	  g.ubp++;
	  break;
	case WLZ_GREY_FLOAT:
	  g.flp++;
	  break;
	case WLZ_GREY_DOUBLE:
	  g.dbp++;
	  break;
	case WLZ_GREY_RGBA:
	  g.rgbp++;
	  break;
	default:
	  break;
	}
      }

      if (over == 1) {
	if (colno > nkl)
	  nkl = colno;
	over = 0;
	nints++;
      }
    }
    nkl--;	/* since we have looked at points beyond interval ends */
    (void )WlzEndGreyScan(&iwsp, &gwsp);
    if( errNum == WLZ_ERR_EOO ){
      errNum = WLZ_ERR_NONE;
    }
  }

  /* domain structure */
  if( errNum == WLZ_ERR_NONE ){
    if( nints > 0 ){
      if((idom = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL,
				       nl1, nll, nk1, nkl, &errNum)) != NULL){
	if( (itvl = (WlzInterval *)
	     AlcMalloc(nints * sizeof(WlzInterval))) == NULL ){
	  errNum = WLZ_ERR_MEM_ALLOC;
	  WlzFreeIntervalDomain(idom);
	}
	else {
	  idom->freeptr = AlcFreeStackPush(idom->freeptr, (void *)itvl, NULL);
	}
      }

      /*
       * second pass - construct intervals
       */
      if( errNum == WLZ_ERR_NONE ){
	errNum = WlzInitGreyScan(obj, &iwsp, &gwsp);
	callData.pix.type = gwsp.pixeltype;
	nints = 0;
	jtvl = itvl;
      }

      /* find thresholded endpoints */
      if( errNum == WLZ_ERR_NONE ){
	while( (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE ){
	  if( iwsp.linpos < nl1 || iwsp.linpos > nll ){
	    continue;
	  }
	  callData.pos.vtY = iwsp.linpos;
	  g = gwsp.u_grintptr;
	  over = 0;

	  for (colno = iwsp.lftpos; colno <= iwsp.rgtpos; colno++) {
	    callData.pix.p = g;
	    callData.pos.vtX = colno;
	    if((*threshCb)(obj, clientData, &callData) ){
	      if (over == 0) {
		over = 1;
		itvl->ileft = colno - nk1;
	      }
	    } else {
	      if (over == 1) {
		over = 0;
		itvl->iright = colno - nk1 - 1;
		nints++;
		itvl++;
	      }
	    }

	    switch( gwsp.pixeltype ){
	    case WLZ_GREY_INT:
	      g.inp++;
	      break;
	    case WLZ_GREY_SHORT:
	      g.shp++;
	      break;
	    case WLZ_GREY_UBYTE:
	      g.ubp++;
	      break;
	    case WLZ_GREY_FLOAT:
	      g.flp++;
	      break;
	    case WLZ_GREY_DOUBLE:
	      g.dbp++;
	      break;
	    case WLZ_GREY_RGBA:
	      g.rgbp++;
	      break;
	    default:
	      break;
	    }
	  }

	  if (over == 1) {
	    over = 0;
	    itvl->iright = colno - nk1 - 1;
	    nints++;
	    itvl++;
	  }
	  /*
	   * end of line ?
	   */
	  if (iwsp.intrmn == 0) {
	    WlzMakeInterval(iwsp.linpos, idom, nints, jtvl);
	    jtvl = itvl;
	    nints = 0;
	  }
	}
	if( errNum == WLZ_ERR_EOO ){
	  errNum = WLZ_ERR_NONE;
	}
      }
    } else {
      /* no thresholded points - make a dummy domain anyway */
      return WlzMakeEmpty(dstErr);
    }
  }

  /* main object */
  if( errNum == WLZ_ERR_NONE ){
    domain.i = idom;
    nobj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain, obj->values,
		       obj->plist, obj, &errNum);
  }

  if( dstErr ){
    *dstErr = errNum;
  }
  return(nobj);
}
Ejemplo n.º 4
0
/*! 
* \ingroup      WlzBinaryOps
* \brief        Calculate the set union of an array of domain objects.
 Domians only unless uvt non-zero in which case make an average grey
 table. Note background values are used in the averaging process. All
 objects must be domain objects of the same type (2D or 3D) unless
 WLZ_EMPTY_OBJ, NULL input objects are an error.

 This function may modify the order of the objects in the array it is
 passed if the array contains empty objects.
*
* \return       Union of the array of object.
* \param    n	number of input objects
* \param    objs	input object array
* \param    uvt	grey-table copy flag, copy if non-zero.
* \param    dstErr	error return.
* \par      Source:
*                WlzUnionN.c
*/
WlzObject *WlzUnionN(
  int		n,
  WlzObject 	**objs,
  int 		uvt,
  WlzErrorNum	*dstErr)
{
  WlzObject		*obj=NULL;
  WlzDomain		domain;
  WlzValues		values;
  WlzIntervalDomain	*idom;
  WlzInterval		*itvl, *jtvl;
  WlzIntervalWSpace	*iwsp;
  WlzIntervalWSpace	*biwsp, *tiwsp, niwsp;
  WlzGreyWSpace		*gwsp, ngwsp;
  WlzObjectType		type;
  int 			i, j, k, l;
  int			inttot, numactive, change, lwas, nints, noverlap;
  WlzPixelV		backg;
  int			line1, lastln;
  int			kol1,lastkl;
  WlzGreyV		gv;
  WlzGreyP		greyptr;
  int			**locbuff;
  int			*locbuffs;
  int			span;
  WlzErrorNum		errNum=WLZ_ERR_NONE;

  /* preliminary stuff - count of non-NULL objects, note WLZ_EMPTY_OBJs
     are ignored but NULL objects are an error */
  if( n < 1 ){
    errNum = WLZ_ERR_PARAM_DATA;
  }
  else {
    for (i=0; i<n ; i++ ){
      if ( objs[i] == NULL ){
	errNum = WLZ_ERR_OBJECT_NULL;
	break;
      }
      if( objs[i]->type == WLZ_EMPTY_OBJ ){
	obj = objs[i];
	for ( j=i; j<n-1 ; j++ ){
	  objs[j] = objs[j+1];
	}
	objs[n-1] = obj;
	n--;
	i--;
      }
    }
  }
	
  /* n has been checked therefore no objects implies all empty */
  if( (errNum == WLZ_ERR_NONE) && (n < 1) ){
    return WlzMakeEmpty(dstErr);
  }

  /* now check they are all of the same type */
  if( errNum == WLZ_ERR_NONE ){
    for(i=1; i < n; i++){
      if( objs[i]->type != objs[0]->type ){
	errNum = WLZ_ERR_OBJECT_TYPE;
	break;
      }
    }
  }

  /* now test the type note empty objects have been discarded */
  if( errNum == WLZ_ERR_NONE ){
    switch( objs[0]->type ){

    case WLZ_2D_DOMAINOBJ:
      break;

    case WLZ_3D_DOMAINOBJ:
      return WlzUnion3d(n, objs, uvt, dstErr);

    case WLZ_TRANS_OBJ:
    default:
      errNum = WLZ_ERR_OBJECT_TYPE;
      break;
    }
  }

  /* now discard empty objects */
  if( errNum == WLZ_ERR_NONE ){
    for (i=0; i<n ; i++ ){
      if( WlzIsEmpty(objs[i], NULL) ){
	obj = objs[i];
	for ( j=i; j<n-1 ; j++ ){
	  objs[j] = objs[j+1];
	}
	objs[n-1] = obj;
	n--;
	i--;
      }
    }
  }
  obj = NULL;

  /* recheck number of objects */
  if( (errNum == WLZ_ERR_NONE) && (n < 1) ){
    return WlzMakeEmpty(dstErr);
  }
  if( (errNum == WLZ_ERR_NONE) && (n == 1) ){
    return WlzMakeMain(objs[0]->type, objs[0]->domain,
		       objs[0]->values, NULL, NULL, dstErr);
  }

  /* check if grey-value merge is possible */
  if( errNum == WLZ_ERR_NONE ){
    for (i=0; i<n ; i++ ){
      if( objs[i]->values.core == NULL ){
	uvt = 0;
	break;
      }
    }
  }

  /*
   * find the line and column bounds of the union.
   */
  if( errNum == WLZ_ERR_NONE ){
    line1 = objs[0]->domain.i->line1;
    lastln = objs[0]->domain.i->lastln;
    kol1 = objs[0]->domain.i->kol1;
    lastkl = objs[0]->domain.i->lastkl;
    for (i=1; i<n; i++) {
      idom = objs[i]->domain.i;
      if (line1 > idom->line1)
	line1 = idom->line1;
      if (lastln < idom->lastln)
	lastln = idom->lastln;
      if (kol1 > idom->kol1)
	kol1 = idom->kol1;
      if (lastkl < idom->lastkl)
	lastkl = idom->lastkl;
    }
    span = lastkl - kol1 +1 ;
    if( (locbuff = (int **) AlcMalloc((n+1)*sizeof(int *))) == NULL ){
      errNum = WLZ_ERR_MEM_ALLOC;
    }
  }

  /* space must be allocated for the largest variety of grey-value */
  if( errNum == WLZ_ERR_NONE ){
    if( (locbuffs = (int *) AlcMalloc(sizeof(double)*span*(n+1))) == NULL ){
      AlcFree((void *) locbuff);
      errNum = WLZ_ERR_MEM_ALLOC;
    }
    else {
      for(i=0; i <= n; i++){
	locbuff[i] = locbuffs + i*span;
      }
    }
  }
  /*
   * count the individual intervals so that sufficient space
   * for the union may be allocated.
   */
  if( errNum == WLZ_ERR_NONE ){
    inttot=0;
    for(i=0; i < n; i++){
      inttot += WlzIntervalCount(objs[i]->domain.i, &errNum);
    }
  }

  /*
   * set up domain, value table structures, and object.
   */
  if( errNum == WLZ_ERR_NONE ){
    if( (idom = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL,
				      line1,lastln,kol1,lastkl,
				      &errNum)) == NULL ){
      AlcFree((void *) locbuffs);
      AlcFree((void *) locbuff);
    }
    else if( (itvl = (WlzInterval *)
	      AlcMalloc(inttot * sizeof(WlzInterval))) == NULL){
      AlcFree((void *) locbuffs);
      AlcFree((void *) locbuff);
      WlzFreeIntervalDomain(idom);
      errNum = WLZ_ERR_MEM_ALLOC;
    }
    else {
      idom->freeptr = AlcFreeStackPush(idom->freeptr, (void *)itvl, NULL);
      lwas = line1;
      jtvl = itvl;
      nints = 0;
      domain.i = idom;
      values.v = NULL;
      if( (obj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain, values,
			     NULL, NULL, &errNum)) == NULL ){
	WlzFreeIntervalDomain( idom );
	AlcFree((void *) locbuffs);
	AlcFree((void *) locbuff);
	return(NULL);
      }
    }
  }    

  /*
   * allocate space for workspaces
   */
  if( errNum == WLZ_ERR_NONE ){
    if( (iwsp = (WlzIntervalWSpace *)
        AlcMalloc (n * sizeof (WlzIntervalWSpace))) == NULL ){
      WlzFreeObj( obj );
      AlcFree((void *) locbuffs);
      AlcFree((void *) locbuff);
      errNum = WLZ_ERR_MEM_ALLOC;
      obj = NULL;
    }
    else {
      biwsp = iwsp;
      tiwsp = iwsp + n;
    }
  }

  /*
   * Construct the union object's table of intervals.
   * Initialise scanning on each object/workspace combination.
   * Scan synchronously, setting up the union of adjacent and
   * overlapping intervals.  Needs a clear head !!
   */
  if( errNum == WLZ_ERR_NONE ){
    for (i=0; i<n; i++) {
      WlzInitRasterScan(objs[i], iwsp, WLZ_RASTERDIR_ILIC);
      WlzNextInterval(iwsp++);
    }
    numactive = n;

    /*
     * find next line and left hand end of next interval of union
     */
    while (numactive > 0) {
      /*
       * find first remaining active object
       */
      iwsp = biwsp;
      while( iwsp->linrmn < 0 ){
	iwsp++;
      }
      /*
       * find minimum line number of remaining active intervals
       */
      l = iwsp->linpos;
      kol1 = iwsp->lftpos;
      lastkl = iwsp->rgtpos;
      for (iwsp++; iwsp<tiwsp; iwsp++)
	if (iwsp->linrmn >= 0 && iwsp->linpos < l) {
	  l = iwsp->linpos;
	  kol1 = iwsp->lftpos;
	  lastkl = iwsp->rgtpos;
	}
      /*
       * find left-most interval in this line
       */
      for (iwsp=biwsp; iwsp<tiwsp; iwsp++)
	if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos < kol1) {
	  kol1 = iwsp->lftpos;
	  lastkl = iwsp->rgtpos;
	}
      /*
       * construct maximal interval with current left end-point
       */
      do {
	change = 0;
	for (iwsp=biwsp; iwsp<tiwsp; iwsp++) {
	  while( iwsp->linrmn >= 0 && iwsp->linpos == l
		&& iwsp->lftpos <= lastkl+1 ){
	    if (iwsp->rgtpos > lastkl) {
	      lastkl = iwsp->rgtpos;
	      change = 1;
	    }
	    if (WlzNextInterval(iwsp) != WLZ_ERR_NONE) {
	      numactive--;
	    }
	  }
	}
      } while (change == 1);
      itvl->ileft = kol1 - idom->kol1;
      itvl->iright = lastkl - idom->kol1;
      if (l == lwas)
	nints++;
      else {
	(void) WlzMakeInterval(lwas,idom,nints,jtvl);
	for (j = lwas+1; j<l; j++) {
	  (void) WlzMakeInterval(j,idom,0,NULL);
	}
	lwas = l;
	nints = 1;
	jtvl = itvl;
      }
      itvl++;
    }
    (void) WlzMakeInterval(lwas,idom,nints,jtvl);
    for (j = lwas+1; j<=lastln; j++) {
      (void) WlzMakeInterval(j,idom,0,NULL);
    }
  }

  /* now deal with the grey-values if required */
  if( (errNum == WLZ_ERR_NONE) && (uvt != 0) ){
    WlzGreyType	grey_type;

    if( (gwsp = (WlzGreyWSpace *)
	 AlcMalloc (n * sizeof (WlzGreyWSpace))) == NULL){
      WlzFreeObj( obj );
      AlcFree((void *) locbuffs);
      AlcFree((void *) locbuff);
      AlcFree((void *) biwsp);
      errNum = WLZ_ERR_MEM_ALLOC;
      obj = NULL;
    }
    
    /* construct an empty "ragged-rectangle" greytable
       with appropriate grey-type */
    if( errNum == WLZ_ERR_NONE ){
      backg = WlzGetBackground(objs[0], NULL);
      grey_type = WlzGreyTableTypeToGreyType(objs[0]->values.core->type,
					     NULL);
      type = WlzGreyTableType(WLZ_GREY_TAB_RAGR, grey_type, NULL);
      if( (values.v = WlzNewValueTb(obj, type, backg, &errNum)) == NULL ){
	WlzFreeObj( obj );
	AlcFree((void *) locbuffs);
	AlcFree((void *) locbuff);
	AlcFree((void *) biwsp);
	obj = NULL;
      }
      else {
	obj->values = WlzAssignValues(values, NULL);
      }
    }

    /* fill the grey table.  Where more than one input objects
       overlap, take mean of grey values. */
    if( errNum == WLZ_ERR_NONE ){
      WlzInitGreyScan(obj, &niwsp, &ngwsp);
      iwsp = biwsp;
      for (i=0; i<n; i++) {
	WlzInitGreyScan(objs[i], iwsp, &gwsp[i]);
	WlzNextGreyInterval(iwsp++);
	if( gwsp[i].pixeltype != grey_type ){
	  AlcFree((void *) gwsp);
	  AlcFree((void *) locbuffs);
	  AlcFree((void *) locbuff);
	  AlcFree((void *) biwsp);
	  WlzFreeObj( obj );
	  obj = NULL;
	  errNum = WLZ_ERR_GREY_TYPE;
	}      
      }
    }

    if( errNum == WLZ_ERR_NONE ){
      while (WlzNextGreyInterval(&niwsp) == WLZ_ERR_NONE) {
	l = niwsp.linpos;
	greyptr = ngwsp.u_grintptr;
	switch( ngwsp.pixeltype ){

	case WLZ_GREY_INT:
	  for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) {
	    noverlap = 0;
	    gv.inv = 0;
	    for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) {
	      while (iwsp->linrmn >= 0
		     && (iwsp->linpos < l
			 || (iwsp->linpos == l && iwsp->rgtpos < k))){
		WlzNextGreyInterval(iwsp);
	      }
	      if (iwsp->linrmn >= 0 && iwsp->linpos == l &&
		  iwsp->lftpos <= k) {
		noverlap++;
		gv.inv += *(gwsp[i].u_grintptr.inp + k - iwsp->lftpos);
	      }
	    }
	    *greyptr.inp = gv.inv / noverlap;
	    greyptr.inp++;
	  }
	  break;

	case WLZ_GREY_SHORT:
	  for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) {
	    noverlap = 0;
	    gv.shv = 0;
	    for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) {
	      while (iwsp->linrmn >= 0
		     && (iwsp->linpos < l
			 || (iwsp->linpos == l && iwsp->rgtpos < k))){
		WlzNextGreyInterval(iwsp);
	      }
	      if (iwsp->linrmn >= 0 && iwsp->linpos == l &&
		  iwsp->lftpos <= k) {
		noverlap++;
		gv.shv += *(gwsp[i].u_grintptr.shp + k - iwsp->lftpos);
	      }
	    }
	    *greyptr.shp = (short )(gv.shv / noverlap);
	    greyptr.shp++;
	  }
	  break;

	case WLZ_GREY_UBYTE:
	  for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) {
	    noverlap = 0;
	    gv.inv = 0;
	    for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) {
	      while (iwsp->linrmn >= 0
		     && (iwsp->linpos < l
			 || (iwsp->linpos == l && iwsp->rgtpos < k))){
		WlzNextGreyInterval(iwsp);
	      }
	      if (iwsp->linrmn >= 0 && iwsp->linpos == l &&
		  iwsp->lftpos <= k) {
		noverlap++;
		gv.inv += *(gwsp[i].u_grintptr.ubp + k - iwsp->lftpos);
	      }
	    }
	    *greyptr.ubp = (WlzUByte )(gv.inv / noverlap);
 	    greyptr.ubp++;
	  }
	  break;

	case WLZ_GREY_FLOAT:
	  for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) {
	    noverlap = 0;
	    gv.flv = 0;
	    for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) {
	      while (iwsp->linrmn >= 0
		     && (iwsp->linpos < l
			 || (iwsp->linpos == l && iwsp->rgtpos < k))){
		WlzNextGreyInterval(iwsp);
	      }
	      if (iwsp->linrmn >= 0 && iwsp->linpos == l &&
		  iwsp->lftpos <= k) {
		noverlap++;
		gv.flv += *(gwsp[i].u_grintptr.flp + k - iwsp->lftpos);
	      }
	    }
	    *greyptr.flp = gv.flv / noverlap;
	    greyptr.flp++;
	  }
	  break;

	case WLZ_GREY_DOUBLE:
	  for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) {
	    noverlap = 0;
	    gv.dbv = 0;
	    for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) {
	      while (iwsp->linrmn >= 0
		     && (iwsp->linpos < l
			 || (iwsp->linpos == l && iwsp->rgtpos < k))){
		WlzNextGreyInterval(iwsp);
	      }
	      if (iwsp->linrmn >= 0 && iwsp->linpos == l &&
		  iwsp->lftpos <= k) {
		noverlap++;
		gv.dbv += *(gwsp[i].u_grintptr.dbp + k - iwsp->lftpos);
	      }
	    }
	    *greyptr.dbp = gv.dbv / noverlap;
	    greyptr.dbp++;
	  }
	  break;
	case WLZ_GREY_RGBA: /* RGBA to be done - do properly RAB */
	  for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) {
	    noverlap = 0;
	    gv.rgbv = 0;
	    for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) {
	      while (iwsp->linrmn >= 0
		     && (iwsp->linpos < l
			 || (iwsp->linpos == l && iwsp->rgtpos < k))){
		WlzNextGreyInterval(iwsp);
	      }
	      if (iwsp->linrmn >= 0 && iwsp->linpos == l &&
		  iwsp->lftpos <= k) {
		noverlap++;
		gv.rgbv += *(gwsp[i].u_grintptr.rgbp + k - iwsp->lftpos);
	      }
	    }
	    *greyptr.rgbp = gv.rgbv / noverlap;
	    greyptr.rgbp++;
	  }
	  break;

	default:
	  break;

	}
      }
    }
    AlcFree((void *) gwsp);
  }

  if( errNum == WLZ_ERR_NONE ){
    AlcFree( (void *) biwsp);
    AlcFree( (void *)locbuff );
    AlcFree( (void *)locbuffs );
  }

  if( dstErr ){
    *dstErr = errNum;
  }
  return( obj );
}
Ejemplo n.º 5
0
/*! 
* \ingroup      WlzBinaryOps
* \brief        Calculate the intersection of a set of objects. If
 uvt=0 calculate domain only, uvt=1 calculate the mmean grey-value at
 each point. Input objects must be all non-NULL and domain objects of
 the same type i.e. either 2D or 3D otherwise an error is returned.
*
* \return       Intersection object with grey-table as required, if the intersection is empty returns WLZ_EMPTY_OBJ, NULL on error.
* \param    n	number of input objects
* \param    objs	input object array
* \param    uvt	grey-table copy flag (1 - copy, 0 - no copy)
* \param    dstErr	error return.
* \par      Source:
*                WlzIntersectN.c
*/
WlzObject *WlzIntersectN(
  int 	n,
  WlzObject **objs,
  int 	uvt,
  WlzErrorNum *dstErr)
{
  WlzObject 		*obj = NULL;
  WlzIntervalDomain 	*idom;
  WlzInterval 		*itvl, *jtvl;
  WlzIntervalWSpace 	*iwsp;
  WlzIntervalWSpace 	*biwsp,*tiwsp,niwsp;
  WlzGreyWSpace 	*gwsp,ngwsp;
  WlzDomain		domain;
  WlzValues		values;
  WlzObjectType		type;
  WlzPixelV		backg;
  WlzGreyP		greyptr;
  WlzGreyV		gv;
  int 			i, j, k, l, inttot, change, lwas, nints;
  int 			line1, lastln;
  int 			kol1, lastkl;
  WlzErrorNum		errNum = WLZ_ERR_NONE;

  /*
   * check pointers
   */
  /* intersecction of no objects is an empty domain */
  domain.i = NULL;
  values.v = NULL;
  if( n < 1 )
  {
    return WlzMakeEmpty(dstErr);
  }

  /* array pointer == NULL or any object pointer == NULL is an error */
  if(objs == NULL){
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else
  {
    for(i=0; i<n; i++){
      if(objs[i] == NULL){
	errNum = WLZ_ERR_OBJECT_NULL;
      }
    }
  }
  if(errNum != WLZ_ERR_NONE)
  {
    obj = NULL;
    if(dstErr) {
      *dstErr = errNum;
    }
    return(obj);
  }

  /* check type of first object */
  switch( objs[0]->type ){

  case WLZ_2D_DOMAINOBJ:
    break;

  case WLZ_3D_DOMAINOBJ:
    return WlzIntersect3d(objs, n, uvt, &errNum);

  case WLZ_EMPTY_OBJ:
    return WlzMakeEmpty(dstErr);

  default:
    errNum = WLZ_ERR_OBJECT_TYPE;
    if(dstErr) {
      *dstErr = errNum;
    }
    return NULL;

  }

  /* check number */
  if (n == 1){
    obj = WlzMakeMain(objs[0]->type, objs[0]->domain, objs[0]->values,
		      NULL, NULL, &errNum);
    if(dstErr) {
      *dstErr = errNum;
    }
    return(obj);
  }

  /* check all objects are non-empty and have the same type
     Note an empty object is not an error */
  for (i=0; i<n; i++){
    if( objs[i]->type != objs[0]->type ){
      if( objs[i]->type == WLZ_EMPTY_OBJ ){
	return WlzMakeEmpty(dstErr);
      }
      else {
	errNum = WLZ_ERR_OBJECT_TYPE;
	if(dstErr) {
	  *dstErr = errNum;
	}
	return NULL;
      }
    }

    /* check for size */
    if( WlzIsEmpty(objs[i], &errNum) ){
      return WlzMakeEmpty(dstErr);
    }
    else {
      if( errNum != WLZ_ERR_NONE ){
	if(dstErr) {
	  *dstErr = errNum;
	}
	return NULL;
      }
    }
  }

  /*
   * Find the line and column bounds of the intersection.
   */
  line1 = objs[0]->domain.i->line1;
  lastln = objs[0]->domain.i->lastln;
  kol1 = objs[0]->domain.i->kol1;
  lastkl = objs[0]->domain.i->lastkl;
  for (i=1; i<n; i++) {
    idom = objs[i]->domain.i;
    if (line1 < idom->line1)
    {
      line1 = idom->line1;
    }
    if (lastln > idom->lastln)
    {
      lastln = idom->lastln;
    }
    if (kol1 < idom->kol1)
    {
      kol1 = idom->kol1;
    }
    if (lastkl > idom->lastkl)
    {
      lastkl = idom->lastkl;
    }
  }
  if( lastkl < kol1 || lastln < line1 ){
    return WlzMakeEmpty(dstErr);
  }

  /*
   * Count the individual intervals so that sufficient space
   * for the intersection may be allocated.
   */
  inttot=0;
  for (i=0; (i < n) && (errNum == WLZ_ERR_NONE); i++) {
    inttot += WlzIntervalCount(objs[i]->domain.i, &errNum);
  }
  if(errNum != WLZ_ERR_NONE) {
    if(dstErr) {
      *dstErr = errNum;
    }
    return NULL;
  }

  /*
   * Set up domain, value table structures, and object.
   */

  if( (idom = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL,
				    line1, lastln, 0, lastkl-kol1,
				    &errNum)) == NULL ){
    if(dstErr) {
      *dstErr = errNum;
    }
    return NULL;
  }
  if( (itvl = (WlzInterval *)
       AlcMalloc (inttot * sizeof(WlzInterval))) == NULL ){
    WlzFreeIntervalDomain(idom);
    errNum = WLZ_ERR_MEM_ALLOC;
    if(dstErr) {
      *dstErr = errNum;
    }
    return NULL;
  }

  idom->freeptr = AlcFreeStackPush(idom->freeptr, (void *)itvl, NULL);
  lwas = line1;
  jtvl = itvl;
  nints = 0;
  domain.i = idom;
  values.v = NULL;
  if( (obj = WlzMakeMain(WLZ_2D_DOMAINOBJ,
			 domain, values, NULL, NULL, &errNum)) == NULL ){
    WlzFreeIntervalDomain(idom);
    if(dstErr) {
      *dstErr = errNum;
    }
    return NULL;
  }

  /*
   * allocate space for workspaces
   */
  if( (iwsp = (WlzIntervalWSpace *)
       AlcMalloc(n * sizeof(WlzIntervalWSpace))) == NULL ){
    WlzFreeObj( obj );
    errNum = WLZ_ERR_MEM_ALLOC;
    if(dstErr) {
      *dstErr = errNum;
    }
    return NULL;
  }
  biwsp = iwsp;
  tiwsp = biwsp + n;

  /*
   * Construct the intersection object's table of intervals.
   * Initialise scanning on each object/workspace combination.
   * Scan synchronously, setting up the intersection of
   * overlapping intervals.  Needs a clear head !!
   */
  for (i=0; (i < n) && (errNum == WLZ_ERR_NONE); i++) {
    errNum = WlzInitRasterScan(objs[i],iwsp,WLZ_RASTERDIR_ILIC);
    if(errNum == WLZ_ERR_NONE) {
      errNum = WlzNextInterval(iwsp++);
    }
  }
  if(errNum != WLZ_ERR_NONE) {
    WlzFreeObj( obj );
    if(dstErr) {
      *dstErr = errNum;
    }
    return NULL;
  }

  l = lwas;
  for (;;) {
    /*
     * find next line of intersection
     */
    do {
      change = 0;
      for (iwsp=biwsp; iwsp<tiwsp; iwsp++) {
	if (iwsp->linpos > l) {
	  l = iwsp->linpos;
        }
      }
      for (iwsp=biwsp; iwsp<tiwsp; iwsp++) {
	while (iwsp->linpos < l) {
	  if ((errNum = WlzNextInterval(iwsp)) != WLZ_ERR_NONE) {
	    if(errNum == WLZ_ERR_EOO)
	    {
	      errNum = WLZ_ERR_NONE;
	    }
	    goto firstfinished;
	  }
	  if (iwsp->linpos > l) {
	    change = 1;
	  }
	}
      }
    } while (change != 0);
    /*
     * find next interval of intersection
     */
    kol1 = biwsp->lftpos;
    lastkl = biwsp->rgtpos;
    while(errNum == WLZ_ERR_NONE) {
      do {
	change = 0;
	for (iwsp=biwsp; iwsp<tiwsp; iwsp++)
	  if (iwsp->lftpos > lastkl) {
	    kol1 = iwsp->lftpos;
	    lastkl = iwsp->rgtpos;
	  } else if (iwsp->lftpos > kol1)
	    kol1 = iwsp->lftpos;
	for (iwsp=biwsp; iwsp<tiwsp; iwsp++) {
	  while (iwsp->rgtpos < kol1) {
	    if ((errNum = WlzNextInterval(iwsp)) != WLZ_ERR_NONE) {
	      if(errNum == WLZ_ERR_EOO)
	      {
	        errNum = WLZ_ERR_NONE;
	      }
	      goto firstfinished;
	    }
	    if (iwsp->linpos != l) {
	      l = iwsp->linpos;
	      goto jumpline;
	    }
	    if (iwsp->lftpos > kol1)
	      change = 1;
	  }
	}
      } while ((change != 0) && (errNum == WLZ_ERR_NONE));
      if(errNum == WLZ_ERR_NONE)
      {
	for (iwsp=biwsp; iwsp < tiwsp; iwsp++) {
	  if (iwsp->rgtpos <= lastkl) {
	    lastkl = iwsp->rgtpos;
	  }
	}
	if (lastkl >= kol1) {
	  itvl->ileft = kol1 - idom->kol1;
	  itvl->iright = lastkl - idom->kol1;
	  if (l == lwas) {
	    nints++;
	  } else {
	    errNum = WlzMakeInterval(lwas,idom,nints,jtvl);
	    for (j = lwas+1; (j < l) && (errNum == WLZ_ERR_NONE); j++) {
	      errNum = WlzMakeInterval(j,idom,0,NULL);
	    }
	    if(errNum == WLZ_ERR_NONE) {
	      lwas = l;
	      nints = 1;
	      jtvl = itvl;
	    }
	  }
	  itvl++;
	}
	kol1 = lastkl+1;
      }
    }

  jumpline:
    ;
  }

firstfinished:
  if(errNum != WLZ_ERR_NONE) {
    WlzFreeObj(obj);
    if(dstErr) {
      *dstErr = errNum;
    }
    return NULL;
  }

  errNum = WlzMakeInterval(lwas,idom,nints,jtvl);
  for (j = lwas+1; (j <= lastln) && (errNum == WLZ_ERR_NONE); j++) {
    errNum = WlzMakeInterval(j,idom,0,NULL);
  }
  if(errNum != WLZ_ERR_NONE)
  {
    WlzFreeObj(obj);
    AlcFree((void *) biwsp);
    if(dstErr)
    {
      *dstErr = errNum;
    }
    return NULL;
  }

  /*
   * standardise the interval list (remove leading and trailing
   * empty lines, set kol1 so that at least one interval commences
   * at zero, set lastkl correctly)
   */
  (void )WlzStandardIntervalDomain(idom);

  /* check for error or empty */
  nints = WlzIntervalCount(idom, &errNum);
  if( nints < 0 ){
    /* error */
    WlzFreeObj(obj);
    AlcFree((void *) biwsp);
    if(dstErr)
    {
      *dstErr = errNum;
    }
    return NULL;
  }
  else if( nints == 0 ){
    /* empty object */
    WlzFreeObj(obj);
    AlcFree((void *) biwsp);
    return WlzMakeEmpty(dstErr);
  }

  if (uvt != 0) {
    WlzGreyType	grey_type;
    if( (gwsp = (WlzGreyWSpace *)
	 AlcMalloc (n * sizeof (WlzGreyWSpace))) == NULL ){
      WlzFreeObj(obj);
      AlcFree((void *) biwsp);
      errNum = WLZ_ERR_MEM_ALLOC;
      if(dstErr)
      {
        *dstErr = errNum;
      }
      return NULL;
    }

    /* construct an empty "ragged-rectangle" (type 1  or 2) greytable
       choosing the grey-value type from the first object in the list */
    backg = WlzGetBackground(objs[0], &errNum);
    if(errNum == WLZ_ERR_NONE) {
      grey_type = WlzGreyTableTypeToGreyType(objs[0]->values.core->type,
      					     &errNum);
    }
    if(errNum == WLZ_ERR_NONE) {
      type = WlzGreyTableType(WLZ_GREY_TAB_RAGR, grey_type, &errNum);
    }
    if((errNum != WLZ_ERR_NONE) ||
       (values.v = WlzNewValueTb(obj, type, backg, &errNum)) == NULL ){
      WlzFreeObj( obj );
      AlcFree((void *) gwsp);
      AlcFree((void *) biwsp);
      if(dstErr)
      {
        *dstErr = errNum;
      }
      return NULL;
    }
    obj->values = WlzAssignValues(values, &errNum);
    if(errNum != WLZ_ERR_NONE) {
      WlzFreeObj( obj );
      AlcFree((void *) gwsp);
      AlcFree((void *) biwsp);
      if(dstErr)
      { 
	*dstErr = errNum;
      }
      return NULL;
    }
	
    /*
     * fill the grey table with mean of grey values.
     */
    /* initialise the work-spaces and check pixel type */
    errNum = WlzInitGreyScan(obj, &niwsp, &ngwsp);
    iwsp = biwsp;
    for (i=0; (i < n) && (errNum == WLZ_ERR_NONE); i++) {
      errNum = WlzInitGreyScan(objs[i], iwsp, &gwsp[i]);
      if(errNum == WLZ_ERR_NONE) {
	errNum = WlzNextGreyInterval(iwsp++);
      }
      if( gwsp[i].pixeltype != grey_type ){
        errNum = WLZ_ERR_GREY_TYPE;
      }
    }
    if(errNum != WLZ_ERR_NONE) {
      WlzFreeObj( obj );
      AlcFree((void *) gwsp);
      AlcFree((void *) biwsp);
      if(dstErr) {
        *dstErr = errNum;
      }
      return NULL;
    }

    while (WlzNextGreyInterval(&niwsp) == WLZ_ERR_NONE) {
      l = niwsp.linpos;
      greyptr = ngwsp.u_grintptr;
      switch( ngwsp.pixeltype ){

      case WLZ_GREY_INT:
	for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) {
	  gv.inv = 0;
	  for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) {
	    while(iwsp->linrmn >= 0 &&
		  (iwsp->linpos < l ||
		   (iwsp->linpos == l && iwsp->rgtpos < k))){
	      (void )WlzNextGreyInterval(iwsp);
	    }
	    gv.inv += *(gwsp[i].u_grintptr.inp + k - iwsp->lftpos);
	  }
	  *greyptr.inp = gv.inv / n;
	  greyptr.inp++;
	}
	break;

      case WLZ_GREY_SHORT:
	for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) {
	  gv.shv = 0;
	  for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) {
	    while(iwsp->linrmn >= 0 &&
		  (iwsp->linpos < l ||
		   (iwsp->linpos == l && iwsp->rgtpos < k))){
	      (void )WlzNextGreyInterval(iwsp);
	    }
	    gv.shv += *(gwsp[i].u_grintptr.shp + k - iwsp->lftpos);
	  }
	  *greyptr.shp = (short )(gv.shv / n);
	  greyptr.shp++;
	}
	break;

      case WLZ_GREY_UBYTE:
	for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) {
	  gv.ubv = 0;
	  for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) {
	    while(iwsp->linrmn >= 0 &&
		  (iwsp->linpos < l ||
		   (iwsp->linpos == l && iwsp->rgtpos < k))){
	      (void )WlzNextGreyInterval(iwsp);
	    }
	    gv.ubv += *(gwsp[i].u_grintptr.ubp + k - iwsp->lftpos);
	  }
	  *greyptr.ubp = (WlzUByte )(gv.ubv / n);
	  greyptr.ubp++;
	}
	break;

      case WLZ_GREY_FLOAT:
	for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) {
	  gv.flv = 0;
	  for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) {
	    while(iwsp->linrmn >= 0 &&
		  (iwsp->linpos < l ||
		   (iwsp->linpos == l && iwsp->rgtpos < k))){
	      (void )WlzNextGreyInterval(iwsp);
	    }
	    gv.flv += *(gwsp[i].u_grintptr.flp + k - iwsp->lftpos);
	  }
	  *greyptr.flp = gv.flv / n;
	  greyptr.flp++;
	}
	break;

      case WLZ_GREY_DOUBLE:
	for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) {
	  gv.dbv = 0;
	  for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) {
	    while(iwsp->linrmn >= 0 &&
		  (iwsp->linpos < l ||
		   (iwsp->linpos == l && iwsp->rgtpos < k))){
	      (void )WlzNextGreyInterval(iwsp);
	    }
	    gv.dbv += *(gwsp[i].u_grintptr.dbp + k - iwsp->lftpos);
	  }
	  *greyptr.dbp = gv.dbv / n;
	  greyptr.dbp++;
	}
	break;

      case WLZ_GREY_RGBA: /* RGBA to be done again RAB */
	for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) {
	  gv.rgbv = 0;
	  for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) {
	    while(iwsp->linrmn >= 0 &&
		  (iwsp->linpos < l ||
		   (iwsp->linpos == l && iwsp->rgtpos < k))){
	      (void )WlzNextGreyInterval(iwsp);
	    }
	    gv.rgbv += *(gwsp[i].u_grintptr.rgbp + k - iwsp->lftpos);
	  }
	  *greyptr.rgbp = gv.rgbv / n;
	  greyptr.rgbp++;
	}
	break;

      default:
	errNum = WLZ_ERR_GREY_TYPE;
	break;

      }
    }
    if(errNum == WLZ_ERR_EOO)
    {
      errNum = WLZ_ERR_NONE;
    }
    AlcFree((void *) gwsp);
  }
  AlcFree((void *) biwsp);

  if(dstErr) {
    *dstErr = errNum;
  }
  return obj;
}