예제 #1
0
파일: WlzRegCCor.c 프로젝트: dscho/Woolz
/*!
* \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);
}
예제 #2
0
/*!
* \return	Interiority score for the test object.
* \ingroup	WlzFeatures
* \brief	Computes an interiority score for the test object with
* 		respect to the given distance object. See WlzInteriority().
* \param	disObj			Given distance object.
* \param	tstObjs			Array of test objects.
* \param	dstErr			Destination error pointer, may be NULL.
*/
static double			WlzInteriorityPrv(
  				  WlzObject *disObj,
				  WlzObject *tstObj,
				  WlzErrorNum *dstErr)
{
  double	score = 0.0;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  if(tstObj->type != WLZ_EMPTY_OBJ)
  {
    WlzObject	*isn = NULL;

    isn = WlzAssignObject(
    	  WlzIntersect2(disObj, tstObj, &errNum), NULL);
    if((errNum == WLZ_ERR_NONE) &&
       (isn != NULL) && (WlzIsEmpty(isn, NULL) == 0))
    {
      WlzPixelV	bgd;
      WlzObjectType gtt;
      WlzObject *ist = NULL,
      		*isv = NULL;

      bgd.v.inv = 0;
      bgd.type = WLZ_GREY_INT;
      gtt = WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_INT, NULL);
      isv = WlzNewObjectValues(isn, gtt, bgd, 0, bgd, &errNum);
      if(errNum == WLZ_ERR_NONE)
      {
        ist = WlzAssignObject(
	      WlzGreyTransfer(isv, disObj, 0, &errNum), NULL);
      }
      (void )WlzFreeObj(isv);
      if(errNum == WLZ_ERR_NONE)
      {
	(void )WlzGreyStats(ist, NULL, NULL, NULL, NULL, NULL, &score, NULL,
			    &errNum);
      }
      (void )WlzFreeObj(ist);
      
    }
    (void )WlzFreeObj(isn);
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(score);
}
예제 #3
0
/*!
* \return       Object area or -1 on error.
* \ingroup      WlzFeatures
* \brief        Calculates simple quick statistics for the domain
*               object with RGBA values. Each component has its
*               statictics computed and entered into the four
*               double[4] arrays.
* \param        srcObj                  Given object.
* \param	colSpc			Colour space.
* \param        dstGType                Pointer for grey type.
* \param        dstMin                  Array for the 4 minimum value.
* \param        dstMax                  Array for the 4 maximum value.
* \param        dstSum                  Array for the 4 sum of values.
* \param        dstSumSq                Array for the 4 sum of squares of
*                                       values.
* \param	dstMean			Array for the 4 mean values.
* \param	dstStdDev		Array for the 4 standard deviation
* 					values.
* \param        dstErr                  Destination pointer for error, may
*                                       be NULL.
*/
int WlzRGBAGreyStats(
  WlzObject	*srcObj,
  WlzRGBAColorSpace	colSpc,
  WlzGreyType	*dstGType,
  double 	*dstMin,
  double 	*dstMax,
  double 	*dstSum,
  double 	*dstSumSq,
  double 	*dstMean,
  double 	*dstStdDev,
  WlzErrorNum 	*dstErr)
{
  int		area;
  WlzCompoundArray	*cmpnd;
  int		i;
  WlzGreyType	gType;
  WlzErrorNum	errNum=WLZ_ERR_NONE;

  /* all object checks done bt RGBAToCOmpound including
     grey-level type */
  if((cmpnd = WlzRGBAToCompound(srcObj, colSpc, &errNum)) != NULL){
    *dstGType = WLZ_GREY_RGBA;
    for(i=0; (i < 4) && (errNum == WLZ_ERR_NONE) ; i++){
      area = WlzGreyStats(cmpnd->o[i], &gType,
			  dstMin + i, dstMax + i,
			  dstSum + i, dstSumSq + i,
			  dstMean + i, dstStdDev + i,
			  &errNum);
    }
    WlzFreeObj((WlzObject *) cmpnd);
  }

  if( dstErr ){
    *dstErr = errNum;
  }
  return area;
}
예제 #4
0
파일: WlzRegCCor.c 프로젝트: dscho/Woolz
/*!
* \return	Translation.
* \ingroup	WlzRegistration
* \brief	Registers the given 2D domain objects using a
*               frequency domain cross correlation, to find
*               the translation which has the highest cross
*               correlation value.
* \param	tObj			The target object. Must have
*                                       been assigned.
* \param	sObj			The source object to be
*                                       registered with target object.
*                                       Must have been assigned.
* \param	initTr			Initial affine transform
*                                       to be applied to the source
*                                       object prior to registration.
* \param        maxTran    		Maximum translation.
* \param	maxTran			Maximum translation.
* \param	winFn			Window function.
* \param	noise			Use Gaussian noise if non-zero.
* \param	dstCCor			Destination ptr for the cross
*                                       correlation value, may be NULL.
* \param	dstErr			Destination error pointer,
*                                       may be NULL.
*/
static WlzDVertex2 WlzRegCCorObjs2DTran(WlzObject *tObj, WlzObject *sObj,
					WlzAffineTransform *initTr,
					WlzDVertex2 maxTran,
					WlzWindowFnType winFn, int noise,
					double *dstCCor, WlzErrorNum *dstErr)
{
  int		oIdx;
  double	cCor = 0.0;
  double	sSq[2];
  double	**oAr[2];
  WlzIBox2	aBox;
  WlzIBox2	oBox[2],
  		pBox[2];
  WlzIVertex2	aSz,
  		aOrg,
		centre,
		radius,
		tran;
  WlzDVertex2	dstTran;
  WlzObject	*oObj[2],
  		*pObj[2];
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  dstTran.vtX = 0.0;
  dstTran.vtY = 0.0;
  oAr[0] = oAr[1] = NULL;
  oObj[0] = oObj[1] = NULL;
  pObj[0] = pObj[1] = NULL;
  oObj[0] = WlzAssignObject(tObj, NULL);
  /* Transform source object. */
  if((initTr == NULL) || WlzAffineTransformIsIdentity(initTr, NULL))
  {
    oObj[1] = WlzAssignObject(sObj, NULL);
  }
  else
  {
    oObj[1] = WlzAssignObject(
              WlzAffineTransformObj(sObj, initTr, WLZ_INTERPOLATION_NEAREST,
				    &errNum), NULL);
  }
  /* Preprocess the objects. */
  if(errNum == WLZ_ERR_NONE)
  {
    oIdx = 0;
    while((errNum == WLZ_ERR_NONE) && (oIdx < 2))
    {
      oBox[oIdx] = WlzBoundingBox2I(oObj[oIdx], &errNum);
      ++oIdx;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    oIdx = 0;
    while((errNum == WLZ_ERR_NONE) && (oIdx < 2))
    {
      centre.vtX = (oBox[oIdx].xMin + oBox[oIdx].xMax) / 2;
      centre.vtY = (oBox[oIdx].yMin + oBox[oIdx].yMax) / 2;
      radius.vtX = (oBox[oIdx].xMax - oBox[oIdx].xMin) / 2;
      radius.vtY = (oBox[oIdx].yMax - oBox[oIdx].yMin) / 2;
      pObj[oIdx] = WlzAssignObject(
                   WlzRegCCorPProcessObj2D(oObj[oIdx], winFn, centre, radius,
      					   &errNum), NULL);
      ++oIdx;
    }
  }
  /* Create double arrays. */
  if(errNum == WLZ_ERR_NONE)
  {
    oIdx = 0;
    while((errNum == WLZ_ERR_NONE) && (oIdx < 2))
    {
      pBox[oIdx] = WlzBoundingBox2I(pObj[oIdx], &errNum);
      ++oIdx;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    aBox.xMin = WLZ_MIN(pBox[0].xMin, pBox[1].xMin) - (int )(maxTran.vtX) + 1;
    aBox.yMin = WLZ_MIN(pBox[0].yMin, pBox[1].yMin) - (int )(maxTran.vtY) + 1;
    aBox.xMax = WLZ_MAX(pBox[0].xMax, pBox[1].xMax) + (int )(maxTran.vtX) + 1;
    aBox.yMax = WLZ_MAX(pBox[0].yMax, pBox[1].yMax) + (int )(maxTran.vtY) + 1;
    aOrg.vtX = aBox.xMin;
    aOrg.vtY = aBox.yMin;
    aSz.vtX = aBox.xMax - aBox.xMin + 1;
    aSz.vtY = aBox.yMax - aBox.yMin + 1;
    (void )AlgBitNextPowerOfTwo((unsigned int *)&(aSz.vtX), aSz.vtX);
    (void )AlgBitNextPowerOfTwo((unsigned int *)&(aSz.vtY), aSz.vtY);
    oIdx = 0;
    while((errNum == WLZ_ERR_NONE) && (oIdx < 2))
    {
      errNum = WlzToArray2D((void ***)&(oAr[oIdx]), pObj[oIdx], aSz, aOrg,
      			    noise, WLZ_GREY_DOUBLE);
      ++oIdx;
    }
  }
  if((dstCCor != NULL) && (errNum == WLZ_ERR_NONE))
  {
    oIdx = 0;
    while((errNum == WLZ_ERR_NONE) && (oIdx < 2))
    {
      WlzArrayStats2D((void **)(oAr[oIdx]), aSz, WLZ_GREY_DOUBLE, NULL, NULL,
		      NULL, &(sSq[oIdx]), NULL, NULL);
      ++oIdx;
    }
  }
#ifdef WLZ_REGCCOR_DEBUG
  if(errNum == WLZ_ERR_NONE)
  {
    FILE	*fP = NULL;
    WlzObject	*cCObjT = NULL;
    
    cCObjT = WlzFromArray2D((void **)(oAr[0]), aSz, aOrg,
			    WLZ_GREY_DOUBLE, WLZ_GREY_DOUBLE,
			    0.0, 1.0, 0, 0, &errNum);
    if(cCObjT)
    {
      if((fP = fopen("oObjT0.wlz", "w")) != NULL)
      {
	(void )WlzWriteObj(fP, cCObjT);
	(void )fclose(fP);
      }
      (void )WlzFreeObj(cCObjT);
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    FILE	*fP = NULL;
    WlzObject	*cCObjT = NULL;
    
    cCObjT = WlzFromArray2D((void **)(oAr[1]), aSz, aOrg,
			    WLZ_GREY_DOUBLE, WLZ_GREY_DOUBLE,
			    0.0, 1.0, 0, 0, &errNum);
    if(cCObjT)
    {
      if((fP = fopen("oObjT1.wlz", "w")) != NULL)
      {
	(void )WlzWriteObj(fP, cCObjT);
	(void )fclose(fP);
      }
      (void )WlzFreeObj(cCObjT);
    }
  }
#endif /* WLZ_REGCCOR_DEBUG */
  /* Cross correlate. */
  if(errNum == WLZ_ERR_NONE)
  {
    (void )AlgCrossCorrelate2D(oAr[0], oAr[1], aSz.vtX, aSz.vtY);
    AlgCrossCorrPeakXY(&(tran.vtX), &(tran.vtY), &cCor, oAr[0],
		       aSz.vtX, aSz.vtY, maxTran.vtX, maxTran.vtY);
  }
#ifdef WLZ_REGCCOR_DEBUG
  if(errNum == WLZ_ERR_NONE)
  {
    FILE	*fP = NULL;
    WlzObject	*cCObjT = NULL;
    
    oIdx = 0;
    while((errNum == WLZ_ERR_NONE) && (oIdx < 2))
    {
      (void )WlzGreyStats(pObj[oIdx], NULL, NULL, NULL, NULL, &(sSq[oIdx]),
			  NULL, NULL, &errNum);
      ++oIdx;
    }
    if(errNum == WLZ_ERR_NONE)
    {
      cCObjT = WlzFromArray2D((void **)(oAr[0]), aSz, aOrg,
			      WLZ_GREY_DOUBLE, WLZ_GREY_DOUBLE,
			      0.0,
			      255.0 / (1.0 + (sqrt(sSq[0] * sSq[1]) *
			      		      aSz.vtX * aSz.vtY)),
			      0, 0, &errNum);
    }
    if(cCObjT)
    {
      if((fP = fopen("cCObjT.wlz", "w")) != NULL)
      {
	(void )WlzWriteObj(fP, cCObjT);
	(void )fclose(fP);
      }
      (void )WlzFreeObj(cCObjT);
    }
  }
#endif /* WLZ_REGCCOR_DEBUG */
  for(oIdx = 0; oIdx < 2; ++oIdx)
  {
    (void )WlzFreeObj(oObj[oIdx]);
    (void )WlzFreeObj(pObj[oIdx]);
    AlcDouble2Free(oAr[oIdx]);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    dstTran.vtX = tran.vtX;
    dstTran.vtY = tran.vtY;
    if(dstCCor)
    {
      cCor = cCor / (1.0 + (sqrt(sSq[0] * sSq[1]) * aSz.vtX * aSz.vtY));
      *dstCCor = cCor;
    }
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(dstTran);
}
예제 #5
0
파일: WlzRegCCor.c 프로젝트: dscho/Woolz
/*!
* \return	Angle of roatation.
* \ingroup	WlzRegistration
* \brief	Polar samples then registers the given 2D domain objects
*               using a frequency domain cross correlation, to find
*               the angle of rotation about the given centre of rotation
*               which has the highest cross correlation value.
*		The rotation is always about the objects cente of mass.
* \param	tObj			The target object. Must have
*                                       been assigned.
* \param	sObj			The source object to be
*                                       registered with target object.
*                                       Must have been assigned.
* \param	initTr			Initial affine transform
*                                       to be applied to the source
*                                       object prior to registration.
* \param	maxRot			Maximum rotation.
* \param	winFn			Window function.
* \param	noise			Use Gaussian noise if non-zero.
* \param	dstErr			Destination error pointer,
*                                       may be NULL.
*/
static double	WlzRegCCorObjs2DRot(WlzObject *tObj, WlzObject *sObj,
				    WlzAffineTransform *initTr, double maxRot,
				    WlzWindowFnType winFn, int noise,
				    WlzErrorNum *dstErr)
{
  int		oIdx,
  		angCnt;
  double	angInc,
  		dstRot = 0.0;
  WlzIBox2	aBox;
  WlzIBox2	oBox[2];
  WlzIVertex2	rot,
  		aSz,
  		aOrg,
		winRad,
		winOrg,
		rotPad,
		rotCentreI;
  double	**oAr[2];
  WlzObject	*oObj[2],
  		*pObj[2],
		*wObj[2];
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  const int	rotCnt = 500;
  const double	distInc = 1.0;

  /* Assign the target and transform source objects. */
  oAr[0] = oAr[1] = NULL;
  oAr[0] = oAr[1] = NULL;
  oObj[0] = oObj[1] = NULL;
  pObj[0] = pObj[1] = NULL;
  wObj[0] = wObj[1] = NULL;
  oObj[0] = WlzAssignObject(tObj, NULL);
  if((initTr == NULL) || WlzAffineTransformIsIdentity(initTr, NULL))
  {
    oObj[1] = WlzAssignObject(sObj, NULL);
  }
  else
  {
    oObj[1] = WlzAssignObject(
    	      WlzAffineTransformObj(sObj, initTr, WLZ_INTERPOLATION_NEAREST,
				   &errNum), NULL);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    oIdx = 0;
    while((errNum == WLZ_ERR_NONE) && (oIdx < 2))
    {
      tObj = WlzAutoCor(oObj[oIdx], &errNum);
      (void )WlzFreeObj(oObj[oIdx]);
      oObj[oIdx] = WlzAssignObject(tObj, NULL);
      ++oIdx;
    }
  }
  /* Compute rectangular to polar transformation. */
  if(errNum == WLZ_ERR_NONE)
  {
    angInc = (2.0 * (maxRot + WLZ_M_PI)) / rotCnt;
    angCnt = (2.0 * WLZ_M_PI) / angInc;
    oIdx = 0;
    while((errNum == WLZ_ERR_NONE) && (oIdx < 2))
    {
      rotCentreI.vtX = 0;
      rotCentreI.vtY = 0;
      if(errNum == WLZ_ERR_NONE)
      {
	pObj[oIdx] = WlzAssignObject(
		     WlzPolarSample(oObj[oIdx], rotCentreI, angInc, distInc,
				    angCnt, 0, &errNum), NULL);
      }
      ++oIdx;
    }
  }
  /* Preproccess the objects using windows or noise. */
  if(errNum == WLZ_ERR_NONE)
  {
    oIdx = 0;
    while((errNum == WLZ_ERR_NONE) && (oIdx < 2))
    {
      oBox[oIdx] = WlzBoundingBox2I(pObj[oIdx], &errNum);
      if(errNum == WLZ_ERR_NONE)
      {
	winOrg.vtX = (oBox[oIdx].xMax + oBox[oIdx].xMin) / 2;
	winOrg.vtY = (oBox[oIdx].yMax + oBox[oIdx].yMin) / 2;
	winRad.vtX = (oBox[oIdx].xMax - oBox[oIdx].xMin) / 2;
	winRad.vtY = (oBox[oIdx].yMax - oBox[oIdx].yMin) / 2;
	wObj[oIdx] = WlzAssignObject(
		     WlzRegCCorPProcessObj2D(pObj[oIdx], winFn,
					     winOrg, winRad, 
					     &errNum), NULL);
      }
      ++oIdx;
    }
  }
  /* Create 2D double arrays from the polar sampled objects. */
  if(errNum == WLZ_ERR_NONE)
  {
    oIdx = 0;
    while((errNum == WLZ_ERR_NONE) && (oIdx < 2))
    {
      oBox[oIdx] = WlzBoundingBox2I(wObj[oIdx], &errNum);
      ++oIdx;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    aBox.xMin = WLZ_MIN(oBox[0].xMin, oBox[1].xMin);
    aBox.yMin = WLZ_MIN(oBox[0].yMin, oBox[1].yMin);
    aBox.xMax = WLZ_MAX(oBox[0].xMax, oBox[1].xMax);
    aBox.yMax = WLZ_MAX(oBox[0].yMax, oBox[1].yMax);
    rotPad.vtX = (aBox.xMax - aBox.xMin) / 2;
    rotPad.vtY = 1 + WLZ_NINT(maxRot / angInc);
    aBox.yMin -= rotPad.vtY;
    aBox.yMax += rotPad.vtY;
    aOrg.vtX = aBox.xMin;
    aOrg.vtY = aBox.yMin;
    aSz.vtX = aBox.xMax - aBox.xMin + 1;
    aSz.vtY = aBox.yMax - aBox.yMin + 1;
    (void )AlgBitNextPowerOfTwo((unsigned int *)&(aSz.vtX), aSz.vtX);
    (void )AlgBitNextPowerOfTwo((unsigned int *)&(aSz.vtY), aSz.vtY);
    oIdx = 0;
    while((errNum == WLZ_ERR_NONE) && (oIdx < 2))
    {
      errNum = WlzToArray2D((void ***)&(oAr[oIdx]), wObj[oIdx], aSz, aOrg,
      			    noise, WLZ_GREY_DOUBLE);
      ++oIdx;
    }
  }
#ifdef WLZ_REGCCOR_DEBUG
  if(errNum == WLZ_ERR_NONE)
  {
    FILE	*fP = NULL;
    WlzObject	*aObj = NULL;

    aObj = WlzFromArray2D((void **)(oAr[0]), aSz, aOrg,
    			  WLZ_GREY_DOUBLE, WLZ_GREY_DOUBLE, 0.0, 1.0,
			  0, 0, &errNum);
    if((fP = fopen("cObjR0.wlz", "w")) != NULL) 
    {
      (void )WlzWriteObj(fP, aObj); 
      (void )fclose(fP);
    }
    WlzFreeObj(aObj);
    aObj = WlzFromArray2D((void **)(oAr[1]), aSz, aOrg,
    			  WLZ_GREY_DOUBLE, WLZ_GREY_DOUBLE, 0.0, 1.0,
			  0, 0, &errNum);
    if((fP = fopen("cObjR1.wlz", "w")) != NULL)
    {
      (void )WlzWriteObj(fP, aObj);
      (void )fclose(fP);
    }
    WlzFreeObj(aObj);
  }
#endif /* WLZ_REGCCOR_DEBUG */
  /* Cross correlate. */
  if(errNum == WLZ_ERR_NONE)
  {
    (void )AlgCrossCorrelate2D(oAr[0], oAr[1], aSz.vtX, aSz.vtY);
    AlgCrossCorrPeakXY(&(rot.vtX), &(rot.vtY), NULL, oAr[0],
		       aSz.vtX, aSz.vtY, rotPad.vtX, rotPad.vtY);
    dstRot = rot.vtY * angInc;
    /* dstRot = -(rot.vtY) * angInc; */
  }
#ifdef WLZ_REGCCOR_DEBUG
  if(errNum == WLZ_ERR_NONE)
  {
    double	sSq[2];
    FILE	*fP = NULL;
    WlzObject	*cCObjR = NULL;
    
    oIdx = 0;
    while((errNum == WLZ_ERR_NONE) && (oIdx < 2))
    {
      (void )WlzGreyStats(wObj[oIdx], NULL, NULL, NULL, NULL, &(sSq[oIdx]),
			  NULL, NULL, &errNum);
      ++oIdx;
    }
    if(errNum == WLZ_ERR_NONE)
    {
      cCObjR = WlzFromArray2D((void **)(oAr[0]), aSz, aOrg,
			      WLZ_GREY_DOUBLE, WLZ_GREY_DOUBLE,
			      0.0,
			      255.0 / (1.0 + (sqrt(sSq[0] * sSq[1]) *
			      		      aSz.vtX * aSz.vtY)),
			      0, 0, &errNum);
    }
    if(cCObjR)
    {
      if((fP = fopen("cCObjR.wlz", "w")) != NULL)
      {
	(void )WlzWriteObj(fP, cCObjR);
	(void )fclose(fP);
      }
      (void )WlzFreeObj(cCObjR);
    }
  }
#endif /* WLZ_REGCCOR_DEBUG */
  for(oIdx = 0; oIdx < 2; ++oIdx)
  {
    (void )WlzFreeObj(oObj[oIdx]);
    (void )WlzFreeObj(pObj[oIdx]);
    (void )WlzFreeObj(wObj[oIdx]);
    AlcDouble2Free(oAr[oIdx]);
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(dstRot);
}
예제 #6
0
int main(
  int   argc,
  char  **argv)
{
  FILE		*inFileObj=NULL, *inFileTiles=NULL;
  char 		optList[] = "f:hv";
  int		option;
  WlzErrorNum	errNum=WLZ_ERR_NONE;
  int		verboseFlg=0;
  int		func=1;
  WlzObject	*imageObj = NULL, *tilesObj=NULL, *obj;
  WlzCompoundArray	*tilesCompObj;
  double	tileVal=0.0;
  int		i;
  WlzPixelV	tmplVal;
  WlzGreyType	dstGType;
  double	dstMin, dstMax, dstSum, dstSumSq, dstMean, dstStdDev;

  /* read the argument list and check for an input file */
  opterr = 0;
  while( (option = getopt(argc, argv, optList)) != EOF ){
    switch( option ){

    case 'f':
      func = atoi(optarg);
      switch (func){
      default:
	fprintf(stderr, "%s: invalid tile function option %d, reset to 1\n", argv[0], func);
	func = 1;
	break;
      case 1: /* average */
	break;
      }
	  
    case 'v':
      verboseFlg = 1;
      break;

    case 'h':
    default:
      usage(argv[0]);
      return 1;

    }
  }

  /* must have image and tile file */
  /* check input file/stream */
  if( (argc - optind) < 2 ){
    fprintf(stderr, "%s: not enough arguments\n", argv[0]);
    usage(argv[0]);
    return 1;
  }
  else {
    if( (inFileObj = fopen(*(argv+optind), "rb")) == NULL ){
      fprintf(stderr, "%s: can't open image object file %s\n", argv[0], *(argv+optind));
      usage(argv[0]);
      return 1;
    }
    if( (inFileTiles = fopen(*(argv+optind+1), "rb")) == NULL ){
      fprintf(stderr, "%s: can't open tiles file %s\n", argv[0], *(argv+optind+1));
      usage(argv[0]);
      return 1;
    }
  }
  
  /* verbose output */
  if( verboseFlg ){
    fprintf(stderr, "%s: tile function value value: %d\n", argv[0], func);
    fprintf(stderr, "%s: image object file: %s\n", argv[0], *(argv+optind));
    fprintf(stderr, "%s: tiles object file: %s\n", argv[0], *(argv+optind+1));
  }

  /* get woolz objects */
  if((imageObj = WlzReadObj(inFileObj, &errNum)) == NULL){
    fprintf(stderr, "%s: can't read image object\n", argv[0]);
    usage(argv[0]);
    return 1;
  }
  imageObj = WlzAssignObject(imageObj, NULL);

  if((tilesObj = WlzReadObj(inFileTiles, &errNum)) == NULL){
    fprintf(stderr, "%s: can't read tiles object\n", argv[0]);
    usage(argv[0]);
    return 1;
  }
  tilesObj = WlzAssignObject(tilesObj, NULL);
  tilesCompObj = (WlzCompoundArray *) tilesObj;

  /* now calculate the tile values */
  switch( tilesObj->type ){
  case WLZ_COMPOUND_ARR_1:
  case WLZ_COMPOUND_ARR_2:
    tmplVal.type = WLZ_GREY_UBYTE;
    tmplVal.v.ubv = 0;
    for(i=0; i < tilesCompObj->n; i++){
      switch( func ){
      case 1: /* average */
	/* get tile object with values */
	if( (obj = WlzGreyTemplate(imageObj, tilesCompObj->o[i], tmplVal, &errNum)) != NULL ){
	  WlzGreyStats(obj, &dstGType, &dstMin, &dstMax, &dstSum, &dstSumSq,
		       &dstMean, &dstStdDev, &errNum);
	  tileVal = dstMean;
	}
	else {
	  fprintf(stderr, "%s: error in tile template\n", argv[0]);
	  tileVal = -1.0;
	}
	break;

      default:
	break;
      }

      if( i > 0 ){
	fprintf(stdout, ", %8.3f", tileVal);
      }
      else{
	fprintf(stdout, "%8.3f", tileVal);
      }
    }
    break;

  default:
    fprintf(stderr, "%s: invalid tiles object type - must be compound array\n", argv[0]);
    return 1;
  }

  return 0;
}
예제 #7
0
파일: WlzGreyStats.c 프로젝트: dscho/Woolz
int             main(int argc, char **argv)
{
  int		area,
  		option,
		ok = 1,
		verbose = 0,
                colFlg = 0,
		usage = 0;
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  FILE		*fP = NULL;
  WlzObject	*inObj = NULL;
  double	min,
  		max,
		sum,
		sumSq,
		mean,
		stdDev;
  double	minA[4],
  		maxA[4],
		sumA[4],
		sumSqA[4],
		meanA[4],
		stdDevA[4];
  WlzGreyType	gType;
  char 		*outFileStr,
  		*inObjFileStr;
  const char	*errMsg;
  static char	optList[] = "co:vh",
		outFileStrDef[] = "-",
  		inObjFileStrDef[] = "-";

  opterr = 0;
  outFileStr = outFileStrDef;
  inObjFileStr = inObjFileStrDef;
  while(ok && ((option = getopt(argc, argv, optList)) != -1))
  {
    switch(option)
    {
    case 'c':
      colFlg = 1;
      break;
    case 'o':
      outFileStr = optarg;
      break;
    case 'v':
      verbose = 1;
      break;
    case 'h':
    default:
      usage = 1;
      ok = 0;
      break;
    }
  }
  if((inObjFileStr == NULL) || (*inObjFileStr == '\0') ||
     (outFileStr == NULL) || (*outFileStr == '\0'))
  {
    ok = 0;
    usage = 1;
  }
  if(ok && (optind < argc))
  {
    if((optind + 1) != argc)
    {
      usage = 1;
      ok = 0;
    }
    else
    {
      inObjFileStr = *(argv + optind);
    }
  }
  if(ok)
  {
    errNum = WLZ_ERR_READ_EOF;
    if((inObjFileStr == NULL) ||
       (*inObjFileStr == '\0') ||
       ((fP = (strcmp(inObjFileStr, "-")?
	      fopen(inObjFileStr, "r"): stdin)) == NULL) ||
       ((inObj= WlzReadObj(fP, &errNum)) == NULL))
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr,
		     "%s: failed to read object from file %s (%s).\n",
		     *argv, inObjFileStr,
		     errMsg);
    }
    if(fP && strcmp(inObjFileStr, "-"))
    {
      fclose(fP);
    }
  }
  if(ok)
  {
    if(colFlg)
    {
      area = WlzRGBAGreyStats(inObj, WLZ_RGBA_SPACE_RGB, &gType,	
			      minA, maxA, sumA, sumSqA, meanA,
			      stdDevA, &errNum);
    }
    else
    {
      area = WlzGreyStats(inObj, &gType, &min, &max, &sum, &sumSq, &mean,
			  &stdDev, &errNum);
    }
    if(errNum != WLZ_ERR_NONE)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr,
      		     "%s: failed to compute object's grey value statistics"
		     " (%s)\n",
		     *argv, errMsg);
    }
  }
  if(ok)
  {
    if(((fP = (strcmp(outFileStr, "-")?
              fopen(outFileStr, "w"):
	      stdout)) == NULL))
    {
      ok = 0;
      (void )fprintf(stderr,
      		     "%s: failed to write output file\n",
		     *argv);
    }
    else
    {
      if( colFlg ){
	if(verbose)
	{
	  (void )fprintf(fP,
			 "area        %d\n"
			 "grey type   %s\n"
			 "min         (%lg, %lg, %lg, %lg)\n"
			 "max         (%lg, %lg, %lg, %lg)\n"
			 "sum         (%lg, %lg, %lg, %lg)\n"
			 "sum sq      (%lg, %lg, %lg, %lg)\n"
			 "mean        (%lg, %lg, %lg, %lg)\n"
			 "std dev     (%lg, %lg, %lg, %lg)\n",
			 area, WlzStringFromGreyType(gType, NULL),
			 minA[0], minA[1], minA[2], minA[3],
			 maxA[0], maxA[1], maxA[2], maxA[3],
			 sumA[0], sumA[1], sumA[2], sumA[3],
			 sumSqA[0], sumSqA[1], sumSqA[2], sumSqA[3],
			 meanA[0], meanA[1], meanA[2], meanA[3],
			 stdDevA[0], stdDevA[1], stdDevA[2], stdDevA[3]);
	}
	else
	{
	  (void )fprintf(fP,
			 "%d %s (%lg,%lg,%lg,%lg) (%lg %lg %lg %lg)\n"
			 "(%lg,%lg,%lg,%lg) (%lg %lg %lg %lg)\n"
			 "(%lg,%lg,%lg,%lg) (%lg %lg %lg %lg)\n",
			 area, WlzStringFromGreyType(gType, NULL),
			 minA[0], minA[1], minA[2], minA[3],
			 maxA[0], maxA[1], maxA[2], maxA[3],
			 sumA[0], sumA[1], sumA[2], sumA[3],
			 sumSqA[0], sumSqA[1], sumSqA[2], sumSqA[3],
			 meanA[0], meanA[1], meanA[2], meanA[3],
			 stdDevA[0], stdDevA[1], stdDevA[2], stdDevA[3]);
	}
      }
      else
      {
	if(verbose)
	{
	  (void )fprintf(fP,
			 "area        % 14d\n"
			 "grey type    %14s\n"
			 "min         % 14g\n"
			 "max         % 14g\n"
			 "sum         % 14g\n"
			 "sum sq      % 14g\n"
			 "mean        % 14g\n"
			 "std dev     % 14g\n",
			 area, WlzStringFromGreyType(gType, NULL),
			 min, max, sum, sumSq, mean, stdDev);
	}
	else
	{
	  (void )fprintf(fP, "%d %s %lg %lg %lg %lg %lg %lg\n",
			 area, WlzStringFromGreyType(gType, NULL),
			 min, max, sum, sumSq, mean, stdDev);
	}
      }
    }
    if(fP && strcmp(outFileStr, "-"))
    {
      fclose(fP);
    }
  }
  if(usage)
  {
    (void )fprintf(stderr,
    "Usage: %s%sExample: %s%s",
    *argv,
    " [-o<out file>] [-c] [-v] [-h] [<in object>]\n"
    "Options:\n"
    "  -c  Colour stats if RGB, otherwise modulus stats calculated\n"
    "  -o  Output file name.\n"
    "  -v  Verbose output flag.\n"
    "  -h  Help, prints this usage message.\n"
    "Calculates the area, minimum, maximum, sum, sum of squares, mean\n"
    "and the standard deviation of the input 2D or 3D Woolz object's\n"
    "grey values.\n"
    "If the verbose output flag is not set then the following are written\n"
    "to the output file in the following order:\n"
    "  <area> <grey type> <min> <max> <sum> <sum of sq> <mean> <std dev>.\n"
    "The input object is read from stdin and values are written to stdout\n"
    "unless the filenames are given.\n",
    *argv,
    " -o stats.txt myobj.wlz\n"
    "The input Woolz object is read from myobj.wlz. The statistics are\n"
    "calculated and  written to out.txt.\n");
  }
  return(!ok);
}
예제 #8
0
/*!
* \return	Woolz error code.
* \ingroup	WlzExtFF
* \brief	Writes the given Woolz object to the given file(s)
*		using the ANALYZE 7.5 file format. The given file name is
*		used to generate the '.hdr' and '.img' filenames.
* \param	gvnFileName		Given file name with .hdr, .img or no
* 					extension.
* \param	obj			Given woolz object.
*/
WlzErrorNum	WlzEffWriteObjAnl(const char *gvnFileName, WlzObject *obj)
{
  int  		cnt = 0;
  double	dMin,
  		dMax;
  FILE		*fP = NULL;
  void	 	*data = NULL;
  WlzGreyP	dataP;
  WlzEffAnlDsr 	dsr;
  WlzGreyType	gType;
  WlzVertex	org,
  		sz;
  char		*fileName = NULL,
  		*hdrFileName = NULL,
		*imgFileName = NULL;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  dataP.v = NULL;
  if((gvnFileName == NULL) || (*gvnFileName == '\0'))
  {
    errNum = WLZ_ERR_PARAM_NULL;
  }
  else if(obj == NULL)
  {
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else if(obj->domain.core == NULL)
  {
    errNum = WLZ_ERR_DOMAIN_NULL;
  }
  else if(obj->values.core == NULL)
  {
    errNum = WLZ_ERR_VALUES_NULL;
  }
  else
  {
    errNum = WlzEffAnlFileNames(&fileName, &hdrFileName, &imgFileName,
				gvnFileName);
  }
  /* Fill in the ANALYZE file header data structures. */
  if(errNum == WLZ_ERR_NONE)
  {
    (void )memset(&dsr, 0, sizeof(WlzEffAnlDsr));
    switch(obj->type)
    {
      case WLZ_2D_DOMAINOBJ:
	org.i2.vtX = obj->domain.i->kol1;
	org.i2.vtY = obj->domain.i->line1;
	sz.i2.vtX = obj->domain.i->lastkl - org.i2.vtX + 1;
	sz.i2.vtY = obj->domain.i->lastln - org.i2.vtY + 1;
	if((sz.i2.vtX <= 0) || (sz.i2.vtY <= 0))
	{
	  errNum = WLZ_ERR_DOMAIN_DATA;
	}
	else
	{
	  dsr.dim.dim[0] = 2;
	  dsr.dim.dim[1] = sz.i2.vtX;
	  dsr.dim.dim[2] = sz.i2.vtY;
	  dsr.dim.pixdim[0] = 2;
	  dsr.dim.pixdim[1] = 1.0;
	  dsr.dim.pixdim[2] = 1.0;
	}
        break;
      case WLZ_3D_DOMAINOBJ:
	org.i3.vtX = obj->domain.p->kol1;
	org.i3.vtY = obj->domain.p->line1;
	org.i3.vtZ = obj->domain.p->plane1;
	sz.i3.vtX = obj->domain.p->lastkl - org.i3.vtX + 1;
	sz.i3.vtY = obj->domain.p->lastln - org.i3.vtY + 1;
	sz.i3.vtZ = obj->domain.p->lastpl - org.i3.vtZ + 1;
	if((sz.i3.vtX <= 0) || (sz.i3.vtY <= 0) || (sz.i3.vtZ <= 0))
	{
	  errNum = WLZ_ERR_DOMAIN_DATA;
	}
        else
	{
	  dsr.dim.dim[0] = 3;
	  dsr.dim.dim[1] = sz.i3.vtX;
	  dsr.dim.dim[2] = sz.i3.vtY;
	  dsr.dim.dim[3] = sz.i3.vtZ;
	  dsr.dim.pixdim[0] = 3;
	  dsr.dim.pixdim[1] = obj->domain.p->voxel_size[0];
	  dsr.dim.pixdim[2] = obj->domain.p->voxel_size[1];
	  dsr.dim.pixdim[3] = obj->domain.p->voxel_size[2];
	}
        break;
      default:
        errNum = WLZ_ERR_OBJECT_TYPE;
	break;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    (void )WlzGreyStats(obj, &gType, &dMin, &dMax, NULL, NULL, NULL, NULL,
    			&errNum);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    dsr.dim.glMax = (int )ceil(dMax);
    dsr.dim.glMin = (int )floor(dMin);
    switch(gType)
    {
      case WLZ_GREY_INT:
        dsr.dim.dataType = WLZEFF_ANL_DT_SIGNED_INT;
        dsr.dim.bitPix = 32;
        break;
      case WLZ_GREY_SHORT:
        dsr.dim.dataType = WLZEFF_ANL_DT_SIGNED_SHORT;
        dsr.dim.bitPix = 16;
	break;
      case WLZ_GREY_UBYTE:
        dsr.dim.dataType = WLZEFF_ANL_DT_UNSIGNED_CHAR;
        dsr.dim.bitPix = 8;
	break;
      case WLZ_GREY_FLOAT:
        dsr.dim.dataType = WLZEFF_ANL_DT_FLOAT;
        dsr.dim.bitPix = 32;
	break;
      case WLZ_GREY_DOUBLE:
        dsr.dim.dataType = WLZEFF_ANL_DT_DOUBLE;
        dsr.dim.bitPix = 64;
	break;
      default:
	errNum = WLZ_ERR_GREY_TYPE;
        break;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    dsr.hk.hdrSz = 348;
    dsr.hk.regular = 'r';
    dsr.hk.extents = 16384;
    (void )strcpy(dsr.hist.descrip, "Converted from Woolz");
    (void )strcpy(dsr.hist.originator, "Woolz");
    (void )strcpy(dsr.hist.generated, "Woolz");
  }
  /* Get Woolz object's values as an array. */
  if(WLZ_ERR_NONE == errNum)
  {
    switch(obj->type)
    {
      case WLZ_2D_DOMAINOBJ:
        cnt = sz.i2.vtX * sz.i2.vtY;
	errNum = WlzToArray2D((void ***)&data, obj, sz.i2, org.i2, 0, gType);
	if(errNum == WLZ_ERR_NONE)
	{
	  switch(gType)
	  {
	    case WLZ_GREY_INT:
	      dataP.inp = *(int **)data;
	      break;
	    case WLZ_GREY_SHORT:
	      dataP.shp = *(short **)data;
	      break;
	    case WLZ_GREY_UBYTE:
	      dataP.ubp = *(WlzUByte **)data;
	      break;
	    case WLZ_GREY_FLOAT:
	      dataP.flp = *(float **)data;
	      break;
	    case WLZ_GREY_DOUBLE:
	      dataP.dbp = *(double **)data;
	      break;
	    default:
	      errNum = WLZ_ERR_GREY_TYPE;
	      break;
	  }
	}
        break;
      case WLZ_3D_DOMAINOBJ:
        cnt = sz.i3.vtX * sz.i3.vtY * sz.i3.vtZ;
	errNum = WlzToArray3D((void ****)&data, obj, sz.i3, org.i3, 0, gType);
	if(errNum == WLZ_ERR_NONE)
	{
	  switch(gType)
	  {
	    case WLZ_GREY_INT:
	      dataP.inp = **(int ***)data;
	      break;
	    case WLZ_GREY_SHORT:
	      dataP.shp = **(short ***)data;
	      break;
	    case WLZ_GREY_UBYTE:
	      dataP.ubp = **(WlzUByte ***)data;
	      break;
	    case WLZ_GREY_FLOAT:
	      dataP.flp = **(float ***)data;
	      break;
	    case WLZ_GREY_DOUBLE:
	      dataP.dbp = **(double ***)data;
	      break;
	    default:
	      errNum = WLZ_ERR_GREY_TYPE;
	      break;
	  }
	}
        break;
      default:
	errNum = WLZ_ERR_OBJECT_TYPE;
        break;
    }
  }
  /* Open the ANALYZE .hdr file and write the header information. */
  if(errNum == WLZ_ERR_NONE)
  {
    if((fP = fopen(hdrFileName, "w")) == NULL)
    {
      errNum = WLZ_ERR_WRITE_EOF;
    }
#ifdef _WIN32
    else if(_setmode(_fileno(fP), 0x8000) == -1)
    {
	errNum = WLZ_ERR_READ_EOF;
    }
#endif
  }
  if(errNum == WLZ_ERR_NONE)
  {
    errNum = WlzEffWriteAnlHdrKey(fP, &dsr);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    errNum = WlzEffWriteAnlHdrImageDim(fP, &dsr);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    errNum = WlzEffWriteAnlHdrDataHistory(fP, &dsr);
  }
  if(fP)
  {
    (void )fclose(fP);
    fP = NULL;
  }
  /* Open the ANALYZE .img file and write the image data. */
  if(errNum == WLZ_ERR_NONE)
  {
    if((fP = fopen(imgFileName, "w")) == NULL)
    {
      errNum = WLZ_ERR_WRITE_EOF;
    }
#ifdef _WIN32
    else if(_setmode(_fileno(fP), 0x8000) == -1)
    {
	errNum = WLZ_ERR_READ_EOF;
    }
#endif
  }
  if(errNum == WLZ_ERR_NONE)
  {
    switch(gType)
    {
      case WLZ_GREY_INT:
	errNum = WlzEffWriteAnlInt(fP, cnt, dataP.inp);
        break;
      case WLZ_GREY_SHORT:
	errNum = WlzEffWriteAnlShort(fP, cnt, dataP.shp);
        break;
      case WLZ_GREY_UBYTE:
	errNum = WlzEffWriteAnlChar(fP, cnt, dataP.ubp);
        break;
      case WLZ_GREY_FLOAT:
	errNum = WlzEffWriteAnlFloat(fP, cnt, dataP.flp);
        break;
      case WLZ_GREY_DOUBLE:
	errNum = WlzEffWriteAnlDouble(fP, cnt, dataP.dbp);
	break;
      default:
        break;
    }
  }
  if(fP)
  {
    (void )fclose(fP);
  }
  if(data)
  {
    switch(obj->type)
    {
      case WLZ_2D_DOMAINOBJ:
	Alc2Free((void **)data);
	break;
      case WLZ_3D_DOMAINOBJ:
	Alc3Free((void ***)data);
	break;
      default:
	break;
    }
  }
  (void )AlcFree(fileName);
  (void )AlcFree(hdrFileName);
  (void )AlcFree(imgFileName);
  return(errNum);
}
예제 #9
0
int		main(int argc, char *argv[])
{
  int		ok = 1,
  		option,
		usage = 0,
		stats = 0;
  char		*inFileStr[2];
  char		*outFileStr;
  int		maxDist = 0;
  WlzObject	*outObj = NULL;
  WlzObject	*inObj[2] = {NULL};
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  const char	*errMsgStr;
  static char	optList[] = "hSm:o:";
  const char    fileStrDef[] = "-";

  /* Parse the argument list and check for input files. */
  opterr = 0;
  outFileStr = (char *)fileStrDef;
  inFileStr[0] = inFileStr[1] = (char *)fileStrDef;
  while(ok && !usage && ((option = getopt(argc, argv, optList)) != EOF))
  {
    switch(option)
    {
      case 'm':
	if((sscanf(optarg, "%d", &maxDist) != 1) || (maxDist < 0))
	{
	  usage = 1;
	}
        break;
      case 'o':
	outFileStr = optarg;
	break;
      case 'h':
      default:
	usage = 1;
	break;
    }
  }
  if(ok)
  {
    ok = !usage;
  }
  if(ok && (optind < argc))
  {
    if((optind + 2) != argc)
    {
      usage = 1;
      ok = 0;
    }
    else
    {
      inFileStr[0] = argv[optind + 0];
      inFileStr[1] = argv[optind + 1];
    }
  }
  /* Read the reference object. */
  if(ok)
  {
    int		idx;

    for(idx = 0; idx < 2; ++idx)
    {
      FILE	*fP = NULL;

      if((inFileStr[idx] == NULL) ||
	 (*inFileStr[idx] == '\0') ||
	 ((fP = (strcmp(inFileStr[idx], "-")?
		fopen(inFileStr[idx], "r"): stdin)) == NULL) ||
	 ((inObj[idx] = WlzAssignObject(
	                WlzReadObj(fP, &errNum), NULL)) == NULL))
      {
	ok = 0;
	(void )fprintf(stderr,
		       "%s: Failed to read object from file %s.\n",
		       argv[0], inFileStr[idx]);
      }
      if(fP && strcmp(inFileStr[idx], "-"))
      {
	(void )fclose(fP); fP = NULL;
      }
    }
  }
  /* Compute the equi-distant distance object. */
  if(ok)
  {
    outObj = WlzAssignObject(
    	     WlzOffsetDist(inObj[0], inObj[1], maxDist, &errNum), NULL);
    if(errNum != WLZ_ERR_NONE)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsgStr);
      (void )fprintf(stderr,
		 "%s: Failed to compute equi-distant distance object, %s.\n",
		 argv[0], errMsgStr);
    }
  }
  /* Output the nearby domain object. */
  if(ok)
  {
    FILE	*fP = NULL;

    if((fP = (strcmp(outFileStr, "-")?
	    fopen(outFileStr, "w"): stdout)) == NULL)
    {
      ok = 0;
      (void )fprintf(stderr,
	  "%s: Failed to open output file %s.\n",
	  argv[0], outFileStr);
    }
    if(ok)
    {
      if(stats == 0)
      {
	/* Output equi-distant distance object. */
	if(ok)
	{
	  errNum = WlzWriteObj(fP, outObj);
	  if(errNum != WLZ_ERR_NONE)
	  {
	    ok = 0;
	    (void )WlzStringFromErrorNum(errNum, &errMsgStr);
	    (void )fprintf(stderr,
		"%s: Failed to write output object, %s.\n",
		argv[0], errMsgStr);
	  }
	}
      }
      else
      {
	int	n;
	double	dMin,
		  dMax,
		  dSum,
		  dSSq,
		  dMean,
		  dSDev;
	n = WlzGreyStats(outObj,
			 NULL, &dMin, &dMax, &dSum, &dSSq, &dMean, &dSDev,
			 &errNum);
	if(errNum != WLZ_ERR_NONE)
	{
	  ok = 0;
	  (void )WlzStringFromErrorNum(errNum, &errMsgStr);
	  (void )fprintf(stderr,
	      "%s: Failed to compute equi-distant distance statistics, %s.\n",
	      argv[0], errMsgStr);
	}
	else
	{
	  (void )fprintf(fP, "%d %lg %lg %lg %lg %lg %lg\n",
			 n, dMin, dMax, dSum, dSSq, dMean, dSDev);
	}
      }
    }
    if(fP && strcmp(outFileStr, "-"))
    {
      (void )fclose(fP); fP = NULL;
    }
  }
  (void )WlzFreeObj(outObj);
  if(usage)
  {
    (void )fprintf(stderr,
    "Usage: %s [-m#] [-S] [-o<output file>] [-h]\n"
    "\t\t[<object 1>] [<object 2>]\n"
    "Version: %s\n"
    "Computes an object with domain and values that are the set of minimum\n"
    "distances between the two given objects. The equidistant boundary is\n"
    "computed between the domains of the two given objects, within the\n"
    " distance limit and within the convex hull of the union of the two\n"
    "given object's domains.\n"
    "By default all files are read from the standard input and written\n"
    "to the standard output.\n"
    "Options:\n"
    "  -m  Maximum distance to consider (default 0, limit is convex hull).\n"
    "  -S  Output statistics rather than distance object. Output statistics\n"
    "      are printed on a single line with the order:\n"
    "      volume, min, max, sum, sum of squares, mean, standard deviation.\n"
    "  -o  Output object file.\n"
    "  -h  Help - prints this usage message\n"
    "By default all files are read from the standard input and written to\n"
    "the standard output.\n"
    "Example:\n"
    "  %s -o out.wlz -o out.wlz obj1.wlz obj2.wlz\n"
    "which creates a domain object corresponding to the minimum equidistant\n"
    "voxel set between the given objects, with maximum distance constrained\n"
    "only be the convex hull of the two given objects. The resulting object\n"
    "is written to the file out.wlz.\n",
    argv[0],
    WlzVersion(),
    argv[0]);
  }
  return(!ok);
}