/*! * \return New Woolz object. * \ingroup WlzAllocation * \brief Creates a new or adds to an existing 3D spatial domain * object using a rectangular buffer of values to a single * plane of the given current object (which may be NULL or * empty if the object is to be created). * The returned object will share domains and values of * planes other than the given plane with the current object. * \param cObj Given current object. * \param og Origin of rectangular buffer. * \param sz Buffer size (note 2D). * \param gType Grey type which must be consistent * with the current object (if it is * valid) and the buffer of values. * \param bufSz Number of values in the buffer * (ie sz.vtX * sz.vtY). * \param bufP Given buffer of values. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzBuildObj3(WlzObject *cObj, WlzIVertex3 og, WlzIVertex2 sz, WlzGreyType gType, int bufSz, WlzGreyP bufP, WlzErrorNum *dstErr) { int nPlnReq = 1; WlzDomain cDom, nDom; WlzValues cVal, nVal; WlzObject *nObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; cDom.core = NULL; nDom.core = NULL; cVal.core = NULL; nVal.core = NULL; if(cObj) { WlzGreyType cGType = WLZ_GREY_ERROR;; switch(cObj->type) { case WLZ_EMPTY_OBJ: cObj = NULL; break; case WLZ_3D_DOMAINOBJ: if(cObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(cObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else { cDom = cObj->domain; cVal = cObj->values; cGType = WlzGreyTypeFromObj(cObj, &errNum); } if((errNum == WLZ_ERR_NONE) && (cGType != gType)) { errNum = WLZ_ERR_GREY_TYPE; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* Create a new object with new plane domain and voxel values. */ if(errNum == WLZ_ERR_NONE) { WlzIBox3 nBox; WlzPixelV bgdV; float vxSz[3]; nBox.xMin = og.vtX; nBox.yMin = og.vtY; nBox.zMin = og.vtZ; nBox.xMax = og.vtX + sz.vtX - 1; nBox.yMax = og.vtY + sz.vtY - 1; nBox.zMax = og.vtZ; if(cObj) { nPlnReq = (og.vtZ < cDom.p->plane1) || (og.vtZ > cDom.p->lastpl) || ((*(cDom.p->domains + og.vtZ - cDom.p->plane1)).core == NULL); nBox.xMin = ALG_MIN(nBox.xMin, cDom.p->kol1); nBox.yMin = ALG_MIN(nBox.yMin, cDom.p->line1); nBox.zMin = ALG_MIN(nBox.zMin, cDom.p->plane1); nBox.xMax = ALG_MAX(nBox.xMax, cDom.p->lastkl); nBox.yMax = ALG_MAX(nBox.yMax, cDom.p->lastln); nBox.zMax = ALG_MAX(nBox.zMax, cDom.p->lastpl); vxSz[0] = cDom.p->voxel_size[0]; vxSz[1] = cDom.p->voxel_size[1]; vxSz[2] = cDom.p->voxel_size[2]; bgdV = WlzGetBackground(cObj, &errNum); } else { vxSz[0] = vxSz[1] = vxSz[2] = 1.0f; bgdV.type = WLZ_GREY_INT; bgdV.v.inv = 0; } if(errNum == WLZ_ERR_NONE) { nDom.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, nBox.zMin, nBox.zMax, nBox.yMin, nBox.yMax, nBox.xMin, nBox.xMax, &errNum); } if(errNum == WLZ_ERR_NONE) { nVal.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, nBox.zMin, nBox.zMax, bgdV, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { nDom.p->voxel_size[0] = vxSz[0]; nDom.p->voxel_size[1] = vxSz[1]; nDom.p->voxel_size[2] = vxSz[2]; nObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, nDom, nVal, NULL, NULL, &errNum); } } /* Set the domain and values on each plane for the new object. */ if(errNum == WLZ_ERR_NONE) { int idZ; for(idZ = nDom.p->plane1; idZ <= nDom.p->lastpl; ++idZ) { int idP; WlzDomain nDom2; WlzValues nVal2; nDom2.core = NULL; nVal2.core = NULL; idP = idZ - nDom.p->plane1; if(idZ == og.vtZ) { /* Plane with buffer. */ WlzIVertex2 og2, sz2; WlzObject *cObj2 = NULL, *nObj2 = NULL; og2.vtX = og.vtX; og2.vtY = og.vtY; sz2.vtX = sz.vtX; sz2.vtY = sz.vtY; if(nPlnReq == 0) { int idP; idP = idZ - cDom.p->plane1; cObj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, *(cDom.p->domains + idP), *(cVal.vox->values + idP), NULL, NULL, &errNum); } nObj2 = WlzBuildObj2(cObj2, og2, sz2, gType, bufSz, bufP, &errNum); if(errNum == WLZ_ERR_NONE) { nDom2 = WlzAssignDomain(nObj2->domain, NULL); nVal2 = WlzAssignValues(nObj2->values, NULL); } (void )WlzFreeObj(cObj2); (void )WlzFreeObj(nObj2); } else if((idZ >= cDom.p->plane1) && (idZ <= cDom.p->lastpl)) { /* Not buffer plane, but previously existing plane. */ int idQ; idQ = idZ - cDom.p->plane1; nDom2 = WlzAssignDomain(*(cDom.p->domains + idQ), NULL); nVal2 = WlzAssignValues(*(cVal.vox->values + idQ), NULL); } if(errNum == WLZ_ERR_NONE) { *(nDom.p->domains + idP) = nDom2; *(nVal.vox->values + idP) = nVal2; } else { break; } } } if(dstErr) { *dstErr = errNum; } return(nObj); }
/*! * \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 WlzArithmetic * \brief Increments all valus of the firstobjct which are within * the domain of the second object. The domain of the first * object must cover that of the second. * Because this is a static object it is assumed that the * two 3D objects are known to be valid. * \param gObj First object. * \param dObj Second object. */ static WlzErrorNum WlzGreyIncValuesInDomain3D(WlzObject *gObj, WlzObject *dObj) { WlzPlaneDomain *gPD, *dPD; WlzVoxelValues *gVV; WlzErrorNum errNum = WLZ_ERR_NONE; gPD = gObj->domain.p; gVV = gObj->values.vox; dPD = dObj->domain.p; if((dPD->plane1 < gPD->plane1) || (dPD->lastpl > gPD->lastpl)) { errNum = WLZ_ERR_DOMAIN_DATA; } else { int p, p0, p1; p0 = ALG_MAX(dPD->plane1, gPD->plane1); p1 = ALG_MIN(dPD->lastpl, gPD->lastpl); #ifdef _OPENMP #pragma omp parallel for #endif for(p = p0; p <= p1; ++p) { if(errNum == WLZ_ERR_NONE) { WlzDomain *doms; WlzValues *vals; WlzErrorNum errNum2D = WLZ_ERR_NONE; doms = dPD->domains + p - dPD->plane1; vals = gVV->values + p - gPD->plane1;; if(((*doms).core != NULL) && ((*vals).core != NULL)) { WlzObject *obj2D = NULL; if((obj2D = WlzAssignObject( WlzMakeMain(WLZ_2D_DOMAINOBJ, *doms, *vals, NULL, NULL, &errNum2D), NULL)) != NULL) { errNum2D = WlzGreyIncValues2D(obj2D); (void )WlzFreeObj(obj2D); } if(errNum2D != WLZ_ERR_NONE) { #ifdef _OPENMP #pragma omp critical { #endif if(errNum == WLZ_ERR_NONE) { errNum = errNum2D; } #ifdef _OPENMP } #endif } } } } } return(errNum); }