Example #1
0
/*!
* \return	Returns a preprocessed object for registration.
* \ingroup	WlzRegistration
* \brief
* \param	obj			Given object.
* \param	inv			Flag, non zero if object values are
*					to be inverted.
* \param	dstErr			Destination error pointer,
*                                       may be NULL.
*/
static WlzObject *WlzRegCCorNormaliseObj2D(WlzObject *obj, int inv,
					WlzErrorNum *dstErr)
{
  WlzGreyType	gType;
  WlzPixelV	min,
  		max,
		mean,
		minN,
		maxN,
		zero;
  WlzObject	*obj0 = NULL;
  WlzErrorNum   errNum = WLZ_ERR_NONE;

  /* Normalise the object inverting the grey values if required -> obj0. */
  minN.v.ubv = 0;
  maxN.v.ubv = 255;
  zero.v.ubv = 0;
  min.type = WLZ_GREY_DOUBLE;
  max.type = WLZ_GREY_DOUBLE;
  mean.type = WLZ_GREY_UBYTE;
  minN.type = WLZ_GREY_UBYTE;
  maxN.type = WLZ_GREY_UBYTE;
  zero.type = WLZ_GREY_UBYTE;
  mean.v.ubv = 128;
  if(inv)
  {
    minN.v.ubv = 255;
    maxN.v.ubv = 0;
  }
  (void )WlzGreyStats(obj, &gType, &(min.v.dbv), &(max.v.dbv),
                      NULL, NULL, NULL, NULL, &errNum);
  if(errNum == WLZ_ERR_NONE)
  {
    WlzValueConvertPixel(&min, min, gType);
    WlzValueConvertPixel(&max, max, gType);
    WlzValueConvertPixel(&minN, minN, gType);
    WlzValueConvertPixel(&maxN, maxN, gType);
    obj0 = WlzCopyObject(obj, &errNum);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    errNum = WlzSetBackground(obj0, zero);
    errNum = WlzGreySetRange(obj0, min, max, minN, maxN, 0);
  }
  if(errNum != WLZ_ERR_NONE)
  {
    (void )WlzFreeObj(obj0); obj0 = NULL;
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(obj0);
}
Example #2
0
/*! 
* \return       Woolz error number
* \ingroup      WlzValuesFilters
* \brief        Normalizes the the grey values of the input object to
*		fill the range 0-255. Colour values are independently
*		reset which will change colour balance. Use WlzGreySetRange
*		directly to avoid this.
*		Note grey-values are reset in place and not copied.
* \par          Source:
*                 WlzGreyNormalise.c
* \param obj	Input object.
* \param    	Dither values if destination range is greater than source
* 		range and this flag is non-zero.
*/
WlzErrorNum WlzGreyNormalise(
  WlzObject	*obj,
  int		dither)
{
  WlzPixelV	min, max, Min, Max;
  WlzErrorNum	errNum=WLZ_ERR_NONE;

  /* get then set the grey-range of the object */
  errNum = WlzGreyRange(obj, &min, &max);
  Min = min;
  Max = max;
  if( errNum == WLZ_ERR_NONE ){
    switch( min.type ){
    case WLZ_GREY_INT:
      Min.v.inv = 0;
      Max.v.inv = 255;
      break;
    case WLZ_GREY_SHORT:
      Min.v.shv = 0;
      Max.v.shv = 255;
      break;
    case WLZ_GREY_UBYTE:
      Min.v.ubv = 0;
      Max.v.ubv = 255;
      break;
    case WLZ_GREY_FLOAT:
      Min.v.flv = 0.0;
      Max.v.flv = 255.0;
      break;
    case WLZ_GREY_DOUBLE:
      Min.v.dbv = 0.0;
      Max.v.dbv = 255.0;
      break;
    case WLZ_GREY_RGBA:
      Min.v.rgbv = 0xff000000;
      Max.v.rgbv = 0xffffffff;
      break;
    default:
      errNum = WLZ_ERR_GREY_TYPE;
      break;
    }
    if(errNum == WLZ_ERR_NONE)
    {
      errNum = WlzGreySetRange(obj, min, max, Min, Max, dither);
    }
  }

  return(errNum);
}
Example #3
0
/*! 
* \ingroup      WlzValuesFilters
* \brief        Set new grey-range by simple linear interpolation. It
 assumes that the min and max values enclose the true range of
 grey-values in the object. Failure to check this could result in a
 segmentation fault.

The transform function is:
\f[g' = \frac{(gMax - gMin)}{(gmax - gmin)} (g - gmin) + gMin + \delta
\f]
Here \f$\delta\f$ is the dither value.
*
* \return       Woolz error number
* \param    obj	Input grey-level object whose values are to be reset.
* \param    min	Initial minimum value
* \param    max	Initial maximum value
* \param    Min	Final minimum value
* \param    Max	Final maximum value
* \param    Dither values if destination range is greater than source range
*           and this flag is non-zero.
* \par      Source:
*                WlzGreySetRange.c
*/
WlzErrorNum WlzGreySetRange(
  WlzObject	*obj,
  WlzPixelV	min,
  WlzPixelV	max,
  WlzPixelV	Min,
  WlzPixelV	Max,
  int		dither)
{
  double		gMin = 0.0,
  			gMax = 0.0,
			sigma = 0.0,
  			factor,
			val;
  WlzIntervalWSpace	iwsp;
  WlzGreyWSpace		gwsp;
  WlzGreyP		gptr;
  WlzObject		*tempobj;
  WlzValues 		*values;
  WlzDomain		*domains;
  int			i, j, nplanes;
  WlzErrorNum		errNum = WLZ_ERR_NONE;

  /* check object */
  if( obj == NULL ){
    errNum = WLZ_ERR_OBJECT_NULL;
  }

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

    case WLZ_2D_DOMAINOBJ:
      if( obj->domain.i == NULL ){
	return WLZ_ERR_DOMAIN_NULL;
      }
      if( obj->values.core == NULL ){
	return WLZ_ERR_VALUES_NULL;
      }
      if( WlzGreyTableIsTiled(obj->values.core->type) ){
	return WLZ_ERR_VALUES_TYPE;
      }
      break;

    case WLZ_3D_DOMAINOBJ:
      /* check planedomain and voxeltable */
      if( obj->domain.p == NULL ){
	return WLZ_ERR_DOMAIN_NULL;
      }
      if( obj->domain.p->type != WLZ_PLANEDOMAIN_DOMAIN ){
	return WLZ_ERR_PLANEDOMAIN_TYPE;
      }
      if( obj->values.vox == NULL ){
	return WLZ_ERR_VALUES_NULL;
      }
      if( obj->values.vox->type != WLZ_VOXELVALUETABLE_GREY ){
	return WLZ_ERR_VOXELVALUES_TYPE;
      }

      /* set range of each plane if non-empty - indicated by NULL */
      domains = obj->domain.p->domains;
      values = obj->values.vox->values;
      nplanes = obj->domain.p->lastpl - obj->domain.p->plane1 + 1;
      for(i=0; i < nplanes; i++, domains++, values++){

	if( (*domains).core == NULL || (*values).core == NULL ){
	  continue;
	}

	tempobj = WlzMakeMain(WLZ_2D_DOMAINOBJ,
			      *domains, *values, NULL, NULL,
			      &errNum);
	if((tempobj == NULL) && (errNum == WLZ_ERR_NONE) ){
	  errNum = WLZ_ERR_UNSPECIFIED;
	  break;
	}

	errNum = WlzGreySetRange(tempobj, min, max, Min, Max, dither);
	WlzFreeObj( tempobj );
	if( errNum != WLZ_ERR_NONE ){
	  break;
	}
      }
      
      return errNum;

    case WLZ_TRANS_OBJ:
      return WlzGreySetRange(obj->values.obj, min, max, Min, Max, dither);

    case WLZ_EMPTY_OBJ:
      return errNum;

    default:
      errNum = WLZ_ERR_OBJECT_TYPE;
      break;
    }
  }

  if( errNum == WLZ_ERR_NONE ){
    /* get conversion function - should use LUT
       use 4 LUTS for rgb type since bounded */
    if( WlzGreyTypeFromObj(obj, &errNum) == WLZ_GREY_RGBA ){
      WlzUByte	rgbaLut[4][256];
      WlzUInt	rgbamin[4], rgbaMin[4];
      double	rgbaFactor[4], val1;
      WlzUInt	red, green, blue, alpha;

      rgbamin[0] = WLZ_RGBA_RED_GET(min.v.rgbv);
      rgbaMin[0] = WLZ_RGBA_RED_GET(Min.v.rgbv);
      if(WLZ_RGBA_RED_GET(max.v.rgbv) > WLZ_RGBA_RED_GET(min.v.rgbv)){
	rgbaFactor[0] = (((double) WLZ_RGBA_RED_GET(Max.v.rgbv) - 
			  WLZ_RGBA_RED_GET(Min.v.rgbv))/
			 (WLZ_RGBA_RED_GET(max.v.rgbv) - 
			  WLZ_RGBA_RED_GET(min.v.rgbv)));
      }
      else {
	rgbaFactor[0] = 0.0;
      }

      rgbamin[1] = WLZ_RGBA_GREEN_GET(min.v.rgbv);
      rgbaMin[1] = WLZ_RGBA_GREEN_GET(Min.v.rgbv);
      if(WLZ_RGBA_GREEN_GET(max.v.rgbv) > WLZ_RGBA_GREEN_GET(min.v.rgbv)){
	rgbaFactor[1] = (((double) WLZ_RGBA_GREEN_GET(Max.v.rgbv) - 
			  WLZ_RGBA_GREEN_GET(Min.v.rgbv))/
			 (WLZ_RGBA_GREEN_GET(max.v.rgbv) - 
			  WLZ_RGBA_GREEN_GET(min.v.rgbv)));
      }
      else {
	rgbaFactor[1] = 0.0;
      }

      rgbamin[2] = WLZ_RGBA_BLUE_GET(min.v.rgbv);
      rgbaMin[2] = WLZ_RGBA_BLUE_GET(Min.v.rgbv);
      if(WLZ_RGBA_BLUE_GET(max.v.rgbv) > WLZ_RGBA_BLUE_GET(min.v.rgbv)){
	rgbaFactor[2] = (((double) WLZ_RGBA_BLUE_GET(Max.v.rgbv) - 
			  WLZ_RGBA_BLUE_GET(Min.v.rgbv))/
			 (WLZ_RGBA_BLUE_GET(max.v.rgbv) - 
			  WLZ_RGBA_BLUE_GET(min.v.rgbv)));
      }
      else {
	rgbaFactor[2] = 0.0;
      }

      rgbamin[3] = WLZ_RGBA_ALPHA_GET(min.v.rgbv);
      rgbaMin[3] = WLZ_RGBA_ALPHA_GET(Min.v.rgbv);
      if(WLZ_RGBA_ALPHA_GET(max.v.rgbv) > WLZ_RGBA_ALPHA_GET(min.v.rgbv)){
	rgbaFactor[3] = (((double) WLZ_RGBA_ALPHA_GET(Max.v.rgbv) - 
			  WLZ_RGBA_ALPHA_GET(Min.v.rgbv))/
			 (WLZ_RGBA_ALPHA_GET(max.v.rgbv) - 
			  WLZ_RGBA_ALPHA_GET(min.v.rgbv)));
      }
      else {
	rgbaFactor[3] = 0.0;
      }

      /* now set up the LUTS */
      for(i=0; i < 4; i++){
	for(j=0; j < 256; j++){
	  val1 = rgbaFactor[i] * (j - rgbamin[i]) + rgbaMin[i];
	  rgbaLut[i][j] = (WlzUByte )WLZ_CLAMP(val1, 0, 255);
	}
      }

      /* set values - can assume rgba grey-type */
      errNum = WlzInitGreyScan(obj, &iwsp, &gwsp);
      if(errNum == WLZ_ERR_NONE) {
	while( WlzNextGreyInterval(&iwsp) == WLZ_ERR_NONE ){

	  gptr = gwsp.u_grintptr;
	  for (i=0; i<iwsp.colrmn; i++, gptr.rgbp++){
	    red = rgbaLut[0][WLZ_RGBA_RED_GET(*gptr.rgbp)];
	    green = rgbaLut[0][WLZ_RGBA_GREEN_GET(*gptr.rgbp)];
	    blue = rgbaLut[0][WLZ_RGBA_BLUE_GET(*gptr.rgbp)];
	    alpha = rgbaLut[0][WLZ_RGBA_ALPHA_GET(*gptr.rgbp)];
	    WLZ_RGBA_RGBA_SET(*gptr.rgbp, red, green, blue, alpha);
	  }
	}
	(void )WlzEndGreyScan(&iwsp, &gwsp);
	if(errNum == WLZ_ERR_EOO){
	  errNum = WLZ_ERR_NONE;
	}
      }
    }
    else {
      WlzValueConvertPixel(&min, min, WLZ_GREY_DOUBLE);
      WlzValueConvertPixel(&max, max, WLZ_GREY_DOUBLE);
      WlzValueConvertPixel(&Min, Min, WLZ_GREY_DOUBLE);
      WlzValueConvertPixel(&Max, Max, WLZ_GREY_DOUBLE);
      if( fabs(max.v.dbv - min.v.dbv) < DBL_EPSILON ){
	return WLZ_ERR_FLOAT_DATA;
      }
      errNum = WlzInitGreyScan(obj, &iwsp, &gwsp);
      if(errNum == WLZ_ERR_NONE) {
	factor = (Max.v.dbv - Min.v.dbv) / (max.v.dbv - min.v.dbv);
	if(dither)
	{
	  if(fabs(factor) < 1.0 + DBL_EPSILON)
	  {
	    dither = 0;
	  }
	  else
	  {
	    sigma = fabs(2.0 / factor);
	    AlgRandSeed(101);
	    switch(gwsp.pixeltype) {
	      case WLZ_GREY_INT:
		gMin = ALG_MAX(Min.v.dbv, INT_MIN);
		gMax = ALG_MIN(Max.v.dbv, INT_MAX);
		break;
	      case WLZ_GREY_SHORT:
		gMin = ALG_MAX(Min.v.dbv, SHRT_MIN);
		gMax = ALG_MIN(Max.v.dbv, SHRT_MAX);
		break;
	      case WLZ_GREY_UBYTE:
		gMin = ALG_MAX(Min.v.dbv, 0);
		gMax = ALG_MIN(Max.v.dbv, 255);
		break;
	      case WLZ_GREY_FLOAT:
		gMin = ALG_MAX(Min.v.dbv, FLT_MIN);
		gMax = ALG_MIN(Max.v.dbv, FLT_MAX);
		break;
	      case WLZ_GREY_DOUBLE:
		gMin = Min.v.dbv;
		gMax = Max.v.dbv;
		break;
	      default:
		break;
	    }
	  }
	}
	while((errNum == WLZ_ERR_NONE) &&
	      ((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE)){
	  gptr = gwsp.u_grintptr;
	  switch (gwsp.pixeltype) {
	    case WLZ_GREY_INT:
	      for (i=0; i<iwsp.colrmn; i++, gptr.inp++){
		if(dither){
		  val = factor * (*gptr.inp +
				  AlgRandZigNormal(0.0, sigma) -
				  min.v.dbv) + Min.v.dbv;
		  val = WLZ_CLAMP(val, gMin, gMax);
		} else {
		  val = factor * (*gptr.inp - min.v.dbv) + Min.v.dbv;
		}
		*gptr.inp = WLZ_NINT(val);
	      }
	      break;
	    case WLZ_GREY_SHORT:
	      for (i=0; i<iwsp.colrmn; i++, gptr.shp++){
		if(dither){
		  val = factor * (*gptr.shp +
				  AlgRandZigNormal(0.0, sigma) -
				  min.v.dbv) + Min.v.dbv;
		  val = WLZ_CLAMP(val, gMin, gMax);
		} else {
		  val = factor * (*gptr.shp - min.v.dbv) + Min.v.dbv;
		}
		*gptr.shp = (short )WLZ_NINT(val);
	      }
	      break;
	    case WLZ_GREY_UBYTE:
	      for (i=0; i<iwsp.colrmn; i++, gptr.ubp++){
		if(dither){
		  val = factor * (*gptr.ubp +
				  AlgRandZigNormal(0.0, sigma) -
				  min.v.dbv) + Min.v.dbv;
		  val = WLZ_CLAMP(val, gMin, gMax);
		} else {
		  val = factor * (*gptr.ubp - min.v.dbv) + Min.v.dbv;
		}
		*gptr.ubp = (WlzUByte )WLZ_NINT(val);
	      }
	      break;
	    case WLZ_GREY_FLOAT:
	      for (i=0; i<iwsp.colrmn; i++, gptr.flp++){
		if(dither){
		  val = factor * (*gptr.flp +
				  AlgRandZigNormal(0.0, sigma) -
				  min.v.dbv) + Min.v.dbv;
		  val = WLZ_CLAMP(val, gMin, gMax);
		} else {
		  val = factor * (*gptr.flp - min.v.dbv) + Min.v.dbv;
		}
		*gptr.flp = (float )val;
	      }
	      break;
	    case WLZ_GREY_DOUBLE:
	      for (i=0; i<iwsp.colrmn; i++, gptr.dbp++){
		if(dither){
		  val = factor * (*gptr.dbp +
				  AlgRandZigNormal(0.0, sigma) -
				  min.v.dbv) + Min.v.dbv;
		  val = WLZ_CLAMP(val, gMin, gMax);
		} else {
		  val = factor * (*gptr.dbp - min.v.dbv) + Min.v.dbv;
		}
		*gptr.dbp = val;
	      }
	      break;
	    default:
	      errNum = WLZ_ERR_GREY_TYPE;
	      break;
	  }
	}
	(void )WlzEndGreyScan(&iwsp, &gwsp);
	if(errNum == WLZ_ERR_EOO){
	  errNum = WLZ_ERR_NONE;
	}
      }
    }
  }
  return errNum;
}
Example #4
0
void install_paint_reference_object(
  WlzObject	*obj)
{
  Widget		toggle;
  WlzPixelV		bckgrnd;
  WlzPixelV		min, max, Min, Max;
  WlzErrorNum		errNum=WLZ_ERR_NONE;

  if( globals.orig_obj != NULL ){
    WlzFreeObj( globals.orig_obj );
  }
  globals.orig_obj = WlzAssignObject(obj, &errNum);
  obj = NULL;

  /* check input object for grey-value type
     convert if necessary */
  if( errNum == WLZ_ERR_NONE ){
    bckgrnd = WlzGetBackground(globals.orig_obj, &errNum);
    Min.type = WLZ_GREY_INT;
    Max.type = WLZ_GREY_INT;
    Min.v.inv = 0;
    Max.v.inv = 255;
  }
  
  if( errNum == WLZ_ERR_NONE ){
    switch( bckgrnd.type ){
    case WLZ_GREY_LONG:
      WlzGreyRange(globals.orig_obj, &min, &max);
      if( (min.v.lnv < 0) || (max.v.lnv > 255) ){
	if((obj = WlzConvertPix(globals.orig_obj, WLZ_GREY_INT, &errNum))){
	  WlzGreySetRange(obj, min, max, Min, Max, 0);
	  bckgrnd = WlzGetBackground(obj, &errNum);
	}
      }
      break;
    case WLZ_GREY_INT:
      WlzGreyRange(globals.orig_obj, &min, &max);
      if( (min.v.inv < 0) || (max.v.inv > 255) ){
	obj = WlzConvertPix(globals.orig_obj, WLZ_GREY_INT, &errNum);
	WlzGreySetRange(obj, min, max, Min, Max, 0);
	bckgrnd = WlzGetBackground(obj, &errNum);
      }
      break;
    case WLZ_GREY_SHORT:
      WlzGreyRange(globals.orig_obj, &min, &max);
      if( (min.v.shv < 0) || (max.v.shv > 255) ){
	if((obj = WlzConvertPix(globals.orig_obj, WLZ_GREY_SHORT, &errNum))){
	  WlzGreySetRange(obj, min, max, Min, Max, 0);
	  bckgrnd = WlzGetBackground(obj, &errNum);
	}
      }
      break;
    case WLZ_GREY_FLOAT:
      WlzGreyRange(globals.orig_obj, &min, &max);
      if( (min.v.flv < 0) || (max.v.flv > 255) ){
	if((obj = WlzConvertPix(globals.orig_obj, WLZ_GREY_INT, &errNum))){
	  WlzGreySetRange(obj, min, max, Min, Max, 0);
	  bckgrnd = WlzGetBackground(obj, &errNum);
	}
      }
      break;
    case WLZ_GREY_DOUBLE:
      WlzGreyRange(globals.orig_obj, &min, &max);
      if( (min.v.dbv < 0) || (max.v.dbv > 255) ){
	if((obj = WlzConvertPix(globals.orig_obj, WLZ_GREY_INT, &errNum))){
	  WlzGreySetRange(obj, min, max, Min, Max, 0);
	  bckgrnd = WlzGetBackground(obj, &errNum);
	}
      }
      break;

    default:
    case WLZ_GREY_UBYTE:
      break;
    }
  }

  /* copy for later transform for display purposes,
     the original is kept for IP purposes note pixconvert loses
     the background value */
  if( errNum == WLZ_ERR_NONE ){
    if( globals.obj != NULL ){
      WlzFreeObj( globals.obj );
    }
    if( obj ){
      globals.obj =
	WlzAssignObject(WlzConvertPix(obj, WLZ_GREY_UBYTE, &errNum), NULL);
      WlzFreeObj(globals.orig_obj);
      globals.orig_obj = WlzAssignObject(obj, NULL);
    }
    else {
      globals.obj =
	WlzAssignObject(WlzConvertPix(globals.orig_obj,
				      WLZ_GREY_UBYTE, &errNum), NULL);
    }
  }

  if( errNum == WLZ_ERR_NONE ){
    min.type = WLZ_GREY_UBYTE;
    max.type = WLZ_GREY_UBYTE;
    Min.type = WLZ_GREY_UBYTE;
    Max.type = WLZ_GREY_UBYTE;
    min.v.ubv = 0;
    max.v.ubv = 255;
    Min.v.ubv = globals.cmapstruct->gmin;
    Max.v.ubv = globals.cmapstruct->gmax;
    errNum = WlzGreySetRange(globals.obj, min, max, Min, Max, 0);
  }

  /* also convert the background values */
  if( errNum == WLZ_ERR_NONE ){
/*  min = WlzGetBackground(globals.orig_obj, NULL);*/
    WlzValueConvertPixel(&bckgrnd, bckgrnd, WLZ_GREY_INT);
    max.type = WLZ_GREY_INT;
    max.v.inv = ((bckgrnd.v.inv * (Max.v.ubv - Min.v.ubv)) / 255) + Min.v.ubv;
    WlzSetBackground(globals.obj, max);

    /* fill blank planes here - should be a resource option */
    if( (toggle = XtNameToWidget(read_obj_dialog, "*.fill_blanks")) ){
      Boolean	fill_blanks, min_domain;
      XtVaGetValues(toggle, XmNset, &fill_blanks, NULL);
      if( fill_blanks ){
	if( (toggle = XtNameToWidget(read_obj_dialog, "*.min_domain")) ){
	  XtVaGetValues(toggle, XmNset, &min_domain, NULL);
	  if( min_domain ){
	    WlzFillBlankPlanes(globals.obj, 1);
	  } else {
	    WlzFillBlankPlanes(globals.obj, 0);
	  }
	}
	else {
	  WlzFillBlankPlanes(globals.obj, 1);
	}
      }
    }

    /* setup the display list and properties dialog */
    setup_ref_display_list_cb(read_obj_dialog, NULL, NULL);
    setup_obj_props_cb(read_obj_dialog, NULL, NULL);
  }

  /* log the object size */
  if( (errNum == WLZ_ERR_NONE) && globals.logfileFp ){
    char strBuf[64];
    sprintf(strBuf, "(%d, %d, %d, %d, %d, %d)",
	    globals.obj->domain.p->kol1, globals.obj->domain.p->line1,
	    globals.obj->domain.p->plane1, globals.obj->domain.p->lastkl,
	    globals.obj->domain.p->lastln, globals.obj->domain.p->lastpl);
    MAPaintLogData("BoundingBox", strBuf, 0, NULL);
    sprintf(strBuf, "%d", (int) WlzVolume(globals.obj, NULL));
    MAPaintLogData("Volume", strBuf, 0, NULL);
  }

  if( errNum != WLZ_ERR_NONE ){
    MAPaintReportWlzError(globals.topl,
			  "install_paint_reference_object", errNum);
  }
  return;
}
Example #5
0
int             main(int argc, char **argv)
{
  int		idx,
		option,
		dither = 0,
		overwrite = 1,
		ok = 1,
		usage = 0;
  WlzImArNorm	norm = WLZ_IMARNORM_NONE;
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  FILE		*fP = NULL;
  WlzObject	*outObj = NULL;
  WlzObject	*inObj[2];
  WlzBinaryOperatorType operator = WLZ_BO_ADD;
  char 		*outObjFileStr;
  char  	*inObjFileStr[2];
  WlzPixelV	gMin[3],
  		gMax[3];
  const char	*errMsg;
  static char	optList[] = "O:o:ab:dgilmsnNh",
		outObjFileStrDef[] = "-",
  		inObjFileStrDef[] = "-";

  opterr = 0;
  inObj[0] = NULL;
  inObj[1] = NULL;
  outObjFileStr = outObjFileStrDef;
  inObjFileStr[0] = inObjFileStrDef;
  inObjFileStr[1] = inObjFileStrDef;
  while(ok && ((option = getopt(argc, argv, optList)) != -1))
  {
    switch(option)
    {
      case 'O':
	if((sscanf(optarg, "%d", &overwrite) != 1) ||
	   (overwrite < 0) || (overwrite > 2))
	{
	  usage = 1;
	  ok = 0;
	}
	break;
      case 'o':
	outObjFileStr = optarg;
	break;
      case 'a':
	operator = WLZ_BO_ADD;
	break;
      case 'b':
	operator = atoi(optarg);
	switch( operator ){
	  case WLZ_BO_ADD:
	  case WLZ_BO_SUBTRACT:
	  case WLZ_BO_MULTIPLY:
	  case WLZ_BO_DIVIDE:
	  case WLZ_BO_MODULUS:
	  case WLZ_BO_EQ:
	  case WLZ_BO_NE:
	  case WLZ_BO_GT:
	  case WLZ_BO_GE:
	  case WLZ_BO_LT:
	  case WLZ_BO_LE:
	  case WLZ_BO_AND:
	  case WLZ_BO_OR:
	  case WLZ_BO_XOR:
	  case WLZ_BO_MAX:
	  case WLZ_BO_MIN:
	  case WLZ_BO_MAGNITUDE:
	    break;
	  default:
	    usage = 1;
	    ok = 0;
	    break;
	}
	break;
      case 'd':
	operator = WLZ_BO_DIVIDE;
	break;
      case 'g':
	operator = WLZ_BO_MAGNITUDE;
	break;
      case 'l':
	operator = WLZ_BO_MODULUS;
	break;
      case 'm':
	operator = WLZ_BO_MULTIPLY;
	break;
      case 's':
	operator = WLZ_BO_SUBTRACT;
	break;
      case 'n':
	norm = WLZ_IMARNORM_INPUT;
	break;
      case 'N':
	norm = WLZ_IMARNORM_256;
	break;
      case 'i':
	dither = 1;
	break;
      case 'h':
      default:
	usage = 1;
	ok = 0;
	break;
    }
  }
  if((inObjFileStr[0] == NULL) || (*inObjFileStr[0] == '\0') ||
     (inObjFileStr[1] == NULL) || (*inObjFileStr[1] == '\0') ||
     (outObjFileStr == NULL) || (*outObjFileStr == '\0'))
  {
    ok = 0;
    usage = 1;
  }
  if(ok && (optind < argc))
  {
    idx = 0;
    while((idx < 2) && (optind < argc))
    {
      inObjFileStr[idx] = *(argv + optind);
      ++optind;
      ++idx;
    }
  }
  if(ok && (optind != argc))
  {
    usage = 1;
    ok = 0;
  }
  if(ok)
  {
    idx = 0;
    while((errNum == WLZ_ERR_NONE) && (idx < 2))
    {
      errNum = WLZ_ERR_READ_EOF;
      if((inObjFileStr[idx] == NULL) ||
	  (*inObjFileStr[idx] == '\0') ||
	  ((fP = (strcmp(inObjFileStr[idx], "-")?
		  fopen(inObjFileStr[idx], "r"): stdin)) == NULL) ||
	  ((inObj[idx]= WlzAssignObject(WlzReadObj(fP,
	  					   &errNum), NULL)) == NULL))
      {
	ok = 0;
	(void )WlzStringFromErrorNum(errNum, &errMsg);
	(void )fprintf(stderr,
		       "%s: failed to read object %d from file %s (%s)\n",
		       *argv, idx, inObjFileStr[idx], errMsg);
      }
      if(fP && strcmp(inObjFileStr[idx], "-"))
      {
	fclose(fP);
      }
      ++idx;
    }
  }
  if(ok)
  {
    idx = 0;
    while((errNum == WLZ_ERR_NONE) && (idx < 2))
    {
      if((inObj[idx]->type != WLZ_2D_DOMAINOBJ) &&
         (inObj[idx]->type != WLZ_3D_DOMAINOBJ))
      {
        ok = 0;
	(void )fprintf(stderr, "%s: input object %d is not a domain object\n",
		       *argv, idx);
      }
      ++idx;
    }
  }
  if(ok && (norm == WLZ_IMARNORM_INPUT))
  {
    if(((errNum = WlzGreyRange(inObj[0], gMin, gMax)) != WLZ_ERR_NONE) ||
       ((errNum = WlzGreyRange(inObj[1], gMin + 1, gMax + 1)) != WLZ_ERR_NONE))
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr,
		     "%s: failed to find input objects grey range (%s)\n",
		     *argv, errMsg);
    }
  }
  if(ok)
  {
    if( WlzGreyTypeFromObj(inObj[0], &errNum) == WLZ_GREY_RGBA ){
      if((outObj = WlzRGBAImageArithmetic(inObj[0], inObj[1], operator, 1,
				      &errNum)) == NULL)
      {
	ok = 0;
	(void )WlzStringFromErrorNum(errNum, &errMsg);
	(void )fprintf(stderr,
		       "%s: failed to compute new object (%s).\n",
		       *argv, errMsg);
      }
    }
    else if((outObj = WlzImageArithmetic(inObj[0], inObj[1], operator, 0,
				    &errNum)) == NULL)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr,
      		     "%s: failed to compute new object (%s).\n",
		     *argv, errMsg);
    }
  }
  if(ok &&
     (norm != WLZ_IMARNORM_NONE) &&
     (WlzGreyTypeFromObj(inObj[0], &errNum) != WLZ_GREY_RGBA) )
  {
    if((errNum = WlzGreyRange(outObj, gMin+ 2, gMax + 2)) != WLZ_ERR_NONE)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr,
      		     "%s: failed to find output object's grey range (%s)\n",
		     *argv, errMsg);
    }
    if(ok)
    {
      if(norm == WLZ_IMARNORM_256)
      {
        gMin[0].type = WLZ_GREY_UBYTE;
	gMin[0].v.ubv = 0;
        gMax[0].type = WLZ_GREY_UBYTE;
	gMax[0].v.ubv = 255;
	(void )WlzValueConvertPixel(gMin, gMin[0], gMin[2].type);
	(void )WlzValueConvertPixel(gMax, gMax[0], gMax[2].type);
      }
      else
      {
	(void )WlzValueConvertPixel(gMin, gMin[0], gMin[2].type);
	(void )WlzValueConvertPixel(gMax, gMax[0], gMax[2].type);
	(void )WlzValueConvertPixel(gMin + 1, gMin[1], gMin[2].type);
	(void )WlzValueConvertPixel(gMax + 1, gMax[1], gMax[2].type);
	switch(gMin[2].type)
	{
	  case WLZ_GREY_INT:
	    if(gMin[1].v.inv < gMin[0].v.inv)
	    {
	      gMin[0].v.inv = gMin[1].v.inv;
	    }
	    if(gMax[1].v.inv > gMax[0].v.inv)
	    {
	      gMax[0].v.inv = gMax[1].v.inv;
	    }
	    break;
	  case WLZ_GREY_SHORT:
	    if(gMin[1].v.shv < gMin[0].v.shv)
	    {
	      gMin[0].v.shv = gMin[1].v.shv;
	    }
	    if(gMax[1].v.shv > gMax[0].v.shv)
	    {
	      gMax[0].v.shv = gMax[1].v.shv;
	    }
	    break;
	  case WLZ_GREY_UBYTE:
	    if(gMin[1].v.ubv < gMin[0].v.ubv)
	    {
	      gMin[0].v.ubv = gMin[1].v.ubv;
	    }
	    if(gMax[1].v.ubv > gMax[0].v.ubv)
	    {
	      gMax[0].v.ubv = gMax[1].v.ubv;
	    }
	    break;
	  case WLZ_GREY_FLOAT:
	    if(gMin[1].v.flv < gMin[0].v.flv)
	    {
	      gMin[0].v.flv = gMin[1].v.flv;
	    }
	    if(gMax[1].v.flv > gMax[0].v.flv)
	    {
	      gMax[0].v.flv = gMax[1].v.flv;
	    }
	    break;
	  case WLZ_GREY_DOUBLE:
	    if(gMin[1].v.dbv < gMin[0].v.dbv)
	    {
	      gMin[0].v.dbv = gMin[1].v.dbv;
	    }
	    if(gMax[1].v.dbv > gMax[0].v.dbv)
	    {
	      gMax[0].v.dbv = gMax[1].v.dbv;
	    }
	    break;
	  default:
	    errNum = WLZ_ERR_GREY_TYPE;
	    break;
	}
      }
    }
    if((errNum = WlzGreySetRange(outObj, gMin[2], gMax[2],
    				 gMin[0], gMax[0], dither)) != WLZ_ERR_NONE)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr,
		     "%s: failed to set output object's grey range (%s)\n",
		     *argv, errMsg);
    }
  }
  if(ok)
  {
    errNum = WLZ_ERR_WRITE_EOF;
    if(((fP = (strcmp(outObjFileStr, "-")?  fopen(outObjFileStr, "w"):
	      				    stdout)) == NULL) ||
       ((errNum = WlzWriteObj(fP, outObj)) != WLZ_ERR_NONE))
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr,
		     "%s: failed to write output object (%s).\n",
		     *argv, errMsg);
    }
    if(fP && strcmp(outObjFileStr, "-"))
    {
      fclose(fP);
    }
  }
  WlzFreeObj(inObj[0]);
  WlzFreeObj(inObj[1]);
  WlzFreeObj(outObj);
  if(usage)
  {

    fprintf(stderr,
	    "Usage: %s"
	    " [-O#] [-o<out file>] [-a] [-b <op>] [-d] [-g] [-i] [-l] [-m] [-s] [-h] "
	    "[<in object 0>] [<in object 1>]\n"
	    "Options:\n"
	    "  -O        Overwrite option (only useful for debugging)\n"
	    "  -o        Output file name.\n"
	    "  -a        Add the object's grey values.\n"
	    "  -b <op>   Apply binary operation to the grey-values.\n"
	    "            op =  %d - Add\n"   
	    "               =  %d - SUBTRACT\n"
	    "               =  %d - MULTIPLY\n"
	    "               =  %d - DIVIDE\n"
	    "               =  %d - MODULUS\n"
	    "               =  %d - EQ\n"
	    "               =  %d - NE\n"
	    "               =  %d - GT\n"
	    "               =  %d - GE\n"
	    "               =  %d - LT\n"
	    "               =  %d - LE\n"
	    "               =  %d - AND\n"
	    "               =  %d - OR\n"
	    "               =  %d - XOR\n"
	    "               =  %d - MAX\n"
	    "               =  %d - MIN\n"
	    "               =  %d - MAGNITUDE\n"
	    "  -d        Divide the grey values of the 1st object by those of the 2nd.\n"
	    "  -g        Vector magnitude of horizontal and vertical component objects\n"
	    "  -i        Dither values if setting range\n"
	    "  -l        Compute the modulus of the grey values of the 1st object wrt\n"
	    "            those of the 2nd.\n"
	    "  -m        Multiply the object's grey values.\n"
	    "  -s        Subtract the grey values of the 2nd object from those of the 1st.\n"
	    "  -n        Normalises the output object to the range of the input objects.\n"
	    "  -N        Normalises the output objects to the range [0-255].\n"
	    "  -h        Help, prints this usage message.\n"
	    "Computes an arithmetic binary (two objects) operation on two domain\n"
	    "objects. The default operator is add.\n"
	    "The input objects are read from stdin and values are written to stdout\n"
	    "unless the filenames are given.\n"
	    "Example:\n%s%s%s",
	    *argv,
	    WLZ_BO_ADD,
	    WLZ_BO_SUBTRACT,
	    WLZ_BO_MULTIPLY,
	    WLZ_BO_DIVIDE,
	    WLZ_BO_MODULUS,
	    WLZ_BO_EQ,
	    WLZ_BO_NE,
	    WLZ_BO_GT,
	    WLZ_BO_GE,
	    WLZ_BO_LT,
	    WLZ_BO_LE,
	    WLZ_BO_AND,
	    WLZ_BO_OR,
	    WLZ_BO_XOR,
	    WLZ_BO_MAX,
	    WLZ_BO_MIN,
	    WLZ_BO_MAGNITUDE,
	    "cat obj1.wlz | ",
	    *argv,
	    " -o obj3.wlz -a obj2.wlz\n"
	    "A new object 'obj3.wlz is formed by adding the grey values of obj1 and\n"
	    "obj2.wlz.\n");
  }
  return(!ok);
}
Example #6
0
int main(int	argc,
	 char	**argv)
{

  WlzObject	*obj;
  FILE		*inFile;
  char 		optList[] = "l:L:u:U:dhv";
  int		dither = 0,
  		option;
  WlzPixelV	max, min, Max, Min;
  WlzPixelV	gmin, gmax;
  int		getminFlg=1, getmaxFlg=1, verboseFlg=0;
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  const char	*errMsg;
  int		objCount=0;
    
  /* read the argument list and check for an input file */
  opterr = 0;
  Max.type = Min.type = max.type = min.type = WLZ_GREY_DOUBLE;
  Max.v.dbv = 255.0;
  Min.v.dbv = 0.0;
  
  while( (option = getopt(argc, argv, optList)) != EOF ){
    switch( option ){
      case 'd':
	dither = 1;
	break;
      case 'l':
	min.v.dbv = atof(optarg);
	getminFlg = 0;
	break;
      case 'L':
	Min.v.dbv = atof(optarg);
	break;
      case 'u':
	max.v.dbv = atof(optarg);
	getmaxFlg = 0;
	break;
      case 'U':
	Max.v.dbv = atof(optarg);
	break;
      case 'v':
	verboseFlg = 1;
	break;
      case 'h':
      default:
	usage(argv[0]);
	return 1;
    }
  }

  inFile = stdin;
  if( optind < argc ){
    if( (inFile = fopen(*(argv+optind), "r")) == NULL ){
      fprintf(stderr, "%s: can't open file %s\n", argv[0], *(argv+optind));
      usage(argv[0]);
      return 1;
    }
  }

  /* read objects and threshold if possible */
  while(((obj = WlzAssignObject(WlzReadObj(inFile, NULL), NULL)) != NULL) &&
        (errNum == WLZ_ERR_NONE))
  {
    objCount++;
    switch( obj->type )
    {
    case WLZ_2D_DOMAINOBJ:
    case WLZ_3D_DOMAINOBJ:
      /* get the existing min and max grey values */
      if( (errNum = WlzGreyRange(obj, &gmin, &gmax)) == WLZ_ERR_NONE ){
	if( getminFlg ){
	  WlzValueConvertPixel(&min, gmin, WLZ_GREY_DOUBLE);
	}
	if( getmaxFlg ){
	  WlzValueConvertPixel(&max, gmax, WLZ_GREY_DOUBLE);
	}

	if( verboseFlg ){
	  fprintf(stderr,
		  "%s:\nconverting object %d with parameters:\n"
		  "\tSource (l, u) = (%f, %f)\n"
		  "\tDestination (L, U) = (%f, %f)\n",
		  argv[0], objCount, min.v.dbv, max.v.dbv,
		  Min.v.dbv, Max.v.dbv);
	}

	errNum = WlzGreySetRange(obj, min, max, Min, Max, dither);
	if( errNum == WLZ_ERR_NONE ){
	  errNum = WlzWriteObj(stdout, obj);
	}
      }
      if( errNum != WLZ_ERR_NONE ){
	(void )WlzStringFromErrorNum(errNum, &errMsg);
	(void )fprintf(stderr,
		       "%s: failed to write object (%s).\n",
		       argv[0], errMsg);
	return(errNum);
      }
      break;

    default:
      if((errNum = WlzWriteObj(stdout, obj)) != WLZ_ERR_NONE) {
	(void )WlzStringFromErrorNum(errNum, &errMsg);
	(void )fprintf(stderr,
		       "%s: failed to write object (%s).\n",
		       argv[0], errMsg);
	return(1);
      }
      break;
    }
    WlzFreeObj(obj);
  }

  return 0;
}
int             main(int argc, char *argv[])
{
  int		option,
		nReg = 0,
		tNReg = 0,
  		ok = 1,
		usage = 0,
		verbose = 0,
		threshSet = 0,
		centreSet = 0;
  double	minArea = 2;
  char		*inExt,
		*dbgExt,
		*inDir,
		*dbgDir,
		*inFile,
		*dbgFile,
  		*inPath = NULL,
		*dbgPath = NULL,
		*outFile = NULL;
  WlzRadDistVal distSort = WLZ_RADDISTVAL_AREA;
  WlzRadDistRec	*distData = NULL;
  WlzPixelV	thrVal;
  WlzDVertex2	centre;
  WlzCompThreshType thrMtd = WLZ_COMPTHRESH_OTSU;
  WlzThresholdType thrMod = WLZ_THRESH_HIGH;
  WlzEffFormat	inFmt = WLZEFF_FORMAT_NONE,
  		dbgFmt = WLZEFF_FORMAT_NONE;
  WlzObject	*inObj = NULL,
		*disObj = NULL,
  		*segObj = NULL;
  WlzGreyValueWSpace *disGVWSp = NULL;
  WlzObject	**regObjs = NULL;
  FILE		*fP = NULL;
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  const int	maxObj = 1000000;
  char		pathBuf[FILENAME_MAX];
  const double	eps = 1.0e-06;
  const char	*errMsg;
  static char	optList[] = "hvAGDHELR:c:d:n:o:t:",
		defFile[] = "-";

  thrVal.type = WLZ_GREY_DOUBLE;
  thrVal.v.dbv = 0.0;
  outFile = defFile;
  while((usage == 0) && ok &&
        ((option = getopt(argc, argv, optList)) != -1))
  {
    switch(option)
    {
      case 'A':
        distSort = WLZ_RADDISTVAL_AREA;
	break;
      case 'D':
        distSort = WLZ_RADDISTVAL_DIST;
	break;
      case 'G':
        distSort = WLZ_RADDISTVAL_ANGLE;
	break;
      case 'H':
        thrMod = WLZ_THRESH_HIGH;
	break;
      case 'E':
        thrMod = WLZ_THRESH_EQUAL;
	break;
      case 'L':
        thrMod = WLZ_THRESH_LOW;
	break;
      case 'R':
        distSort = WLZ_RADDISTVAL_RADIUS;
	break;
      case 'h':
        usage = 1;
	break;
      case 'v':
        verbose = 1;
	break;
      case 'c':
	centreSet = 1;
        if(sscanf(optarg, "%lg,%lg", &(centre.vtX), &(centre.vtY)) != 2)
	{
	  usage = 1;
	}
        break;
      case 'd':
        dbgPath = optarg;
	break;
      case 'o':
        outFile = optarg;
	break;
      case 'n':
        if(sscanf(optarg, "%lg", &minArea) != 1)
	{
	  usage = 1;
	}
	break;
      case 't':
	threshSet = 1;
        if(sscanf(optarg, "%lg", &(thrVal.v.dbv)) != 1)
	{
	  usage = 1;
	}
	break;
      default:
        usage = 1;
	break;
    }
  }
  ok = !usage;
  if(ok)
  {
    if((optind + 1) != argc)
    {
      usage = 1;
      ok = 0;
    }
    else
    {
      inPath = *(argv + optind);
    }
  }
  if(ok && verbose)
  {
    (void )fprintf(stderr, "inPath = %s\n", inPath);
  }
  /* Parse input file path into path + name + ext. */
  if(ok)
  {
    ok = (usage = WlzRadDistParsePath(inPath, &inDir, &inFile, &inExt,
                                      &inFmt)) == 0;
  }
  if(ok && verbose)
  {
    (void )fprintf(stderr, "inDir = %s\n", inDir);
    (void )fprintf(stderr, "inFile = %s\n", inFile);
    (void )fprintf(stderr, "inExt = %s\n", (inExt)? inExt: "(null)");
    (void )fprintf(stderr, "inFmt = %s\n",
    		   WlzEffStringFromFormat(inFmt, NULL));
  }
  /* Read image. */
  if(ok)
  {
    errNum = WLZ_ERR_READ_EOF;
    if(inExt)
    {
      (void )sprintf(pathBuf, "%s/%s.%s", inDir, inFile, inExt);
    }
    else
    {
      (void )sprintf(pathBuf, "%s/%s", inDir, inFile);
    }
    if(((inObj = WlzAssignObject(WlzEffReadObj(NULL, pathBuf, inFmt,
    					       0, 0, 0,
					       &errNum), NULL)) == NULL) ||
       (inObj->type != WLZ_2D_DOMAINOBJ))
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr,
      		     "%s: Failed to read 2D image object from file %s (%s)\n",
		     *argv, pathBuf, errMsg);
    }
  }
  if(ok && verbose)
  {
    (void )fprintf(stderr, "read input image ok.\n");
  }
  /* Convert to grey if needed, normalise 0 - 255 if needed and compute
   * threshold value unless already known. */
  if(ok)
  {
    if(WlzGreyTypeFromObj(inObj, NULL) == WLZ_GREY_RGBA)
    {
      WlzObject *ppObj;

      ppObj = WlzAssignObject(
	      WlzRGBAToModulus(inObj, &errNum), NULL);
      if(errNum == WLZ_ERR_NONE)
      {
	(void )WlzFreeObj(inObj);
	inObj = ppObj;
      }
    }
    if(threshSet == 0)
    {
      WlzObject *hObj = NULL;

      errNum = WlzGreyNormalise(inObj, 1);
      if(errNum == WLZ_ERR_NONE)
      {
        hObj = WlzHistogramObj(inObj, 256, 0.0, 1.0, &errNum);
      }
      if(errNum == WLZ_ERR_NONE)
      {
	threshSet = 1;
        errNum = WlzCompThreshold(&thrVal.v.dbv, hObj, thrMtd, 0);
      }
      (void )WlzFreeObj(hObj);
    }
    if(errNum != WLZ_ERR_NONE)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr, "%s: failed to normalise object (%s)\n",
		     *argv, errMsg);
    }
  }
  /* Segment the object. */
  if(ok)
  {
    if(inObj->values.core == NULL)
    {
      segObj = WlzAssignObject(inObj, NULL);
    }
    else
    {
      segObj = WlzAssignObject(
               WlzThreshold(inObj, thrVal, thrMod, &errNum), NULL);
      if(errNum != WLZ_ERR_NONE)
      {
	ok = 0;
	(void )WlzStringFromErrorNum(errNum, &errMsg);
	(void )fprintf(stderr, "%s: failed to segment image (%s)\n",
		       *argv, errMsg);
      }
    }
  }
  /* Compute object with the same domain as the input object but in which
   * the values are the minimum distance from an edge. */
  if(ok)
  {
    WlzObject	*bObj = NULL;

    bObj = WlzBoundaryDomain(inObj, &errNum);
    if(errNum == WLZ_ERR_NONE)
    {
      disObj = WlzAssignObject(       
               WlzDistanceTransform(inObj, bObj, WLZ_OCTAGONAL_DISTANCE,
	       			    0.0, 0.0, &errNum), NULL);
    }
    if(errNum == WLZ_ERR_NONE)
    {
      disGVWSp = WlzGreyValueMakeWSp(disObj, &errNum);
    }
    if(errNum != WLZ_ERR_NONE)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr, "%s: failed to compute distance object (%s)\n",
		     *argv, errMsg);
    }
    (void )WlzFreeObj(bObj);
  }
  /* Output the debug image if required. */
  if(ok && dbgPath)
  {
    WlzObject	*dbgObj;

    dbgObj = WlzAssignObject(WlzCopyObject(inObj, &errNum), NULL);
    if(errNum == WLZ_ERR_NONE)
    {
      WlzPixelV	iMin,
		iMax,
		oMin,
		oMax;

      if(dbgObj->values.core == NULL)
      {
        WlzValues tmpVal;

	oMax.type = WLZ_GREY_UBYTE;
	oMax.v.ubv = 255;
	tmpVal.v = WlzNewValueTb(dbgObj,
				 WlzGreyTableType(WLZ_GREY_TAB_RAGR,
				                  WLZ_GREY_UBYTE, NULL),
	                         oMax, &errNum);
        if(errNum == WLZ_ERR_NONE)
	{
	  dbgObj->values = WlzAssignValues(tmpVal, NULL);
	}
      }
      else
      {
        WlzObject *tmpObj = NULL;

	oMin.type = WLZ_GREY_UBYTE;
	oMin.v.ubv = 0;
	oMax.type = WLZ_GREY_UBYTE;
	oMax.v.ubv = 200;
	errNum = WlzGreyRange(dbgObj, &iMin, &iMax);
	if(errNum == WLZ_ERR_NONE)
	{
	  errNum = WlzGreySetRange(dbgObj, iMin, iMax, oMin, oMax, 0);
	}
	if(errNum == WLZ_ERR_NONE)
	{
	  tmpObj = WlzMakeMain(inObj->type, segObj->domain, dbgObj->values,
	                       NULL, NULL, &errNum);
	}
	if(errNum == WLZ_ERR_NONE)
	{
	  oMax.v.ubv = 255;
	  errNum = WlzGreySetValue(tmpObj, oMax);
	}
	(void )WlzFreeObj(tmpObj);
	if(errNum == WLZ_ERR_NONE)
	{
	  tmpObj = WlzConvertPix(dbgObj, WLZ_GREY_UBYTE, &errNum);
	  (void )WlzFreeObj(dbgObj);
	  dbgObj = WlzAssignObject(tmpObj, NULL);
	}
      }
    }
    if(errNum == WLZ_ERR_NONE)
    {
      (void )WlzRadDistParsePath(dbgPath, &dbgDir, &dbgFile, &dbgExt,
      			         &dbgFmt);
      if(dbgExt)
      {
	(void )sprintf(pathBuf, "%s/%s.%s", dbgDir, dbgFile, dbgExt);
      }
      else
      {
	(void )sprintf(pathBuf, "%s/%s", dbgDir, dbgFile);
      }
      errNum = WlzEffWriteObj(NULL, pathBuf, dbgObj, dbgFmt);
    }
    (void )WlzFreeObj(dbgObj);
    if(errNum != WLZ_ERR_NONE)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr, "%s: failed to output the debug image (%s)\n",
		     *argv, errMsg);
    }
  }
  /* Label the segmented object. */
  if(ok)
  {
    errNum = WlzLabel(segObj, &nReg, &regObjs, maxObj, 0, WLZ_8_CONNECTED);
    if(errNum != WLZ_ERR_NONE)
    {
      ok = 0;
      errNum = WLZ_ERR_MEM_ALLOC;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr, "%s: failed to split into components (%s)\n",
		     *argv, errMsg);
    }
    if(ok && verbose)
    {
      (void )fprintf(stderr, "nReg = %d\n", nReg);
    }
  }
  /* Compute centre of mass if not known. */
  if(ok)
  {
    if(centreSet == 0)                          
    {
      centre = WlzCentreOfMass2D(inObj, 1, NULL, &errNum);
      if(errNum != WLZ_ERR_NONE)
      {
	ok = 0;
	(void )WlzStringFromErrorNum(errNum, &errMsg);
	(void )fprintf(stderr, "%s: failed to compute centre of mass (%s)\n",
		       *argv, errMsg);
      }
    }
    if(ok && verbose)
    {
      (void )fprintf(stderr, "centre = %lg,%lg\n", centre.vtX, centre.vtY);
    }
  }
  /* Allocate a radial distribution table. */
  if(ok)
  {
    if((distData = (WlzRadDistRec *)
                   AlcCalloc(nReg, sizeof(WlzRadDistRec))) == NULL)
    {
      ok = 0;
      errNum = WLZ_ERR_MEM_ALLOC;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr, "%s: failed to allocate result lable (%s)\n",
		     *argv, errMsg);
    }
    
  }
  /* Compute the redial distribution data. */
  if(ok)
  {
    int		idR = 0,
    		idS = 0;

    while((errNum == WLZ_ERR_NONE) && (idR < nReg))
    {
      double	mass;
      WlzDVertex2 com;

      com = WlzCentreOfMass2D(regObjs[idR], 1, &mass, NULL);
      if(mass > minArea - eps)
      {
	WlzGreyValueGet(disGVWSp, 0.0, com.vtY, com.vtX);
	distData[idS].pos = com;
	distData[idS].area = mass;
	WLZ_VTX_2_SUB(com, centre, com);
	distData[idS].radius = WLZ_VTX_2_LENGTH(com);
	distData[idS].angle = ALG_M_PI + atan2(com.vtY, com.vtX);
	switch(disGVWSp->gType)
	{
	  case WLZ_GREY_LONG:
	    distData[idS].dist = *(disGVWSp->gPtr[0].lnp);
	    break;
	  case WLZ_GREY_INT:
	    distData[idS].dist = *(disGVWSp->gPtr[0].inp);
	    break;
	  case WLZ_GREY_SHORT:
	    distData[idS].dist = *(disGVWSp->gPtr[0].shp);
	    break;
	  case WLZ_GREY_UBYTE:
	    distData[idS].dist = *(disGVWSp->gPtr[0].ubp);
	    break;
	  case WLZ_GREY_FLOAT:
	    distData[idS].dist = *(disGVWSp->gPtr[0].flp);
	    break;
	  case WLZ_GREY_DOUBLE:
	    distData[idS].dist = *(disGVWSp->gPtr[0].dbp);
	    break;
	  default:
	    distData[idS].dist = 0.0;
	    break;
	}
	++idS;
      }
      ++idR;
    }
    tNReg = idS;
    switch(distSort)
    {
      case WLZ_RADDISTVAL_AREA:
        (void )qsort(distData, tNReg, sizeof(WlzRadDistRec),
		     WlzRadDistRecSortArea);
	break;
      case WLZ_RADDISTVAL_ANGLE:
        (void )qsort(distData, tNReg, sizeof(WlzRadDistRec), 
		     WlzRadDistRecSortAngle);
	break;
      case WLZ_RADDISTVAL_RADIUS:
        (void )qsort(distData, tNReg, sizeof(WlzRadDistRec),
		     WlzRadDistRecSortRadius);
	break;
      case WLZ_RADDISTVAL_DIST:
        (void )qsort(distData, tNReg, sizeof(WlzRadDistRec),
		     WlzRadDistRecSortDist);
	break;
    }
  }
  /* Output the sorted radial distribution table. */
  if(ok)
  {
    if(((fP = strcmp(outFile, "-")?
              fopen(outFile, "w"): stdout)) == NULL)
    {
      ok = 0;
      (void )fprintf(stderr, "%s: failed to open output file %s\n",
                     *argv, outFile);
    }
  }
  if(ok)
  {
    int		idR;

    for(idR = 0; idR < tNReg; ++idR)
    {
      double a;

      a = (distData[idR].angle > 0.0)?
	  0   + (180 * distData[idR].angle / ALG_M_PI):
          360 + (180 * distData[idR].angle / ALG_M_PI);
      (void )fprintf(fP, "%g %g %g %g,%g %g\n",
		     a,
                     distData[idR].radius,
		     distData[idR].area,
		     distData[idR].pos.vtX,
		     distData[idR].pos.vtY,
		     distData[idR].dist);
    }
  }
  if(strcmp(outFile, "-"))
  {
    (void )fclose(fP);
  }
  /* Tidy up. */
  AlcFree(distData);
  WlzGreyValueFreeWSp(disGVWSp);
  (void )WlzFreeObj(inObj);
  (void )WlzFreeObj(disObj);
  (void )WlzFreeObj(segObj);
  if(regObjs)
  {
    int		idR;

    for(idR = 0; idR < nReg; ++idR)
    {
      (void )WlzFreeObj(regObjs[idR]);
    }
    AlcFree(regObjs);
  }
  if(usage)
  {
    (void )fprintf(stderr,
    "Usage: %s [-h] [-v] [-A] [-D] [-G] [-H] [-E] [-L] [-R]\n"
    "\t\t[-c #,#] [-d <debug image>] [-n #]  [-o <out file>]\n"
    "\t\t[-t #] [<input image>]\n"
    "Segments the given object using a threshold value and outputs the \n"
    "radial distribution of the thresholded components.\n"
    "Version: %s\n"
    "Options:\n"
    "  -h  Help - prints this usage masseage.\n"
    "  -v  Verbose output.\n"
    "  -A  Sort output by area (default).\n"
    "  -D  Sort output by distance from boundary.\n"
    "  -G  Sort output by angle.\n"
    "  -H  Threshold high, use pixels at or above threshold (default).\n"
    "  -E  Threshold equal, use pixels at threshold.\n"
    "  -L  Threshold low, use pixels below threshold.\n"
    "  -R  Sort output by radial distance from centre.\n"
    "  -c  Centre (default is image centre).\n"
    "  -d  Debug image.\n"
    "  -n  Minimum area (default %g).\n"
    "  -t  Threshold value (default is to compute using Otsu's method).\n"
    "By default the input image object is read from the standard input and\n"
    "the radial distribution is written to the standard output.\n"
    "The image formats understood include wlz, jpg and tif.\n"
    "The output format is:\n"
    "  <angle> <dist from centre> <area> <x pos>,<y pos> <dist form boundary>\n"
    "Example:\n"
    "  %s -o out.txt -d debug.jpg in.tif\n"
    "The input image is read from in.tif, a debug image showing the\n"
    "segmented regions is written to debug.jpg and the radial distribution\n"
    "statistics are written to the file out.txt. With the output in\n"
    "out.txt, the following R code would plot the data as a set of circles\n"
    "with radius proportional to the square root of the component area:\n"
    "  data <- read.table(\"out.txt\")\n"
    "  attach(data)\n"
    "  symbols(x=data$V1, y=data$V2, circles=sqrt(data$V3))\n",
    argv[0],
    WlzVersion(),
    minArea,
    argv[0]);
  }
  return(!ok);
}