예제 #1
0
WlzObject *WlzRGBABoxThreshold(
  WlzObject	*obj,
  WlzPixelV	lowVal,
  WlzPixelV	highVal,
  WlzErrorNum	*dstErr)
{
  WlzErrorNum	errNum=WLZ_ERR_NONE;
  WlzObject	*rtnObj=NULL;
  int		h, l;
  WlzUInt	combineMode;

  /* check and reset low annd high values */
  l = WLZ_RGBA_RED_GET(lowVal.v.rgbv);
  h = WLZ_RGBA_RED_GET(highVal.v.rgbv);
  if( l > h ){
    WLZ_RGBA_RED_SET(highVal.v.rgbv, l);
    WLZ_RGBA_RED_SET(lowVal.v.rgbv, h);
  }
  l = WLZ_RGBA_GREEN_GET(lowVal.v.rgbv);
  h = WLZ_RGBA_GREEN_GET(highVal.v.rgbv);
  if( l > h ){
    WLZ_RGBA_GREEN_SET(highVal.v.rgbv, l);
    WLZ_RGBA_GREEN_SET(lowVal.v.rgbv, h);
  }
  l = WLZ_RGBA_BLUE_GET(lowVal.v.rgbv);
  h = WLZ_RGBA_BLUE_GET(highVal.v.rgbv);
  if( l > h ){
    WLZ_RGBA_BLUE_SET(highVal.v.rgbv, l);
    WLZ_RGBA_BLUE_SET(lowVal.v.rgbv, h);
  }

  /* set all AND for combine value and call multi-threshold */
  WLZ_RGBA_RGBA_SET(combineMode,
		    WLZ_BO_AND, WLZ_BO_AND, WLZ_BO_AND, 255);
  rtnObj = WlzRGBAMultiThreshold(obj, lowVal, highVal,
				 combineMode, &errNum);

  /* check error and return */
  if( dstErr ){
    *dstErr = errNum;
  }
  return rtnObj;
}
예제 #2
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;
}
예제 #3
0
/*!
* \return	Woolz error code.
* \ingroup	WlzExtFF
* \brief	Writes the given object to a jpeg image.
* \param	fP			Given file stream.
* \param	obj			Given object to be written.
* \param	params			Jpeg parameters string, currently this
*					is a single ascii integer, which should
*					have the range 1 - 100 and rpresents
*					the image quality with 100 being
*					lossless.
*/
WlzErrorNum WlzEffWriteObjJpeg(
  FILE 		*fP,
  WlzObject 	*obj,
  char		*params)
{
  WlzErrorNum			errNum=WLZ_ERR_NONE;
  struct jpeg_compress_struct cinfo;
  struct my_error_mgr		jerr;
  JSAMPARRAY 	buffer = NULL;	/* Output row buffer */
  int		quality = 100;	/* Output quality. */
  int 		row_stride;	/* physical row width in input buffer */
  int		width, height;
  WlzIntervalWSpace	iwsp;
  WlzGreyWSpace		gwsp;
  int		i, j;
  WlzObject	*rectObj=NULL;
  WlzGreyType 	gType = WLZ_GREY_ERROR;

  /* check input */
  if( fP == NULL ){
    errNum = WLZ_ERR_PARAM_NULL;
  }
  if( obj ){
    switch( obj->type ){
    case WLZ_2D_DOMAINOBJ:
      if( obj->domain.core ){
	if( obj->values.core == NULL ){
	  errNum = WLZ_ERR_VALUES_NULL;
	}
	else {
	  WlzIBox2	cutBox;
	  
	  cutBox.xMin = obj->domain.i->kol1;
	  cutBox.yMin = obj->domain.i->line1;
	  cutBox.xMax = obj->domain.i->lastkl;
	  cutBox.yMax = obj->domain.i->lastln;
	  gType = WlzGreyTypeFromObj(obj, &errNum);
	  if((rectObj = WlzCutObjToBox2D(obj, cutBox, gType,
					 0, 0.0, 0.0, &errNum)) != NULL){
	    width = rectObj->domain.i->lastkl - rectObj->domain.i->kol1 + 1;
	    height = rectObj->domain.i->lastln - rectObj->domain.i->line1 + 1;
	  }
	}
      }
      else {
	errNum = WLZ_ERR_DOMAIN_NULL;
      }
      break;

    case WLZ_TRANS_OBJ:
      errNum = WlzEffWriteObjJpeg(fP, obj->values.obj, params);
      break;

    case WLZ_EMPTY_OBJ:
      return WLZ_ERR_NONE;

    default:
      errNum = WLZ_ERR_OBJECT_TYPE;
      break;
    }
  }
  else {
    errNum = WLZ_ERR_OBJECT_NULL;
  }

  /* We set up the normal JPEG error routines, then override error_exit. */
  if( errNum == WLZ_ERR_NONE ){
    cinfo.err = jpeg_std_error(&jerr.pub);
    jerr.pub.error_exit = my_error_exit;
    /* Establish the setjmp return context for my_error_exit to use. */
    if (setjmp(jerr.setjmp_buffer)) {
      /* If we get here, the JPEG code has signaled an error.
       * We need to clean up the JPEG object, close the input file, and return.
       */
      jpeg_destroy_compress(&cinfo);
      if( rectObj ){
	WlzFreeObj(rectObj);
      }
      errNum = WLZ_ERR_WRITE_INCOMPLETE;
    }
  }

  if( errNum == WLZ_ERR_NONE ){
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, fP);

    /* set the image parameters */
    width = obj->domain.i->lastkl - obj->domain.i->kol1 + 1;
    height = obj->domain.i->lastln - obj->domain.i->line1 + 1;
    cinfo.image_width = width;
    cinfo.image_height = height;
    switch( gType ){
    case WLZ_GREY_INT:
    case WLZ_GREY_SHORT:
    case WLZ_GREY_FLOAT:
    case WLZ_GREY_DOUBLE:
      errNum = WLZ_ERR_UNIMPLEMENTED;
      break;

    case WLZ_GREY_UBYTE:
      cinfo.input_components = 1;
      cinfo.in_color_space = JCS_GRAYSCALE;
      break;

    case WLZ_GREY_RGBA:
      cinfo.input_components = 3;
      cinfo.in_color_space = JCS_RGB;
      break;
    default:
      break;
    }

    if( errNum == WLZ_ERR_NONE ){
      /* set the default parameters */
      jpeg_set_defaults(&cinfo);

      /* check for other parameters */
      if( params ){
	sscanf(params, "%d", &quality);
      }
      jpeg_set_quality(&cinfo, quality, TRUE);

      /* JSAMPLEs per row in output buffer */
      row_stride = cinfo.image_width * cinfo.input_components;
      /* Make a one-row-high sample array that will go away when done with
       * image */
      buffer = (*cinfo.mem->alloc_sarray)
	((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

    }
    else {
      jpeg_destroy_compress(&cinfo);
      if( rectObj ){
	WlzFreeObj(rectObj);
      }
    }
  }

  if( errNum == WLZ_ERR_NONE ){
    jpeg_start_compress(&cinfo, TRUE);

    /* loop through the woolz object setting the output buffer
       note this is the "input" to the compressor */
    if((errNum = WlzInitGreyScan(rectObj, &iwsp, &gwsp)) == WLZ_ERR_NONE){
      while((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE){
	WlzUInt val;
	switch( gType ){
	case WLZ_GREY_UBYTE:
	  for(i=0, j=0; i < width; i++){
	    buffer[0][j++] = gwsp.u_grintptr.ubp[i];
	  }
	  break;
	case WLZ_GREY_RGBA:
	  for(i=0, j=0; i < width; i++){
	    val = gwsp.u_grintptr.rgbp[i];
	    buffer[0][j++] = WLZ_RGBA_RED_GET(val);
	    buffer[0][j++] = WLZ_RGBA_GREEN_GET(val);
	    buffer[0][j++] = WLZ_RGBA_BLUE_GET(val);
	  }
	  break;
	default:
	  break;
	}
	(void) jpeg_write_scanlines(&cinfo, buffer, 1);
      }

      if( errNum == WLZ_ERR_EOO ){
	errNum = WLZ_ERR_NONE;
      }

    }
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
    WlzFreeObj(rectObj);
  }

  return errNum;
}
예제 #4
0
/*! 
* \ingroup      WlzValuesFilters
* \brief        Perform a 1D convolution on a 1D array of data. Typically
 used to pass to WlzSepTrans(). The params variable is a 1D convolution mask.
*
* \return       Woolz error
* \param    stwspc	Separable transfom work space
* \param    params	parameters passed from top-level calling function,
 unchanged by WlzSepTrans()
* \par      Source:
*                WlzGauss.c
*/  
WlzErrorNum Wlz1DConv(
  WlzSepTransWSpace	*stwspc,
  void			*params)
{
  Wlz1DConvMask	*convParams = (Wlz1DConvMask *) params;
  int 		i, j, n, *mask, factor, length;
  int		intSum;
  double	dblSum;
  WlzGreyP	inbuf, outbuf;
  WlzUInt	red, green, blue;
    
  /* set some local parameters */
  n = convParams->mask_size / 2;
  mask = convParams->mask_values + n;
  factor = convParams->norm_factor;
  inbuf = stwspc->inbuf.p;
  outbuf = stwspc->outbuf.p;
  length = stwspc->len;

  /* calculate the new value  - use int for WlzUByte, short and int
     double otherwise, separate rgb values each use WlzUInt */
  switch( stwspc->inbuf.type ){

  case WLZ_GREY_INT:

    /* first convolve up to the half-width of the mask */
    for(i=0; (i < n) && (i < length); i++){
      intSum = *inbuf.inp * mask[0];
      for(j=1; j <= n; j++){
	intSum += inbuf.inp[(j+i)>(length-1)?-i+length-1:j] * mask[j];
	intSum += inbuf.inp[-((i>j)?j:i)] * mask[-j];
      }
      inbuf.inp++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = intSum/factor;
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(intSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(intSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )(intSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = intSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(intSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }

    /* now the central portion */
    while( i < (length-n-1) ){
      intSum = *inbuf.inp * mask[0];
      for(j=1; j <= n; j++){
	intSum += inbuf.inp[j] * mask[j];
	intSum += inbuf.inp[-j] * mask[-j];
      }
      inbuf.inp++;
      i++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = intSum/factor;
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(intSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(intSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )(intSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = intSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(intSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }   

    /* now the last bit within a half-width of the end */
    while( i < length ){
      intSum = *inbuf.inp * mask[0];
      for(j=1; j <= n; j++){
	intSum += inbuf.inp[(j+i)>(length-1)?-i+length-1:j] * mask[j];
	intSum += inbuf.inp[-j] * mask[-j];
      }
      inbuf.inp++;
      i++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = intSum/factor;
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(intSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(intSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )(intSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = intSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(intSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }      
    break;

  case WLZ_GREY_SHORT:

    /* first convolve up to the half-width of the mask */
    for(i=0; (i < n) && (i < length); i++){
      intSum = *inbuf.shp * mask[0];
      for(j=1; j <= n; j++){
	intSum += inbuf.shp[(j+i)>(length-1)?-i+length-1:j] * mask[j];
	intSum += inbuf.shp[-((i>j)?j:i)] * mask[-j];
      }
      inbuf.shp++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = intSum/factor;
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(intSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(intSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )(intSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = intSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(intSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }

    /* now the central portion */
    while( i < (length-n-1) ){
      intSum = *inbuf.shp * mask[0];
      for(j=1; j <= n; j++){
	intSum += inbuf.shp[j] * mask[j];
	intSum += inbuf.shp[-j] * mask[-j];
      }
      inbuf.shp++;
      i++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = intSum/factor;
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(intSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(intSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ =(float )( intSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = intSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(intSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }   

    /* now the last bit within a half-width of the end */
    while( i < length ){
      intSum = *inbuf.shp * mask[0];
      for(j=1; j <= n; j++){
	intSum += inbuf.shp[(j+i)>(length-1)?-i+length-1:j] * mask[j];
	intSum += inbuf.shp[-j] * mask[-j];
      }
      inbuf.shp++;
      i++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = intSum/factor;
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(intSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(intSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )(intSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = intSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(intSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }      
    break;

  case WLZ_GREY_UBYTE:

    /* first convolve up to the half-width of the mask */
    for(i=0; (i < n) && (i < length); i++){
      intSum = *inbuf.ubp * mask[0];
      for(j=1; j <= n; j++){
	intSum += inbuf.ubp[(j+i)>(length-1)?-i+length-1:j] * mask[j];
	intSum += inbuf.ubp[-((i>j)?j:i)] * mask[-j];
      }
      inbuf.ubp++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = intSum/factor;
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(intSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(intSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )(intSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = intSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(intSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }

    /* now the central portion */
    while( i < (length-n-1) ){
      intSum = *inbuf.ubp * mask[0];
      for(j=1; j <= n; j++){
	intSum += inbuf.ubp[j] * mask[j];
	intSum += inbuf.ubp[-j] * mask[-j];
      }
      inbuf.ubp++;
      i++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = intSum/factor;
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(intSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(intSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )(intSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = intSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(intSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }   

    /* now the last bit within a half-width of the end */
    while( i < length ){
      intSum = *inbuf.ubp * mask[0];
      for(j=1; j <= n; j++){
	intSum += inbuf.ubp[(j+i)>(length-1)?-i+length-1:j] * mask[j];
	intSum += inbuf.ubp[-j] * mask[-j];
      }
      inbuf.ubp++;
      i++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = intSum/factor;
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(intSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(intSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )(intSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = intSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(intSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }      
    break;

  case WLZ_GREY_FLOAT:

    /* first convolve up to the half-width of the mask */
    for(i=0; (i < n) && (i < length); i++){
      dblSum = *inbuf.flp * mask[0];
      for(j=1; j <= n; j++){
	dblSum += inbuf.flp[(j+i)>(length-1)?-i+length-1:j] * mask[j];
	dblSum += inbuf.flp[-((i>j)?j:i)] * mask[-j];
      }
      inbuf.flp++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = (int )(dblSum/factor);
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(dblSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(dblSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )(dblSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = dblSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(dblSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }

    /* now the central portion */
    while( i < (length-n-1) ){
      dblSum = *inbuf.flp * mask[0];
      for(j=1; j <= n; j++){
	dblSum += inbuf.flp[j] * mask[j];
	dblSum += inbuf.flp[-j] * mask[-j];
      }
      inbuf.flp++;
      i++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = (int )(dblSum/factor);
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(dblSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(dblSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )(dblSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = dblSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(dblSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }   

    /* now the last bit within a half-width of the end */
    while( i < length ){
      dblSum = *inbuf.flp * mask[0];
      for(j=1; j <= n; j++){
	dblSum += inbuf.flp[(j+i)>(length-1)?-i+length-1:j] * mask[j];
	dblSum += inbuf.flp[-j] * mask[-j];
      }
      inbuf.flp++;
      i++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = (int )(dblSum/factor);
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(dblSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(dblSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )(dblSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = dblSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(dblSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }      
    break;

  case WLZ_GREY_DOUBLE:

    /* first convolve up to the half-width of the mask */
    for(i=0; (i < n) && (i < length); i++){
      dblSum = *inbuf.dbp * mask[0];
      for(j=1; j <= n; j++){
	dblSum += inbuf.dbp[(j+i)>(length-1)?-i+length-1:j] * mask[j];
	dblSum += inbuf.dbp[-((i>j)?j:i)] * mask[-j];
      }
      inbuf.dbp++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = (int )(dblSum/factor);
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(dblSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(dblSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )(dblSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = dblSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(dblSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }

    /* now the central portion */
    while( i < (length-n-1) ){
      dblSum = *inbuf.dbp * mask[0];
      for(j=1; j <= n; j++){
	dblSum += inbuf.dbp[j] * mask[j];
	dblSum += inbuf.dbp[-j] * mask[-j];
      }
      inbuf.dbp++;
      i++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = (int )(dblSum/factor);
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(dblSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(dblSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )(dblSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = dblSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(dblSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }   

    /* now the last bit within a half-width of the end */
    while( i < length ){
      dblSum = *inbuf.dbp * mask[0];
      for(j=1; j <= n; j++){
	dblSum += inbuf.dbp[(j+i)>(length-1)?-i+length-1:j] * mask[j];
	dblSum += inbuf.dbp[-j] * mask[-j];
      }
      inbuf.dbp++;
      i++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = (int )(dblSum/factor);
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )(dblSum/factor);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )(dblSum/factor);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )(dblSum/factor);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = dblSum/factor;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(dblSum/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, red, red, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }      
    break;

  case WLZ_GREY_RGBA:

    /* first convolve up to the half-width of the mask */
    for(i=0; (i < n) && (i < length); i++){
      red = WLZ_RGBA_RED_GET(*inbuf.rgbp) * mask[0];
      green = WLZ_RGBA_GREEN_GET(*inbuf.rgbp) * mask[0];
      blue = WLZ_RGBA_BLUE_GET(*inbuf.rgbp) * mask[0];
      for(j=1; j <= n; j++){
	red += WLZ_RGBA_RED_GET(inbuf.rgbp[(j+i)>(length-1)?-i+length-1:j])
	  * mask[j];
	red += WLZ_RGBA_RED_GET(inbuf.rgbp[-((i>j)?j:i)]) * mask[-j];
	green += WLZ_RGBA_GREEN_GET(inbuf.rgbp[(j+i)>(length-1)?-i+length-1:j])
	  * mask[j];
	green += WLZ_RGBA_GREEN_GET(inbuf.rgbp[-((i>j)?j:i)]) * mask[-j];
	blue += WLZ_RGBA_BLUE_GET(inbuf.rgbp[(j+i)>(length-1)?-i+length-1:j])
	  * mask[j];
	blue += WLZ_RGBA_BLUE_GET(inbuf.rgbp[-((i>j)?j:i)]) * mask[-j];
      }
      inbuf.rgbp++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = (int )((red+green+blue)/factor/3.0);
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )((red+green+blue)/factor/3.0);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )((red+green+blue)/factor/3.0);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )((red+green+blue)/factor/3.0);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = (red+green+blue)/factor/3.0;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(red/factor, 0, 255);
	green = (WlzUInt )WLZ_CLAMP(green/factor, 0, 255);
	blue = (WlzUInt )WLZ_CLAMP(blue/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, green, blue, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }

    /* now the central portion */
    while( i < (length-n-1) ){
      red = WLZ_RGBA_RED_GET(*inbuf.rgbp) * mask[0];
      green = WLZ_RGBA_GREEN_GET(*inbuf.rgbp) * mask[0];
      blue = WLZ_RGBA_BLUE_GET(*inbuf.rgbp) * mask[0];
      for(j=1; j <= n; j++){
	red += WLZ_RGBA_RED_GET(inbuf.rgbp[j]) * mask[j];
	red += WLZ_RGBA_RED_GET(inbuf.rgbp[-j]) * mask[-j];
	green += WLZ_RGBA_GREEN_GET(inbuf.rgbp[j]) * mask[j];
	green += WLZ_RGBA_GREEN_GET(inbuf.rgbp[-j]) * mask[-j];
	blue += WLZ_RGBA_BLUE_GET(inbuf.rgbp[j]) * mask[j];
	blue += WLZ_RGBA_BLUE_GET(inbuf.rgbp[-j]) * mask[-j];
      }
      inbuf.rgbp++;
      i++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = (int )((red+green+blue)/factor/3.0);
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )((red+green+blue)/factor/3.0);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte )((red+green+blue)/factor/3.0);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )((red+green+blue)/factor/3.0);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = (red+green+blue)/factor/3.0;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(red/factor, 0, 255);
	green = (WlzUInt )WLZ_CLAMP(green/factor, 0, 255);
	blue = (WlzUInt )WLZ_CLAMP(blue/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, green, blue, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }   

    /* now the last bit within a half-width of the end */
    while( i < length ){
      red = WLZ_RGBA_RED_GET(*inbuf.rgbp) * mask[0];
      green = WLZ_RGBA_GREEN_GET(*inbuf.rgbp) * mask[0];
      blue = WLZ_RGBA_BLUE_GET(*inbuf.rgbp) * mask[0];
      for(j=1; j <= n; j++){
	red += WLZ_RGBA_RED_GET(inbuf.rgbp[(j+i)>(length-1)?-i+length-1:j])
	  * mask[j];
	red += WLZ_RGBA_RED_GET(inbuf.rgbp[-j]) * mask[-j];
	green += WLZ_RGBA_GREEN_GET(inbuf.rgbp[(j+i)>(length-1)?-i+length-1:j])
	  * mask[j];
	green += WLZ_RGBA_GREEN_GET(inbuf.rgbp[-j]) * mask[-j];
	blue += WLZ_RGBA_BLUE_GET(inbuf.rgbp[(j+i)>(length-1)?-i+length-1:j])
	  * mask[j];
	blue += WLZ_RGBA_BLUE_GET(inbuf.rgbp[-j]) * mask[-j];
      }
      inbuf.rgbp++;
      i++;
      switch( stwspc->outbuf.type ){
      case WLZ_GREY_INT:
	*outbuf.inp++ = (int )((red+green+blue)/factor/3.0);
	break;
      case WLZ_GREY_SHORT:
	*outbuf.shp++ = (short )((red+green+blue)/factor/3.0);
	break;
      case WLZ_GREY_UBYTE:
	*outbuf.ubp++ = (WlzUByte)((red+green+blue)/factor/3.0);
	break;
      case WLZ_GREY_FLOAT:
	*outbuf.flp++ = (float )((red+green+blue)/factor/3.0);
	break;
      case WLZ_GREY_DOUBLE:
	*outbuf.dbp++ = (red+green+blue)/factor/3.0;
	break;
      case WLZ_GREY_RGBA:
	red = (WlzUInt )WLZ_CLAMP(red/factor, 0, 255);
	green = (WlzUInt )WLZ_CLAMP(green/factor, 0, 255);
	blue = (WlzUInt )WLZ_CLAMP(blue/factor, 0, 255);
	WLZ_RGBA_RGBA_SET(*outbuf.rgbp, red, green, blue, 255);
	outbuf.rgbp++;
	break;
      default:
        return WLZ_ERR_GREY_TYPE;
	break;
      }
    }      
    break;

  default:
    return WLZ_ERR_GREY_TYPE;
    break;
  }

  return WLZ_ERR_NONE;
}
예제 #5
0
XImage *HGU_XmObjToXImageLut2D(
    XWindowAttributes	*win_att,
    WlzObject	*obj,
    HGU_XmLut	lut,
    WlzErrorNum	*dstErr)
{
    XImage		*rtnImage=NULL;
    Dimension		width, height;
    WlzUByte			*data, *dst_data;
    WlzGreyValueWSpace	*gVWSp = NULL;
    WlzErrorNum		errNum=WLZ_ERR_NONE;
    int			i, j;
    int			rIndx=0, gIndx=0, bIndx=0, aIndx=0;
    WlzUInt		r, g, b, a;

    /* allocate space for the data */
    width = obj->domain.i->lastkl - obj->domain.i->kol1 + 1;
    height = obj->domain.i->lastln - obj->domain.i->line1 + 1;
    if( (gVWSp = WlzGreyValueMakeWSp(obj, &errNum)) ) {
        if( (data = (WlzUByte *) AlcMalloc(((win_att->depth == 8)?1:4)
                                           *width*height*sizeof(char))) ) {
            dst_data = data;
            if( (rtnImage = XCreateImage(DisplayOfScreen(win_att->screen),
                                         win_att->visual, win_att->depth,
                                         ZPixmap, 0, (char *) dst_data,
                                         width, height, 8, 0)) ) {

                /* establish rgb index values if 24 bit */
                if( win_att->depth == 24 ) {
                    rIndx = HGU_XmGetColorIndexFromMask24(win_att->visual->red_mask,
                                                          rtnImage->byte_order);
                    gIndx = HGU_XmGetColorIndexFromMask24(win_att->visual->green_mask,
                                                          rtnImage->byte_order);
                    bIndx = HGU_XmGetColorIndexFromMask24(win_att->visual->blue_mask,
                                                          rtnImage->byte_order);
                    aIndx = HGU_XmGetColorIndexFromMask24(~(win_att->visual->red_mask|
                                                            win_att->visual->green_mask|
                                                            win_att->visual->blue_mask),
                                                          rtnImage->byte_order);
                }

                /* fill in the values */
                a = 0xff;
                for(j=0; j < height; j++) {
                    for(i=0; i < width; i++, data++) {
                        WlzGreyValueGet(gVWSp, 0, j + obj->domain.i->line1,
                                        i + obj->domain.i->kol1);
                        switch( gVWSp->gType ) {
                        default:
                        case WLZ_GREY_INT:
                            r = *(gVWSp->gPtr[0].inp);
                            g = b = r;
                            break;
                        case WLZ_GREY_SHORT:
                            r = *(gVWSp->gPtr[0].shp);
                            g = b = r;
                            break;
                        case WLZ_GREY_UBYTE:
                            r = *(gVWSp->gPtr[0].ubp);
                            g = b = r;
                            break;
                        case WLZ_GREY_FLOAT:
                            r = *(gVWSp->gPtr[0].flp);
                            g = b = r;
                            break;
                        case WLZ_GREY_DOUBLE:
                            r = *(gVWSp->gPtr[0].dbp);
                            g = b = r;
                            break;
                        case WLZ_GREY_RGBA:
                            b = *(gVWSp->gPtr[0].rgbp);
                            r = WLZ_RGBA_RED_GET(b);
                            g = WLZ_RGBA_GREEN_GET(b);
                            b = WLZ_RGBA_BLUE_GET(b);
                            break;
                        }

                        switch( lut.core->type ) {
                        case HGU_XmLUT_GREY:
                            r = lut.g->lut[r - lut.g->min];
                            g = lut.g->lut[g - lut.g->min];
                            b = lut.g->lut[b - lut.g->min];
                            break;

                        case HGU_XmLUT_RGB:
                            r = lut.rgb->lut[0][r - lut.rgb->min[0]];
                            g = lut.rgb->lut[1][g - lut.rgb->min[1]];
                            b = lut.rgb->lut[2][b - lut.rgb->min[2]];
                            break;

                        case HGU_XmLUT_COMPOUND:
                            break;
                        }
                        switch( win_att->depth ) {
                        case 24:
                            data[rIndx] = r;
                            data[gIndx] = g;
                            data[bIndx] = b;
                            data[aIndx] = a;
                            data += 3;
                            break;

                        case 8:
                            data[0] = r;
                            break;
                        }
                    }
                }
            }
            else {
                errNum = WLZ_ERR_UNSPECIFIED;
                AlcFree((void *) dst_data);
            }
        }
        else {
            errNum = WLZ_ERR_MEM_ALLOC;
        }
        WlzGreyValueFreeWSp(gVWSp);
    }

    if( dstErr ) {
        *dstErr = errNum;
    }
    return rtnImage;
}
예제 #6
0
파일: WlzSplitObj.c 프로젝트: dscho/Woolz
/*!
* \return	Woolz error code.
* \ingroup	WlzBinaryOps
* \brief	Splits the given montage object into component objects
*		clipped from the montage object.  The montage object
*		must be composed of component images embedded in a
*		background, with little variation in the background
*		values.
* \param	mObj			Montage object, which must be either
*					a WLZ_2D_DOMAINOBJ or a
*					WLZ_3D_DOMAINOBJ with values.
* \param	gapV			Value for the uniform background.
*					Must be either WLZ_GREY_INT or
*					WLZ_GREY_RGBA.
* \param	tol			Tolerance (fraction) for the
*					variation in background values.
* \param	bWidth			Additional boundary width added
*					to detected images before they are
*					clipped.
* \param	minArea			Minimum area for a valid component
*					image, must be greater than zero.
* \param	maxComp			Maximum number of components.
* \param	dstNComp		Destination pointer for the number of
*					components extracted, must not be NULL.
* \param	dstComp			Destination pointer for the extracted
*					components, must not be NULL.
*/
WlzErrorNum 	WlzSplitMontageObj(WlzObject *mObj, WlzPixelV gapV,
				      double tol, int bWidth, int minArea,
				      int maxComp,
				      int *dstNComp, WlzObject ***dstComp)
{
  int		id0,
  		id1,
		area,
		nLComp = 0;
  WlzObject	*gObj = NULL,
  		*tObj = NULL;
  WlzObject	**lComp;
  WlzGreyType	objG;
  WlzBox	box;
  WlzPixelV	gapLV,
  		gapHV;
  WlzConnectType lCon;
  int		tI[8];
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  tol = WLZ_CLAMP(tol, 0.0, 1.0);
  if(mObj == NULL)
  {
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else if(minArea < 1)
  {
    errNum = WLZ_ERR_PARAM_DATA;
  }
  else
  {
    switch(mObj->type)
    {
      case WLZ_2D_DOMAINOBJ:
	lCon = WLZ_4_CONNECTED;
        break;
      case WLZ_3D_DOMAINOBJ:
	lCon = WLZ_6_CONNECTED;
        break;
      default:
        errNum = WLZ_ERR_OBJECT_TYPE;
	break;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    objG = WlzGreyTypeFromObj(mObj, &errNum);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    switch(gapV.type)
    {
      case WLZ_GREY_INT: /* FALLTHROUGH */
      case WLZ_GREY_RGBA:
        break;
      default:
	errNum = WLZ_ERR_GREY_TYPE;
	break;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    if(objG == WLZ_GREY_RGBA)
    {
      if(gapV.type != WLZ_GREY_RGBA)
      {
        (void )WlzValueConvertPixel(&gapV, gapV, WLZ_GREY_RGBA);
      }
    }
    else
    {
      if(gapV.type != WLZ_GREY_INT)
      {
        (void )WlzValueConvertPixel(&gapV, gapV, WLZ_GREY_INT);
      }
    }
    gapLV.type = gapHV.type = gapV.type;
    if(gapV.type == WLZ_GREY_INT)
    {
      tI[0] = gapV.v.inv * tol;
      gapLV.v.inv = gapV.v.inv - tI[0];
      gapHV.v.inv = gapV.v.inv + tI[0];
      tObj = WlzThreshold(mObj, gapLV, WLZ_THRESH_HIGH, &errNum);
      if((errNum == WLZ_ERR_NONE) && (tObj != NULL))
      {
	gObj = WlzThreshold(tObj, gapHV, WLZ_THRESH_LOW, &errNum);
      }
      (void )WlzFreeObj(tObj);
      tObj = NULL;
    }
    else /* gapV.type == WLZ_GREY_RGBA */
    {
	tI[0] = WLZ_RGBA_RED_GET(gapV.v.rgbv);
	tI[1] = (int )floor((double )(tI[0]) * tol);
	tI[2] = tI[0] - tI[1];
	tI[5] = tI[0] + tI[1];
	tI[0] = WLZ_RGBA_GREEN_GET(gapV.v.rgbv);
	tI[1] = (int )floor((double )(tI[0]) * tol);
	tI[3] = tI[0] - tI[1];
	tI[6] = tI[0] + tI[1];
	tI[0] = WLZ_RGBA_BLUE_GET(gapV.v.rgbv);
	tI[1] = (int )floor((double )(tI[0]) * tol);
	tI[4] = tI[0] - tI[1];
	tI[7] = tI[0] + tI[1];
	tI[2] = WLZ_CLAMP(tI[2], 0, 255);
	tI[3] = WLZ_CLAMP(tI[3], 0, 255);
	tI[4] = WLZ_CLAMP(tI[4], 0, 255);
	WLZ_RGBA_RGBA_SET(gapLV.v.rgbv, tI[2], tI[3], tI[4], 255);
	tI[5] = WLZ_CLAMP(tI[5], 0, 255);
	tI[6] = WLZ_CLAMP(tI[6], 0, 255);
	tI[7] = WLZ_CLAMP(tI[7], 0, 255);
	WLZ_RGBA_RGBA_SET(gapHV.v.rgbv, tI[5], tI[6], tI[7], 255);
        gObj = WlzRGBABoxThreshold(mObj, gapLV, gapHV, &errNum);
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    tObj = WlzDiffDomain(mObj, gObj, &errNum);
  }
  (void )WlzFreeObj(gObj);
  if(errNum == WLZ_ERR_NONE)
  {
    errNum = WlzLabel(tObj, &nLComp, &lComp, maxComp, 0, lCon);
  }
  (void )WlzFreeObj(tObj);
  if(errNum == WLZ_ERR_NONE)
  {
    /* Get rid of small objects using minArea as the threshold. */
    id0 = 0;
    id1 = 0;
    while(id0 < nLComp)
    {
      switch((*(lComp + id0))->type)
      {
        case WLZ_2D_DOMAINOBJ:
	  area = WlzArea(*(lComp + id0), NULL);
	  break;
        case WLZ_3D_DOMAINOBJ:
	  area = WlzVolume(*(lComp + id0), NULL);
	  break;
        default:
          area = 0;
	  break;
      }
      if(area >= minArea)
      {
        *(lComp + id1) = *(lComp + id0);
        ++id1;
      }
      else
      {
        (void )WlzFreeObj(*(lComp + id0));
	*(lComp + id0) = NULL;
      }
      ++id0;
    }
    nLComp = id1;
  }
  if(errNum == WLZ_ERR_NONE)
  {
    /* Clip rectangular objects from the montage object. */
    id0 = 0;
    while((errNum == WLZ_ERR_NONE) && (id0 < nLComp))
    {
      if(tObj->type == WLZ_2D_DOMAINOBJ)
      {
        box.i2 = WlzBoundingBox2I(*(lComp + id0), &errNum);
	box.i2.xMin -= bWidth;
	box.i2.yMin -= bWidth;
	box.i2.xMax += bWidth;
	box.i2.yMax += bWidth;
	(void )WlzFreeObj(*(lComp + id0));
	*(lComp + id0) = WlzClipObjToBox2D(mObj, box.i2, &errNum);
      }
      else /* tObj->type == WLZ_3D_DOMAINOBJ */
      {
        box.i3 = WlzBoundingBox3I(*(lComp + id0), &errNum);
	box.i3.xMin -= bWidth;
	box.i3.yMin -= bWidth;
	box.i3.zMin -= bWidth;
	box.i3.xMax += bWidth;
	box.i3.yMax += bWidth;
	box.i3.zMax += bWidth;
	(void )WlzFreeObj(*(lComp + id0));
	*(lComp + id0) = WlzClipObjToBox3D(mObj, box.i3, &errNum);
      }
      ++id0;
    }
  }
  *dstNComp = nLComp;
  *dstComp = lComp;
  return(errNum);
}
예제 #7
0
/*! 
* \ingroup      WlzThreshold
* \brief        Apply independent thresholds to each colour channel
 independently and combine according to the settings encoded in
 combineMode. Each channel can have one of two modes: WLZ_BO_AND
 and WLZ_BO_OR. These are encoded into a single mode variable using
 the RGBA macro, e.g.:
 WLZ_RGBA_RGBA_SET(combineMode, redMode, greenMode, blueMode, 255);

 The macro WLZ_RGBA_RED_GET(combineMode) will return redMode and
 similarly for green and blue.
*
* \return       Thresholded object
* \param    obj	Object to be thresholded
* \param    lowVal	RGB low values
* \param    highVal	RGB high values
* \param    combineMode	Combination rules as an RGBA encoded unsigned integer
* \param    dstErr	Error return
* \par      Source:
*                WlzRGBAThreshold.c
*/
WlzObject *WlzRGBAMultiThreshold(
  WlzObject	*obj,
  WlzPixelV	lowVal,
  WlzPixelV	highVal,
  WlzUInt	combineMode,
  WlzErrorNum	*dstErr)
{
  WlzErrorNum	errNum=WLZ_ERR_NONE;
  WlzObject	*rtnObj=NULL;
  WlzObject	*obj1, *obj2;
  WlzValues	values;
  WlzCompoundArray	*cobj=NULL;
  int		low[3], high[3];
  WlzUInt	mode[3]; 

  /* check inputs */
  if( obj == NULL ){
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else {
    /* must be grey-type RGBA or compound with at least three channels */
    switch( obj->type ){
    case WLZ_2D_DOMAINOBJ:
    case WLZ_3D_DOMAINOBJ:
      if( obj->values.core == NULL ){
	errNum = WLZ_ERR_VALUES_NULL;
      }
      else {
	/* create compound object */
	if((cobj = WlzRGBAToCompound(obj, WLZ_RGBA_SPACE_RGB,
	                             &errNum)) != NULL){
	  cobj = (WlzCompoundArray *) WlzAssignObject((WlzObject *) cobj,
						      &errNum);
	}
      }
      break;

    case WLZ_TRANS_OBJ:
      if((obj1 = WlzRGBAMultiThreshold(obj->values.obj, lowVal, highVal,
				       combineMode, &errNum)) != NULL){
	values.obj = WlzAssignObject(obj1, NULL);
	rtnObj = WlzMakeMain(obj->type, obj->domain, values,
			     NULL, obj, &errNum);
      }
      break;

    case WLZ_COMPOUND_ARR_1:
    case WLZ_COMPOUND_ARR_2:
      cobj = (WlzCompoundArray *) WlzAssignObject(obj, &errNum);
      if( cobj->n < 3 ){
	errNum = WLZ_ERR_OBJECT_DATA;
	WlzFreeObj((WlzObject *) cobj);
      }
      else if((cobj->o[0]->values.core == NULL) ||
	      (cobj->o[1]->values.core == NULL) ||
	      (cobj->o[2]->values.core == NULL)){
	errNum = WLZ_ERR_VALUES_NULL;
      }
      break;

    case WLZ_EMPTY_OBJ:
      rtnObj = WlzMakeEmpty(&errNum);
      break;

    default:
      errNum = WLZ_ERR_OBJECT_TYPE;
      break;
    }
  }

  if((errNum == WLZ_ERR_NONE) && (rtnObj == NULL)){
    if((lowVal.type != WLZ_GREY_RGBA) ||
       (highVal.type != WLZ_GREY_RGBA)){
      errNum = WLZ_ERR_PARAM_TYPE;
    }
    else {
      low[0] = WLZ_RGBA_RED_GET(lowVal.v.rgbv);
      low[1] = WLZ_RGBA_GREEN_GET(lowVal.v.rgbv);
      low[2] = WLZ_RGBA_BLUE_GET(lowVal.v.rgbv);
      high[0] = WLZ_RGBA_RED_GET(highVal.v.rgbv);
      high[1] = WLZ_RGBA_GREEN_GET(highVal.v.rgbv);
      high[2] = WLZ_RGBA_BLUE_GET(highVal.v.rgbv);
    }
  }

  if((errNum == WLZ_ERR_NONE) && (rtnObj == NULL)){
    mode[0] = WLZ_RGBA_RED_GET(combineMode);
    mode[1] = WLZ_RGBA_GREEN_GET(combineMode);
    mode[2] = WLZ_RGBA_BLUE_GET(combineMode);
  }

  /* get thresholded channels */
  if((errNum == WLZ_ERR_NONE) &&
     (cobj != NULL) && (rtnObj == NULL)){
    WlzObject	*objs[3];
    int		i;
    WlzPixelV	threshV;

    for(i=0; i < 3; i++){
      threshV.type = WLZ_GREY_INT;
      threshV.v.inv = low[i];
      if((obj1 = WlzThreshold(cobj->o[i], threshV, WLZ_THRESH_HIGH,
      			      &errNum)) != NULL){
	obj1 = WlzAssignObject(obj1, &errNum);
	threshV.v.inv = high[i] + 1;
	if((obj2 = WlzThreshold(obj1, threshV, WLZ_THRESH_LOW,
	                        &errNum)) != NULL){
	  objs[i] = WlzAssignObject(obj2, &errNum);
	}
	else {
	  objs[i] = NULL;
	}
	WlzFreeObj(obj1);
      }
      else {
	objs[i] = NULL;
      }
    }

    /* combine according to mode
       what to do here? AND against a channel implies that the threshold
       constraint must be satisfied, OR implies it may be satisfied so
       all AND implies intersection, all OR implies union. Otherwise union
       of ORs and intersect with the ANDs. What about XOR? */
    /* find union of all then intersect with ANDs */
    obj1 = WlzAssignObject(WlzMakeEmpty(&errNum), NULL);
    for(i=0; (i < 3) && (errNum == WLZ_ERR_NONE); i++){
      if( objs[i] ){
	obj2 = WlzUnion2(obj1, objs[i], &errNum);
	WlzFreeObj(obj1);
	obj1 = WlzAssignObject(obj2, &errNum);
      }
    }
    for(i=0; i < 3; i++){
      if( objs[i] ){
	if( (mode[i] == WLZ_BO_AND) && (errNum == WLZ_ERR_NONE) ){
	  obj2 = WlzIntersect2(obj1, objs[i], &errNum);
	  WlzFreeObj(obj1);
	  obj1 = WlzAssignObject(obj2, &errNum);
	}
	WlzFreeObj(objs[i]);
      }
    }

    /* create the return object and add grey-table if possible */
    if( obj1 ){
      if( WlzIsEmpty(obj1, &errNum) ){
	rtnObj = WlzMakeMain(obj1->type, obj1->domain, obj1->values,
			     NULL, NULL, &errNum);
      }
      else {
	if( obj1->type == obj->type ){
	  rtnObj = WlzMakeMain(obj1->type, obj1->domain, obj->values,
			       NULL, NULL, &errNum);
	}
	else {
	  rtnObj = WlzMakeMain(obj1->type, obj1->domain, obj1->values,
			       NULL, NULL, &errNum);
	}
      }
      WlzFreeObj(obj1);
    }
  }

  if( cobj ){
    WlzFreeObj((WlzObject *) cobj);
  }

  /* check error and return */
  if( dstErr ){
    *dstErr = errNum;
  }
  return rtnObj;
}
예제 #8
0
int WlzVectorThreshCb(
  WlzObject	*obj,
  void		*clientData,
  WlzThreshCbStr	*cbs)
{
  WlzVectorThresholdStruct *vts=(WlzVectorThresholdStruct *) clientData;
  int		i, rtnVal=-1;
  double	d, d1, vect[3];
  WlzUInt	val;

  switch( cbs->pix.type ){
  case WLZ_GREY_INT:
    vect[0] = vect[1] = vect[2] = *(cbs->pix.p.inp);
    break;
  case WLZ_GREY_SHORT:
    vect[0] = vect[1] = vect[2] = *(cbs->pix.p.shp);
    break;
  case WLZ_GREY_UBYTE:
    vect[0] = vect[1] = vect[2] = *(cbs->pix.p.ubp);
    break;
  case WLZ_GREY_FLOAT:
    vect[0] = vect[1] = vect[2] = *(cbs->pix.p.flp);
    break;
  case WLZ_GREY_DOUBLE:
    vect[0] = vect[1] = vect[2] = *(cbs->pix.p.dbp);
    break;
  case WLZ_GREY_RGBA:
    val = *(cbs->pix.p.rgbp);
    vect[0] = WLZ_RGBA_RED_GET(val);
    vect[1] = WLZ_RGBA_GREEN_GET(val);
    vect[2] = WLZ_RGBA_BLUE_GET(val);
    break;
  default:
    break;
  }

  /* calculate threshold rule */
  switch( vts->type ){
  case WLZ_RGBA_THRESH_SPHERE:
    for(i=0, d=0.0; i < 3; i++){
      d1 = vect[i] - vts->origin[i];
      d += d1 * d1;
    }
    break;

  case WLZ_RGBA_THRESH_SLICE:
    for(i=0, d=0.0; i < 3; i++){
      d += (vect[i] - vts->origin[i]) * vts->direction[i];
    }
    break;

  default:
    rtnVal = -1;
    break;
  }
  if((d >= 0.0) && (d <= vts->dist)){
    rtnVal = 1;
  }
  else {
    rtnVal = 0;
  }

  return rtnVal;
}
예제 #9
0
/*! 
* \ingroup      WlzValuesUtils
* \brief        Calculate the pixel value for a given channel.
For grey-pixel types the colour channel values are set equal to the
 grey value i.e. the pixel is assumed to be (g,g,g). If the grey-channel
 is requested of a colour pixel the modulus is returned. For colour
 pixels the error return value is -1, for grey pixels the error return
 should be tested since all values are valid (except grey-type WlzUByte).
 Hue and saturation are zero for grey-pixel types.
*
* \return       requested value of pixel
* \param    pixVal	input pixel value structure
* \param    chan        requested pixel channel
* \param    dstErr	error destination
* \par      Source:
*                WlzRGBAPixelUtils.c
*/
double WlzRGBAPixelValue(
  WlzPixelV		pixVal,
  WlzRGBAColorChannel	chan,
  WlzErrorNum		*dstErr)
{
  WlzErrorNum	errNum=WLZ_ERR_NONE;
  double	val=-1;
  int		col[3];

  switch( pixVal.type ){
  case WLZ_GREY_INT:
    switch( chan ){
    case WLZ_RGBA_CHANNEL_HUE:
    case WLZ_RGBA_CHANNEL_SATURATION:
      val = 0.0;
      break;

    default:
      val = pixVal.v.inv;
      break;
    }
    break;

  case WLZ_GREY_SHORT:
    switch( chan ){
    case WLZ_RGBA_CHANNEL_HUE:
    case WLZ_RGBA_CHANNEL_SATURATION:
      val = 0.0;
      break;

    default:
      val = pixVal.v.shv;
      break;
    }
    break;

  case WLZ_GREY_UBYTE:
    switch( chan ){
    case WLZ_RGBA_CHANNEL_HUE:
    case WLZ_RGBA_CHANNEL_SATURATION:
      val = 0.0;
      break;

    default:
      val = pixVal.v.ubv;
      break;
    }
    break;

  case WLZ_GREY_FLOAT:
    switch( chan ){
    case WLZ_RGBA_CHANNEL_HUE:
    case WLZ_RGBA_CHANNEL_SATURATION:
      val = 0.0;
      break;

    default:
      val = pixVal.v.flv;
      break;
    }
    break;

  case WLZ_GREY_DOUBLE:
    switch( chan ){
    case WLZ_RGBA_CHANNEL_HUE:
    case WLZ_RGBA_CHANNEL_SATURATION:
      val = 0.0;
      break;

    default:
      val = pixVal.v.dbv;
      break;
    }
    break;

  case WLZ_GREY_RGBA:
    switch( chan ){
    case WLZ_RGBA_CHANNEL_GREY:
      /* ????? */
      val = WLZ_RGBA_MODULUS(pixVal.v.rgbv);
      break;

    case WLZ_RGBA_CHANNEL_RED:
      val = WLZ_RGBA_RED_GET(pixVal.v.rgbv);
      break;

    case WLZ_RGBA_CHANNEL_GREEN:
      val = WLZ_RGBA_GREEN_GET(pixVal.v.rgbv);
      break;

    case WLZ_RGBA_CHANNEL_BLUE:
      val = WLZ_RGBA_BLUE_GET(pixVal.v.rgbv);
      break;

    case WLZ_RGBA_CHANNEL_HUE:
      col[0] = WLZ_RGBA_RED_GET(pixVal.v.rgbv);
      col[1] = WLZ_RGBA_GREEN_GET(pixVal.v.rgbv);
      col[2] = WLZ_RGBA_BLUE_GET(pixVal.v.rgbv);
      WlzRGBAConvertRGBToHSV_UBYTENormalised(col);
      val = col[0];
      break;

    case WLZ_RGBA_CHANNEL_SATURATION:
      col[0] = WLZ_RGBA_RED_GET(pixVal.v.rgbv);
      col[1] = WLZ_RGBA_GREEN_GET(pixVal.v.rgbv);
      col[2] = WLZ_RGBA_BLUE_GET(pixVal.v.rgbv);
      WlzRGBAConvertRGBToHSV_UBYTENormalised(col);
      val = col[1];
      break;

    case WLZ_RGBA_CHANNEL_BRIGHTNESS:
      col[0] = WLZ_RGBA_RED_GET(pixVal.v.rgbv);
      col[1] = WLZ_RGBA_GREEN_GET(pixVal.v.rgbv);
      col[2] = WLZ_RGBA_BLUE_GET(pixVal.v.rgbv);
      WlzRGBAConvertRGBToHSV_UBYTENormalised(col);
      val = col[2];
      break;

    case WLZ_RGBA_CHANNEL_CYAN:
      val = (WLZ_RGBA_BLUE_GET(pixVal.v.rgbv) +
	     WLZ_RGBA_GREEN_GET(pixVal.v.rgbv)) / 2;
      break;

    case WLZ_RGBA_CHANNEL_MAGENTA:
      val = (WLZ_RGBA_BLUE_GET(pixVal.v.rgbv) +
	     WLZ_RGBA_RED_GET(pixVal.v.rgbv)) / 2;
      break;

    case WLZ_RGBA_CHANNEL_YELLOW:
      val = (WLZ_RGBA_RED_GET(pixVal.v.rgbv) +
	     WLZ_RGBA_GREEN_GET(pixVal.v.rgbv)) / 2;
      break;

    default:
      errNum = WLZ_ERR_GREY_TYPE;
      break;

    }
    break;

  case WLZ_GREY_BIT:
  default:
    errNum = WLZ_ERR_GREY_TYPE;
    break;
  }
  if(errNum == WLZ_ERR_NONE){
    if( val < 0 ){
      val = -1.0;
      errNum = WLZ_ERR_GREY_DATA;
    }
  }

  if( dstErr ){
    *dstErr = errNum;
  }
  return val;
}
예제 #10
0
/*! 
* \ingroup      WlzValuesUtils
* \brief        Convert a RGBA image to a compound object. The RGBA
*		 channels are at array indices 0,1,2,3 respectively
*		 and the sub-object grey types will be WLZ_GREY_UBYTE.
*
* \return       Compound array of rgba values
* \param    obj				Input domain object with value type
* 					WLZ_GREY_RGBA
* \param    colSpc			The colour space.
* \param    dstErr			Destination error ponyer, may be NULL.
*/
WlzCompoundArray *WlzRGBAToCompound(
  WlzObject	*obj,
  WlzRGBAColorSpace	colSpc,
  WlzErrorNum	*dstErr)
{
  WlzCompoundArray	*cobj=NULL;
  WlzErrorNum		errNum=WLZ_ERR_NONE;

  /* check object type, and value type */
  if( obj ){
    switch( obj->type ){
    case WLZ_2D_DOMAINOBJ:
      if( obj->domain.core == NULL ){
	errNum = WLZ_ERR_DOMAIN_NULL;
      }
      else if ( obj->values.core == NULL ){
	errNum = WLZ_ERR_VALUES_NULL;
      }
      else if( WlzGreyTypeFromObj(obj, &errNum) != WLZ_GREY_RGBA ){
	errNum = WLZ_ERR_VALUES_TYPE;
      }
      break;

    case WLZ_3D_DOMAINOBJ:
      if( obj->domain.core == NULL ){
	errNum = WLZ_ERR_DOMAIN_NULL;
      }
      else if( obj->domain.p->type != WLZ_PLANEDOMAIN_DOMAIN ){
	errNum = WLZ_ERR_DOMAIN_TYPE;
      }
      else if ( obj->values.core == NULL ){
	errNum = WLZ_ERR_VALUES_NULL;
      }
      else if( obj->values.vox->type != WLZ_VOXELVALUETABLE_GREY ){
	errNum = WLZ_ERR_VALUES_TYPE;
      }
      else if( WlzGreyTypeFromObj(obj, &errNum) != WLZ_GREY_RGBA ){
	errNum = WLZ_ERR_VALUES_TYPE;
      }
      return WlzRGBAToCompound3D(obj, colSpc, dstErr);

    case WLZ_TRANS_OBJ:
      /* not difficult, do it later */
      errNum = WLZ_ERR_OBJECT_TYPE;
      break;

    case WLZ_COMPOUND_ARR_1:
    case WLZ_COMPOUND_ARR_2:
      /* bit recursive this ! */
      errNum = WLZ_ERR_OBJECT_TYPE;
      break;

    case WLZ_EMPTY_OBJ:
      return (WlzCompoundArray *) WlzMakeEmpty(dstErr);

    default:
      errNum = WLZ_ERR_OBJECT_TYPE;
    }
  }
  else {
    errNum = WLZ_ERR_OBJECT_NULL;
  }

  /* check colour space */
  if( errNum == WLZ_ERR_NONE ){
    switch( colSpc ){
    case WLZ_RGBA_SPACE_RGB:
    case WLZ_RGBA_SPACE_HSB:
    case WLZ_RGBA_SPACE_CMY:
      break;

    default:
      errNum = WLZ_ERR_PARAM_DATA;
      break;
    }
  }

  /* create compound object return */
  if( errNum == WLZ_ERR_NONE ){
    WlzValues	values;
    WlzObject	*objs[4];
    WlzObjectType	type;
    WlzPixelV	oldBck, newBck;

    type = WlzGreyTableType(
      WlzGreyTableTypeToTableType(obj->values.core->type, &errNum),
      WLZ_GREY_UBYTE, &errNum);
    oldBck = WlzGetBackground(obj, &errNum);

    /* red */
    newBck.type = WLZ_GREY_UBYTE;
    newBck.v.ubv = (WlzUByte )WLZ_RGBA_RED_GET(oldBck.v.rgbv);
    values.v = WlzNewValueTb(obj, type, newBck, &errNum);
    objs[0] = WlzMakeMain(obj->type, obj->domain, values,
			  NULL, NULL, &errNum);
    /* green */
    newBck.v.ubv = (WlzUByte )WLZ_RGBA_GREEN_GET(oldBck.v.rgbv);
    values.v = WlzNewValueTb(obj, type, newBck, &errNum);
    objs[1] = WlzMakeMain(obj->type, obj->domain, values,
			  NULL, NULL, &errNum);
    /* blue */
    newBck.v.ubv = (WlzUByte )WLZ_RGBA_BLUE_GET(oldBck.v.rgbv);
    values.v = WlzNewValueTb(obj, type, newBck, &errNum);
    objs[2] = WlzMakeMain(obj->type, obj->domain, values,
			  NULL, NULL, &errNum);
    /* alpha */
    newBck.v.ubv = (WlzUByte )WLZ_RGBA_ALPHA_GET(oldBck.v.rgbv);
    values.v = WlzNewValueTb(obj, type, newBck, &errNum);
    objs[3] = WlzMakeMain(obj->type, obj->domain, values,
			  NULL, NULL, &errNum);

    /* create compound object, object pointers are assigned for mode=3
       so no need to free objects */
    cobj = WlzMakeCompoundArray(WLZ_COMPOUND_ARR_1, 3, 4, &(objs[0]),
				 obj->type, &errNum);
  }

  /* iterate through objects setting values */
  if( errNum == WLZ_ERR_NONE ){
    WlzIntervalWSpace	iwsp0, iwsp[4];
    WlzGreyWSpace	gwsp0, gwsp[4];
    int			i, j, k;
    int			a, col[3];

    errNum = WlzInitGreyScan(obj, &iwsp0, &gwsp0);
    for(i=0; i < 4; i++){
      errNum = WlzInitGreyScan(cobj->o[i], &(iwsp[i]), &(gwsp[i]));
    }
    while((errNum == WLZ_ERR_NONE) &&
	  ((errNum = WlzNextGreyInterval(&iwsp0)) == WLZ_ERR_NONE)){
      for(i=0; i < 4; i++){
	errNum = WlzNextGreyInterval(&(iwsp[i]));
      }
      switch( colSpc ){
      case WLZ_RGBA_SPACE_RGB:
	for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++,
	      gwsp0.u_grintptr.rgbp++){
	  *(gwsp[0].u_grintptr.ubp++) =
	    (WlzUByte )WLZ_RGBA_RED_GET(*(gwsp0.u_grintptr.rgbp));
	  *(gwsp[1].u_grintptr.ubp++) =
	    (WlzUByte )WLZ_RGBA_GREEN_GET(*(gwsp0.u_grintptr.rgbp));
	  *(gwsp[2].u_grintptr.ubp++) =
	    (WlzUByte )WLZ_RGBA_BLUE_GET(*(gwsp0.u_grintptr.rgbp));
	  *(gwsp[3].u_grintptr.ubp++) =
	    (WlzUByte )WLZ_RGBA_ALPHA_GET(*(gwsp0.u_grintptr.rgbp));
	}
	break;
      
      case WLZ_RGBA_SPACE_HSB: /* each normalised to [0,255] */
	for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++,
	      gwsp0.u_grintptr.rgbp++){
	  col[0] = WLZ_RGBA_RED_GET(*(gwsp0.u_grintptr.rgbp));
	  col[1] = WLZ_RGBA_GREEN_GET(*(gwsp0.u_grintptr.rgbp));
	  col[2] = WLZ_RGBA_BLUE_GET(*(gwsp0.u_grintptr.rgbp));
	  a = WLZ_RGBA_ALPHA_GET(*(gwsp0.u_grintptr.rgbp));
	  WlzRGBAConvertRGBToHSV_UBYTENormalised(col);
	  *(gwsp[0].u_grintptr.ubp++) = (WlzUByte )(col[0]);
	  *(gwsp[1].u_grintptr.ubp++) = (WlzUByte )(col[1]);
	  *(gwsp[2].u_grintptr.ubp++) = (WlzUByte )(col[2]);
	  *(gwsp[3].u_grintptr.ubp++) = (WlzUByte )a;
	    }
	break;
      
      case WLZ_RGBA_SPACE_CMY:
	for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++,
	      gwsp0.u_grintptr.rgbp++){
	  col[0] = WLZ_RGBA_RED_GET(*(gwsp0.u_grintptr.rgbp));
	  col[1] = WLZ_RGBA_GREEN_GET(*(gwsp0.u_grintptr.rgbp));
	  col[2] = WLZ_RGBA_BLUE_GET(*(gwsp0.u_grintptr.rgbp));
	  a = WLZ_RGBA_ALPHA_GET(*(gwsp0.u_grintptr.rgbp));
	  *(gwsp[0].u_grintptr.ubp++) = (WlzUByte )((col[1] + col[2]) / 2);
	  *(gwsp[1].u_grintptr.ubp++) = (WlzUByte )((col[2] + col[0]) / 2);
	  *(gwsp[2].u_grintptr.ubp++) = (WlzUByte )((col[0] + col[1]) / 2);
	  *(gwsp[3].u_grintptr.ubp++) = (WlzUByte )a;
	    }
	break;
      default:
        errNum = WLZ_ERR_GREY_TYPE;
	break;
      }
    }
    if( errNum == WLZ_ERR_EOO ){
      errNum = WLZ_ERR_NONE;
    }
  }
      

  if( dstErr ){
    *dstErr = errNum;
  }
  return cobj;
}
예제 #11
0
WlzErrorNum	WlzGreyScalarDivValue(
  WlzObject	*obj,
  WlzPixelV	val)
{
  WlzObject		*tmpObj;
  WlzIntervalWSpace	iwsp;
  WlzGreyWSpace		gwsp;
  WlzGreyP		gptr;
  WlzPixelV		tmpVal;
  WlzDomain		*domains;
  WlzValues		*values;
  int			i, nplanes;
  int			red = 0, green = 0, blue = 0, alpha = 0;
  WlzErrorNum		errNum=WLZ_ERR_NONE;

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

    case WLZ_2D_DOMAINOBJ:
      if( obj->domain.i == NULL ){
	errNum = WLZ_ERR_DOMAIN_NULL;
      }
      else if( obj->values.v == NULL ){
	errNum = WLZ_ERR_VALUES_NULL;
      }
      break;

    case WLZ_3D_DOMAINOBJ:
      /* check planedomain and voxeltable */
      if( obj->domain.p == NULL ){
	errNum =  WLZ_ERR_DOMAIN_NULL;
      }
      else if( obj->domain.p->type != WLZ_PLANEDOMAIN_DOMAIN ){
	errNum = WLZ_ERR_DOMAIN_TYPE;
      }
      else if( obj->values.vox == NULL ){
	errNum = WLZ_ERR_VALUES_NULL;
      }
      else if( obj->values.vox->type != WLZ_VOXELVALUETABLE_GREY ){
	errNum = WLZ_ERR_VALUES_TYPE;
      }
      else {
	/* 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; (errNum == WLZ_ERR_NONE) && (i < nplanes);
	    i++, domains++, values++){

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

	  if((tmpObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains, *values,
				    NULL, NULL,	NULL)) != NULL){
	    errNum = WlzGreyScalarDivValue(tmpObj, val);
	    WlzFreeObj( tmpObj );
	  }
	}
      }
      return errNum;

    case WLZ_TRANS_OBJ:
      return WlzGreyScalarDivValue(obj->values.obj, val);

    case WLZ_EMPTY_OBJ:
      return errNum;

    default:
      errNum = WLZ_ERR_OBJECT_TYPE;
      break;
    }
  }

  if( errNum == WLZ_ERR_NONE ){
    errNum = WlzInitGreyScan(obj, &iwsp, &gwsp);
    WlzValueConvertPixel(&tmpVal, val, WLZ_GREY_DOUBLE);
    while( (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++)
	  *gptr.inp /= tmpVal.v.dbv;
	break;

      case WLZ_GREY_SHORT:
	for (i=0; i<iwsp.colrmn; i++, gptr.shp++)
	  *gptr.shp /= tmpVal.v.dbv;
	break;

      case WLZ_GREY_UBYTE:
	for (i=0; i<iwsp.colrmn; i++, gptr.ubp++)
	  *gptr.ubp /= tmpVal.v.dbv;
	break;

      case WLZ_GREY_FLOAT:
	for (i=0; i<iwsp.colrmn; i++, gptr.flp++)
	  *gptr.flp /= tmpVal.v.dbv;
	break;

      case WLZ_GREY_DOUBLE:
	for (i=0; i<iwsp.colrmn; i++, gptr.dbp++)
	  *gptr.dbp /= tmpVal.v.dbv;
	break;

      case WLZ_GREY_RGBA:
	for (i=0; i<iwsp.colrmn; i++, gptr.rgbp++)
	  red = WLZ_RGBA_RED_GET(*gptr.rgbp) / tmpVal.v.dbv;
	  green = WLZ_RGBA_GREEN_GET(*gptr.rgbp) / tmpVal.v.dbv;
	  blue = WLZ_RGBA_BLUE_GET(*gptr.rgbp) / tmpVal.v.dbv;
	  alpha = WLZ_RGBA_ALPHA_GET(*gptr.rgbp);
	  red = WLZ_CLAMP(red, 0, 255);
	  green = WLZ_CLAMP(red, 0, 255);
	  blue = WLZ_CLAMP(red, 0, 255);
	  WLZ_RGBA_RGBA_SET(*gptr.rgbp, red, green, blue, alpha);
	break;

      default:
	errNum = WLZ_ERR_GREY_TYPE;
	break;
      }
    }
    if( errNum == WLZ_ERR_EOO ){
      errNum = WLZ_ERR_NONE;
    }
  }

  return errNum;
}
예제 #12
0
/*!
* \return	Shade corrected object or NULL on error.
* \ingroup	WlzValueFilters
* \brief	Shade corrects the given 2D domain object with grey
*               values. Grey value types known to be the same.
* \param	srcObj			Given object to be shade
*                                       corrected.
* \param	shdObj			Given bright field object.
* \param	nrmVal			Normalization value.
* \param	inPlace			Modify the grey values of the
*                                       given object if non-zero.
* \param	dstErr			Destination error pointer, may
*                                       be null.
*/
static WlzObject *WlzShadeCorrect2DG(WlzObject *srcObj, WlzObject *shdObj,
				     double nrmVal, int inPlace,
				     WlzErrorNum *dstErr)
{
  int		tI0,
  		iCnt, red, green, blue;
  double	tD0;
  WlzUInt	tUI0, tUI1;
  WlzObject	*uObj = NULL,
		*uSrcObj = NULL,
		*uShdObj = NULL,
  		*rtnObj = NULL;
  WlzGreyP	srcPix,
  		shdPix,
		rtnPix;
  WlzValues	newVal;
  WlzIntervalWSpace srcIWSp,
  		shdIWSp,
		rtnIWSp;
  WlzGreyWSpace	srcGWSp,
  		shdGWSp,
		rtnGWSp;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  /* Find intersection of the given and shade objects. */
  uObj = WlzIntersect2(srcObj, shdObj, &errNum);
  /* Make new objects with the values of the given and shade objects
   * but the domain of their intersection. */
  if(errNum == WLZ_ERR_NONE)
  {
    uSrcObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, uObj->domain, srcObj->values,
    			  NULL, NULL, &errNum);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    uShdObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, uObj->domain, shdObj->values,
    			  NULL, NULL, &errNum);
  }
  /* Make a new object, again using the union for the domain, but this time
   * either sharing the given objects values or creating a new value table. */
  if(errNum == WLZ_ERR_NONE)
  {
    if(inPlace)
    {
      rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, uObj->domain, srcObj->values,
      			   NULL, NULL, &errNum);
    }
    else
    {
      newVal.v = WlzNewValueTb(uObj, srcObj->values.core->type,
      			       WlzGetBackground(srcObj, NULL), &errNum);
      if(errNum == WLZ_ERR_NONE)
      {
        if((rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, uObj->domain, newVal,
			         NULL, NULL, &errNum)) == NULL)
        {
	  (void )WlzFreeValueTb(newVal.v);
	}
      }
    }
  }

  /* Work through the intervals setting the grey values. */
  if(errNum == WLZ_ERR_NONE)
  {
    if(((errNum = WlzInitGreyScan(uSrcObj, &srcIWSp,
    				  &srcGWSp)) == WLZ_ERR_NONE) &&
       ((errNum = WlzInitGreyScan(uShdObj, &shdIWSp,
    				  &shdGWSp)) == WLZ_ERR_NONE) &&
       ((errNum = WlzInitGreyScan(rtnObj, &rtnIWSp,
    				  &rtnGWSp)) == WLZ_ERR_NONE))
    {
      while(((errNum = WlzNextGreyInterval(&srcIWSp)) == WLZ_ERR_NONE) &&
            ((errNum = WlzNextGreyInterval(&shdIWSp)) == WLZ_ERR_NONE) &&
            ((errNum = WlzNextGreyInterval(&rtnIWSp)) == WLZ_ERR_NONE))
      {
	srcPix = srcGWSp.u_grintptr;
	shdPix = shdGWSp.u_grintptr;
	rtnPix = rtnGWSp.u_grintptr;
	iCnt = rtnIWSp.rgtpos - rtnIWSp.lftpos + 1;
        switch(rtnGWSp.pixeltype)
	{
	  case WLZ_GREY_INT:
	    while(iCnt-- > 0)
	    {
	      tD0 = (*(srcPix.inp)++ * nrmVal) / (*(shdPix.inp)++ + 1.0);
	      *(rtnPix.inp)++ = WLZ_NINT(tD0);
	    }
	    break;
	  case WLZ_GREY_SHORT:
	    while(iCnt-- > 0)
	    {
	      tD0 = (*(srcPix.shp)++ * nrmVal) / (*(shdPix.shp)++ + 1.0);
	      tI0 = WLZ_NINT(tD0);
	      *(rtnPix.shp)++ = (short )WLZ_CLAMP(tI0, SHRT_MIN, SHRT_MAX);
	    }
	    break;
	  case WLZ_GREY_UBYTE:
	    while(iCnt-- > 0)
	    {
	      tD0 = (*(srcPix.ubp)++ * nrmVal) / (*(shdPix.ubp)++ + 1.0);
	      tI0 = WLZ_NINT(tD0);
	      *(rtnPix.ubp)++ = (WlzUByte )WLZ_CLAMP(tI0, 0, 255);
	    }
	    break;
	  case WLZ_GREY_FLOAT:
	    while(iCnt-- > 0)
	    {
	      tD0 = (*(srcPix.flp)++ * nrmVal) / (*(shdPix.flp)++ + 1.0);
	      *(rtnPix.flp)++ = (float )tD0;
	    }
	    break;
	  case WLZ_GREY_DOUBLE:
	    while(iCnt-- > 0)
	    {
	      tD0 = (*(srcPix.dbp)++ * nrmVal) / (*(shdPix.dbp)++ + 1.0);
	      *(rtnPix.dbp)++ = tD0;
	    }
	    break;
	  case WLZ_GREY_RGBA:
	    while(iCnt-- > 0)
	    {
	      /* slightly different logic here. Avoid divide by zero
		 by explicit check */
	      tUI0 = *(srcPix.rgbp)++;
	      tUI1 = *(shdPix.rgbp)++;
	      red = WLZ_RGBA_RED_GET(tUI1);
	      red = (red)?
		    (int )(((WLZ_RGBA_RED_GET(tUI0) * nrmVal))/red):
		    (int )nrmVal;
	      red = WLZ_CLAMP(red, 0, 255);
	      green = WLZ_RGBA_GREEN_GET(tUI1);
	      green = (green)?
	              (int )(((WLZ_RGBA_GREEN_GET(tUI0) * nrmVal))/green):
		      (int )nrmVal;
	      green = WLZ_CLAMP(green, 0, 255);
	      blue = WLZ_RGBA_BLUE_GET(tUI1);
	      blue = (blue)?
	             (int )(((WLZ_RGBA_BLUE_GET(tUI0) * nrmVal))/blue):
	             (int )nrmVal;
	      blue = WLZ_CLAMP(blue, 0, 255);
	      WLZ_RGBA_RGBA_SET(tUI0, red, green, blue, 255);
	      *(rtnPix.rgbp)++ = tUI0;
	    }
	    break;
	  default:
	    errNum = WLZ_ERR_GREY_TYPE;
	    break;
	}
      }
      if(errNum == WLZ_ERR_EOO)         /* Reset error from end of intervals */
      {
        errNum = WLZ_ERR_NONE;
      }
    }
  }
  (void )WlzFreeObj(uObj);
  (void )WlzFreeObj(uSrcObj);
  (void )WlzFreeObj(uShdObj);
  if(errNum != WLZ_ERR_NONE)
  {
    (void )WlzFreeObj(rtnObj);
    rtnObj = NULL;
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(rtnObj);
}