/*! * \return New Woolz domain object with gradient grey values or * NULL on error. * \ingroup WlzValuesFilters * \brief Computes the gradient of the gray values in the * given Woolz 2D domain object. * \param dstGrdY Destination pointer for the * gradient (partial derivative) * through lines, may be NULL. * \param dstGrdX Destination pointer for the * gradient (partial derivative) * through columns, may be NULL. * \param srcObj Given source object. * \param flt Recursive filter to use. * \param dstErr Destination error pointer, may * be null. */ static WlzObject *WlzGreyGradient2D(WlzObject **dstGrdY, WlzObject **dstGrdX, WlzObject *srcObj, WlzRsvFilter *flt, WlzErrorNum *dstErr) { WlzObject *grdX = NULL, *grdY = NULL, *dstObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; if(srcObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(srcObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(srcObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else if(WlzGreyTableIsTiled(srcObj->values.core->type)) { errNum = WLZ_ERR_VALUES_TYPE; } if(errNum == WLZ_ERR_NONE) { grdX = WlzRsvFilterObj(srcObj, flt, WLZ_RSVFILTER_ACTION_X, &errNum); } if(errNum == WLZ_ERR_NONE) { grdY = WlzRsvFilterObj(srcObj, flt, WLZ_RSVFILTER_ACTION_Y, &errNum); } if(errNum == WLZ_ERR_NONE) { dstObj = WlzImageArithmetic(grdY, grdX, WLZ_BO_MAGNITUDE, 0, &errNum); } if(dstGrdX && (errNum == WLZ_ERR_NONE)) { *dstGrdX = grdX; } else if(grdX) { WlzFreeObj(grdX); } if(dstGrdY && (errNum == WLZ_ERR_NONE)) { *dstGrdY = grdY; } else if(grdY) { WlzFreeObj(grdY); } if(dstErr) { *dstErr = errNum; } return(dstObj); }
/*! * \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. * \param gObj First object. * \param dObj Second object. */ WlzErrorNum WlzGreyIncValuesInDomain(WlzObject *gObj, WlzObject *dObj) { WlzErrorNum errNum = WLZ_ERR_NONE; if((gObj == NULL) || (dObj == NULL)) { errNum = WLZ_ERR_OBJECT_NULL; } else if((gObj->domain.core == NULL) || (dObj->domain.core == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(gObj->type != dObj->type) { errNum = WLZ_ERR_OBJECT_TYPE; } else if(gObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else if(WlzGreyTableIsTiled(gObj->values.core->type)) { errNum = WLZ_ERR_VALUES_TYPE; } else { switch(gObj->type) { case WLZ_2D_DOMAINOBJ: errNum = WlzGreyIncValuesInDomain2D(gObj, dObj); break; case WLZ_3D_DOMAINOBJ: errNum = WlzGreyIncValuesInDomain3D(gObj, dObj); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } return(errNum); }
/*! * \return Grey value work space or NULL on error. * \ingroup WlzAccess * \brief Creates a grey value work space from the given object. * The resulting grey value work space should be freed * using WlzGreyValueFreeWSp(). * \param obj Given object. * \param dstErrNum Destination error pointer, may be NULL. */ WlzGreyValueWSpace *WlzGreyValueMakeWSp(WlzObject *obj, WlzErrorNum *dstErrNum) { int planeIdx, numPlanes; WlzDomain *planeDomains; WlzValues *planeValues; WlzObjectType gTabType0, gTabType1 = WLZ_DUMMY_ENTRY; WlzGreyType gType0 = WLZ_GREY_ERROR, gType1 = WLZ_GREY_ERROR; WlzPixelV bkdPix; WlzAffineTransform *trans0, *trans1; WlzGreyValueWSpace *gVWSp = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; bkdPix.v.ubv = 0; bkdPix.type = WLZ_GREY_INT; WLZ_DBG((WLZ_DBG_LVL_1), ("WlzGreyValueMakeWSp FE %p %p\n", obj, dstErrNum)); if(obj == NULL) { errNum = WLZ_ERR_PARAM_DATA; } else { 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((gVWSp = (WlzGreyValueWSpace *)AlcCalloc(1, sizeof(WlzGreyValueWSpace))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { gVWSp->objType = obj->type; gVWSp->values = obj->values; gVWSp->gType = WlzGreyTableTypeToGreyType(obj->values.core->type, &errNum); if(errNum == WLZ_ERR_NONE) { gVWSp->gTabType = WlzGreyTableTypeToTableType( obj->values.core->type, &errNum); gVWSp->gTabType2D = gVWSp->gTabType; } if(errNum == WLZ_ERR_NONE) { switch(gVWSp->gTabType2D) { case WLZ_GREY_TAB_RAGR: gVWSp->values2D = obj->values; bkdPix = gVWSp->values2D.v->bckgrnd; break; case WLZ_GREY_TAB_RECT: gVWSp->values2D = obj->values; bkdPix = gVWSp->values2D.r->bckgrnd; break; case WLZ_GREY_TAB_INTL: gVWSp->values2D = obj->values; bkdPix = gVWSp->values2D.i->bckgrnd; break; case WLZ_GREY_TAB_TILED: gVWSp->values2D = obj->values; bkdPix = gVWSp->values2D.t->bckgrnd; break; default: errNum = WLZ_ERR_VALUES_TYPE; break; } } if(errNum == WLZ_ERR_NONE) { switch(gVWSp->gType) { case WLZ_GREY_LONG: case WLZ_GREY_INT: case WLZ_GREY_SHORT: case WLZ_GREY_UBYTE: case WLZ_GREY_FLOAT: case WLZ_GREY_DOUBLE: case WLZ_GREY_RGBA: break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } if((gVWSp->gType != bkdPix.type) && (errNum == WLZ_ERR_NONE)) { errNum = WLZ_ERR_VALUES_DATA; } } if(errNum == WLZ_ERR_NONE) { gVWSp->gBkd = bkdPix.v; gVWSp->domain = obj->domain; gVWSp->iDom2D = obj->domain.i; if((gVWSp->iDom2D->type != WLZ_INTERVALDOMAIN_INTVL) && (gVWSp->iDom2D->type != WLZ_INTERVALDOMAIN_RECT)) { errNum = WLZ_ERR_DOMAIN_TYPE; } } break; case WLZ_3D_DOMAINOBJ: if(obj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(obj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else if(obj->domain.core->type != WLZ_PLANEDOMAIN_DOMAIN) { errNum = WLZ_ERR_DOMAIN_TYPE; } else if((gVWSp = (WlzGreyValueWSpace *)AlcCalloc(1, sizeof(WlzGreyValueWSpace))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { gVWSp->objType = obj->type; gVWSp->domain = obj->domain; gVWSp->values = obj->values; if(WlzGreyTableIsTiled(obj->values.core->type) == WLZ_GREY_TAB_TILED) { gVWSp->gTabType = WLZ_GREY_TAB_TILED; gVWSp->gTabType2D = WLZ_GREY_TAB_TILED; gVWSp->gType = WlzGreyTableTypeToGreyType( obj->values.core->type, &errNum); gVWSp->plane = obj->domain.p->plane1; gVWSp->iDom2D = (*(obj->domain.p->domains)).i; gVWSp->gBkd = obj->values.t->bckgrnd.v; if(obj->values.t->bckgrnd.type != gVWSp->gType) { errNum = WLZ_ERR_VALUES_DATA; } } else { gVWSp->gTabType = WLZ_VOXELVALUETABLE_GREY; /* Put in a list of grey-table types - purely for efficiency to avoid re-computing the type for each voxel request. When table types are no longer computed this in principle could go */ numPlanes = obj->domain.p->lastpl - obj->domain.p->plane1 + 1; if((gVWSp->gTabTypes3D = (WlzObjectType *) AlcCalloc(numPlanes, sizeof(WlzObjectType))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } if(errNum == WLZ_ERR_NONE) { WlzObjectType *gTabTypes3D; gVWSp->values2D.core = NULL; planeIdx = obj->domain.p->plane1; planeDomains = obj->domain.p->domains; planeValues = obj->values.vox->values; gTabTypes3D = gVWSp->gTabTypes3D; while((planeIdx <= obj->domain.p->lastpl) && (errNum == WLZ_ERR_NONE)) { if(((*planeValues).core) && ((*planeValues).core->type != WLZ_EMPTY_OBJ)) { gType0 = WlzGreyTableTypeToGreyType( (*planeValues).core->type, &errNum); if(errNum == WLZ_ERR_NONE) { gTabType0 = WlzGreyTableTypeToTableType((*planeValues). core->type, &errNum); *gTabTypes3D = gTabType0; } if(errNum == WLZ_ERR_NONE) { if((gType0 != gType1) && (gType1 != WLZ_GREY_ERROR)) { errNum = WLZ_ERR_VALUES_DATA; } else { gType1 = gType0; gTabType1 = gTabType0; if(gVWSp->values2D.core == NULL) { gVWSp->plane = planeIdx; gVWSp->iDom2D = (*planeDomains).i; gVWSp->values2D = *planeValues; } } } } ++planeIdx; ++planeDomains; ++planeValues; ++gTabTypes3D; } if((gType1 == WLZ_GREY_ERROR) || (gTabType1 == WLZ_DUMMY_ENTRY)) { errNum = WLZ_ERR_VALUES_DATA; } } if(errNum == WLZ_ERR_NONE) { gVWSp->gType = gType0; gVWSp->gTabType2D = gVWSp->gTabTypes3D[0]; switch(gVWSp->gTabType2D) { case WLZ_GREY_TAB_RAGR: bkdPix = gVWSp->values2D.v->bckgrnd; break; case WLZ_GREY_TAB_RECT: bkdPix = gVWSp->values2D.r->bckgrnd; break; case WLZ_GREY_TAB_INTL: bkdPix = gVWSp->values2D.i->bckgrnd; break; case WLZ_GREY_TAB_TILED: bkdPix = gVWSp->values2D.t->bckgrnd; break; default: errNum = WLZ_ERR_VALUES_TYPE; break; } if((gVWSp->gType != bkdPix.type) && (errNum == WLZ_ERR_NONE)) { errNum = WLZ_ERR_VALUES_DATA; } else if((gVWSp->iDom2D->type != WLZ_INTERVALDOMAIN_INTVL) && (gVWSp->iDom2D->type != WLZ_INTERVALDOMAIN_RECT)) { errNum = WLZ_ERR_DOMAIN_TYPE; } else { gVWSp->gBkd = bkdPix.v; } } } } break; case WLZ_TRANS_OBJ: trans0 = NULL; while((errNum == WLZ_ERR_NONE) && (obj->type == WLZ_TRANS_OBJ)) { if(trans0 == NULL) { trans0 = WlzAffineTransformCopy(obj->domain.t, &errNum); } else { if((trans1 = WlzAffineTransformProduct(trans0, obj->domain.t, &errNum)) != NULL) { WlzFreeAffineTransform(trans0); trans0 = trans1; trans1 = NULL; } } if((obj = obj->values.obj) == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } } if(errNum == WLZ_ERR_NONE) { gVWSp = WlzGreyValueMakeWSp(obj, &errNum); } if(errNum == WLZ_ERR_NONE) { gVWSp->invTrans = WlzAffineTransformInverse(trans0, &errNum); } if(trans0) { WlzFreeAffineTransform(trans0); } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if((errNum != WLZ_ERR_NONE) && (gVWSp != NULL)) { WlzGreyValueFreeWSp(gVWSp); gVWSp = NULL; } if(dstErrNum) { *dstErrNum = errNum; } WLZ_DBG((WLZ_DBG_LVL_FN|WLZ_DBG_LVL_1), ("WlzGreyValueMakeWSp FX %p\n", gVWSp)); return(gVWSp); }
/*! * \ingroup WlzValuesFilters * \brief Perform 2D seperable transform on a 2D grey-level image. * It is the users responsibility to ensure that the grey-value * types are appropriate. * Now extended to include compound objects. * * \return Pointer to transformed object * \param obj Input object pointer * \param x_fun Convolution function to be applied in the x-direction (along the rows). * \param x_params Parameter pointer to be passed to the x-function. * \param y_fun Convolution function to be applied in the y-direction (down the columns). * \param y_params Parameter pointer to be passed to the y-function. * \param dstErr error return. * \par Source: * WlzSepTrans.c */ WlzObject *WlzSepTrans( WlzObject *obj, WlzIntervalConvFunc x_fun, void *x_params, WlzIntervalConvFunc y_fun, void *y_params, WlzErrorNum *dstErr) { WlzIntervalWSpace iwspace; WlzGreyWSpace gwspace; WlzSepTransWSpace stwspc; WlzValues values; WlzObject *obj1, *obj2; int i, width, height; WlzCompoundArray *cobj1, *cobj2; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object pointers and type */ obj2 = NULL; stwspc.outbuf.p.dbp = NULL; if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( obj->type ){ case WLZ_2D_DOMAINOBJ: /* check domain and valuetable */ if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; break; } if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; break; } if(WlzGreyTableIsTiled(obj->values.core->type)){ errNum = WLZ_ERR_VALUES_TYPE; break; } break; default: case WLZ_3D_DOMAINOBJ: errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_TRANS_OBJ: if((obj1 = WlzSepTrans(obj->values.obj, x_fun, x_params, y_fun, y_params, &errNum)) != NULL){ values.obj = obj1; return WlzMakeMain(obj->type, obj->domain, values, NULL, obj, dstErr); } break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: cobj1 = (WlzCompoundArray *) obj; if((cobj2 = WlzMakeCompoundArray(cobj1->type, 1, cobj1->n, NULL, cobj1->otype, &errNum)) != NULL){ /* transform each object, ignore type errors */ for(i=0; i < cobj1->n; i++){ cobj2->o[i] = WlzAssignObject(WlzSepTrans(cobj1->o[i], x_fun, x_params, y_fun, y_params, &errNum), NULL); } return (WlzObject *) cobj2; } break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); } } /* make space for a calculation buffer - assume worst case of doubles */ if( errNum == WLZ_ERR_NONE ){ width = obj->domain.i->lastkl - obj->domain.i->kol1 + 1; height = obj->domain.i->lastln - obj->domain.i->line1 + 1; stwspc.inbuf.type = WlzGreyTableTypeToGreyType(obj->values.core->type, NULL); stwspc.bckgrnd = WlzGetBackground(obj, NULL); switch( stwspc.inbuf.type ){ case WLZ_GREY_INT: case WLZ_GREY_SHORT: case WLZ_GREY_UBYTE: stwspc.outbuf.type = WLZ_GREY_INT; break; default: stwspc.outbuf.type = stwspc.inbuf.type; break; } if( (stwspc.outbuf.p.dbp = (double *) AlcMalloc(sizeof(double)*(width>height?width:height))) == NULL){ errNum = WLZ_ERR_MEM_ALLOC; } } /* tranpose the object - interchange x & y coordinates */ if( errNum == WLZ_ERR_NONE ){ obj1 = WlzTransposeObj(obj, &errNum); } /* perform the y convolution */ if((errNum == WLZ_ERR_NONE) && ((errNum = WlzInitGreyScan(obj1, &iwspace, &gwspace)) == WLZ_ERR_NONE)) { while( (errNum = WlzNextGreyInterval(&iwspace)) == WLZ_ERR_NONE ){ stwspc.inbuf.p.inp = gwspace.u_grintptr.inp; stwspc.len = iwspace.rgtpos - iwspace.lftpos + 1; if((errNum = (*y_fun)(&stwspc, y_params)) == WLZ_ERR_NONE){ switch( stwspc.inbuf.type ){ case WLZ_GREY_INT: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.inp++) *stwspc.inbuf.p.inp = stwspc.outbuf.p.inp[i]; break; case WLZ_GREY_SHORT: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.shp++) *stwspc.inbuf.p.shp = (short )(stwspc.outbuf.p.inp[i]); break; case WLZ_GREY_UBYTE: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.ubp++) *stwspc.inbuf.p.ubp = (WlzUByte )(stwspc.outbuf.p.inp[i]); break; case WLZ_GREY_FLOAT: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.flp++) *stwspc.inbuf.p.flp = stwspc.outbuf.p.flp[i]; break; case WLZ_GREY_DOUBLE: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.dbp++) *stwspc.inbuf.p.dbp = stwspc.outbuf.p.dbp[i]; break; case WLZ_GREY_RGBA: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.rgbp++) *stwspc.inbuf.p.rgbp = stwspc.outbuf.p.rgbp[i]; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } else { break; /* break from the while loop */ } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } } /* rotate back and free temporary object */ if( errNum == WLZ_ERR_NONE ){ obj2 = WlzTransposeObj(obj1, &errNum); WlzFreeObj(obj1); } /* perform x convolution */ if((errNum == WLZ_ERR_NONE) && ((errNum = WlzInitGreyScan(obj2, &iwspace, &gwspace)) == WLZ_ERR_NONE)) { while((errNum = WlzNextGreyInterval(&iwspace)) == WLZ_ERR_NONE){ stwspc.inbuf.p.inp = gwspace.u_grintptr.inp; stwspc.len = iwspace.rgtpos - iwspace.lftpos + 1; if( (errNum = (*x_fun)(&stwspc, x_params)) == WLZ_ERR_NONE ){ switch( gwspace.pixeltype ){ case WLZ_GREY_INT: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.inp++) *stwspc.inbuf.p.inp = stwspc.outbuf.p.inp[i]; break; case WLZ_GREY_SHORT: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.shp++) *stwspc.inbuf.p.shp = (short )(stwspc.outbuf.p.inp[i]); break; case WLZ_GREY_UBYTE: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.ubp++) *stwspc.inbuf.p.ubp = (WlzUByte )(stwspc.outbuf.p.inp[i]); break; case WLZ_GREY_FLOAT: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.flp++) *stwspc.inbuf.p.flp = stwspc.outbuf.p.flp[i]; break; case WLZ_GREY_DOUBLE: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.dbp++) *stwspc.inbuf.p.dbp = stwspc.outbuf.p.dbp[i]; break; case WLZ_GREY_RGBA: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.rgbp++) *stwspc.inbuf.p.rgbp = stwspc.outbuf.p.rgbp[i]; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } else { break; /* break from the while loop */ } } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } /* free the buffer and return transformed object */ if( stwspc.outbuf.p.dbp ){ AlcFree((void *) stwspc.outbuf.p.dbp); } if( dstErr ){ *dstErr = errNum; } return obj2; }
/*! * \return Shade corrected object or NULL on error. * \ingroup WlzValueFilters * \brief Shade corrects the given domain object with grey * values. * \f[ p_i = n \frac{(o_i - d_i)}{(s_i - d_i} \f] * The shade corrected image P with values \f$p_i\f$ is * created by applying a correction factor to each image * value of the given image O with values \f$o_i\f$. * \f$s_i\f$ and \f$d_i\f$ are the bright and dark-field * shade image values respectively. * \param srcObj Given object to be shade corrected. * \param shdObj Given bright field object. * \param shdDFObj Given dark field object (may be NULL). * \param nrmVal Normalization value. * \param inPlace Modify the grey values of the given * object in place if non-zero. * \param dstErr Destination error pointer, may * be null. */ WlzObject *WlzShadeCorrectBFDF( WlzObject *srcObj, WlzObject *shdObj, WlzObject *shdDFObj, double nrmVal, int inPlace, WlzErrorNum *dstErr) { WlzObject *rtnObj = NULL; WlzObject *obj1, *obj2; WlzCompoundArray *inCobj, *outCobj; WlzObject **outArray; WlzValues values; int i; WlzErrorNum errNum = WLZ_ERR_NONE; if((srcObj == NULL) || (shdObj == NULL)) { errNum = WLZ_ERR_OBJECT_NULL; } else if((srcObj->domain.core == NULL) || (shdObj->domain.core == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } else if((srcObj->values.core == NULL) || (shdObj->values.core == NULL)) { errNum = WLZ_ERR_VALUES_NULL; } else if(WlzGreyTableIsTiled(srcObj->values.core->type) || WlzGreyTableIsTiled(shdObj->values.core->type)) { errNum = WLZ_ERR_VALUES_TYPE; } else { switch(srcObj->type) { case WLZ_2D_DOMAINOBJ: if(shdObj->type != srcObj->type) { errNum = WLZ_ERR_OBJECT_TYPE; } else if( shdDFObj ){ if( WlzGreyTypeFromObj(srcObj, &errNum) == WLZ_GREY_RGBA ){ obj1 = WlzRGBAImageArithmetic(srcObj, shdDFObj, WLZ_BO_SUBTRACT, 0, &errNum); obj2 = WlzRGBAImageArithmetic(shdObj, shdDFObj, WLZ_BO_SUBTRACT, 0, &errNum); } else { obj1 = WlzImageArithmetic(srcObj, shdDFObj, WLZ_BO_SUBTRACT, 0, &errNum); obj2 = WlzImageArithmetic(shdObj, shdDFObj, WLZ_BO_SUBTRACT, 0, &errNum); } rtnObj = WlzShadeCorrect2D(obj1, obj2, nrmVal, inPlace, &errNum); WlzFreeObj(obj1); WlzFreeObj(obj2);; } else { rtnObj = WlzShadeCorrect2D(srcObj, shdObj, nrmVal, inPlace, &errNum); } break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: inCobj = (WlzCompoundArray *) srcObj; if( inCobj->n > 0 ){ if( (outArray = (WlzObject **) AlcCalloc(inCobj->n, sizeof(WlzObject *))) == NULL){ errNum = WLZ_ERR_MEM_ALLOC; } else { for(i=0; (i < inCobj->n) && (errNum == WLZ_ERR_NONE); i++){ /* allow special behaviour of a non-compound shade image to be used for each object in a compound but must align */ switch( shdObj->type ){ case WLZ_2D_DOMAINOBJ: case WLZ_3D_DOMAINOBJ: outArray[i] = WlzShadeCorrectBFDF(inCobj->o[i], shdObj, shdDFObj, nrmVal, inPlace, &errNum); break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: outArray[i] = WlzShadeCorrectBFDF(inCobj->o[i], ((WlzCompoundArray *) shdObj)->o[i], shdDFObj? ((WlzCompoundArray *) shdDFObj)->o[i]:NULL, nrmVal, inPlace, &errNum); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if( errNum == WLZ_ERR_NONE ){ outCobj = WlzMakeCompoundArray(srcObj->type, 3, inCobj->n, outArray, outArray[0]->type, &errNum); rtnObj = (WlzObject *) outCobj; } else { while( i >= 0 ){ WlzFreeObj(outArray[i--]); } } AlcFree(outArray); } } else { errNum = WLZ_ERR_OBJECT_DATA; } break; case WLZ_3D_DOMAINOBJ: errNum = WLZ_ERR_UNIMPLEMENTED; break; case WLZ_TRANS_OBJ: if((rtnObj = WlzShadeCorrectBFDF(srcObj->values.obj, shdObj, shdDFObj, nrmVal, inPlace, &errNum)) != NULL){ values.obj = rtnObj; return WlzMakeMain(WLZ_TRANS_OBJ, srcObj->domain, values, NULL, NULL, dstErr); } break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if(dstErr) { *dstErr = errNum; } return(rtnObj); }
/*! * \return New object or NULL on error. * \ingroup WlzValuesUtils * \brief Transfers grey values from the source object to the * destination object within the intersection of the source * and destination. Grey values within the destination * object outside of the source object are unchanged. * It is an error if either object has a different dimension * or grey value type, except for when either is an empty * object. * \param dObj Destination object which may be * empty, but otherwise should be of the * same dimension as the source object * with valid values.. * \param sObj Source object which if not empty must * have both a valid domain and valid * values. * \param inplace Overwrite the destination object's * values if non zero. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzGreyTransfer( WlzObject *dObj, WlzObject *sObj, int inplace, WlzErrorNum *dstErr) { WlzObject *rObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; if((dObj == NULL) || (sObj == NULL)) { errNum = WLZ_ERR_OBJECT_NULL; } else if(WlzIsEmpty(dObj, NULL)) { rObj = WlzMakeEmpty(&errNum); } else if(WlzIsEmpty(sObj, NULL)) { rObj = WlzMakeMain(dObj->type, dObj->domain, dObj->values, dObj->plist, NULL, &errNum); } else if(dObj->type != sObj->type) { errNum = WLZ_ERR_OBJECT_TYPE; } else if((dObj->domain.core == NULL) || (sObj->domain.core == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(sObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else { switch(sObj->type) { case WLZ_2D_DOMAINOBJ: case WLZ_3D_DOMAINOBJ: /* FALLTHROUGH */ { WlzObject *rIObj = NULL; rIObj = WlzIntersect2(dObj, sObj, &errNum); if((errNum == WLZ_ERR_NONE) && (WlzIsEmpty(rIObj, NULL) == 0)) { rObj = (inplace)? WlzMakeMain(dObj->type, dObj->domain, dObj->values, dObj->plist, NULL, &errNum): WlzCopyObject(dObj, &errNum); if(errNum == WLZ_ERR_NONE) { /* If the destination object does not have values then * create them to match the domain of the destination * object. */ if((sObj->values.core != NULL) && (rObj->values.core == NULL)) { WlzPixelV bgdV; WlzGreyType gType; WlzObjectType gTT; WlzValues newVal; newVal.core = NULL; bgdV = WlzGetBackground(sObj, &errNum); if(errNum == WLZ_ERR_NONE) { gType = WlzGreyTypeFromObj(sObj, &errNum); } if(errNum == WLZ_ERR_NONE) { gTT = WlzGreyTableType(WLZ_GREY_TAB_RAGR, gType, NULL); if(rObj->type == WLZ_2D_DOMAINOBJ) { newVal.v = WlzNewValueTb(rObj, gTT, bgdV, &errNum); } else /* rObj->type == WLZ_3D_DOMAINOBJ */ { newVal.vox = WlzNewValuesVox(rObj, gTT, bgdV, &errNum); } } if(errNum == WLZ_ERR_NONE) { rObj->values = WlzAssignValues(newVal, NULL); } if(errNum == WLZ_ERR_NONE) { errNum = WlzGreySetValue(rObj, bgdV); } } } if(errNum == WLZ_ERR_NONE) { if(sObj->type == WLZ_2D_DOMAINOBJ) { WlzObject *sIObj; rIObj->values = WlzAssignValues(rObj->values, NULL); sIObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, rIObj->domain, sObj->values, NULL, NULL, &errNum); if(errNum == WLZ_ERR_NONE) { errNum = WlzGreyTransfer2D(rIObj, sIObj); } (void )WlzFreeObj(sIObj); } else /* sObj->type == WLZ_3D_DOMAINOBJ */ { int p, rTiled, sTiled, nPlanes; rTiled = WlzGreyTableIsTiled(rObj->values.core->type); sTiled = WlzGreyTableIsTiled(sObj->values.core->type); nPlanes = rIObj->domain.p->lastpl - rIObj->domain.p->plane1 + 1; #ifdef _OPENMP #pragma omp parallel for #endif for(p = 0; p < nPlanes; ++p) { if(errNum == WLZ_ERR_NONE) { int pln; WlzDomain dom; WlzValues val; WlzObject *rIObj2D = NULL, *sIObj2D = NULL; WlzErrorNum errNum2D = WLZ_ERR_NONE; pln = p + rIObj->domain.p->plane1; dom = rIObj->domain.p->domains[p]; val = (rTiled)? rObj->values: rObj->values.vox->values[pln - rObj->values.vox->plane1]; rIObj2D = WlzMakeMain(WLZ_2D_DOMAINOBJ, dom, val, NULL, NULL, &errNum2D); if(errNum2D == WLZ_ERR_NONE) { val = (sTiled)? sObj->values: sObj->values.vox->values[pln - sObj->values.vox->plane1]; sIObj2D = WlzMakeMain(WLZ_2D_DOMAINOBJ, dom, val, NULL, NULL, &errNum2D); } if(errNum2D == WLZ_ERR_NONE) { errNum2D = WlzGreyTransfer2D(rIObj2D, sIObj2D); } (void )WlzFreeObj(rIObj2D); (void )WlzFreeObj(sIObj2D); #ifdef _OPENMP #pragma omp critical { #endif if((errNum == WLZ_ERR_NONE) && (errNum2D != WLZ_ERR_NONE)) { errNum = errNum2D; } #ifdef _OPENMP } #endif } } } } } (void )WlzFreeObj(rIObj); } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if(errNum != WLZ_ERR_NONE) { WlzFreeObj(rObj); rObj = NULL; } if(dstErr) { *dstErr = errNum; } return(rObj); }
/*! * \return Rescaled object. * \ingroup WlzTransform * \brief Rescales the given object using an integer scale. * \param gObj Given object. * \param scale Integer scale factor. * \param expand If zero use \f$\frac{1}{scale}\f$. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzIntRescaleObj(WlzObject *gObj, int scale, int expand, WlzErrorNum *dstErr) { WlzObject *rObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; if(gObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(scale < 1) { errNum = WLZ_ERR_PARAM_DATA; } else { switch(gObj->type) { case WLZ_2D_DOMAINOBJ: /* FALLTHROUGH */ case WLZ_3D_DOMAINOBJ: if(gObj->domain.i == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(gObj->domain.i->type == WLZ_EMPTY_DOMAIN) { rObj = WlzMakeEmpty(&errNum); } else if(scale == 1) { rObj = WlzMakeMain(gObj->type, gObj->domain, gObj->values, NULL, NULL, &errNum); } else { if(gObj->values.core && WlzGreyTableIsTiled(gObj->values.core->type)) { errNum = WLZ_ERR_VALUES_TYPE; } else { rObj = (gObj->type == WLZ_2D_DOMAINOBJ)? WlzIntRescaleObj2D(gObj, scale, expand, &errNum): WlzIntRescaleObj3D(gObj, scale, expand, &errNum); } } break; case WLZ_TRANS_OBJ: /* FALLTHROUGH */ case WLZ_2D_POLYGON: /* FALLTHROUGH */ case WLZ_BOUNDLIST: /* FALLTHROUGH */ case WLZ_3D_POLYGON: errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_EMPTY_OBJ: rObj = WlzMakeEmpty(&errNum); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if(dstErr) { *dstErr = errNum; } return(rObj); }
/*! * \return The filtered object, or NULL on error. * \ingroup WlzValueFilters * \brief Applies a recursive filter to the given object. * \param srcObj Given object. * \param ftr Recursive filter. * \param actionMsk Action mask. * \param dstErr Destination error pointer, may * be null. */ WlzObject *WlzRsvFilterObj(WlzObject *srcObj, WlzRsvFilter *ftr, int actionMsk, WlzErrorNum *dstErr) { WlzValues tVal; WlzObject *xObj = NULL, *yObj = NULL, *xyObj = NULL, *zObj = NULL, *dstObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; if((srcObj == NULL) || (ftr == NULL)) { errNum = WLZ_ERR_OBJECT_NULL; } else if(srcObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(srcObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else if(WlzGreyTableIsTiled(srcObj->values.core->type)) { errNum = WLZ_ERR_VALUES_TYPE; } else { switch(srcObj->type) { case WLZ_EMPTY_OBJ: dstObj = WlzMakeEmpty(&errNum); break; case WLZ_2D_DOMAINOBJ: if((actionMsk & (WLZ_RSVFILTER_ACTION_X | WLZ_RSVFILTER_ACTION_Y)) != 0) { /* Filter in each required direction. */ if((actionMsk & WLZ_RSVFILTER_ACTION_X) != 0) { xObj = WlzRsvFilterObj2DX(srcObj, ftr, &errNum); } if((errNum == WLZ_ERR_NONE) && ((actionMsk & WLZ_RSVFILTER_ACTION_Y) != 0)) { yObj = WlzRsvFilterObj2DY((xObj)? xObj: srcObj, ftr, &errNum); } if(errNum == WLZ_ERR_NONE) { if(yObj) { dstObj = yObj; yObj = NULL; } else if(xObj) { dstObj = xObj; xObj = NULL; } } if(xObj) { WlzFreeObj(xObj); } if(yObj) { WlzFreeObj(yObj); } } else { /* No filtering required. */ dstObj = WlzNewGrey(srcObj, &errNum); } break; case WLZ_3D_DOMAINOBJ: if((actionMsk & (WLZ_RSVFILTER_ACTION_X | WLZ_RSVFILTER_ACTION_Y | WLZ_RSVFILTER_ACTION_Z)) != 0) { if((actionMsk & (WLZ_RSVFILTER_ACTION_X | WLZ_RSVFILTER_ACTION_Y)) != 0) { xyObj = WlzRsvFilterObj3DXY(srcObj, ftr, actionMsk, &errNum); } if((errNum == WLZ_ERR_NONE) && ((actionMsk & WLZ_RSVFILTER_ACTION_Z) != 0)) { zObj = WlzRsvFilterObj3DZ((xyObj)? xyObj: srcObj, ftr, &errNum); } if(errNum == WLZ_ERR_NONE) { if(zObj) { dstObj = zObj; zObj = NULL; } else if(xyObj) { dstObj = xyObj; xyObj = NULL; } } if(xyObj) { WlzFreeObj(xyObj); } if(zObj) { WlzFreeObj(zObj); } } else { /* No filtering required. */ tVal = WlzCopyValues(srcObj->type, srcObj->values, srcObj->domain, &errNum); if(errNum == WLZ_ERR_NONE) { dstObj= WlzMakeMain(srcObj->type, srcObj->domain, tVal, NULL, NULL, &errNum); } } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if(dstErr) { *dstErr = errNum; } return(dstObj); }
/*! * \ingroup WlzAllocation * \brief Free space allocated to a woolz object. * * \return Error number, values: WLZ_ERR_NONE, WLZ_ERR_MEM_FREE * \param obj Object to be freed. * \par Source: * WlzFreeSpace.c */ WlzErrorNum WlzFreeObj(WlzObject *obj) { int i; WlzCompoundArray *ca = (WlzCompoundArray *) obj; WlzErrorNum errNum = WLZ_ERR_NONE; WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_FN|WLZ_DBG_LVL_1), ("WlzFreeObj FE %p\n", obj)); /* check the object pointer and linkcount */ if (obj == NULL){ return( WLZ_ERR_NONE ); } if( WlzUnlink(&(obj->linkcount), &errNum) ){ /* Check linkcount */ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_2D_DOMAINOBJ " "%p %d %p %d %p\n", obj, (obj->domain.i), (obj->domain.i?obj->domain.i->linkcount: 0), (obj->values.core), ((obj->values.core)? obj->values.core->linkcount: 0), (obj->plist))); errNum = WlzFreeDomain(obj->domain); if((errNum == WLZ_ERR_NONE) && (obj->values.core != NULL)) { if(WlzGreyTableIsTiled(obj->values.core->type) == WLZ_GREY_TAB_TILED) { errNum = WlzFreeTiledValues(obj->values.t); } else { errNum = WlzFreeValueTb(obj->values.v); } } if(errNum == WLZ_ERR_NONE) { errNum = WlzFreePropertyList(obj->plist); } if(errNum == WLZ_ERR_NONE) { errNum = WlzFreeObj(obj->assoc); } break; case WLZ_3D_DOMAINOBJ: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_3D_DOMAINOBJ %p, " "%d %p %d %p\n", obj, obj->domain.i, (obj->domain.p? obj->domain.p->linkcount: 0), obj->values.core, (obj->values.core? obj->values.core->linkcount: 0), obj->plist)); errNum = WlzFreePlaneDomain(obj->domain.p); if((errNum == WLZ_ERR_NONE) && (obj->values.core != NULL)){ if(WlzGreyTableIsTiled(obj->values.core->type) == WLZ_GREY_TAB_TILED) { errNum = WlzFreeTiledValues(obj->values.t); } else { errNum = WlzFreeVoxelValueTb(obj->values.vox); } } if(errNum == WLZ_ERR_NONE) { errNum = WlzFreePropertyList(obj->plist); } if(errNum == WLZ_ERR_NONE) { errNum = WlzFreeObj(obj->assoc); } break; case WLZ_TRANS_OBJ: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_TRANS_OBJ %p, " "%d %p %d %p\n", obj, obj->domain.t, ((obj->domain.t)?(obj->domain.t)->linkcount: 0), obj->values.obj, ((obj->values.obj)?(obj->values.obj)->linkcount: 0), obj->plist)); if( WlzFreeAffineTransform(obj->domain.t) || WlzFreeObj(obj->values.obj) || WlzFreePropertyList(obj->plist) || WlzFreeObj(obj->assoc) ){ errNum = WLZ_ERR_MEM_FREE; } break; case WLZ_2D_POLYGON: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_2D_POLYGON %p\n", obj, obj->domain.poly)); errNum = WlzFreePolyDmn(obj->domain.poly); break; case WLZ_BOUNDLIST: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_BOUNDLIST %p\n", obj, obj->domain.b)); errNum = WlzFreeBoundList(obj->domain.b); break; case WLZ_CONTOUR: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_CONTOUR %p\n", obj, obj->domain.ctr)); errNum = WlzFreeContour(obj->domain.ctr); break; case WLZ_CONV_HULL: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_CONV_HULL %p %p\n", obj, obj->domain.core, obj->values.core)); if(obj->domain.core) { switch(obj->domain.core->type) { case WLZ_CONVHULL_DOMAIN_2D: errNum = WlzFreeConvexHullDomain2(obj->domain.cvh2); break; case WLZ_CONVHULL_DOMAIN_3D: errNum = WlzFreeConvexHullDomain3(obj->domain.cvh3); break; default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } } break; case WLZ_CMESH_2D: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_CMESH_2D %p, " "%d %p %d %p\n", obj, obj->domain.cm2, ((obj->domain.cm2)? (obj->domain.cm2)->linkcount: 0), obj->values.x, ((obj->values.x)? (obj->values.x)->linkcount: 0), obj->plist)); errNum = WlzCMeshFree2D(obj->domain.cm2); if((errNum == WLZ_ERR_NONE) && (obj->values.core != NULL)) { errNum = WlzFreeIndexedValues(obj->values.x); } if((errNum == WLZ_ERR_NONE) && (obj->plist != NULL)) { errNum = WlzFreePropertyList(obj->plist); } if((errNum == WLZ_ERR_NONE) && (obj->assoc != NULL)) { errNum = WlzFreeObj(obj->assoc); } break; case WLZ_CMESH_2D5: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_CMESH_2D5 %p, " "%d %p %d %p\n", obj, obj->domain.cm2d5, ((obj->domain.cm2d5)? (obj->domain.cm2d5)->linkcount: 0), obj->values.x, ((obj->values.x)? (obj->values.x)->linkcount: 0), obj->plist)); errNum = WlzCMeshFree2D5(obj->domain.cm2d5); if((errNum == WLZ_ERR_NONE) && (obj->values.core != NULL)) { errNum = WlzFreeIndexedValues(obj->values.x); } if((errNum == WLZ_ERR_NONE) && (obj->plist != NULL)) { errNum = WlzFreePropertyList(obj->plist); } if((errNum == WLZ_ERR_NONE) && (obj->assoc != NULL)) { errNum = WlzFreeObj(obj->assoc); } break; case WLZ_CMESH_3D: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_CMESH_3D %p, " "%d %p %d %p\n", obj, obj->domain.cm3, ((obj->domain.cm3)?(obj->domain.cm3)->linkcount: 0), obj->values.x, ((obj->values.x)?(obj->values.x)->linkcount: 0), obj->plist)); errNum = WlzCMeshFree3D(obj->domain.cm3); if((errNum == WLZ_ERR_NONE) && (obj->values.core != NULL)) { errNum = WlzFreeIndexedValues(obj->values.x); } if((errNum == WLZ_ERR_NONE) && (obj->plist != NULL)) { errNum = WlzFreePropertyList(obj->plist); } if((errNum == WLZ_ERR_NONE) && (obj->assoc != NULL)) { errNum = WlzFreeObj(obj->assoc); } break; case WLZ_POINTS: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_POINTS %p\n", obj, obj->domain.pts)); errNum = WlzFreeDomain(obj->domain); if((errNum == WLZ_ERR_NONE) && (obj->values.core != NULL)) { errNum = WlzFreePointValues(obj->values.pts); } if((errNum == WLZ_ERR_NONE) && (obj->plist != NULL)) { errNum = WlzFreePropertyList(obj->plist); } if((errNum == WLZ_ERR_NONE) && (obj->assoc != NULL)) { errNum = WlzFreeObj(obj->assoc); } break; case WLZ_HISTOGRAM: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_CONV_HULL %p\n", obj, obj->domain.hist)); errNum = WlzFreeDomain(obj->domain); break; case WLZ_RECTANGLE: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_RECTANGLE %p\n", obj, obj->domain.r)); errNum = WlzFreeDomain(obj->domain); break; case WLZ_AFFINE_TRANS: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_AFFINE_TRANS\n", obj)); errNum = WlzFreeAffineTransform(obj->domain.t); break; case WLZ_LUT: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_LUT\n", obj)); errNum = WlzFreeDomain(obj->domain); if(errNum == WLZ_ERR_NONE) { errNum = WlzFreeLUTValues(obj->values); } break; case WLZ_COMPOUND_ARR_1: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_COMPOUND_ARR_1\n", ca)); for (i=0; i<ca->n; i++){ if( WlzFreeObj(ca->o[i]) != WLZ_ERR_NONE ){ errNum = WLZ_ERR_MEM_FREE; } } break; case WLZ_COMPOUND_ARR_2: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_COMPOUND_ARR_2\n", ca)); for (i=0; i<ca->n; i++){ if( WlzFreeObj(ca->o[i]) != WLZ_ERR_NONE ){ errNum = WLZ_ERR_MEM_FREE; } } break; case WLZ_PROPERTY_OBJ: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_PROPERTY_OBJ\n", obj)); errNum = WlzFreePropertyList(obj->plist); break; case WLZ_EMPTY_OBJ: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p WLZ_EMPTY_OBJ\n", obj)); break; default: WLZ_DBG((WLZ_DBG_ALLOC|WLZ_DBG_LVL_1), ("WlzFreeObj %p %d\n", obj, (int )(obj->type))); errNum = WLZ_ERR_OBJECT_TYPE; break; } /* End of switch */ AlcFree((void *) obj); } return( errNum ); }
static WlzObject *WlzCbThreshold3d( WlzObject *obj, WlzThreshCbFn threshCb, void *clientData, WlzErrorNum *dstErr) { WlzObject *obj1, *temp; WlzPlaneDomain *pdom, *npdom; WlzVoxelValues *voxtab, *nvoxtab; WlzDomain *domains, *ndomains, domain; WlzValues *values, *nvalues, vals; int i, nplanes; WlzErrorNum errNum=WLZ_ERR_NONE; /* no need to check the object pointer or type because this procedure can only be accessed via WlzThreshold. The domain and valuetable must be checked however */ obj1 = NULL; if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( WlzGreyTableIsTiled(obj->values.core->type) ){ errNum = WLZ_ERR_VALUES_TYPE; } /* check types */ if( errNum == WLZ_ERR_NONE ){ switch( obj->domain.p->type ){ case WLZ_PLANEDOMAIN_DOMAIN: break; default: errNum = WLZ_ERR_PLANEDOMAIN_TYPE; break; } } if( errNum == WLZ_ERR_NONE ){ switch( obj->values.vox->type ){ case WLZ_VOXELVALUETABLE_GREY: break; default: errNum = WLZ_ERR_VOXELVALUES_TYPE; break; } } /* make new planedomain and voxelvaluetable */ if( errNum == WLZ_ERR_NONE ){ pdom = obj->domain.p; voxtab = obj->values.vox; npdom = WlzMakePlaneDomain(pdom->type, pdom->plane1, pdom->lastpl, pdom->line1, pdom->lastln, pdom->kol1, pdom->lastkl, &errNum); } if((errNum == WLZ_ERR_NONE) && ((nvoxtab = WlzMakeVoxelValueTb(voxtab->type, voxtab->plane1, voxtab->lastpl, voxtab->bckgrnd, NULL, &errNum)) == NULL) ){ WlzFreePlaneDomain(npdom); } if( errNum == WLZ_ERR_NONE ){ /* set up variables */ domains = pdom->domains; ndomains = npdom->domains; values = voxtab->values; nvalues = nvoxtab->values; nplanes = pdom->lastpl - pdom->plane1 + 1; /* copy voxel_sizes */ for(i=0; i < 3; i++){ npdom->voxel_size[i] = pdom->voxel_size[i]; } } /* threshold each plane */ while( (errNum == WLZ_ERR_NONE) && nplanes-- ){ if(((*domains).core == NULL) || ((*values).core == NULL)){ (*ndomains).core = NULL; (*nvalues).core = NULL; } else if((temp = WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains, *values, NULL, NULL, &errNum)) != NULL){ if( (temp->domain.i != NULL) && (obj1 = WlzCbThreshold(temp, threshCb, clientData, &errNum)) ){ *ndomains = WlzAssignDomain(obj1->domain, NULL); *nvalues = WlzAssignValues(obj1->values, NULL); WlzFreeObj(obj1); } else { (*ndomains).core = NULL; (*nvalues).core = NULL; } } else { WlzFreePlaneDomain(npdom); WlzFreeVoxelValueTb( nvoxtab ); break; } domains++; ndomains++; values++; nvalues++; } /* standardise the plane domain */ if((errNum == WLZ_ERR_NONE) && ((errNum = WlzStandardPlaneDomain(npdom, nvoxtab)) != WLZ_ERR_NONE) ){ WlzFreePlaneDomain( npdom ); WlzFreeVoxelValueTb( nvoxtab ); } /* return a new object */ if( errNum == WLZ_ERR_NONE ){ domain.p = npdom; vals.vox = nvoxtab; if((obj1 = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, vals, NULL, obj, &errNum)) != NULL){ /* nvoxtab->original = obj1; */ nvoxtab->original_table = WlzAssignValues(obj->values, NULL); } else { WlzFreePlaneDomain( npdom ); WlzFreeVoxelValueTb( nvoxtab ); } } if( dstErr ){ *dstErr = errNum; } return obj1; }
/*! * \return New object with the rojection. * \ingroup WlzTransform * \brief Use the view transform to define a projection from * 3D to 2D and then project the object onto this plane. * The object supplied to this function must be a 3D * spatial domain object (WLZ_3D_DOMAINOBJ) with either * no values or for integration WLZ_GREY_UBYTE values. * Integration will assign each output pixel the sum of * all input voxels mapped via either the domain density * or the voxel density. * The integration is controled by the integrate parameter * with valid values: * WLZ_PROJECT_INT_MODE_NONE - a "shadow domain" without values * is computed, * WLZ_PROJECT_INT_MODE_DOMAIN - the voxels of the domain are * integrated using * \f[ p = \frac{1}{255} n d \f] * WLZ_PROJECT_INT_MODE_VALUES - the voxel values are integrated * using * \f[ p = \frac{1}{255} \sum{l\left[v\right]}. \f] * Where * \f$p\f$ is the projected image value, * \f$n\f$ is the number of voxels projected for \f$p\f$, * \f$d\f$ is the density of domain voxels, * \f$l\f$ is the voxel value density look up table and * \f$v\f$ is a voxel value. * \param obj The given object. * \param vStr Given view structure defining the * projection plane. * \param intMod This may take three values: * WLZ_PROJECT_INT_MODE_NONE, * WLZ_PROJECT_INT_MODE_DOMAIN or * WLZ_PROJECT_INT_MODE_VALUES. * \param denDom Density of domain voxels this value * is not used unless the integration * mode is WLZ_PROJECT_INT_MODE_DOMAIN. * \param denVal Density look up table for object * voxel density values which must be * an array of 256 values. This may be * NULL if the integration mode is not * WLZ_PROJECT_INT_MODE_VALUES. * \param depth If greater than zero, the projection * depth perpendicular to the viewing * plane. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzProjectObjToPlane(WlzObject *obj, WlzThreeDViewStruct *vStr, WlzProjectIntMode intMod, WlzUByte denDom, WlzUByte *denVal, double depth, WlzErrorNum *dstErr) { int nThr = 1, itvVal = 0; WlzIVertex2 prjSz; WlzIBox2 prjBox = {0}; double pln[4]; WlzObject *bufObj = NULL, *prjObj = NULL; WlzThreeDViewStruct *vStr1 = NULL; double **vMat = NULL; WlzValues nullVal; WlzErrorNum errNum = WLZ_ERR_NONE; WlzAffineTransform *rescaleTr = NULL; WlzGreyValueWSpace **gVWSp = NULL; void ***prjAry = NULL; const double eps = 0.000001; #ifdef WLZ_DEBUG_PROJECT3D_TIME struct timeval times[3]; #endif /* WLZ_DEBUG_PROJECT3D_TIME */ nullVal.core = NULL; if(obj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(obj->type != WLZ_3D_DOMAINOBJ) { errNum = WLZ_ERR_OBJECT_TYPE; } else if(obj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(obj->domain.core->type != WLZ_PLANEDOMAIN_DOMAIN) { errNum = WLZ_ERR_DOMAIN_TYPE; } else if(vStr == NULL) { errNum = WLZ_ERR_TRANSFORM_NULL; } else if((intMod == WLZ_PROJECT_INT_MODE_VALUES) && (obj->values.core == NULL)) { errNum = WLZ_ERR_VALUES_NULL; } #ifdef WLZ_DEBUG_PROJECT3D_TIME gettimeofday(times + 0, NULL); #endif /* WLZ_DEBUG_PROJECT3D_TIME */ /* Create new view transform without voxel scaling. The voxel scaling * is done after the projection. */ if(errNum == WLZ_ERR_NONE) { if((vStr1 = WlzMake3DViewStruct(WLZ_3D_VIEW_STRUCT, &errNum)) != NULL) { vStr1->fixed = vStr->fixed; vStr1->theta = vStr->theta; vStr1->phi = vStr->phi; vStr1->zeta = vStr->zeta; vStr1->dist = vStr->dist; vStr1->scale = vStr->scale; vStr1->voxelSize[0] = 1.0; vStr1->voxelSize[1] = 1.0; vStr1->voxelSize[2] = 1.0; vStr1->voxelRescaleFlg = 0; vStr1->interp = vStr->interp; vStr1->view_mode = vStr->view_mode; vStr1->up = vStr->up; vStr1->initialised = WLZ_3DVIEWSTRUCT_INIT_NONE; vMat = vStr1->trans->mat; errNum = WlzInit3DViewStructAffineTransform(vStr1); if(errNum == WLZ_ERR_NONE) { errNum = Wlz3DViewStructTransformBB(obj, vStr1); } if(errNum != WLZ_ERR_NONE) { WlzFree3DViewStruct(vStr1); vStr1 = NULL; } } } /* Compute bounding box of the projection. */ if(errNum == WLZ_ERR_NONE) { prjBox.xMin = WLZ_NINT(vStr1->minvals.vtX); prjBox.yMin = WLZ_NINT(vStr1->minvals.vtY); prjBox.xMax = WLZ_NINT(vStr1->maxvals.vtX); prjBox.yMax = WLZ_NINT(vStr1->maxvals.vtY); prjSz.vtX = prjBox.xMax - prjBox.xMin + 1; prjSz.vtY = prjBox.yMax - prjBox.yMin + 1; } /* Compute post projection scaling. */ if((errNum == WLZ_ERR_NONE) && (vStr->voxelRescaleFlg != 0)) { WlzIBox2 sBox; WlzIVertex2 sSz; WlzThreeDViewStruct *vStr2; vStr2 = WlzMake3DViewStruct(WLZ_3D_VIEW_STRUCT, &errNum); if(errNum == WLZ_ERR_NONE) { vStr2->fixed = vStr->fixed; vStr2->theta = vStr->theta; vStr2->phi = vStr->phi; vStr2->zeta = vStr->zeta; vStr2->dist = vStr->dist; vStr2->scale = vStr->scale; vStr2->voxelSize[0] = vStr->voxelSize[0]; vStr2->voxelSize[1] = vStr->voxelSize[1]; vStr2->voxelSize[2] = vStr->voxelSize[2]; vStr2->voxelRescaleFlg = vStr->voxelRescaleFlg; vStr2->interp = vStr->interp; vStr2->view_mode = vStr->view_mode; vStr2->up = vStr->up; vStr2->initialised = WLZ_3DVIEWSTRUCT_INIT_NONE; errNum = WlzInit3DViewStructAffineTransform(vStr2); if(errNum == WLZ_ERR_NONE) { errNum = Wlz3DViewStructTransformBB(obj, vStr2); } if(errNum == WLZ_ERR_NONE) { sBox.xMin = WLZ_NINT(vStr2->minvals.vtX); sBox.yMin = WLZ_NINT(vStr2->minvals.vtY); sBox.xMax = WLZ_NINT(vStr2->maxvals.vtX); sBox.yMax = WLZ_NINT(vStr2->maxvals.vtY); sSz.vtX = sBox.xMax - sBox.xMin + 1; sSz.vtY = sBox.yMax - sBox.yMin + 1; rescaleTr = WlzMakeAffineTransform(WLZ_TRANSFORM_2D_AFFINE, &errNum); } if(errNum == WLZ_ERR_NONE) { double **m; m = rescaleTr->mat; m[0][0] = (sSz.vtX * eps) / (prjSz.vtX * eps); m[1][1] = (sSz.vtY * eps) / (prjSz.vtY * eps); m[0][2] = sBox.xMin - WLZ_NINT(m[0][0] * prjBox.xMin); m[1][2] = sBox.yMin - WLZ_NINT(m[1][1] * prjBox.yMin); } (void )WlzFree3DViewStruct(vStr2); } } /* Compute plane equation, used to clip intervals if depth was given. */ if((errNum == WLZ_ERR_NONE) && (depth > eps)) { Wlz3DViewGetPlaneEqn(vStr1, pln + 0, pln + 1, pln + 2, pln + 3); } /* Create rectangular projection array buffers, one for each thread, * also if integrating values create a grey value workspace per thread. */ if(errNum == WLZ_ERR_NONE) { int idB; #ifdef _OPENMP #pragma omp parallel { #pragma omp master { nThr = omp_get_num_threads(); } } #endif if((prjAry = (void ***)AlcCalloc(nThr, sizeof(void **))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { if(intMod == WLZ_PROJECT_INT_MODE_NONE) { for(idB = 0; idB < nThr; ++idB) { if(AlcUnchar2Calloc((WlzUByte ***)&(prjAry[idB]), prjSz.vtY, prjSz.vtX) != ALC_ER_NONE) { errNum = WLZ_ERR_MEM_ALLOC; break; } } } else { for(idB = 0; idB < nThr; ++idB) { if(AlcInt2Calloc((int ***)&(prjAry[idB]), prjSz.vtY, prjSz.vtX) != ALC_ER_NONE) { errNum = WLZ_ERR_MEM_ALLOC; break; } } } } if((errNum == WLZ_ERR_NONE) && (intMod == WLZ_PROJECT_INT_MODE_VALUES)) { itvVal = (WlzGreyTableIsTiled(obj->values.core->type) == 0); if(itvVal == 0) { if((gVWSp = AlcCalloc(nThr, sizeof(WlzGreyValueWSpace *))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { for(idB = 0; idB < nThr; ++idB) { gVWSp[idB] = WlzGreyValueMakeWSp(obj, &errNum); if(gVWSp[idB]->gType != WLZ_GREY_UBYTE) { errNum = WLZ_ERR_GREY_TYPE; break; } } } } } } /* Scan through the 3D domain setting value in the projection array. */ if(errNum == WLZ_ERR_NONE) { int pIdx, pCnt; WlzDomain *doms; WlzValues *vals = NULL; doms = obj->domain.p->domains; if(itvVal) { vals = obj->values.vox->values; } pCnt = obj->domain.p->lastpl - obj->domain.p->plane1 + 1; #ifdef _OPENMP #pragma omp parallel for #endif for(pIdx = 0; pIdx < pCnt; ++pIdx) { int thrId = 0; if((errNum == WLZ_ERR_NONE) && (doms[pIdx].core != NULL)) { WlzObject *obj2; WlzGreyWSpace gWSp; WlzIntervalWSpace iWSp; WlzErrorNum errNum2 = WLZ_ERR_NONE; #ifdef _OPENMP thrId = omp_get_thread_num(); #endif obj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, doms[pIdx], (vals)? vals[pIdx]: nullVal, NULL, NULL, &errNum2); if(errNum2 == WLZ_ERR_NONE) { if(itvVal) { errNum2 = WlzInitGreyScan(obj2, &iWSp, &gWSp); } else { errNum2 = WlzInitRasterScan(obj2, &iWSp, WLZ_RASTERDIR_ILIC); } } if(errNum2 == WLZ_ERR_NONE) { double plnZ, vMZX, vMZY; WlzIVertex3 p0, p1; p0.vtZ = p1.vtZ = obj->domain.p->plane1 + pIdx; vMZX = (vMat[0][2] * p0.vtZ) + vMat[0][3] - prjBox.xMin; vMZY = (vMat[1][2] * p0.vtZ) + vMat[1][3] - prjBox.yMin; plnZ = (pln[2] * p0.vtZ) + pln[3]; while(((itvVal == 0) && ((errNum2 = WlzNextInterval(&iWSp)) == WLZ_ERR_NONE)) || ((itvVal != 0) && ((errNum2 = WlzNextGreyInterval(&iWSp)) == WLZ_ERR_NONE))) { int skip = 0; WlzDVertex2 q0, q1; p0.vtX = iWSp.lftpos; p1.vtX = iWSp.rgtpos; p0.vtY = p1.vtY = iWSp.linpos; if(depth > eps) { int c; double d0, d1, plnYZ; /* Clip the 3D line segment p0,p1 using the plane equation. */ plnYZ = (pln[1] * p0.vtY) + plnZ; d0 = (pln[0] * p0.vtX) + plnYZ; d1 = (pln[0] * p1.vtX) + plnYZ; c = ((d1 > depth) << 3) | ((d0 > depth) << 2) | ((d1 < -depth) << 1) | (d0 < -depth); if(c) { if((c == 3) || (c == 12)) /* 00-- or ++00 */ { /* Both out of range, so don't render. */ skip = 1; } else { if(fabs(pln[0]) > eps) { double plnX; plnX = -1.0 / pln[0]; if((c & 1) != 0) /* x0x- */ { p0.vtX = plnX * (plnYZ + depth); } else if((c & 4) != 0) /* x+x0 */ { p0.vtX = plnX * (plnYZ - depth); } if((c & 2) != 0) /* 0x-x */ { p1.vtX = plnX * (plnYZ + depth); } else if((c & 8) != 0) /* +x0x */ { p1.vtX = plnX * (plnYZ - depth); } } } } } if(skip == 0) { q0.vtX = (vMat[0][0] * p0.vtX) + (vMat[0][1] * p0.vtY) + vMZX; q0.vtY = (vMat[1][0] * p0.vtX) + (vMat[1][1] * p0.vtY) + vMZY; q1.vtX = (vMat[0][0] * p1.vtX) + (vMat[0][1] * p1.vtY) + vMZX; q1.vtY = (vMat[1][0] * p1.vtX) + (vMat[1][1] * p1.vtY) + vMZY; switch(intMod) { case WLZ_PROJECT_INT_MODE_NONE: { WlzIVertex2 u0, u1; WLZ_VTX_2_NINT(u0, q0); WLZ_VTX_2_NINT(u1, q1); WlzProjectObjLine((WlzUByte **)(prjAry[thrId]), u0, u1); } break; case WLZ_PROJECT_INT_MODE_DOMAIN: { int np, nq; WlzDVertex3 dq; WlzIVertex2 u0, u1; WLZ_VTX_2_NINT(u0, q0); WLZ_VTX_2_NINT(u1, q1); WLZ_VTX_2_SUB(dq, q0, q1); np = denDom * (iWSp.rgtpos - iWSp.lftpos + 1); nq = (int )ceil(WLZ_VTX_2_LENGTH(dq) + eps); WlzProjectObjLineDom((int **)(prjAry[thrId]), np / nq, u0, u1); } break; case WLZ_PROJECT_INT_MODE_VALUES: if(itvVal) { WlzProjectObjLineVal((int **)(prjAry[thrId]), denVal, gWSp.u_grintptr.ubp, NULL, vMat, vMZX, vMZY, p0, p1); } else { WlzProjectObjLineVal((int **)(prjAry[thrId]), denVal, NULL, gVWSp[thrId], vMat, vMZX, vMZY, p0, p1); } break; } } } (void )WlzEndGreyScan(&iWSp, &gWSp); if(errNum2 == WLZ_ERR_EOO) { errNum2 = WLZ_ERR_NONE; } } (void )WlzFreeObj(obj2); if(errNum2 != WLZ_ERR_NONE) { #ifdef _OPENMP #pragma omp critical { #endif if(errNum == WLZ_ERR_NONE) { errNum = errNum2; } #ifdef _OPENMP } #endif } } } } /* Free grey value workspaces if they were created. */ if(gVWSp) { int idB; for(idB = 0; idB < nThr; ++idB) { WlzGreyValueFreeWSp(gVWSp[idB]); } AlcFree(gVWSp); } if(errNum == WLZ_ERR_NONE) { int idB; size_t idC, bufSz; WlzGreyP buf0, buf1; WlzIVertex2 prjOrg; prjOrg.vtX = prjBox.xMin; prjOrg.vtY = prjBox.yMin; bufSz = prjSz.vtX * prjSz.vtY; for(idB = 1; idB < nThr; ++idB) { if(intMod == WLZ_PROJECT_INT_MODE_NONE) { buf0.ubp = ((WlzUByte ***)(prjAry))[0][0], buf1.ubp = ((WlzUByte ***)(prjAry))[idB][0]; for(idC = 0; idC < bufSz; ++idC) { buf0.ubp[idC] += buf1.ubp[idC]; } } else { buf0.inp = ((int ***)(prjAry))[0][0], buf1.inp = ((int ***)(prjAry))[idB][0]; for(idC = 0; idC < bufSz; ++idC) { buf0.inp[idC] += buf1.inp[idC]; } } } switch(intMod != WLZ_PROJECT_INT_MODE_NONE) { buf0.inp = ((int ***)(prjAry))[0][0]; for(idC = 0; idC < bufSz; ++idC) { buf0.inp[idC] /= 256; } } if(intMod == WLZ_PROJECT_INT_MODE_NONE) { bufObj = WlzAssignObject( WlzFromArray2D((void **)(prjAry[0]), prjSz, prjOrg, WLZ_GREY_UBYTE, WLZ_GREY_UBYTE, 0.0, 1.0, 1, 0, &errNum), NULL); } else { bufObj = WlzAssignObject( WlzFromArray2D((void **)(prjAry[0]), prjSz, prjOrg, WLZ_GREY_INT, WLZ_GREY_INT, 0.0, 1.0, 1, 0, &errNum), NULL); } } /* Free the projection array(s). */ if(prjAry) { int idB; for(idB = 0; idB < nThr; ++idB) { (void )Alc2Free((prjAry[idB])); } AlcFree(prjAry); } /* Make return object using threshold. */ if(errNum == WLZ_ERR_NONE) { WlzPixelV tV; WlzObject *tObj = NULL; tV.type = WLZ_GREY_UBYTE; tV.v.ubv = 1; tObj = WlzAssignObject( WlzThreshold(bufObj, tV, WLZ_THRESH_HIGH, &errNum), NULL); if(tObj) { if(intMod == WLZ_PROJECT_INT_MODE_NONE) { prjObj = WlzMakeMain(tObj->type, tObj->domain, nullVal, NULL, NULL, &errNum); } else { prjObj = WlzMakeMain(tObj->type, tObj->domain, tObj->values, NULL, NULL, &errNum); } } (void )WlzFreeObj(tObj); } (void )WlzFreeObj(bufObj); (void )WlzFree3DViewStruct(vStr1); /* Scale image. */ if(rescaleTr != NULL) { if(errNum == WLZ_ERR_NONE) { WlzObject *tObj = NULL; tObj = WlzAffineTransformObj(prjObj, rescaleTr, WLZ_INTERPOLATION_NEAREST, &errNum); (void )WlzFreeObj(prjObj); prjObj = tObj; } (void )WlzFreeAffineTransform(rescaleTr); } #ifdef WLZ_DEBUG_PROJECT3D_TIME gettimeofday(times + 1, NULL); ALC_TIMERSUB(times + 1, times + 0, times + 2); (void )fprintf(stderr, "WlzGetProjectionFromObject: Elapsed time = %g\n", times[2].tv_sec + (0.000001 * times[2].tv_usec)); #endif /* WLZ_DEBUG_PROJECT3D_TIME */ if(dstErr) { *dstErr = errNum; } return(prjObj); }
/*! * \ingroup WlzBinaryOps * \brief Calculate the intersection of a set of objects. If uvt=0 calculate domain only, uvt=1 calculate the mmean grey-value at each point. Input objects must be all non-NULL and domain objects of the same type i.e. either 2D or 3D otherwise an error is returned. * * \return Intersection object with grey-table as required, if the intersection is empty returns WLZ_EMPTY_OBJ, NULL on error. * \param n number of input objects * \param objs input object array * \param uvt grey-table copy flag (1 - copy, 0 - no copy) * \param dstErr error return. * \par Source: * WlzIntersectN.c */ WlzObject *WlzIntersectN( int n, WlzObject **objs, int uvt, WlzErrorNum *dstErr) { WlzObject *obj = NULL; WlzIntervalDomain *idom; WlzInterval *itvl, *jtvl; WlzIntervalWSpace *iwsp; WlzIntervalWSpace *biwsp,*tiwsp,niwsp; WlzGreyWSpace *gwsp,ngwsp; WlzDomain domain; WlzValues values; WlzObjectType type; WlzPixelV backg; WlzGreyP greyptr; WlzGreyV gv; int i, j, k, l, inttot, change, lwas, nints; int line1, lastln; int kol1, lastkl; WlzErrorNum errNum = WLZ_ERR_NONE; /* * check pointers */ /* intersecction of no objects is an empty domain */ domain.i = NULL; values.v = NULL; if( n < 1 ) { return WlzMakeEmpty(dstErr); } /* array pointer == NULL or any object pointer == NULL is an error */ if(objs == NULL){ errNum = WLZ_ERR_OBJECT_NULL; } else { for(i=0; i<n; i++){ if(objs[i] == NULL){ errNum = WLZ_ERR_OBJECT_NULL; } } } if(errNum != WLZ_ERR_NONE) { obj = NULL; if(dstErr) { *dstErr = errNum; } return(obj); } /* check type of first object */ switch( objs[0]->type ){ case WLZ_2D_DOMAINOBJ: break; case WLZ_3D_DOMAINOBJ: return WlzIntersect3d(objs, n, uvt, &errNum); case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; if(dstErr) { *dstErr = errNum; } return NULL; } /* check number */ if (n == 1){ obj = WlzMakeMain(objs[0]->type, objs[0]->domain, objs[0]->values, NULL, NULL, &errNum); if(dstErr) { *dstErr = errNum; } return(obj); } /* check all objects are non-empty and have the same type Note an empty object is not an error */ for (i=0; i<n; i++){ if( objs[i]->type != objs[0]->type ){ if( objs[i]->type == WLZ_EMPTY_OBJ ){ return WlzMakeEmpty(dstErr); } else { errNum = WLZ_ERR_OBJECT_TYPE; if(dstErr) { *dstErr = errNum; } return NULL; } } /* check for size */ if( WlzIsEmpty(objs[i], &errNum) ){ return WlzMakeEmpty(dstErr); } else { if( errNum != WLZ_ERR_NONE ){ if(dstErr) { *dstErr = errNum; } return NULL; } } } /* This function doesn't support objects with tiled values if the * uvt flag is set. */ if((errNum == WLZ_ERR_NONE) && uvt) { for(i = 0; i < n; ++i) { if(objs[i] && objs[i]->values.core && WlzGreyTableIsTiled(objs[i]->values.core->type)) { errNum = WLZ_ERR_VALUES_TYPE; break; } } if(errNum != WLZ_ERR_NONE) { *dstErr = errNum; return NULL; } } /* * Find the line and column bounds of the intersection. */ line1 = objs[0]->domain.i->line1; lastln = objs[0]->domain.i->lastln; kol1 = objs[0]->domain.i->kol1; lastkl = objs[0]->domain.i->lastkl; for (i=1; i<n; i++) { idom = objs[i]->domain.i; if (line1 < idom->line1) { line1 = idom->line1; } if (lastln > idom->lastln) { lastln = idom->lastln; } if (kol1 < idom->kol1) { kol1 = idom->kol1; } if (lastkl > idom->lastkl) { lastkl = idom->lastkl; } } if( lastkl < kol1 || lastln < line1 ){ return WlzMakeEmpty(dstErr); } /* * Count the individual intervals so that sufficient space * for the intersection may be allocated. */ inttot=0; for (i=0; (i < n) && (errNum == WLZ_ERR_NONE); i++) { inttot += WlzIntervalCount(objs[i]->domain.i, &errNum); } if(errNum != WLZ_ERR_NONE) { if(dstErr) { *dstErr = errNum; } return NULL; } /* * Set up domain, value table structures, and object. */ if( (idom = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, line1, lastln, 0, lastkl-kol1, &errNum)) == NULL ){ if(dstErr) { *dstErr = errNum; } return NULL; } if( (itvl = (WlzInterval *) AlcMalloc (inttot * sizeof(WlzInterval))) == NULL ){ WlzFreeIntervalDomain(idom); errNum = WLZ_ERR_MEM_ALLOC; if(dstErr) { *dstErr = errNum; } return NULL; } idom->freeptr = AlcFreeStackPush(idom->freeptr, (void *)itvl, NULL); lwas = line1; jtvl = itvl; nints = 0; domain.i = idom; values.v = NULL; if( (obj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain, values, NULL, NULL, &errNum)) == NULL ){ WlzFreeIntervalDomain(idom); if(dstErr) { *dstErr = errNum; } return NULL; } /* * allocate space for workspaces */ if( (iwsp = (WlzIntervalWSpace *) AlcMalloc(n * sizeof(WlzIntervalWSpace))) == NULL ){ WlzFreeObj( obj ); errNum = WLZ_ERR_MEM_ALLOC; if(dstErr) { *dstErr = errNum; } return NULL; } biwsp = iwsp; tiwsp = biwsp + n; /* * Construct the intersection object's table of intervals. * Initialise scanning on each object/workspace combination. * Scan synchronously, setting up the intersection of * overlapping intervals. Needs a clear head !! */ for (i=0; (i < n) && (errNum == WLZ_ERR_NONE); i++) { errNum = WlzInitRasterScan(objs[i],iwsp,WLZ_RASTERDIR_ILIC); if(errNum == WLZ_ERR_NONE) { errNum = WlzNextInterval(iwsp++); } } if(errNum != WLZ_ERR_NONE) { WlzFreeObj( obj ); if(dstErr) { *dstErr = errNum; } return NULL; } l = lwas; for (;;) { /* * find next line of intersection */ do { change = 0; for (iwsp=biwsp; iwsp<tiwsp; iwsp++) { if (iwsp->linpos > l) { l = iwsp->linpos; } } for (iwsp=biwsp; iwsp<tiwsp; iwsp++) { while (iwsp->linpos < l) { if ((errNum = WlzNextInterval(iwsp)) != WLZ_ERR_NONE) { if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } goto firstfinished; } if (iwsp->linpos > l) { change = 1; } } } } while (change != 0); /* * find next interval of intersection */ kol1 = biwsp->lftpos; lastkl = biwsp->rgtpos; while(errNum == WLZ_ERR_NONE) { do { change = 0; for (iwsp=biwsp; iwsp<tiwsp; iwsp++) if (iwsp->lftpos > lastkl) { kol1 = iwsp->lftpos; lastkl = iwsp->rgtpos; } else if (iwsp->lftpos > kol1) kol1 = iwsp->lftpos; for (iwsp=biwsp; iwsp<tiwsp; iwsp++) { while (iwsp->rgtpos < kol1) { if ((errNum = WlzNextInterval(iwsp)) != WLZ_ERR_NONE) { if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } goto firstfinished; } if (iwsp->linpos != l) { l = iwsp->linpos; goto jumpline; } if (iwsp->lftpos > kol1) change = 1; } } } while ((change != 0) && (errNum == WLZ_ERR_NONE)); if(errNum == WLZ_ERR_NONE) { for (iwsp=biwsp; iwsp < tiwsp; iwsp++) { if (iwsp->rgtpos <= lastkl) { lastkl = iwsp->rgtpos; } } if (lastkl >= kol1) { itvl->ileft = kol1 - idom->kol1; itvl->iright = lastkl - idom->kol1; if (l == lwas) { nints++; } else { errNum = WlzMakeInterval(lwas,idom,nints,jtvl); for (j = lwas+1; (j < l) && (errNum == WLZ_ERR_NONE); j++) { errNum = WlzMakeInterval(j,idom,0,NULL); } if(errNum == WLZ_ERR_NONE) { lwas = l; nints = 1; jtvl = itvl; } } itvl++; } kol1 = lastkl+1; } } jumpline: ; } firstfinished: if(errNum != WLZ_ERR_NONE) { WlzFreeObj(obj); if(dstErr) { *dstErr = errNum; } return NULL; } errNum = WlzMakeInterval(lwas,idom,nints,jtvl); for (j = lwas+1; (j <= lastln) && (errNum == WLZ_ERR_NONE); j++) { errNum = WlzMakeInterval(j,idom,0,NULL); } if(errNum != WLZ_ERR_NONE) { WlzFreeObj(obj); AlcFree((void *) biwsp); if(dstErr) { *dstErr = errNum; } return NULL; } /* * standardise the interval list (remove leading and trailing * empty lines, set kol1 so that at least one interval commences * at zero, set lastkl correctly) */ (void )WlzStandardIntervalDomain(idom); /* check for error or empty */ nints = WlzIntervalCount(idom, &errNum); if( nints < 0 ){ /* error */ WlzFreeObj(obj); AlcFree((void *) biwsp); if(dstErr) { *dstErr = errNum; } return NULL; } else if( nints == 0 ){ /* empty object */ WlzFreeObj(obj); AlcFree((void *) biwsp); return WlzMakeEmpty(dstErr); } if (uvt != 0) { WlzGreyType grey_type; if( (gwsp = (WlzGreyWSpace *) AlcMalloc (n * sizeof (WlzGreyWSpace))) == NULL ){ WlzFreeObj(obj); AlcFree((void *) biwsp); errNum = WLZ_ERR_MEM_ALLOC; if(dstErr) { *dstErr = errNum; } return NULL; } /* construct an empty "ragged-rectangle" (type 1 or 2) greytable choosing the grey-value type from the first object in the list */ backg = WlzGetBackground(objs[0], &errNum); if(errNum == WLZ_ERR_NONE) { grey_type = WlzGreyTableTypeToGreyType(objs[0]->values.core->type, &errNum); } if(errNum == WLZ_ERR_NONE) { type = WlzGreyTableType(WLZ_GREY_TAB_RAGR, grey_type, &errNum); } if((errNum != WLZ_ERR_NONE) || (values.v = WlzNewValueTb(obj, type, backg, &errNum)) == NULL ){ WlzFreeObj( obj ); AlcFree((void *) gwsp); AlcFree((void *) biwsp); if(dstErr) { *dstErr = errNum; } return NULL; } obj->values = WlzAssignValues(values, &errNum); if(errNum != WLZ_ERR_NONE) { WlzFreeObj( obj ); AlcFree((void *) gwsp); AlcFree((void *) biwsp); if(dstErr) { *dstErr = errNum; } return NULL; } /* * fill the grey table with mean of grey values. */ /* initialise the work-spaces and check pixel type */ errNum = WlzInitGreyScan(obj, &niwsp, &ngwsp); iwsp = biwsp; for (i=0; (i < n) && (errNum == WLZ_ERR_NONE); i++) { errNum = WlzInitGreyScan(objs[i], iwsp, &gwsp[i]); if(errNum == WLZ_ERR_NONE) { errNum = WlzNextGreyInterval(iwsp++); } if( gwsp[i].pixeltype != grey_type ){ errNum = WLZ_ERR_GREY_TYPE; } } if(errNum != WLZ_ERR_NONE) { WlzFreeObj( obj ); AlcFree((void *) gwsp); AlcFree((void *) biwsp); if(dstErr) { *dstErr = errNum; } return NULL; } while (WlzNextGreyInterval(&niwsp) == WLZ_ERR_NONE) { l = niwsp.linpos; greyptr = ngwsp.u_grintptr; switch( ngwsp.pixeltype ){ case WLZ_GREY_INT: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { gv.inv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while(iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ (void )WlzNextGreyInterval(iwsp); } gv.inv += *(gwsp[i].u_grintptr.inp + k - iwsp->lftpos); } *greyptr.inp = gv.inv / n; greyptr.inp++; } break; case WLZ_GREY_SHORT: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { gv.shv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while(iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ (void )WlzNextGreyInterval(iwsp); } gv.shv += *(gwsp[i].u_grintptr.shp + k - iwsp->lftpos); } *greyptr.shp = (short )(gv.shv / n); greyptr.shp++; } break; case WLZ_GREY_UBYTE: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { gv.ubv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while(iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ (void )WlzNextGreyInterval(iwsp); } gv.ubv += *(gwsp[i].u_grintptr.ubp + k - iwsp->lftpos); } *greyptr.ubp = (WlzUByte )(gv.ubv / n); greyptr.ubp++; } break; case WLZ_GREY_FLOAT: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { gv.flv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while(iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ (void )WlzNextGreyInterval(iwsp); } gv.flv += *(gwsp[i].u_grintptr.flp + k - iwsp->lftpos); } *greyptr.flp = gv.flv / n; greyptr.flp++; } break; case WLZ_GREY_DOUBLE: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { gv.dbv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while(iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ (void )WlzNextGreyInterval(iwsp); } gv.dbv += *(gwsp[i].u_grintptr.dbp + k - iwsp->lftpos); } *greyptr.dbp = gv.dbv / n; greyptr.dbp++; } break; case WLZ_GREY_RGBA: /* RGBA to be done again RAB */ for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { gv.rgbv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while(iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ (void )WlzNextGreyInterval(iwsp); } gv.rgbv += *(gwsp[i].u_grintptr.rgbp + k - iwsp->lftpos); } *greyptr.rgbp = gv.rgbv / n; greyptr.rgbp++; } break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } AlcFree((void *) gwsp); } AlcFree((void *) biwsp); if(dstErr) { *dstErr = errNum; } return obj; }
/*! * \ingroup WlzValuesUtils * \brief Transfer grey values from the source object to the destination object. Currently it is assumed that the objects are of the same type (2D/3D) and have the same grey-value type. * * \return Woolz object with transferred grey values * \param obj destination object * \param srcObj source object * \param dstErr error return * \par Source: * WlzGreyTransfer.c */ WlzObject *WlzGreyTransfer( WlzObject *obj, WlzObject *srcObj, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzObject *obj1, *obj2; WlzValues values; WlzIntervalWSpace iwsp1, iwsp2; WlzGreyWSpace gwsp1, gwsp2; int size; WlzErrorNum errNum=WLZ_ERR_NONE; /* check destination obj */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if(WlzGreyTableIsTiled(obj->values.core->type)) { errNum = WLZ_ERR_VALUES_TYPE; } else { rtnObj = WlzCopyObject(obj, &errNum); } break; case WLZ_3D_DOMAINOBJ: return WlzGreyTransfer3d(obj, srcObj, dstErr); case WLZ_TRANS_OBJ: if((values.obj = WlzGreyTransfer(obj->values.obj, srcObj, &errNum)) != NULL){ return WlzMakeMain(WLZ_TRANS_OBJ, obj->domain, values, NULL, NULL, dstErr); } break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* check the source object */ if( errNum == WLZ_ERR_NONE ){ if( srcObj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( srcObj->type ){ case WLZ_2D_DOMAINOBJ: break; case WLZ_TRANS_OBJ: srcObj = srcObj->values.obj; break; case WLZ_EMPTY_OBJ: if( dstErr ){ *dstErr = errNum; } return rtnObj; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } } /* copy source obj values within the intersection */ if( errNum == WLZ_ERR_NONE ){ if((srcObj->type != WLZ_EMPTY_OBJ) ){ if( (obj1 = WlzIntersect2(srcObj, rtnObj, &errNum)) ){ obj1->values = WlzAssignValues(rtnObj->values, NULL); obj2 = WlzMakeMain(obj1->type, obj1->domain, srcObj->values, NULL, NULL, NULL); errNum = WlzInitGreyScan(obj1, &iwsp1, &gwsp1); errNum = WlzInitGreyScan(obj2, &iwsp2, &gwsp2); switch( gwsp1.pixeltype ){ case WLZ_GREY_INT: size = sizeof(int); break; case WLZ_GREY_SHORT: size = sizeof(short); break; case WLZ_GREY_UBYTE: size = sizeof(WlzUByte); break; case WLZ_GREY_FLOAT: size = sizeof(float); break; case WLZ_GREY_DOUBLE: size = sizeof(double); break; case WLZ_GREY_RGBA: size = sizeof(WlzUInt); break; default: errNum = WLZ_ERR_GREY_TYPE; break; } while((errNum == WLZ_ERR_NONE) && (errNum = WlzNextGreyInterval(&iwsp1)) == WLZ_ERR_NONE){ (void) WlzNextGreyInterval(&iwsp2); memcpy((void *) gwsp1.u_grintptr.inp, (const void *) gwsp2.u_grintptr.inp, size * iwsp1.colrmn); } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzFreeObj(obj2); WlzFreeObj(obj1); } else { WlzFreeObj(rtnObj); rtnObj = NULL; } } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \ingroup WlzValuesUtils * \brief static function to implement WlzGreyTransfer for 3D objects. * * \return woolz object * \param obj destination object * \param srcObj source object * \param dstErr error return * \par Source: * WlzGreyTransfer.c */ static WlzObject *WlzGreyTransfer3d( WlzObject *obj, WlzObject *srcObj, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzObject *obj1, *obj2, *tmpObj; WlzDomain *domains; WlzValues values, *valuess; WlzPlaneDomain *pdom; int p; WlzErrorNum errNum=WLZ_ERR_NONE; /* check the object - it is non-NULL and 3D but the domain needs checking */ if( obj->domain.p == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else { switch( obj->domain.p->type ){ case WLZ_2D_DOMAINOBJ: /* check there is a valuetable */ if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if(WlzGreyTableIsTiled(obj->values.core->type)) { errNum = WLZ_ERR_VALUES_TYPE; } break; default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } } /* check the source object */ if( errNum == WLZ_ERR_NONE ){ if( srcObj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( srcObj->type ){ case WLZ_3D_DOMAINOBJ: if( srcObj->domain.p ){ switch( srcObj->domain.p->type ){ case WLZ_2D_DOMAINOBJ: break; default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } } else { errNum = WLZ_ERR_DOMAIN_NULL; } break; case WLZ_EMPTY_OBJ: return WlzCopyObject(obj, dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } } /* now we have a 3D obj and 3D srcObject so run through the source and map values as required */ if( errNum == WLZ_ERR_NONE ){ WlzDomain *objDoms; WlzValues *objVals; /* attach a voxel table with empty values list */ values.vox = WlzMakeVoxelValueTb(obj->values.vox->type, obj->domain.p->plane1, obj->domain.p->lastpl, obj->values.vox->bckgrnd, NULL, NULL); rtnObj = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); /* set some local variables */ pdom = rtnObj->domain.p; domains = rtnObj->domain.p->domains; valuess = rtnObj->values.vox->values; objDoms = obj->domain.p->domains; objVals = obj->values.vox->values; /* calculate the new valuetables */ for(p=pdom->plane1; p <= pdom->lastpl; p++, domains++, valuess++, objDoms++, objVals++){ if(((*domains).core)){ obj1 = WlzMakeMain(WLZ_2D_DOMAINOBJ, *objDoms, *objVals, NULL, NULL, &errNum); obj1 = WlzAssignObject(obj1, &errNum); if((p >= srcObj->domain.p->plane1) && (p <= srcObj->domain.p->lastpl) && (srcObj->domain.p->domains[p-srcObj->domain.p->plane1].core)){ obj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, srcObj->domain.p->domains[p-srcObj->domain.p->plane1], srcObj->values.vox->values[p-srcObj->domain.p->plane1], NULL, NULL, &errNum); } else { obj2 = WlzMakeEmpty(NULL); } obj2 = WlzAssignObject(obj2, &errNum); tmpObj = WlzGreyTransfer(obj1, obj2, &errNum); *valuess = WlzAssignValues(tmpObj->values, &errNum); WlzFreeObj(obj1); WlzFreeObj(obj2); WlzFreeObj(tmpObj); } } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
int main(int argc, char *argv[]) { int option, ok = 1, nFiles = 0, usage = 0; WlzIVertex3 offset; WlzErrorNum errNum = WLZ_ERR_NONE; WlzObject *tlObj = NULL; char *tlFileStr; const char *errMsg; static char optList[] = "ht:x:y:z:", tlFileStrDef[] = "-"; opterr = 0; tlFileStr = tlFileStrDef; WLZ_VTX_3_SET(offset, 0, 0, 0); while((usage == 0) && ((option = getopt(argc, argv, optList)) != -1)) { switch(option) { case 't': tlFileStr = optarg; break; case 'x': if(sscanf(optarg, "%d", &(offset.vtX)) != 1) { usage = 1; } break; case 'y': if(sscanf(optarg, "%d", &(offset.vtY)) != 1) { usage = 1; } break; case 'z': if(sscanf(optarg, "%d", &(offset.vtZ)) != 1) { usage = 1; } break; case 'h': /* FALLTHROUGH */ default: usage = 1; break; } } if(usage == 0) { if((nFiles = argc - optind) <= 0) { usage = 1; } } ok = !usage; if(ok) { FILE *fP = NULL; errNum = WLZ_ERR_READ_EOF; if(((fP = fopen(tlFileStr, "r+")) == NULL) || ((tlObj= WlzAssignObject(WlzReadObj(fP, &errNum), NULL)) == NULL)) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: Failed to open tiled object in file %s (%s).\n", *argv, tlFileStr, errMsg); } if(fP) { (void )fclose(fP); } } if(ok) { if(tlObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(tlObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(tlObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else if(WlzGreyTableIsTiled(tlObj->values.core->type) == 0) { errNum = WLZ_ERR_VALUES_TYPE; } if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: invalid tiled object in file %s (%s).\n", *argv, tlFileStr, errMsg); } } if(ok) { int idx; for(idx = 0; idx < nFiles; ++idx) { char *inFileStr; if((inFileStr = *(argv + optind + idx)) != NULL) { FILE *fP = NULL; if((fP = (strcmp(inFileStr, "-")? fopen(inFileStr, "r"): stdin)) == NULL) { ok = 0; (void )fprintf(stderr, "%s: Failed to open input file %s.\n", argv[0], inFileStr); } if(ok) { WlzObject *obj1 = NULL, *obj2 = NULL, *inObj = NULL; inObj = WlzAssignObject(WlzReadObj(fP, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { if(inObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else { switch(inObj->type) { case WLZ_2D_DOMAINOBJ: if(tlObj->type == WLZ_3D_DOMAINOBJ) { obj1 = WlzConstruct3DObjFromObj(1, &inObj, 0, 1.0f, 1.0f, 1.0f, &errNum); } else { obj1 = WlzAssignObject(inObj, NULL); } break; case WLZ_3D_DOMAINOBJ: obj1 = WlzAssignObject(inObj, NULL); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } } if(errNum == WLZ_ERR_NONE) { obj2 = WlzShiftObject(obj1, offset.vtX, offset.vtY, offset.vtZ, &errNum); } if(errNum == WLZ_ERR_NONE) { errNum = WlzCopyObjectGreyValues(tlObj, obj2); } (void )WlzFreeObj(obj1); (void )WlzFreeObj(obj2); (void )WlzFreeObj(inObj); } } } } (void )WlzFreeObj(tlObj); if(usage) { (void )fprintf(stderr, "Usage: %s%s%s%s", *argv, " [-h] [-t <tiled object>] [-x #] [-y #] [-z #]\n" " [<input objects>]\n" "Sets the values in the tiled object using the values in the given\n" "input object(s).\n" "Version: ", WlzVersion(), "\n" "Options:\n" " -h Prints this usage information.\n" " -t The tiled object.\n" " -x Column offset.\n" " -y Line offset.\n" " -z Plane offset.\n"); } return(!ok); }
/*! * \ingroup WlzValuesUtils * \brief Makes a dithered object from the given grey-level Woolz object. The destination bits are determined by the number of shades in the dithered image (usually 1 bit) and the bit planes to use (typically to match the bit-planes of a display mask). * * \return Object with dithered grey values. * \param o Input object. * \param destBits Destination bit planes for dithered values. * \param dstErr Error return. * \par Source: * WlzGreyDitherObj.c */ WlzObject *WlzGreyDitherObj( WlzObject *o, unsigned int destBits, WlzErrorNum *dstErr) { WlzObject *obj=NULL; WlzIntervalWSpace iwsp1, iwsp2; WlzGreyWSpace gwsp1, gwsp2; int i, j, m, g, G; int n_to; int bit_val[8], permute_val[256]; int factor_from, factor_to, mask_start; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object type - 1 only */ if( o == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( o->type ){ case WLZ_2D_DOMAINOBJ: /* check it has a valuetable */ if( o->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( WlzGreyTableIsTiled(o->values.core->type) ){ errNum = WLZ_ERR_VALUES_TYPE; } break; case WLZ_3D_DOMAINOBJ: case WLZ_TRANS_OBJ: errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_EMPTY_OBJ: obj = WlzMakeEmpty(&errNum); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if( !obj && (errNum == WLZ_ERR_NONE) ){ /* count the bits in the mask */ for(i=1, n_to=0; i <= destBits; i <<= 1 ) { if( i & destBits ) n_to++; } /* check numbers of bits */ if( n_to == 0 ){ errNum = WLZ_ERR_PARAM_DATA; } else { /* make a new object with the same domain */ if((obj = WlzNewGrey(o, &errNum)) != NULL){ if( n_to < 8 ){ /* set up some factors */ factor_from = 255; factor_to = (1<<n_to) - 1; mask_start = (1 << (8-n_to)) - 1; /* set up bit permute lut */ for(i=0, j=1, m=destBits; i < n_to; i++) { while( !(m&1) ) { m = m >> 1; j = j << 1; } m = m >> 1; bit_val[i] = j; } for(i=0; i < (1<<n_to); i++) { permute_val[i] = 0; for(j=0, m=1; j < n_to; j++, m = m<<1 ){ permute_val[i] += (i&m) * bit_val[j]; } } for(;i < 256; i++){ permute_val[i] = 0; } /* now scan the objects */ WlzInitGreyScan(o,&iwsp1,&gwsp1); WlzInitGreyScan(obj,&iwsp2,&gwsp2); while((WlzNextGreyInterval(&iwsp1) == WLZ_ERR_NONE) && (WlzNextGreyInterval(&iwsp2) == WLZ_ERR_NONE ) ) { j = iwsp1.linpos; G = rand() & mask_start; switch( gwsp1.pixeltype ) { case WLZ_GREY_INT: for(i=iwsp1.lftpos; i<=iwsp1.rgtpos; i++, gwsp1.u_grintptr.inp++, gwsp2.u_grintptr.inp++ ) { G += (*gwsp1.u_grintptr.inp) & 255; g = (G * factor_to) / factor_from; (*gwsp2.u_grintptr.inp) = permute_val[g]; G -= (g * factor_from) / factor_to; } break; case WLZ_GREY_SHORT: for(i=iwsp1.lftpos; i<=iwsp1.rgtpos; i++, gwsp1.u_grintptr.shp++, gwsp2.u_grintptr.shp++ ) { G += (*gwsp1.u_grintptr.shp) & 255; g = (G * factor_to) / factor_from; (*gwsp2.u_grintptr.shp) = (short )(permute_val[g]); G -= (g * factor_from) / factor_to; } break; case WLZ_GREY_UBYTE: for(i=iwsp1.lftpos; i<=iwsp1.rgtpos; i++, gwsp1.u_grintptr.ubp++, gwsp2.u_grintptr.ubp++ ) { G += (*gwsp1.u_grintptr.ubp); g = (G * factor_to) / factor_from; (*gwsp2.u_grintptr.ubp) = (WlzUByte )(permute_val[g]); G -= (g * factor_from) / factor_to; } break; case WLZ_GREY_RGBA: /* RGBA to be done RAB */ default: errNum = WLZ_ERR_GREY_TYPE; break; } } } } } }
/*! * \ingroup WlzValuesUtils * \brief Calculate the modulus of the grey-level gradient at each point. The gradient images are calculated using WlzGauss2() with width parameter set to <tt>width</tt>. Will now calculate the modulus for each object of a compound object if appropriate. * * \return Object with values set to the gradient modulus at each pixel. * \param obj Input object. * \param width Width parameter for the gaussian gradient operator. * \param dstErr Error return. * \par Source: * WlzGreyModGradient.c */ WlzObject *WlzGreyModGradient( WlzObject *obj, double width, WlzErrorNum *dstErr) { WlzObject *xobj, *yobj, *returnobj=NULL; WlzIntervalWSpace iwsp1, iwsp2, iwsp3; WlzGreyWSpace gwsp1, gwsp2, gwsp3; WlzCompoundArray *cobj1, *cobj2; int i; double g1, g2, g3; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object */ if( obj ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.core ){ switch( obj->domain.core->type ){ case WLZ_EMPTY_DOMAIN: returnobj = WlzMakeEmpty(&errNum); break; default: if( obj->values.core ){ if( (obj->values.core->type == WLZ_EMPTY_VALUES) || WlzGreyTableIsTiled(obj->values.core->type) ){ errNum = WLZ_ERR_VALUES_TYPE; } } else { errNum = WLZ_ERR_VALUES_NULL; } break; } } else { errNum = WLZ_ERR_DOMAIN_NULL; } /* one last check for rgb values */ if(WlzGreyTableTypeToGreyType(obj->values.core->type, NULL) == WLZ_GREY_RGBA){ return WlzRGBAModGradient(obj, width, dstErr); } break; case WLZ_EMPTY_OBJ: returnobj = WlzMakeEmpty(&errNum); break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: cobj1 = (WlzCompoundArray *) obj; if((cobj2 = WlzMakeCompoundArray(cobj1->type, 1, cobj1->n, NULL, cobj1->otype, &errNum)) != NULL){ /* transform each object, ignore type errors */ for(i=0; i < cobj1->n; i++){ cobj2->o[i] = WlzAssignObject(WlzGreyModGradient(cobj1->o[i], width, &errNum), NULL); } return (WlzObject *) cobj2; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } else { errNum = WLZ_ERR_OBJECT_NULL; } /* if WlzUByte grey values then copy to int */ if( (errNum == WLZ_ERR_NONE) && !returnobj ){ if(WlzGreyTableTypeToGreyType(obj->values.core->type, NULL) == WLZ_GREY_UBYTE) { returnobj = WlzConvertPix(obj, WLZ_GREY_INT, NULL); } else { returnobj = WlzMakeMain(WLZ_2D_DOMAINOBJ, obj->domain, WlzCopyValues(obj->type, obj->values, obj->domain, &errNum), NULL, NULL, NULL); } /* calculate gradient images */ xobj = WlzGauss2(returnobj, width, width, 1, 0, NULL); yobj = WlzGauss2(returnobj, width, width, 0, 1, NULL); /* calculate modulus - lockstep raster scan assumes equal domains */ errNum = WlzInitGreyScan(returnobj, &iwsp1, &gwsp1); errNum = WlzInitGreyScan(xobj, &iwsp2, &gwsp2); errNum = WlzInitGreyScan(yobj, &iwsp3, &gwsp3); while((errNum == WLZ_ERR_NONE) && (WlzNextGreyInterval(&iwsp1) == WLZ_ERR_NONE) ) { (void) WlzNextGreyInterval(&iwsp2); (void) WlzNextGreyInterval(&iwsp3); switch( gwsp1.pixeltype ) { default: case WLZ_GREY_INT: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.inp++; g3 = *gwsp3.u_grintptr.inp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.inp++ = (int) g1; } break; case WLZ_GREY_SHORT: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.shp++; g3 = *gwsp3.u_grintptr.shp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.shp++ = (short) g1; } break; case WLZ_GREY_UBYTE: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.ubp++; g3 = *gwsp3.u_grintptr.ubp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.ubp++ = (WlzUByte) g1; } break; case WLZ_GREY_FLOAT: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.flp++; g3 = *gwsp3.u_grintptr.flp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.flp++ = (float) g1; } break; case WLZ_GREY_DOUBLE: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.dbp++; g3 = *gwsp3.u_grintptr.dbp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.dbp++ = (double) g1; } break; case WLZ_GREY_RGBA: /* RGBA to be done - should not get here */ errNum = WLZ_ERR_GREY_TYPE; break; } } /* check for normal return */ if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } /* clean up */ WlzFreeObj( xobj ); WlzFreeObj( yobj ); } /* check error return */ if( dstErr ){ *dstErr = errNum; } return( returnobj ); }
/*! * \return Rescaled object. * \ingroup WlzTransform * \brief Rescales the given 3D domain object using an integer scale. * \param gObj Given object. * \param scale Integer scale factor. * \param expand If zero use \f$\frac{1}{scale}\f$. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzIntRescaleObj3D(WlzObject *gObj, int scale, int expand, WlzErrorNum *dstErr) { int gPIdx, nPIdx; WlzDomain gDom, nDom; WlzValues gVal, nVal, dumVal; WlzObject *gTObj = NULL, *nTObj = NULL, *rObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; WlzIBox3 nBox; nDom.core = NULL; nVal.core = NULL; dumVal.core = NULL; gDom = gObj->domain; gVal = gObj->values; if(expand) { nBox.xMin = gDom.p->kol1 * scale; nBox.xMax = ((gDom.p->lastkl + 1) * scale) - 1; nBox.yMin = gDom.p->line1 * scale; nBox.yMax = ((gDom.p->lastln + 1) * scale) - 1; nBox.zMin = gDom.p->plane1 * scale; nBox.zMax = ((gDom.p->lastpl + 1) * scale) - 1; } else { nBox.xMin = gDom.p->kol1 / scale; nBox.xMax = gDom.p->lastkl / scale; nBox.yMin = gDom.p->line1 / scale; nBox.yMax = gDom.p->lastln / scale; nBox.zMin = gDom.p->plane1 / scale; nBox.zMax = gDom.p->lastpl / scale; } nDom.p = WlzMakePlaneDomain(gDom.p->type, nBox.zMin, nBox.zMax, nBox.yMin, nBox.yMax, nBox.xMin, nBox.xMax, &errNum); if(errNum == WLZ_ERR_NONE) { if(gVal.core && (gVal.core->type != WLZ_EMPTY_OBJ)) { if(WlzGreyTableIsTiled(gVal.core->type)) { errNum = WLZ_ERR_VALUES_TYPE; } else { nVal.vox = WlzMakeVoxelValueTb(gVal.vox->type, nBox.zMin, nBox.zMax, WlzGetBackground(gObj, NULL), NULL, &errNum); } } } if(errNum == WLZ_ERR_NONE) { nPIdx = nBox.zMin; while((errNum == WLZ_ERR_NONE) && (nPIdx <= nBox.zMax)) { gPIdx = (expand)? nPIdx / scale: nPIdx * scale; if(nVal.vox) { gTObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, *(gDom.p->domains + gPIdx), *(gVal.vox->values + gPIdx), NULL, NULL, &errNum); } else { gTObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, *(gDom.p->domains + gPIdx), dumVal, NULL, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { nTObj = WlzIntRescaleObj2D(gTObj, scale, expand, &errNum); } (void )WlzFreeObj(gTObj); gTObj = NULL; if(errNum == WLZ_ERR_NONE) { *(nDom.p->domains + nPIdx) = WlzAssignDomain(nTObj->domain, NULL); if(nVal.vox) { *(nVal.vox->values + nPIdx) = WlzAssignValues(nTObj->values, NULL); } } (void )WlzFreeObj(nTObj); nTObj = NULL; ++nPIdx; } } if(errNum == WLZ_ERR_NONE) { rObj = WlzMakeMain(gObj->type, nDom, nVal, NULL, NULL, &errNum); } else { (void )WlzFreePlaneDomain(nDom.p); (void )WlzFreeVoxelValueTb(nVal.vox); } if(dstErr) { *dstErr = errNum; } return(rObj); }
static WlzObject *WlzGreyTemplate3d( WlzObject *obj, WlzObject *tmpl, WlzPixelV tmplVal, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzObject *tmpObj = NULL, *obj1 = NULL, *obj2 = NULL; WlzDomain domain, *domains; WlzValues values, *valuess; WlzPlaneDomain *pdom; int p; WlzErrorNum errNum=WLZ_ERR_NONE; /* check the object - it is non-NULL and 3D but the domain needs checking */ if( obj->domain.p == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else { switch( obj->domain.p->type ){ case WLZ_2D_DOMAINOBJ: /* check there is a valuetable */ if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( WlzGreyTableIsTiled(obj->values.core->type) ){ errNum = WLZ_ERR_VALUES_TYPE; } break; default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } } /* check the template and create the return object */ if( errNum == WLZ_ERR_NONE ){ if( tmpl == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { values.core = NULL; switch( tmpl->type ){ case WLZ_2D_DOMAINOBJ: pdom = obj->domain.p; if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, pdom->plane1, pdom->lastpl, pdom->line1, pdom->lastpl, pdom->kol1, pdom->lastkl, &errNum)) != NULL){ domain.p->voxel_size[0] = pdom->voxel_size[0]; domain.p->voxel_size[1] = pdom->voxel_size[1]; domain.p->voxel_size[2] = pdom->voxel_size[2]; for(p=pdom->plane1; p <= pdom->lastpl; p++){ domain.p->domains[p - pdom->plane1] = WlzAssignDomain(tmpl->domain, NULL); } rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } break; case WLZ_2D_POLYGON: pdom = obj->domain.p; if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, pdom->plane1, pdom->lastpl, pdom->line1, pdom->lastpl, pdom->kol1, pdom->lastkl, &errNum)) != NULL){ domain.p->voxel_size[0] = pdom->voxel_size[0]; domain.p->voxel_size[1] = pdom->voxel_size[1]; domain.p->voxel_size[2] = pdom->voxel_size[2]; obj1 = WlzPolyToObj(tmpl->domain.poly, WLZ_SIMPLE_FILL, &errNum); for(p=pdom->plane1; p <= pdom->lastpl; p++){ domain.p->domains[p - pdom->plane1] = WlzAssignDomain(obj1->domain, NULL); } WlzFreeObj(obj1); rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } break; case WLZ_BOUNDLIST: pdom = obj->domain.p; if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, pdom->plane1, pdom->lastpl, pdom->line1, pdom->lastpl, pdom->kol1, pdom->lastkl, &errNum)) != NULL){ domain.p->voxel_size[0] = pdom->voxel_size[0]; domain.p->voxel_size[1] = pdom->voxel_size[1]; domain.p->voxel_size[2] = pdom->voxel_size[2]; obj1 = WlzBoundToObj(tmpl->domain.b, WLZ_SIMPLE_FILL, &errNum); for(p=pdom->plane1; p <= pdom->lastpl; p++){ domain.p->domains[p - pdom->plane1] = WlzAssignDomain(obj1->domain, NULL); } WlzFreeObj(obj1); rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } break; case WLZ_3D_DOMAINOBJ: if( tmpl->domain.p ){ switch( tmpl->domain.p->type ){ case WLZ_2D_DOMAINOBJ: domain.p = tmpl->domain.p; break; case WLZ_PLANEDOMAIN_POLYGON: case WLZ_PLANEDOMAIN_CONV_HULL: pdom = tmpl->domain.p; if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, pdom->plane1, pdom->lastpl, pdom->line1, pdom->lastpl, pdom->kol1, pdom->lastkl, &errNum)) != NULL){ domain.p->voxel_size[0] = pdom->voxel_size[0]; domain.p->voxel_size[1] = pdom->voxel_size[1]; domain.p->voxel_size[2] = pdom->voxel_size[2]; for(p=pdom->plane1; p <= pdom->lastpl; p++){ if( pdom->domains[p-pdom->plane1].core ){ obj1 = WlzPolyToObj(pdom->domains[p-pdom->plane1].poly, WLZ_SIMPLE_FILL, &errNum); domain.p->domains[p - pdom->plane1] = WlzAssignDomain(obj1->domain, NULL); } WlzFreeObj(obj1); } values.core = NULL; rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } break; case WLZ_PLANEDOMAIN_BOUNDLIST: pdom = tmpl->domain.p; if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, pdom->plane1, pdom->lastpl, pdom->line1, pdom->lastpl, pdom->kol1, pdom->lastkl, &errNum)) != NULL){ domain.p->voxel_size[0] = pdom->voxel_size[0]; domain.p->voxel_size[1] = pdom->voxel_size[1]; domain.p->voxel_size[2] = pdom->voxel_size[2]; for(p=pdom->plane1; p <= pdom->lastpl; p++){ if( pdom->domains[p-pdom->plane1].core ){ obj1 = WlzBoundToObj(pdom->domains[p-pdom->plane1].b, WLZ_SIMPLE_FILL, &errNum); domain.p->domains[p - pdom->plane1] = WlzAssignDomain(obj1->domain, NULL); } WlzFreeObj(obj1); } values.core = NULL; rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } break; default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } if( errNum == WLZ_ERR_NONE ){ rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } } else { errNum = WLZ_ERR_DOMAIN_NULL; } break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } } /* now we have a 3D obj and 3D template so run through the template and map values as required, note we must check that all the valuetables have the same type ie switch to obj type if necessary */ if( errNum == WLZ_ERR_NONE ){ WlzDomain *objDoms; WlzValues *objVals; WlzGreyType gtype=WLZ_GREY_UBYTE; /* attach a voxel table with empty values list */ values.vox = WlzMakeVoxelValueTb(obj->values.vox->type, rtnObj->domain.p->plane1, rtnObj->domain.p->lastpl, obj->values.vox->bckgrnd, NULL, NULL); rtnObj->values = WlzAssignValues(values, NULL); /* set some local variables */ pdom = rtnObj->domain.p; domains = rtnObj->domain.p->domains; valuess = rtnObj->values.vox->values; objDoms = obj->domain.p->domains; objVals = obj->values.vox->values; /* calculate the new valuetables */ for(p=pdom->plane1; p <= pdom->lastpl; p++, domains++, valuess++){ if(((*domains).core)){ if((p >= obj->domain.p->plane1) && (p <= obj->domain.p->lastpl) && (objDoms[p - obj->domain.p->plane1].core) ){ tmpObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, objDoms[p - obj->domain.p->plane1], objVals[p - obj->domain.p->plane1], NULL, NULL, NULL); gtype = WlzGreyTableTypeToGreyType(tmpObj->values.core->type, NULL); } else { tmpObj = WlzMakeEmpty(NULL); } tmpObj = WlzAssignObject(tmpObj, NULL); values.core = NULL; obj1 = WlzAssignObject( WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains, values, NULL, NULL, NULL), NULL); if((obj2 = WlzGreyTemplate(tmpObj, obj1, tmplVal, &errNum)) != NULL){ *valuess = WlzAssignValues(obj2->values, NULL); WlzFreeObj(obj2); } WlzFreeObj(obj1); WlzFreeObj(tmpObj); } } /* now check all valuetables have the same grey type */ domains = rtnObj->domain.p->domains; valuess = rtnObj->values.vox->values; for(p=pdom->plane1; p <= pdom->lastpl; p++, domains++, valuess++){ if((*domains).core && (WlzGreyTableTypeToGreyType((*valuess).core->type, NULL) != gtype)){ obj1 = WlzAssignObject( WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains, *valuess, NULL, NULL, NULL), NULL); if((obj2 = WlzConvertPix(obj1, gtype, &errNum)) != NULL){ /* substitute the valuetable in the voxel table array */ WlzFreeValues(*valuess); *valuess = WlzAssignValues(obj2->values, NULL); WlzFreeObj(obj2); } WlzFreeObj(obj1); } } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \return The background value. If the returned pixel value type is * WLZ_GREY_ERROR then an error has occurred. * \ingroup WlzValuesUtils * \brief Gets the background value of the given object. * \param obj Given object. * \param dstErr Destination error pointer, may be NULL. */ WlzPixelV WlzGetBackground( WlzObject *obj, WlzErrorNum *dstErr) { WlzPlaneDomain *planedmn; WlzPixelV bgd; WlzErrorNum errNum=WLZ_ERR_NONE; /* set up an invalid background return */ bgd.type = WLZ_GREY_ERROR; bgd.v.inv = 0; 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 ){ errNum = WLZ_ERR_DOMAIN_NULL; break; } if( obj->values.v == NULL ){ bgd.type = WLZ_GREY_INT; bgd.v.inv = 0; break; } switch( WlzGreyTableTypeToTableType(obj->values.core->type, NULL) ){ case WLZ_GREY_TAB_RAGR: bgd = obj->values.v->bckgrnd; break; case WLZ_GREY_TAB_RECT: bgd = obj->values.r->bckgrnd; break; case WLZ_GREY_TAB_INTL: bgd = obj->values.i->bckgrnd; break; default: errNum = WLZ_ERR_VALUES_TYPE; break; } break; case WLZ_3D_DOMAINOBJ: if( obj->domain.p == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; break; } if( obj->values.core == NULL ){ bgd.type = WLZ_GREY_INT; bgd.v.inv = 0; errNum = WLZ_ERR_NONE; break; } planedmn = obj->domain.p; if( planedmn->type != WLZ_PLANEDOMAIN_DOMAIN ){ errNum = WLZ_ERR_PLANEDOMAIN_TYPE; break; } if(WlzGreyTableIsTiled(obj->values.core->type)) { bgd = obj->values.t->bckgrnd; } else if(obj->values.core->type == WLZ_VOXELVALUETABLE_GREY) { bgd = obj->values.vox->bckgrnd; } else { errNum = WLZ_ERR_VALUES_TYPE; } break; case WLZ_TRANS_OBJ: return( WlzGetBackground(obj->values.obj, dstErr) ); case WLZ_EMPTY_OBJ: bgd.type = WLZ_GREY_INT; bgd.v.inv = 0; errNum = WLZ_ERR_NONE; break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if( dstErr ){ *dstErr = errNum; } return bgd; }
/*! * \ingroup WlzValuesUtils * \brief * * \return New object with the same domain <tt>tmpl</tt> but values in the intersection with <tt>obj</tt> set to those of the object. Returns NULL on error. * \param obj Input object to which the template is applied * \param tmpl Template object * \param tmplVal Template value for regions in the template not in the original object * \param dstErr Error return. * \par Source: * WlzGreyTemplate.c */ WlzObject *WlzGreyTemplate( WlzObject *obj, WlzObject *tmpl, WlzPixelV tmplVal, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzObject *obj1, *obj2; WlzValues values; WlzPixelV bckgrnd; WlzObjectType type; WlzGreyType gtype=WLZ_GREY_UBYTE; WlzIntervalWSpace iwsp1, iwsp2; WlzGreyWSpace gwsp1, gwsp2; int size; WlzErrorNum errNum = WLZ_ERR_NONE; /* check obj */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( WlzGreyTableIsTiled(obj->values.core->type) ){ errNum = WLZ_ERR_VALUES_TYPE; } else { bckgrnd = WlzGetBackground(obj, &errNum); } if(errNum == WLZ_ERR_NONE) { gtype = WlzGreyTableTypeToGreyType(obj->values.core->type, NULL); } break; case WLZ_3D_DOMAINOBJ: return WlzGreyTemplate3d(obj, tmpl, tmplVal, dstErr); case WLZ_TRANS_OBJ: if((values.obj = WlzGreyTemplate(obj->values.obj, tmpl, tmplVal, &errNum)) != NULL){ return WlzMakeMain(WLZ_TRANS_OBJ, obj->domain, values, NULL, NULL, dstErr); } break; case WLZ_EMPTY_OBJ: bckgrnd.type = WLZ_GREY_UBYTE; bckgrnd.v.ubv = 0; break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* check the template */ if( errNum == WLZ_ERR_NONE ){ if( tmpl == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { values.core = NULL; switch( tmpl->type ){ case WLZ_2D_DOMAINOBJ: rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, tmpl->domain, values, NULL, NULL, &errNum); break; case WLZ_TRANS_OBJ: rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, tmpl->values.obj->domain, values, NULL, NULL, &errNum); break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); case WLZ_2D_POLYGON: rtnObj = WlzPolyToObj(tmpl->domain.poly, WLZ_SIMPLE_FILL, &errNum); break; case WLZ_BOUNDLIST: rtnObj = WlzBoundToObj(tmpl->domain.b, WLZ_SIMPLE_FILL, &errNum); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } } /* attach a value table to the template and set to the template value, note the background is set to the input object or zero if empty */ if( errNum == WLZ_ERR_NONE ){ type = WlzGreyTableType(WLZ_GREY_TAB_RAGR, gtype, NULL); if((values.v = WlzNewValueTb(rtnObj, type, bckgrnd, &errNum)) != NULL){ rtnObj->values = WlzAssignValues(values, NULL); errNum = WlzGreySetValue(rtnObj, tmplVal); } } /* copy input obj values within the intersection */ if( errNum == WLZ_ERR_NONE ){ if((obj->type != WLZ_EMPTY_OBJ) ){ if( (obj1 = WlzIntersect2(obj, rtnObj, &errNum)) ){ obj1->values = WlzAssignValues(rtnObj->values, NULL); obj2 = WlzMakeMain(obj1->type, obj1->domain, obj->values, NULL, NULL, NULL); errNum = WlzInitGreyScan(obj1, &iwsp1, &gwsp1); errNum = WlzInitGreyScan(obj2, &iwsp2, &gwsp2); switch( gwsp1.pixeltype ){ case WLZ_GREY_INT: size = sizeof(int); break; case WLZ_GREY_SHORT: size = sizeof(short); break; case WLZ_GREY_UBYTE: size = sizeof(WlzUByte); break; case WLZ_GREY_FLOAT: size = sizeof(float); break; case WLZ_GREY_DOUBLE: size = sizeof(double); break; case WLZ_GREY_RGBA: size = sizeof(WlzUInt); break; default: errNum = WLZ_ERR_GREY_TYPE; break; } while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp1)) == WLZ_ERR_NONE)){ (void) WlzNextGreyInterval(&iwsp2); memcpy((void *) gwsp1.u_grintptr.inp, (const void *) gwsp2.u_grintptr.inp, size * iwsp1.colrmn); } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzFreeObj(obj2); WlzFreeObj(obj1); } else { WlzFreeObj(rtnObj); rtnObj = NULL; } } } 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 Coordinates of center of mass. * \ingroup WlzFeatures * \brief Calculates the centre of mass of a WLZ_3D_DOMAIN_OBJ. * If the object has values and the binary object flag is not set * then the centre of mass is calculated using the grey level * information. * \f[ C_x = \frac{\sum_x{\sum_y{\sum_z{x G(x,y,z)}}}} {\sum_x{\sum_y{\sum_z{G(x,y,z)}}}} , C_y = \frac{\sum_x{\sum_y{\sum_z{y G(x,y,z)}}}} {\sum_x{\sum_y{\sum_z{G(x,y,z)}}}} C_z = \frac{\sum_x{\sum_y{\sum_z{z G(x,y,z)}}}}, {\sum_x{\sum_y{\sum_z{G(x,y,z)}}}} \f] * Where \f$(C_x,C_y,C_z)\f$ are the coordinates of the centre of * mass. * If the given object does not have grey values or the * binary object flag is set (ie non zero) then every * pixel within the objects domain has the same mass. * \param srcObj Given object. * \param binObjFlag Binary object flag. * \param dstMass Destination pointer for mass, may be * NULL. * \param dstErr Destination pointer for error, may be * NULL. */ static WlzDVertex3 WlzCentreOfMassDom3D(WlzObject *srcObj, int binObjFlag, double *dstMass, WlzErrorNum *dstErr) { int planeIdx, planeCount; double mass = 0.0, mass2D; WlzDVertex2 cMass2D; WlzDVertex3 cMass, sum; WlzDomain srcDom, dummyDom; WlzDomain *srcDomains; WlzValues dummyValues; WlzValues *srcValues; WlzObject *srcObj2D; WlzErrorNum errNum = WLZ_ERR_NONE; sum.vtX = 0.0; sum.vtY = 0.0; sum.vtZ = 0.0; cMass.vtX = 0.0; cMass.vtY = 0.0; cMass.vtZ = 0.0; dummyDom.core = NULL; dummyValues.core = NULL; if((srcDom = srcObj->domain).core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(srcDom.core->type != WLZ_PLANEDOMAIN_DOMAIN) { errNum = WLZ_ERR_DOMAIN_TYPE; } else if((srcDomains = srcDom.p->domains) == NULL) { errNum = WLZ_ERR_DOMAIN_DATA; } else if((binObjFlag == 0) && (srcObj->values.core != NULL) && WlzGreyTableIsTiled(srcObj->values.core->type)) { errNum = WLZ_ERR_VOXELVALUES_TYPE; } else { if((srcObj->values.core == NULL) || ((srcValues = srcObj->values.vox->values) == NULL)) { binObjFlag = 1; } srcObj2D = WlzMakeMain(WLZ_2D_DOMAINOBJ, dummyDom, dummyValues, NULL, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { planeIdx = 0; planeCount = srcDom.p->lastpl - srcDom.p->plane1 + 1; while((errNum == WLZ_ERR_NONE) && (planeCount-- > 0)) { srcObj2D->domain = *(srcDomains + planeIdx); if(binObjFlag) { srcObj2D->values.core = NULL; } else { srcObj2D->values = *(srcValues + planeIdx); } cMass2D = WlzCentreOfMass2D(srcObj2D, binObjFlag, &mass2D, &errNum); sum.vtX += cMass2D.vtX * mass2D; sum.vtY += cMass2D.vtY * mass2D; sum.vtZ += (srcDom.p->plane1 + planeIdx) * mass2D; mass += mass2D; ++planeIdx; } srcObj2D->domain.core = NULL; srcObj2D->values.core = NULL; (void )WlzFreeObj(srcObj2D); if(errNum == WLZ_ERR_NONE) { if((mass > DBL_EPSILON) || (mass < (-(DBL_EPSILON)))) { cMass.vtX = sum.vtX / mass; cMass.vtY = sum.vtY / mass; cMass.vtZ = sum.vtZ / mass; } if(dstMass) { *dstMass = mass; } } } if(dstErr) { *dstErr = errNum; } return(cMass); }