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; }
/*! * \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; }
/*! * \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; }
/*! * \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; }
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; }
/*! * \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); }
/*! * \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; }
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; }
/*! * \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; }
/*! * \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; }
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; }
/*! * \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); }