예제 #1
0
int main(
  int   argc,
  char  **argv)
{
  FILE		*inFile;
  char 		optList[] = "d:m:t:hv";
  int		option;
  WlzErrorNum	errNum=WLZ_ERR_NONE;
  int		verboseFlg=0;
  int		type=1;
  WlzObject	*obj = NULL, *obj1, *obj2, *obj3;
  double	matchVal=0.0;
  double	s1, s2, s3, s4;
  double	delta=0.01;
  double	**mixing=NULL, **contrib=NULL;
  int		k, l;
  int		numCatRows=-1, numCatCols=-1;

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

    case 'd':
      delta = atof(optarg);
      if((delta >= 1.0) || (delta <= 1.0e-10)){
	delta = 0.01;
	fprintf(stderr, "%s: invalid delta, reset to 0.01", argv[0]);
      }
      break;

    case 'm':
      if((inFile = fopen(optarg, "r")) != NULL){
	if( fscanf(inFile, "%d, %d", &numCatCols, &numCatRows) < 2 ){
	  fprintf(stderr, "%s: can't read mixing matrix dimensions\n", argv[0]);
	  usage(argv[0]);
	  return 1;
	}
	AlcDouble2Malloc(&mixing, numCatRows, numCatCols);
	AlcDouble2Malloc(&contrib, numCatRows, numCatCols);
	for(l=0; l < numCatRows; l++){
	  for(k=0; k < numCatCols; k++){
	    if( fscanf(inFile, "%lg,", &(mixing[l][k])) < 1 ){
	      fprintf(stderr, "%s: can't read mixing matrix\n", argv[0]);
	      usage(argv[0]);
	      return 1;
	    }
	  }
	}
	for(l=0; l < numCatRows; l++){
	  for(k=0; k < numCatCols; k++){
	    if( fscanf(inFile, "%lg,", &(contrib[l][k])) < 1 ){
	      fprintf(stderr, "%s: can't read contributing matrix\n", argv[0]);
	      usage(argv[0]);
	      return 1;
	    }
	  }
	}
      }
      else {
	fprintf(stderr, "%s: can't open matrix file\n", argv[0]);
	usage(argv[0]);
	return 1;
      }
      break; 

    case 't':
      type = atoi(optarg);
      break;

    case 'v':
      verboseFlg = 1;
      break;

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

    }
  }

  /* verbose output */
  if( verboseFlg ){
    fprintf(stderr, "%s: parameter values:\n", argv[0]);
    fprintf(stderr, "\ttype = %d, delta = %f\n", type, delta);
    if( type == 6 ){
      fprintf(stderr, "\t mixing matrix:\n");
      for(l=0; l < numCatRows; l++){
	for(k=0; k < numCatCols; k++){
	  fprintf(stderr, "%f, ", mixing[l][k]);
	}
	fprintf(stderr, "\n");
      }
      fprintf(stderr, "\n");
      fprintf(stderr, "\t contributing matrix:\n");
      for(l=0; l < numCatRows; l++){
	for(k=0; k < numCatCols; k++){
	  fprintf(stderr, "%f, ", contrib[l][k]);
	}
	fprintf(stderr, "\n");
      }
    }
  }

  /* get objects from stdin */
  inFile = stdin;
  if((obj1 = WlzReadObj(inFile, &errNum)) != NULL){
    switch( obj1->type ){
    case WLZ_2D_DOMAINOBJ:
    case WLZ_3D_DOMAINOBJ:
    case WLZ_EMPTY_OBJ:
      break;

    default:
      fprintf(stderr, "%s: invalid object type: %d\n", argv[0],
	      obj->type);
      usage(argv[0]);
      return 1;
    }
  }
  else {
    fprintf(stderr, "%s: can't read first object\n", argv[0]);
    usage(argv[0]);
    return 1;
  }

  if((obj2 = WlzReadObj(inFile, &errNum)) != NULL){
    if( (obj2->type != obj1->type) && (obj2->type != WLZ_EMPTY_OBJ) ){
      fprintf(stderr, "%s: objects must be same type\n", argv[0]);
      usage(argv[0]);
      return 1;
    }
  }
  else {
    fprintf(stderr, "%s: can't read second object\n", argv[0]);
    usage(argv[0]);
    return 1;
  }

  /* this can fail silently but if there is an object it must
     be valid */
  if((obj3 = WlzReadObj(inFile, &errNum)) != NULL){
    if( (obj3->type != obj1->type) && (obj3->type != WLZ_EMPTY_OBJ) ){
      fprintf(stderr, "%s: objects must be same type\n", argv[0]);
      usage(argv[0]);
      return 1;
    }
  }

  /* now calculate a match value */
  switch( type ){
  case 1:
    if((obj = WlzIntersect2(obj1, obj2, &errNum)) != NULL){
      s1 = WlzSize(obj, &errNum);
      WlzFreeObj(obj);
    }
    else {
      s1 = 0;
    }
    if((obj = WlzUnion2(obj1, obj2, &errNum)) != NULL){
      s2 = WlzSize(obj, &errNum);
      WlzFreeObj(obj);
    }
    else {
      s2 = 1;
    }
    matchVal = s1 / s2;
    break;

  case 2:
    if((obj = WlzIntersect2(obj1, obj2, &errNum)) != NULL){
      s1 = WlzSize(obj, &errNum);
      WlzFreeObj(obj);
    }
    else {
      s1 = 0;
    }
    if((obj = WlzUnion2(obj1, obj2, &errNum)) != NULL){
      s2 = WlzSize(obj, &errNum);
      WlzFreeObj(obj);
    }
    else {
      s2 = 1;
    }
    matchVal = s1 / s2;
    if( type == 2 ){
      s1 = WlzSize(obj1, &errNum);
      s2 = WlzSize(obj2, &errNum);
      if( s2 > s1 ){
	if( matchVal == 0.0 ){
	  matchVal = 10.0;
	}
	else {
	  matchVal = 1.0 / matchVal;
	  matchVal = WLZ_MIN(matchVal, 10.0);
	}
      }
    }
    break;

  case 3:
    if((obj = WlzIntersect2(obj1, obj2, &errNum)) != NULL){
      s1 = WlzSize(obj, &errNum);
      WlzFreeObj(obj);
    }
    else {
      s1 = 0;
    }
    s2 = WlzSize(obj1, &errNum);
    matchVal = 0.0;
    if( s2 > 0 ){
      matchVal = s1 / s2;
    }
    break;

  case 4:
    if((obj = WlzIntersect2(obj1, obj2, &errNum)) != NULL){
      s1 = WlzSize(obj, &errNum);
      WlzFreeObj(obj);
    }
    else {
      s1 = 0;
    }
    s2 = WlzSize(obj2, &errNum);
    matchVal = 0.0;
    if( s2 > 0 ){
      matchVal = s1 / s2;
    }
    break;

  case 5:
    /* this is a coparative measure designed to give a value of 1
       to a random pattern and between zero and infinite for
       matches to one or the other. For analysis for clustering
       probably better to use the logarithm. Zero and infinite are
       delta and 1/delta. */
    /* must be a third object */
    if( obj3 == NULL ){
      fprintf(stderr, "%s: for match option 5 3 input object required\n",
	      argv[0]);
      return 1;
    }
    s1 = WlzSize(obj2, &errNum);
    if((obj = WlzIntersect2(obj1, obj2, &errNum)) != NULL){
      s2 = WlzSize(obj, &errNum);
      WlzFreeObj(obj);
    }
    else {
      s2 = 0.0;
    }
    s3 = WlzSize(obj3, &errNum);
    if((obj = WlzIntersect2(obj1, obj3, &errNum)) != NULL){
      s4 = WlzSize(obj, &errNum);
      WlzFreeObj(obj);
    }
    else {
      s4 = 0.0;
    }
    if((s1 < 0.0) || (s2 < 0.0) || (s3 < 0.0) || (s4 < 0.0)){
      /* just fail */
      fprintf(stderr, "%s: something gone wrong, negative size.\n",
	      argv[0]);
      return 1;
    }
    /* calculating (s2/s1) * (s3/s4) */
    /* if the denominator non-zero then simple formula */
    if( s2 > 0.0 ){
      if( s4 > 0.0 ){
	matchVal = (s2/s1) * (s3/s4);
      }
      else {
	matchVal = s2 / s1;
      }
    }
    else {
      if( s4 > 0.0 ){
	matchVal = s3/s4;
      }
      else {
	matchVal = 1.0;
      }
    }
    matchVal = WLZ_MAX(matchVal, delta);
    matchVal = WLZ_MIN(matchVal, 1.0/delta);
    break;

  case 6:
    /* this requires a mixing and contributing matrix and the images
       read in must have grey-values set to the right categories */
    if((numCatRows == -1) || (numCatCols == -1) ||
       (mixing == NULL) || (contrib == NULL)){
      fprintf(stderr, "%s: bad matrix data\n", argv[0]);
      usage(argv[0]);
      return 1;
    }
    matchVal = WlzMixtureValue(obj1, obj2, numCatRows, numCatCols,
			       mixing, contrib, &errNum);
    break;

  default:
    fprintf(stderr, "%s: invalid match type\n", argv[0]);
    usage(argv[0]);
    return 1;
  }

  /* print value */
  fprintf(stdout, "%f\n", matchVal);
  return 0;
}
예제 #2
0
/*!
* \return	Autocorrelated object or NULL on error.
* \ingroup	WlzRegistration
* \brief	Computes the autocorrelation of the given 2D object, see
*		WlzAutoCor().
* \param	gObj			Given object.
* \param	dstErr			Destination error pointer, may be NULL.
*/
static WlzObject *WlzAutoCor2D(WlzObject *gObj, WlzErrorNum *dstErr)
{
  WlzIVertex2	aSz,
		wSz,
		aOrg,
  		wOrg;
  WlzIBox2	box;
  double	**wAr = NULL,
  		**aAr = NULL;
  WlzObject     *aObj = NULL;
  WlzErrorNum   errNum = WLZ_ERR_NONE;

  if(gObj == NULL)
  {
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else if(gObj->domain.core == NULL)
  {
    errNum = WLZ_ERR_DOMAIN_NULL;
  }
  else if(gObj->values.core == NULL)
  {
    errNum = WLZ_ERR_VALUES_NULL;
  }
  if(errNum == WLZ_ERR_NONE)
  {
    box = WlzBoundingBox2I(gObj, &errNum);
    aSz.vtX = box.xMax - box.xMin + 1;
    aSz.vtY = box.yMax - box.yMin + 1;
    /* Make sure aSz is even in x and y. */
    if((aSz.vtX & 1) != 0)
    {
      aSz.vtX += 1;
    }
    if((aSz.vtY & 1) != 0)
    {
      aSz.vtY += 1;
    }
    wOrg.vtX = box.xMin - (aSz.vtX / 2);
    wOrg.vtY = box.yMin - (aSz.vtY / 2);
    wSz.vtX = aSz.vtX * 2;
    wSz.vtY = aSz.vtY * 2;
    (void )AlgBitNextPowerOfTwo((unsigned int *)&(wSz.vtX), wSz.vtX);
    (void )AlgBitNextPowerOfTwo((unsigned int *)&(wSz.vtY), wSz.vtY);
    errNum = WlzToArray2D((void ***)&wAr, gObj, wSz, wOrg, 0, WLZ_GREY_DOUBLE);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    (void )AlgAutoCorrelate2D(wAr, wSz.vtX, wSz.vtY);
    if(AlcDouble2Malloc(&aAr, aSz.vtY, aSz.vtX) != ALC_ER_NONE)
    {
      errNum = WLZ_ERR_MEM_ALLOC;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    WlzAutoCorRearrange2D(aAr, aSz, wAr, wSz);
    aOrg.vtX = -(aSz.vtX / 2);
    aOrg.vtY = -(aSz.vtY / 2);
    aObj = WlzFromArray2D((void **)aAr, aSz, aOrg,
                          WLZ_GREY_DOUBLE, WLZ_GREY_DOUBLE, 0.0, 1.0,
			  0, 0, &errNum);
  }
  if(errNum != WLZ_ERR_NONE)
  {
    if(aObj != NULL)
    {
      (void )WlzFreeObj(aObj);
    }
  }
  (void )Alc2Free((void **)wAr);
  (void )Alc2Free((void **)aAr);
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(aObj);
}
예제 #3
0
int		main(int argc, char *argv[])
{
  int		iX,
		iY,
  		oX,
  		oY,
		rep,
		option,
		ok = 1,
		usage = 0,
		nRep = 16,
             	dataSz = 256,
  		dataSz2,
		dataSz3,
		dataSz4;
  long		seed;
  double	sum;
  double	**data0 = NULL,
  		**data1 = NULL;
  AlgError	errNum = ALG_ERR_NONE;
  static char	optList[] = "hn:s:";

  while(ok && ((option = getopt(argc, argv, optList)) != -1))
  {
    switch(option)
    {
      case 'n':
        if(sscanf(optarg, "%d", &nRep) != 1)
	{
	  usage = 1;
	}
	break;
      case 's':
        if(sscanf(optarg, "%ld", &seed) != 1)
	{
	  usage = 1;
	}
	break;
      case 'h': /* FALLTHROUGH */
      default:
	usage = 1;
	break;
    }
  }
  ok = (usage == 0);
  if(ok)
  {
    dataSz2 = (dataSz - 1) / 2;
    dataSz3 = (dataSz - 1) / 3;
    dataSz4 = (dataSz - 1) / 4;
    AlgRandSeed(seed);
    if((AlcDouble2Malloc(&data0, dataSz, dataSz) != ALC_ER_NONE) ||
       (AlcDouble2Malloc(&data1, dataSz, dataSz) != ALC_ER_NONE))
    {
      ok = 0;
      (void )fprintf(stderr, "%s: Failed to allocate data arrays.\n",* argv);
    }
  }
  if(ok)
  {
    for(rep = 0; rep < nRep; ++rep)
    {
      iX = (int )(dataSz4 * (0.5 - AlgRandUniform()));
      iY = (int )(dataSz4 * (0.5 - AlgRandUniform()));
      for(oY = 0; oY < dataSz; ++oY)
      {
	for(oX = 0; oX < dataSz; ++oX)
	{
	  *(*(data0 + oY) + oX) = 0.0;
	  *(*(data1 + oY) + oX) = 0.0;
        }
      }
      *(*(data0 + dataSz2 + iY) + dataSz2 + iX) = 1.0;
      *(*(data1 + dataSz2) + dataSz2) = 1.0;
      errNum = AlgCrossCorrelate2D(data0, data1, dataSz, dataSz);
      if(errNum == ALG_ERR_NONE)
      {
	sum = 0;
	for(oY = 0; oY < dataSz; ++oY)
	{
	  for(oX = 0; oX < dataSz; ++oX)
	  {
	    sum += *(*(data0 + oY) + oX);
	  }
	}
	if(sum < 1.0)
	{
	  sum = 1.0;
	}
	AlgCrossCorrPeakXY(&oX, &oY, NULL, data0, dataSz, dataSz,
			   dataSz3, dataSz3);
	(void )fprintf(stderr, "%d %d %d %d", iX, iY, oX, oY);
	if((iX != oX) || (iY != oY))
	{
	  (void )fprintf(stderr, " 0\n");
	}
	else
	{
	  (void )fprintf(stderr, " 1\n");
	}
      }
    }
  }
  if(usage)
  {
    (void )fprintf(stderr,
    "Usage: %s%s",
    *argv,
    " [-h] [-n #] [-s #]\n"
    "Options:\n"
    "  -h   Prints this usage information.\n"
    "  -n  Number of repeats.\n"
    "  -s  Seed for random number generator.\n"
    "Tests AlgCrossCorrelate2D() and AlgCrossCorrPeakXY() by creating\n"
    "arrays with a single non-zero value, in one of which the non-zero\n"
    "value is offset. The output consists of the offset, the computed\n"
    "offset and finaly 1 if the two are equal or 0 if they are not.\n");
  }
  return(!ok);
}
예제 #4
0
/*!
* \return	New Woolz domain object with maximal domain and grey
*		values which encode the gradient's direction or NULL
*		on error.
* \ingroup	WlzFeatures
* \brief	Computes the maximal domain and gradient direction of
*               given Woolz 2D domain object.
* \note         All the objects domains are known to be the same.
* \param	grdM			Gradient magnitude.
* \param	grdY			Gradient (partial derivative)
*                                       through lines.
* \param	grdX			Gradient (partial derivative)
*                                       through columns.
* \param	minThrV			Minimum gradient value to
*                                       consider.
* \param	dstErr			Destination error pointer, may
*                                       be null.
*/
static WlzObject *WlzNMSuppress2D(WlzObject *grdM,
				  WlzObject *grdY, WlzObject *grdX,
				  WlzPixelV minThrV, WlzErrorNum *dstErr)
{
  int		idN,
		inLen,
		outLen,
  		inLnIdx = 0;
  WlzGreyType	gType,
  		bufType;
  WlzIVertex2	bufSz,
  		inPos,
		outPos,
		orgPos;
  WlzValues	tmpVal;
  WlzDomain	dstDom,
  		grdDom;
  WlzIntervalWSpace tmpIWSp = {0},
  		grdMIWSp = {0},
  		grdYIWSp = {0},
		grdXIWSp = {0};
  WlzGreyWSpace tmpGWSp,
  		grdMGWSp,
  		grdYGWSp,
		grdXGWSp;
  WlzPixelV	zeroV;
  WlzGreyP	grdMBufGP,
  		grdYBufGP,
		grdXBufGP;
  WlzDynItvPool pool;
  WlzObject	*dstObj = NULL,
  		*tmpObj = NULL;
  void 		*grdYBuf = NULL,
		*grdXBuf = NULL;
  void		**grdMBuf = NULL;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  tmpVal.core = NULL;
  pool.itvBlock = NULL;
  dstDom.core = NULL;
  if((grdM->type != WLZ_2D_DOMAINOBJ) ||
     (grdY->type != WLZ_2D_DOMAINOBJ) ||
     (grdX->type != WLZ_2D_DOMAINOBJ))
  {
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else if((grdM->domain.core == NULL) ||
          (grdY->domain.core == NULL) ||
          (grdX->domain.core == NULL))
  {
    errNum = WLZ_ERR_DOMAIN_NULL;
  }
  else if((grdM->values.core == NULL) ||
  	  (grdY->values.core == NULL) ||
	  (grdX->values.core == NULL))
  {
    errNum = WLZ_ERR_VALUES_NULL;
  }
  else
  {
    /* Find required buffer type (WLZ_GREY_DOUBLE or WLZ_GREY_INT). */
    bufType = WLZ_GREY_INT;
    gType = WlzGreyTableTypeToGreyType(grdM->values.core->type, &errNum);
    if(errNum == WLZ_ERR_NONE)
    {
      if((gType == WLZ_GREY_FLOAT) || (gType == WLZ_GREY_DOUBLE))
      {
	bufType = WLZ_GREY_DOUBLE;
      }
      else
      {
	gType = WlzGreyTableTypeToGreyType(grdY->values.core->type, &errNum);
	if(errNum == WLZ_ERR_NONE)
	{
	  if((gType == WLZ_GREY_FLOAT) || (gType == WLZ_GREY_DOUBLE))
	  {
	    bufType = WLZ_GREY_DOUBLE;
	  }
	  else
	  {
	    gType = WlzGreyTableTypeToGreyType(grdX->values.core->type,
	    				       &errNum);
	    if(errNum == WLZ_ERR_NONE)
	    {
	      if((gType == WLZ_GREY_FLOAT) || (gType == WLZ_GREY_DOUBLE))
	      {
		bufType = WLZ_GREY_DOUBLE;
	      }
	    }
	  }
	}
      }
    }
  }
  /* Convert minimum gradient threshold value. */
  if(errNum == WLZ_ERR_NONE)
  {
    if(bufType == WLZ_GREY_INT)
    {
      errNum = WlzValueConvertPixel(&minThrV, minThrV, WLZ_GREY_INT);
    }
    else /* bufType == WLZ_GREY_DOUBLE */
    {
      errNum = WlzValueConvertPixel(&minThrV, minThrV, WLZ_GREY_DOUBLE);
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    grdDom = grdM->domain;
    /* Make destination object with WLZ_GREY_UBYTE greys. */
    zeroV.type = WLZ_GREY_UBYTE;
    zeroV.v.inv = 0;
    tmpVal.v = WlzNewValueTb(grdM, WlzGreyTableType(WLZ_GREY_TAB_RAGR,
						    WLZ_GREY_UBYTE, NULL),
			     zeroV, &errNum);
    if(errNum == WLZ_ERR_NONE)
    {
      /* Use the input domain while calculating the new maximal domain. */
      tmpObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, grdM->domain, tmpVal,
			   NULL, NULL, &errNum);
    }
  }
  /* Initialize the memory pool with some size of block. Any +ve number
   * greater than the maximum number of intervals in any destination line
   * would work but the fewer allocations then the more efficient the code,
   * hence this attempt to guess the required number of intervals in the
   * destination domain. */
  if(errNum == WLZ_ERR_NONE)
  {
    pool.itvsInBlock = (((grdDom.i->lastkl - grdDom.i->kol1 + 1) *
			(grdDom.i->lastln - grdDom.i->line1 + 1)) / 64) +
		       grdDom.i->lastkl - grdDom.i->kol1 + 1024;
  }
  /* Make gradient buffers. */
  if(errNum == WLZ_ERR_NONE)
  {
    bufSz.vtY = 3;
    bufSz.vtX = grdDom.i->lastkl - grdDom.i->kol1 + 1;
    if(bufType == WLZ_GREY_INT)
    {
      if((AlcInt2Malloc((int ***)&grdMBuf,
			bufSz.vtY, bufSz.vtX) != ALC_ER_NONE) ||
	 ((grdYBuf = AlcMalloc(sizeof(int) * bufSz.vtX)) == NULL) ||
	 ((grdXBuf = AlcMalloc(sizeof(int) * bufSz.vtX)) == NULL))
      {
	errNum = WLZ_ERR_MEM_ALLOC;
      }
      else
      {
	grdYBufGP.inp = (int *)grdYBuf;
	grdXBufGP.inp = (int *)grdXBuf;
      }
    }
    else /* bufType == WLZ_GREY_DOUBLE */
    {
      if((AlcDouble2Malloc((double ***)&grdMBuf,
			   bufSz.vtY, bufSz.vtX) != ALC_ER_NONE) ||
	 ((grdYBuf = AlcMalloc(sizeof(double) * bufSz.vtX)) == NULL) ||
	 ((grdXBuf = AlcMalloc(sizeof(double) * bufSz.vtX)) == NULL))
      {
	errNum = WLZ_ERR_MEM_ALLOC;
      }
      else
      {
	grdYBufGP.dbp = (double *)grdYBuf;
	grdXBufGP.dbp = (double *)grdXBuf;
      }
    }
  }
  /* Make destination interval domain with interval lines but not intervals. */
  if(errNum == WLZ_ERR_NONE)
  {
    dstDom.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL,
    				     grdDom.i->line1, grdDom.i->lastln,
				     grdDom.i->kol1, grdDom.i->lastkl,
				     &errNum);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    /* Scan down through the gradient objects. */
    if(((errNum = WlzInitGreyScan(tmpObj,
    				  &tmpIWSp, &tmpGWSp)) == WLZ_ERR_NONE) &&
       ((errNum = WlzInitGreyScan(grdM,
    				  &grdMIWSp, &grdMGWSp)) == WLZ_ERR_NONE) &&
       ((errNum = WlzInitGreyScan(grdY,
    				  &grdYIWSp, &grdYGWSp)) == WLZ_ERR_NONE) &&
       ((errNum = WlzInitGreyScan(grdX,
    				  &grdXIWSp, &grdXGWSp)) == WLZ_ERR_NONE))
    {
      orgPos.vtX = grdDom.i->kol1;
      orgPos.vtY = grdDom.i->line1;
      while((errNum == WLZ_ERR_NONE) &&
            ((errNum = WlzNextGreyInterval(&grdMIWSp)) == WLZ_ERR_NONE))
      {
        inLen = grdMIWSp.rgtpos - grdMIWSp.lftpos + 1;
	inPos.vtX = grdMIWSp.lftpos - orgPos.vtX;
	/* Process any lines between this and the last by clearing the
	 * gradient magnitude buffer . */
	if(grdMIWSp.nwlpos > 0)
	{
	  idN = (grdMIWSp.nwlpos >= 3)? 3: grdMIWSp.nwlpos;
	  while(--idN >= 0)
	  {
	    inPos.vtY = grdMIWSp.linpos - orgPos.vtY - idN;
	    inLnIdx = (3 + inPos.vtY) % 3;
	    if(bufType == WLZ_GREY_INT)
	    {
	      WlzValueSetInt(*((int **)grdMBuf + inLnIdx), 0,
	      		     bufSz.vtX);
	    }
	    else /* bufType == WLZ_GREY_DOUBLE */
	    {
	      WlzValueSetDouble(*((double **)grdMBuf + inLnIdx), 0,
	      			bufSz.vtX);
	    }
	  }
	}
	/* Copy intervals to values buffers. */
	if(bufType == WLZ_GREY_INT)
	{
	  grdMBufGP.inp = *((int **)grdMBuf + inLnIdx);
	}
	else /* bufType == WLZ_GREY_DOUBLE */
	{
	  grdMBufGP.dbp = *((double **)grdMBuf + inLnIdx);
	}
	WlzValueCopyGreyToGrey(grdMBufGP, inPos.vtX, bufType,
			       grdMGWSp.u_grintptr, 0, grdMGWSp.pixeltype,
			       inLen);
	if(grdMIWSp.intrmn == 0)
	{
	  while((errNum == WLZ_ERR_NONE) &&
	        (tmpIWSp.linpos < grdMIWSp.linpos))
	  {
	    outPos.vtY = tmpIWSp.linpos - orgPos.vtY;
	    if(outPos.vtY >= 0)
	    {
	      outLen = tmpIWSp.rgtpos - tmpIWSp.lftpos + 1;
	      outPos.vtX = tmpIWSp.lftpos - orgPos.vtX;
	      WlzValueCopyGreyToGrey(grdYBufGP, 0, bufType,
				     grdYGWSp.u_grintptr, 0,
				     grdYGWSp.pixeltype, outLen);
	      WlzValueCopyGreyToGrey(grdXBufGP, 0, bufType,
				     grdXGWSp.u_grintptr, 0,
				     grdXGWSp.pixeltype, outLen);
	      if(bufType == WLZ_GREY_INT)
	      {
		errNum = WlzNMSuppress2DBufI(dstDom.i,
					     (int **)grdMBuf,
					     (int *)grdYBuf,
					     (int *)grdXBuf,
					     &pool,
					     tmpGWSp.u_grintptr.ubp,
					     outLen, outPos, orgPos,
					     minThrV.v.inv);
	      }
	      else /* bufType == WLZ_GREY_DOUBLE */
	      {
		errNum = WlzNMSuppress2DBufD(dstDom.i,
				    	     (double **)grdMBuf,
				    	     (double *)grdYBuf,
					     (double *)grdXBuf,
					     &pool,
					     tmpGWSp.u_grintptr.ubp,
					     outLen, outPos, orgPos,
					     minThrV.v.dbv);
	      }
	    }
	    if(errNum == WLZ_ERR_NONE)
	    {
	      errNum = WlzNextGreyInterval(&tmpIWSp);
	    }
	    if(errNum == WLZ_ERR_NONE)
	    {
	      errNum = WlzNextGreyInterval(&grdYIWSp);
	    }
	    if(errNum == WLZ_ERR_NONE)
	    {
	      errNum = WlzNextGreyInterval(&grdXIWSp);
	    }
	  }
        }
      }
      if(errNum == WLZ_ERR_EOO)
      {
        errNum = WLZ_ERR_NONE;
      }
    }
    if(tmpIWSp.gryptr == &tmpGWSp)
    {
      (void )WlzEndGreyScan(&tmpIWSp, &tmpGWSp);
    }
    if(grdMIWSp.gryptr == &grdMGWSp)
    {
      (void )WlzEndGreyScan(&grdMIWSp, &grdMGWSp);
    }
    if(grdYIWSp.gryptr == &grdYGWSp)
    {
      (void )WlzEndGreyScan(&grdYIWSp, &grdYGWSp);
    }
    if(grdXIWSp.gryptr == &grdXGWSp)
    {
      (void )WlzEndGreyScan(&grdXIWSp, &grdXGWSp);
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    if((errNum = WlzStandardIntervalDomain(dstDom.i)) == WLZ_ERR_NONE)
    {
      dstObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, dstDom, tmpVal,
			   NULL, NULL, &errNum);
    }
  }
  if(tmpObj)
  {
    WlzFreeObj(tmpObj);
  }
  if(errNum != WLZ_ERR_NONE)
  {
    if(tmpObj == NULL)
    {
      if(dstDom.core)
      {
        (void )WlzFreeDomain(dstDom);
      }
      if(tmpVal.core)
      {
        (void )WlzFreeValues(tmpVal);
      }
    }
  }
  if(grdMBuf)
  {
    Alc2Free(grdMBuf);
  }
  if(grdYBuf)
  {
    AlcFree(grdYBuf);
  }
  if(grdXBuf)
  {
    AlcFree(grdXBuf);
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(dstObj);
}
예제 #5
0
int main(
  int   argc,
  char  **argv)
{
  FILE		*inFile;
  char 		optList[] = "d:m:t:hv";
  int		option;
  WlzErrorNum	errNum=WLZ_ERR_NONE;
  int		verboseFlg=0;
  int		type=1;
  int		numRows=0, numCols=0;
  WlzObject	*obj, *obj1, *obj2, *obj3;
  WlzObject	**rowDoms, **colDoms;
  WlzObjectType	objType;
  double	matchVal=0.0;
  double	s1, s2, s3, s4;
  double	delta=0.01;
  double	**mixing=NULL, **contrib=NULL;
  int		i, j, k, l;
  int		numCatRows=-1, numCatCols=-1;
  WlzDBox3	box1, box2;

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

    case 'd':
      delta = atof(optarg);
      if((delta >= 1.0) || (delta <= 1.0e-10)){
	delta = 0.01;
	fprintf(stderr, "%s: invalid delta, reset to 0.01", argv[0]);
      }
      break;

    case 'm':
      if((inFile = fopen(optarg, "r")) != NULL){
	if( fscanf(inFile, "%d, %d", &numCatCols, &numCatRows) < 2 ){
	  fprintf(stderr, "%s: can't read mixing matrix dimensions\n", argv[0]);
	  usage(argv[0]);
	  return 1;
	}
	AlcDouble2Malloc(&mixing, numCatRows, numCatCols);
	AlcDouble2Malloc(&contrib, numCatRows, numCatCols);
	for(l=0; l < numCatRows; l++){
	  for(k=0; k < numCatCols; k++){
	    if( fscanf(inFile, "%lg,", &(mixing[l][k])) < 1 ){
	      fprintf(stderr, "%s: can't read mixing matrix\n", argv[0]);
	      usage(argv[0]);
	      return 1;
	    }
	  }
	}
	for(l=0; l < numCatRows; l++){
	  for(k=0; k < numCatCols; k++){
	    if( fscanf(inFile, "%lg,", &(contrib[l][k])) < 1 ){
	      fprintf(stderr, "%s: can't read contributing matrix\n", argv[0]);
	      usage(argv[0]);
	      return 1;
	    }
	  }
	}
      }
      else {
	fprintf(stderr, "%s: can't open matrix file\n", argv[0]);
	usage(argv[0]);
	return 1;
      }
      break; 

    case 't':
      type = atoi(optarg);
      break;

    case 'v':
      verboseFlg = 1;
      break;

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

    }
  }

  /* there must be two more arguments */
  if( (argc - optind) < 2 ){
    fprintf(stderr, "%s: not enough arguments\n", argv[0]);
    usage(argv[0]);
    return 1;
  }
  numRows = atoi(*(argv+optind));
  numCols = atoi(*(argv+optind+1));
  if((numRows <= 0) || (numCols <= 0)){
    fprintf(stderr, "%s: both number of rows and columns must be > 0\n", argv[0]);
    usage(argv[0]);
    return 1;
  }

  /* verbose output */
  if( verboseFlg ){
    fprintf(stderr, "%s: parameter values:\n", argv[0]);
    fprintf(stderr, "\ttype = %d, delta = %f\n", type, delta);
    if( type == 6 ){
      fprintf(stderr, "\t mixing matrix:\n");
      for(l=0; l < numCatRows; l++){
	for(k=0; k < numCatCols; k++){
	  fprintf(stderr, "%f, ", mixing[l][k]);
	}
	fprintf(stderr, "\n");
      }
      fprintf(stderr, "\n");
      fprintf(stderr, "\t contributing matrix:\n");
      for(l=0; l < numCatRows; l++){
	for(k=0; k < numCatCols; k++){
	  fprintf(stderr, "%f, ", contrib[l][k]);
	}
	fprintf(stderr, "\n");
      }
    }
  }

  /* get objects from stdin */
  inFile = stdin;
  rowDoms = (WlzObject **) AlcMalloc(sizeof(WlzObject *) * numRows);
  for(i=0; i < numRows; i++){
    if((rowDoms[i] =  WlzReadObj(inFile, &errNum)) != NULL){
    if((i == 0) || (objType == WLZ_EMPTY_OBJ)){
      objType = rowDoms[i]->type;
    }
    if((rowDoms[i]->type != objType) &&
       (rowDoms[i]->type != WLZ_EMPTY_OBJ)){
      fprintf(stderr, "%s: invalid object type: %d\n", argv[0],
	      rowDoms[i]->type);
      usage(argv[0]);
      return 1;
    }
    }
    else {
      fprintf(stderr, "%s: not enough row objects\n", argv[0]);
    }
  }

  /* now the column domains */
  if( type == 5 ){
    colDoms = (WlzObject **) AlcMalloc(sizeof(WlzObject *) * numCols * 2);
    for(i=0; i < numCols*2; i++){
      if((colDoms[i] =  WlzReadObj(inFile, &errNum)) != NULL){
	if((colDoms[i]->type != objType) &&
	   (colDoms[i]->type != WLZ_EMPTY_OBJ)){
	  fprintf(stderr, "%s: invalid object type: %d\n", argv[0],
		  colDoms[i]->type);
	  usage(argv[0]);
	  return 1;
	}
      }
      else {
	fprintf(stderr, "%s: not enough row objects\n", argv[0]);
      }
    }
  }
  else {
    colDoms = (WlzObject **) AlcMalloc(sizeof(WlzObject *) * numCols);
    for(i=0; i < numCols; i++){
      if((colDoms[i] =  WlzReadObj(inFile, &errNum)) != NULL){
	if((colDoms[i]->type != objType) &&
	   (colDoms[i]->type != WLZ_EMPTY_OBJ)){
	  fprintf(stderr, "%s: invalid object type: %d\n", argv[0],
		  colDoms[i]->type);
	  usage(argv[0]);
	  return 1;
	}
      }
      else {
	fprintf(stderr, "%s: not enough row objects\n", argv[0]);
      }
    }
  }

  /* now calculate the match values */
  for(i=0; i < numRows; i ++){
    if( verboseFlg ){
      fprintf(stderr, "%s: start row %d\n", argv[0], i+1);
    }
    obj1 = rowDoms[i];
    for(j=0; j < numCols; j++){
      if( type == 5 ){
	obj2 = colDoms[j*2];
	obj3 = colDoms[j*2 + 1];
      }
      else {
	obj2 = colDoms[j];
      }
      
      switch( type ){
      case 1:
	if((obj = WlzIntersect2(obj1, obj2, &errNum)) != NULL){
	  s1 = WlzSize(obj, &errNum);
	  WlzFreeObj(obj);
	}
	else {
	  s1 = 0;
	}
	if((obj = WlzUnion2(obj1, obj2, &errNum)) != NULL){
	  s2 = WlzSize(obj, &errNum);
	  WlzFreeObj(obj);
	}
	else {
	  s2 = 1;
	}
	matchVal = s1 / s2;
	break;

      case 2:
	if((obj = WlzIntersect2(obj1, obj2, &errNum)) != NULL){
	  s1 = WlzSize(obj, &errNum);
	  WlzFreeObj(obj);
	}
	else {
	  s1 = 0;
	}
	if((obj = WlzUnion2(obj1, obj2, &errNum)) != NULL){
	  s2 = WlzSize(obj, &errNum);
	  WlzFreeObj(obj);
	}
	else {
	  s2 = 1;
	}
	matchVal = s1 / s2;
	if( type == 2 ){
	  s1 = WlzSize(obj1, &errNum);
	  s2 = WlzSize(obj2, &errNum);
	  if( s2 > s1 ){
	    if( matchVal == 0.0 ){
	      matchVal = 10.0;
	    }
	    else {
	      matchVal = 1.0 / matchVal;
	      matchVal = WLZ_MIN(matchVal, 10.0);
	    }
	  }
	}
	break;

      case 3:
	if((obj = WlzIntersect2(obj1, obj2, &errNum)) != NULL){
	  s1 = WlzSize(obj, &errNum);
	  WlzFreeObj(obj);
	}
	else {
	  s1 = 0;
	}
	s2 = WlzSize(obj1, &errNum);
	matchVal = 0.0;
	if( s2 > 0 ){
	  matchVal = s1 / s2;
	}
	break;

      case 4:
	if((obj = WlzIntersect2(obj1, obj2, &errNum)) != NULL){
	  s1 = WlzSize(obj, &errNum);
	  WlzFreeObj(obj);
	}
	else {
	  s1 = 0;
	}
	s2 = WlzSize(obj2, &errNum);
	matchVal = 0.0;
	if( s2 > 0 ){
	  matchVal = s1 / s2;
	}
	break;

      case 5:
	/* this is a coparative measure designed to give a value of 1
	   to a random pattern and between zero and infinite for
	   matches to one or the other. For analysis for clustering
	   probably better to use the logarithm. Zero and infinite are
	   delta and 1/delta. */
	/* must be a third object */
	if( obj3 == NULL ){
	  fprintf(stderr, "%s: for match option 5 3 input object required\n",
		  argv[0]);
	  return 1;
	}
	s1 = WlzSize(obj2, &errNum);
	if((obj = WlzIntersect2(obj1, obj2, &errNum)) != NULL){
	  s2 = WlzSize(obj, &errNum);
	  WlzFreeObj(obj);
	}
	else {
	  s2 = 0.0;
	}
	s3 = WlzSize(obj3, &errNum);
	if((obj = WlzIntersect2(obj1, obj3, &errNum)) != NULL){
	  s4 = WlzSize(obj, &errNum);
	  WlzFreeObj(obj);
	}
	else {
	  s4 = 0.0;
	}
	if((s1 < 0.0) || (s2 < 0.0) || (s3 < 0.0) || (s4 < 0.0)){
	  /* just fail */
	  fprintf(stderr, "%s: something gone wrong, negative size.\n",
		  argv[0]);
	  return 1;
	}
	/* calculating (s2/s1) * (s3/s4) */
	/* if the denominator non-zero then simple formula */
	if( s2 > 0.0 ){
	  if( s4 > 0.0 ){
	    matchVal = (s2/s1) * (s3/s4);
	  }
	  else {
	    matchVal = s2 / s1;
	  }
	}
	else {
	  if( s4 > 0.0 ){
	    matchVal = s3/s4;
	  }
	  else {
	    matchVal = 1.0;
	  }
	}
	matchVal = WLZ_MAX(matchVal, delta);
	matchVal = WLZ_MIN(matchVal, 1.0/delta);
	break;

      case 6:
	/* this requires a mixing and contributing matrix and the images
	   read in must have grey-values set to the right categories */
	if((numCatRows == -1) || (numCatCols == -1) ||
	   (mixing == NULL) || (contrib == NULL)){
	  fprintf(stderr, "%s: bad matrix data\n", argv[0]);
	  usage(argv[0]);
	  return 1;
	}
	matchVal = WlzMixtureValue(obj1, obj2, numCatRows, numCatCols,
				   mixing, contrib, &errNum);
	break;

      case 7:
	box1 = WlzBoundingBox3D(obj1, &errNum);
	box2 = WlzBoundingBox3D(obj2, &errNum);
	s1 = (box1.xMax + box1.xMin)/2.0 - (box2.xMax + box2.xMin)/2.0;
	s2 = (box1.yMax + box1.yMin)/2.0 - (box2.yMax + box2.yMin)/2.0;
	matchVal = sqrt(s1*s1 + s2*s2);
	break;

      case 8:
	if((obj = WlzIntersect2(obj1, obj2, &errNum)) != NULL){
	  s1 = WlzSize(obj, &errNum);
	  WlzFreeObj(obj);
	}
	else {
	  s1 = -1;
	}
	matchVal = s1;
	break;

      default:
	fprintf(stderr, "%s: invalid match type\n", argv[0]);
	usage(argv[0]);
	return 1;
      }

      /* print value */
      fprintf(stdout, "%f", matchVal);
      if( (numCols - j) > 1 ){
	fprintf(stdout, "\t");
      }
      if( verboseFlg ){
	fprintf(stderr, ".");
      }
    }
    fprintf(stdout, "\n");
    if( verboseFlg ){
      fprintf(stderr, "\n%s: completed row %d\n", argv[0], i+1);
    }
  }

  return 0;
}
예제 #6
0
/*!
* \return	The value held in the given Java object.
* \ingroup	JWlz
* \brief	Returns a 2D array built from the given 2D java array.
* \param	jEnv			Given JNI environment ptr.
* \param	cObjName		The Java woolz C object class string.	
* \param	jObjName		The Java woolz Java object class
* 					string.
* \param	jniObjName		The Java woolz JNI object class string.
* \param	idrCnt			Indirection count (ie 1 for *, 2 for
* 					**, ...).
* \param	pKey			Parameter key.
* \param	jWArray			The Java Woolz array.
* \param	wArraySz		The number of elements in the Java
* 					Woolz array.
* \param	isCpy			Destination pointer for JNI copy flag.
*/
jlong 		WlzJavaArray2DGet(JNIEnv *jEnv,
				       char *cObjName,
				       char *jObjName,
				       char *jniObjName,
				       int idrCnt, int pKey,
				       jarray jWArray,
				       WlzIVertex2 wArraySz,
				       jboolean *isCpy)
{
  int		idY,
  		ok = 0;
  void		*bufJ;
  jobject	aryJ1D;
  void		**aryW2D = NULL;
  jlong		rtnVal = 0;

  if(jWArray && (wArraySz.vtX > 0) && (wArraySz.vtY > 0))
  {
    switch(pKey)
    {
      case WLZ_JPM_KEY_BYTE_ARY2:
	ok = AlcChar2Malloc((char ***)&aryW2D,
			    wArraySz.vtY, wArraySz.vtX) == ALC_ER_NONE;
	if(ok)
	{
	  idY = 0;
	  while(ok && (idY < wArraySz.vtY))
	  {
	    ok = ((aryJ1D = (*jEnv)->GetObjectArrayElement(jEnv,
	    					(jobjectArray )jWArray,
						idY)) != NULL) &&
	         ((bufJ = (void *)(*jEnv)->GetByteArrayElements(jEnv,
				    		(jbyteArray )aryJ1D,
						isCpy)) == NULL);
	    if(ok)
	    {
	      (void )memcpy(*((WlzUByte **)aryW2D + idY), bufJ,
	      		    wArraySz.vtX * sizeof(jbyte));
	      if(*isCpy)
	      {
	        (*jEnv)->ReleaseByteArrayElements(jEnv, (jbyteArray )aryJ1D,
						  (jbyte *)bufJ, 0);
	        *isCpy = JNI_FALSE;
	      }
	    }
	    ++idY;
	  }
	}
	break;
      case WLZ_JPM_KEY_SHORT_ARY2:
	ok = AlcShort2Malloc((short ***)&aryW2D,
			     wArraySz.vtY, wArraySz.vtX) == ALC_ER_NONE;
	if(ok)
	{
	  idY = 0;
	  while(ok && (idY < wArraySz.vtY))
	  {
	    ok = ((aryJ1D = (*jEnv)->GetObjectArrayElement(jEnv,
	    					(jobjectArray )jWArray,
						idY)) != NULL) &&
	         ((bufJ = (void *)(*jEnv)->GetShortArrayElements(jEnv,
		 				(jshortArray )aryJ1D,
						isCpy)) != NULL);
	    if(ok)
	    {
	      (void )memcpy(*((WlzUByte **)aryW2D + idY), bufJ,
	      		    wArraySz.vtX * sizeof(short));
	      if(*isCpy)
	      {
	        (*jEnv)->ReleaseShortArrayElements(jEnv,
						(jshortArray )aryJ1D,
						(jshort *)bufJ, 0);
	        *isCpy = JNI_FALSE;
	      }
	    }
	    ++idY;
	  }
	}
	break;
      case WLZ_JPM_KEY_INT_ARY2:
	ok = AlcInt2Malloc((int ***)&aryW2D,
			   wArraySz.vtY, wArraySz.vtX) == ALC_ER_NONE;
	if(ok)
	{
	  idY = 0;
	  while(ok && (idY < wArraySz.vtY))
	  {
	    ok = ((aryJ1D = (*jEnv)->GetObjectArrayElement(jEnv,
	    					(jobjectArray )jWArray,
						idY)) != NULL) &&
	         ((bufJ = (void *)(*jEnv)->GetIntArrayElements(jEnv,
						(jintArray )aryJ1D,
						isCpy)) != NULL);
	    if(ok)
	    {
	      (void )memcpy(*((WlzUByte **)aryW2D + idY), bufJ,
	      		    wArraySz.vtX * sizeof(int));
	      if(*isCpy)
	      {
	        (*jEnv)->ReleaseIntArrayElements(jEnv,
						(jintArray )aryJ1D,
						(jint *)bufJ, 0);
	        *isCpy = JNI_FALSE;
	      }
	    }
	    ++idY;
	  }
	}
	break;
      case WLZ_JPM_KEY_FLOAT_ARY2:
	ok = AlcFloat2Malloc((float ***)&aryW2D,
			     wArraySz.vtY, wArraySz.vtX) == ALC_ER_NONE;
        if(ok)
	{
	  idY = 0;
	  while(ok && (idY < wArraySz.vtY))
	  {
	    ok = ((aryJ1D = (*jEnv)->GetObjectArrayElement(jEnv,
	    					(jobjectArray )jWArray,
						idY)) != NULL) &&
	       ((bufJ = (void *)(*jEnv)->GetFloatArrayElements(jEnv,
						(jfloatArray )aryJ1D,
						 isCpy)) != NULL);
	    if(ok)
	    {
	      (void )memcpy(*((WlzUByte **)aryW2D + idY), bufJ,
	      		    wArraySz.vtX * sizeof(float));
	      if(*isCpy)
	      {
	        (*jEnv)->ReleaseFloatArrayElements(jEnv,
						(jfloatArray )aryJ1D,
						(jfloat *)bufJ, 0);
	        *isCpy = JNI_FALSE;
	      }
	    }
	    ++idY;
	  }
	}
	break;
      case WLZ_JPM_KEY_DOUBLE_ARY2:
	ok = AlcDouble2Malloc((double ***)&aryW2D,
			      wArraySz.vtY, wArraySz.vtX) == ALC_ER_NONE;
	if(ok)
	{
	  idY = 0;
	  while(ok && (idY < wArraySz.vtY))
	  {
	    ok = ((aryJ1D = (*jEnv)->GetObjectArrayElement(jEnv,
	    					(jobjectArray )jWArray,
						idY)) != NULL) &&
	       ((bufJ = (void *)(*jEnv)->GetDoubleArrayElements(jEnv,
						(jdoubleArray )aryJ1D,
						isCpy)) != NULL);
	    if(ok)
	    {
	      (void )memcpy(*((WlzUByte **)aryW2D + idY), bufJ,
	      		    wArraySz.vtX * sizeof(double));
	      if(*isCpy)
	      {
	        (*jEnv)->ReleaseDoubleArrayElements(jEnv,
						(jdoubleArray )aryJ1D,
						(jdouble *)bufJ, 0);
	        *isCpy = JNI_FALSE;
	      }
	    }
	    ++idY;
	  }
	}
	break;
      default:
	break;
    }
    if(ok)
    {
      rtnVal = (jlong )aryW2D;
      *isCpy = JNI_TRUE;
    }
    else if(aryW2D)
    {
      Alc2Free(aryW2D);
    }
  }
  return(rtnVal);
}
예제 #7
0
/*!
* \return	New Woolz domain object with gradient grey values or NULL on
*		error.
* \ingroup      WlzValuesFilters
* \brief	Computes the magnitude of the gray values in the
*               3 given Woolz 2D domain objects.
* \param	srcObj0			First object.
* \param	srcObj1			Second object.
* \param	srcObj2			Third object.
* \param	dstErr			Destination error pointer, may be null.
*/
static WlzObject *WlzGreyMagnitude2D3(WlzObject *srcObj0, WlzObject *srcObj1,
				      WlzObject *srcObj2,
				      WlzErrorNum *dstErr)
{
  int		idN,
		itvLen,
  		bufSz;
  double	**iBufA = NULL;
  WlzObject     *tObj0,
		*istObj = NULL,
                *dstObj = NULL;
  WlzObject	*iObjA[3],
  		*tObjA[3];
  WlzGreyP	tGP0;
  WlzGreyType	dstGType = WLZ_GREY_ERROR;
  WlzGreyType	gTypeA[3];
  WlzPixelV	dstBgd;
  WlzPixelV	bgdA[3];
  WlzValues	dstVal;
  WlzIntervalWSpace dstIWSp;
  WlzGreyWSpace	dstGWSp;
  WlzIntervalWSpace iIWSpA[3];
  WlzGreyWSpace	iGWSpA[3];
  WlzErrorNum   errNum = WLZ_ERR_NONE;

  *(iObjA + 0) = *(iObjA + 1) = *(iObjA + 2) = NULL;
  /* Check source objects. */
  if((srcObj0 == NULL) || (srcObj1 == NULL) ||(srcObj2 == NULL))
  {
    errNum = WLZ_ERR_OBJECT_NULL;;
  }
  else if((srcObj0->type != WLZ_2D_DOMAINOBJ) ||
          (srcObj1->type != WLZ_2D_DOMAINOBJ) ||
          (srcObj2->type != WLZ_2D_DOMAINOBJ))
  {
    errNum = WLZ_ERR_OBJECT_TYPE;
  }
  else if((srcObj0->domain.core == NULL) ||
          (srcObj1->domain.core == NULL) ||
          (srcObj2->domain.core == NULL))
  {
    errNum = WLZ_ERR_DOMAIN_NULL;
  }
  else if((srcObj0->values.core == NULL) ||
          (srcObj1->values.core == NULL) ||
          (srcObj2->values.core == NULL))
  {
    errNum = WLZ_ERR_VALUES_NULL;
  }
  /* Compute the intersection of the source objects. */
  if(errNum == WLZ_ERR_NONE)
  {
    *(tObjA + 0) = srcObj0;
    *(tObjA + 1) = srcObj1;
    *(tObjA + 2) = srcObj2;
    istObj = WlzIntersectN(3, tObjA, 0, &errNum);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    *(iObjA + 0) = WlzMakeMain(WLZ_2D_DOMAINOBJ,
    			       istObj->domain, srcObj0->values,
    			       NULL, NULL, &errNum);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    *(iObjA + 1) = WlzMakeMain(WLZ_2D_DOMAINOBJ,
    			       istObj->domain, srcObj1->values,
    			       NULL, NULL, &errNum);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    *(iObjA + 2) = WlzMakeMain(WLZ_2D_DOMAINOBJ,
    			       istObj->domain, srcObj2->values,
    			       NULL, NULL, &errNum);
  }
  /* Get background value and grey types */
  idN = 0;
  while((errNum == WLZ_ERR_NONE) && (idN < 3))
  {
    tObj0 = *(iObjA + idN);
    *(gTypeA + idN) = WlzGreyTableTypeToGreyType(tObj0->values.core->type,
				                 &errNum);
    if(errNum == WLZ_ERR_NONE)
    {
      *(bgdA + idN) = WlzGetBackground(tObj0, &errNum);
    }
    ++idN;
  }
  /* Promote grey types. */
  if(errNum == WLZ_ERR_NONE)
  {
    if((*(gTypeA + 0) == WLZ_GREY_DOUBLE) ||
       (*(gTypeA + 1) == WLZ_GREY_DOUBLE) ||
       (*(gTypeA + 2) == WLZ_GREY_DOUBLE))
    {
      dstGType = WLZ_GREY_DOUBLE;
    }
    else if((*(gTypeA + 0) == WLZ_GREY_FLOAT) ||
	    (*(gTypeA + 1) == WLZ_GREY_FLOAT) ||
	    (*(gTypeA + 2) == WLZ_GREY_FLOAT))
    {
      dstGType = WLZ_GREY_FLOAT;
    }
    else if((*(gTypeA + 0) == WLZ_GREY_INT) ||
	    (*(gTypeA + 1) == WLZ_GREY_INT) ||
	    (*(gTypeA + 2) == WLZ_GREY_INT))
    {
      dstGType = WLZ_GREY_INT;
    }
    else if((*(gTypeA + 0) == WLZ_GREY_SHORT) ||
	    (*(gTypeA + 1) == WLZ_GREY_SHORT) ||
	    (*(gTypeA + 2) == WLZ_GREY_SHORT))
    {
      dstGType = WLZ_GREY_SHORT;
    }
    else if((*(gTypeA + 0) == WLZ_GREY_UBYTE) ||
	    (*(gTypeA + 1) == WLZ_GREY_UBYTE) ||
	    (*(gTypeA + 2) == WLZ_GREY_UBYTE))
    {
      dstGType = WLZ_GREY_SHORT;
    }
    else
    {
      /* RGBA to be done RAB */
      errNum = WLZ_ERR_GREY_TYPE;
    }
  }
  /* Make destination object with intersection domain and new values. */
  if(errNum == WLZ_ERR_NONE)
  {
    (void )WlzValueConvertPixel(&dstBgd, *(bgdA + 0), dstGType);
    dstVal.v = WlzNewValueTb(*(iObjA + 0),
    			     WlzGreyValueTableType(0, WLZ_GREY_TAB_RAGR,
			     dstGType, NULL),
			     dstBgd, &errNum);
    if(errNum == WLZ_ERR_NONE)
    {
      dstObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, istObj->domain, dstVal,
      			   NULL, NULL, &errNum);
    }
  }
  if(istObj)
  {
    WlzFreeObj(istObj);
  }
  /* Make buffers. */
  if(errNum == WLZ_ERR_NONE)
  {
    bufSz = dstObj->domain.i->lastkl - dstObj->domain.i->kol1 + 1;
    if(AlcDouble2Malloc(&iBufA, 3, bufSz) != ALC_ER_NONE)
    {
      errNum = WLZ_ERR_MEM_ALLOC;
    }
  }
  /* Scan through the objects computing the magnitude. */
  if(errNum == WLZ_ERR_NONE)
  {
    idN = 0;
    while((errNum == WLZ_ERR_NONE) && (idN < 3))
    {
      errNum = WlzInitGreyScan(*(iObjA + idN), iIWSpA + idN, iGWSpA + idN);
      ++idN;
    }
    if(errNum == WLZ_ERR_NONE)
    {
      errNum = WlzInitGreyScan(dstObj, &dstIWSp, &dstGWSp);
    }
    while((errNum == WLZ_ERR_NONE) &&
    	  ((errNum = WlzNextGreyInterval(iIWSpA + 0)) == WLZ_ERR_NONE) &&
	  ((errNum = WlzNextGreyInterval(iIWSpA + 1)) == WLZ_ERR_NONE) &&
	  ((errNum = WlzNextGreyInterval(iIWSpA + 2)) == WLZ_ERR_NONE) &&
	  ((errNum = WlzNextGreyInterval(&dstIWSp)) == WLZ_ERR_NONE))
    {
      itvLen = dstIWSp.rgtpos - dstIWSp.lftpos + 1;
      /* Copy intervals to double buffers. */
      idN = 0;
      while(idN < 3)
      {
	tGP0.dbp = *(iBufA + idN);
        WlzValueCopyGreyToGrey(tGP0, 0,
			       WLZ_GREY_DOUBLE,
			       (iGWSpA + idN)->u_grintptr, 0,
			       (iGWSpA + idN)->pixeltype,
			       itvLen);
        ++idN;
      }
      /* Compute magnitude. */
      WlzBufMagD3(*(iBufA + 0), *(iBufA + 1), *(iBufA + 2), itvLen);
      /* Clamp into destination interval. */
      tGP0.dbp = *(iBufA + 0);
      WlzValueClampGreyIntoGrey(dstGWSp.u_grintptr, 0, dstGWSp.pixeltype,
				tGP0, 0, WLZ_GREY_DOUBLE,
				itvLen);
    }
    if(errNum == WLZ_ERR_EOO)
    {
      errNum = WLZ_ERR_NONE;
    }
  }
  /* Free intersection objects. */
  idN = 0;
  while(idN < 3)
  {
    if(iObjA[idN])
    {
      WlzFreeObj(iObjA[idN]);
    }
    ++idN;
  }
  /* Free buffers. */
  if(iBufA)
  {
    Alc2Free((void **)iBufA);
  }
  /* Tidy up on error. */
  if(dstObj && (errNum != WLZ_ERR_NONE))
  {
    WlzFreeObj(dstObj);
    dstObj = NULL;
  }
  /* Pass back error status. */
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(dstObj);
}