/*! * \ingroup WlzAllocation * \brief Free a voxel value table * * \return Error number, values: WLZ_ERR_NONE, WLZ_ERR_VOXELVALUES_TYPE and from WlzFreeValues(). * \param voxtab * \par Source: * WlzFreeSpace.c */ WlzErrorNum WlzFreeVoxelValueTb(WlzVoxelValues *voxtab) { WlzValues *values; int nplanes; WlzErrorNum errNum = WLZ_ERR_NONE; /* check the object pointer and linkcount */ if (voxtab == NULL){ return( WLZ_ERR_NONE ); } /* check the type */ if( voxtab->type != WLZ_VOXELVALUETABLE_GREY ){ return WLZ_ERR_VOXELVALUES_TYPE; } if( WlzUnlink(&(voxtab->linkcount), &errNum) ){ nplanes = voxtab->lastpl - voxtab->plane1 + 1; values = voxtab->values; while( nplanes-- ){ errNum |= WlzFreeValues(*values); values++; } WlzFreeVoxelValueTb(voxtab->original_table.vox); AlcFreeStackFree(voxtab->freeptr); AlcFree((char *) voxtab); } return( errNum ); }
/*! * \ingroup WlzAllocation * \brief Free a values structure, currently only WlzRagRValues and WlzRectValues DO NOT call this function with any other values structure types! * * \return Error number, values: WLZ_ERR_NONE, WLZ_ERR_VALUES_DATA. * \param values Values union to be freed. * \par Source: * WlzFreeSpace.c */ WlzErrorNum WlzFreeValues(WlzValues values) { WlzErrorNum errNum = WLZ_ERR_NONE; /* check the object pointer and linkcount */ if (values.v == NULL){ return( WLZ_ERR_NONE ); } if( WlzUnlink(&(values.v->linkcount), &errNum) ){ /* if there is a freeptr then free it */ if (values.v->freeptr != NULL){ /* it is illegal for a table to point to itself */ if( values.v->original_table.v != NULL ){ return( WLZ_ERR_VALUES_DATA ); } (void )AlcFreeStackFree(values.v->freeptr); } if( values.v->original_table.v ){ errNum = WlzFreeValues( values.v->original_table ); } AlcFree((void *) values.v); } return( errNum ); }
/*! * \ingroup WlzAllocation * \brief Convenience routine to free a ragged rect valuetable. * * \return Error number, values: WLZ_ERR_NONE and from WlzFreeValues(). * \param vdmn Value domain to be freed. * \par Source: * WlzFreeSpace.c */ WlzErrorNum WlzFreeValueTb(WlzRagRValues *vdmn) { WlzValues values; /* check the object pointer and linkcount */ if (vdmn == NULL){ return( WLZ_ERR_NONE ); } values.v = vdmn; return( WlzFreeValues( values ) ); }
/*! * \return New grey value domain object with incrementing values. * \ingroup WlzValuesUtils * \brief Creates a new 2D domain object with integer values that * increment throughout the object in scan order. Object * values are set by incrementing the given value in place. * \param in Input domain object. * \param val Pointer to current value, this is * incremented in place. * \param dstErr Destination error pointer, may be NULL. */ static WlzObject *WlzGreyNewIncValues2D(WlzObject *in, int *val, WlzErrorNum *dstErr) { WlzObject *out = NULL; WlzObjectType gTT; WlzPixelV bgd; WlzValues values; WlzErrorNum errNum = WLZ_ERR_NONE; bgd.type = WLZ_GREY_INT; bgd.v.inv = 0; values.core = NULL; gTT = WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_INT, &errNum); if(errNum == WLZ_ERR_NONE) { values.v = WlzNewValueTb(in, gTT, bgd, &errNum); } if(errNum == WLZ_ERR_NONE) { out = WlzMakeMain(in->type, in->domain, values, in->plist, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { errNum = WlzGreySetIncValuesItr(out, val); } if(errNum != WLZ_ERR_NONE) { if(out != NULL) { (void )WlzFreeObj(out); out = NULL; } else if(values.core != NULL) { (void )WlzFreeValues(values); } } if(dstErr != NULL) { *dstErr = errNum; } return(out); }
/*! * \return New 3D object. * \ingroup WlzAllocation * \brief Constructs a 3D domain object from 2D domain objects read * from the given files. Each file is read in turn and added * to the 3D object. An empty plane can be specified by * setting the file string to NULL. Either all or none of * the 2D objects must have values. When the 2D objects * have values then the background value of the first 2D * object is set to be the background value of the 3D object. * \param nFileStr Number of file strings. * \param fileStr File strings. * \param plane1 The plane coordinate of the first * 2D object. * \param xSz Column voxel size. * \param ySz Line voxel size. * \param zSz Plane voxel size. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzConstruct3DObjFromFile(int nFileStr, char **fileStr, int plane1, float xSz, float ySz, float zSz, WlzErrorNum *dstErr) { int idx, lastpl; WlzDomain dom3D; WlzValues val3D; WlzObject *obj2D = NULL, *obj3D = NULL; WlzPixelV bgd; FILE *fP = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; dom3D.core = NULL; val3D.core = NULL; lastpl = plane1 + nFileStr - 1; if((nFileStr <= 0) || (fileStr == NULL) || (*fileStr == NULL)) { errNum = WLZ_ERR_PARAM_NULL; } else { if((fP = fopen(*fileStr, "r")) == NULL) { errNum = WLZ_ERR_READ_EOF; } else { obj2D = WlzReadObj(fP, &errNum); (void )fclose(fP); fP = NULL; } } if(errNum == WLZ_ERR_NONE) { switch(obj2D->type) { case WLZ_EMPTY_OBJ: break; case WLZ_2D_DOMAINOBJ: if(obj2D->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* Make a plane domain, set column and line bounds later. */ if(errNum == WLZ_ERR_NONE) { dom3D.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, plane1, lastpl, 0, 1, 0, 1, &errNum); } if(errNum == WLZ_ERR_NONE) { dom3D.p->voxel_size[0] = xSz; dom3D.p->voxel_size[1] = ySz; dom3D.p->voxel_size[2] = zSz; } /* Make a voxel value table. */ if(errNum == WLZ_ERR_NONE) { if(obj2D->values.core) { bgd = WlzGetBackground(obj2D, &errNum); if(errNum == WLZ_ERR_NONE) { val3D.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, plane1, lastpl, bgd, NULL, &errNum); } } } idx = 0; while((errNum == WLZ_ERR_NONE) && (idx < nFileStr)) { if(obj2D) { switch(obj2D->type) { case WLZ_EMPTY_OBJ: break; case WLZ_2D_DOMAINOBJ: if(obj2D->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } if(errNum == WLZ_ERR_NONE) { *(dom3D.p->domains + idx) = WlzAssignDomain(obj2D->domain, NULL); if(val3D.core) { if((obj2D->domain.core != NULL) && (obj2D->values.core == NULL)) { errNum = WLZ_ERR_VALUES_NULL; } else { *(val3D.vox->values + idx) = WlzAssignValues(obj2D->values, NULL); } } } WlzFreeObj(obj2D); obj2D = NULL; } if(errNum == WLZ_ERR_NONE) { ++idx; if((idx < nFileStr) && *(fileStr + idx)) { if((fP = fopen(*(fileStr + idx), "r")) == NULL) { errNum = WLZ_ERR_READ_EOF; } else { obj2D = WlzReadObj(fP, &errNum); (void )fclose(fP); fP = NULL; } } } } if(errNum == WLZ_ERR_NONE) { errNum = WlzStandardPlaneDomain(dom3D.p, val3D.vox); } if(errNum == WLZ_ERR_NONE) { obj3D = WlzMakeMain(WLZ_3D_DOMAINOBJ, dom3D, val3D, NULL, NULL, &errNum); } if(errNum != WLZ_ERR_NONE) { if(dom3D.core) { (void )WlzFreeDomain(dom3D); } if(val3D.core) { (void )WlzFreeValues(val3D); } } if(dstErr) { *dstErr = errNum; } return(obj3D); }
/*! * \return New 3D object. * \ingroup WlzAllocation * \brief Constructs a 3D domain object from 2D domain objects. Each * 2D object is assigned in turn to the 3D object no domains * or values are copied. An empty can be specified by * setting the 2D object to NULL. Either all or none of * the 2D objects must have values. When the 2D objects * have values then the background value of the first 2D * object is set to be the background value of the 3D object. * \param nObjs Number of objects. * \param objs The 2D objects, the first of which * MUST not be NULL. * \param plane1 The plane coordinate of the first * 2D object. * \param xSz Column voxel size. * \param ySz Line voxel size. * \param zSz Plane voxel size. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzConstruct3DObjFromObj(int nObjs, WlzObject **objs, int plane1, float xSz, float ySz, float zSz, WlzErrorNum *dstErr) { int idx, lastpl; WlzDomain dom3D; WlzValues val3D; WlzObject *obj2D, *obj3D = NULL; WlzPixelV bgd; WlzErrorNum errNum = WLZ_ERR_NONE; dom3D.core = NULL; val3D.core = NULL; lastpl = plane1 + nObjs - 1; if((nObjs <= 0) || (objs == NULL)) { errNum = WLZ_ERR_PARAM_NULL; } else if((obj2D = *objs) == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else { switch(obj2D->type) { case WLZ_EMPTY_OBJ: break; case WLZ_2D_DOMAINOBJ: if(obj2D->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* Make a plane domain, set column and line bounds later. */ if(errNum == WLZ_ERR_NONE) { dom3D.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, plane1, lastpl, 0, 1, 0, 1, &errNum); } if(errNum == WLZ_ERR_NONE) { dom3D.p->voxel_size[0] = xSz; dom3D.p->voxel_size[1] = ySz; dom3D.p->voxel_size[2] = zSz; } /* Make a voxel value table. */ if(errNum == WLZ_ERR_NONE) { if(obj2D->values.core) { bgd = WlzGetBackground(obj2D, &errNum); if(errNum == WLZ_ERR_NONE) { val3D.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, plane1, lastpl, bgd, NULL, &errNum); } } } for(idx = 0; (errNum == WLZ_ERR_NONE) && (idx < nObjs); ++idx) { obj2D = *(objs + idx); if(obj2D) { switch(obj2D->type) { case WLZ_EMPTY_OBJ: break; case WLZ_2D_DOMAINOBJ: if(obj2D->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } if(errNum == WLZ_ERR_NONE) { *(dom3D.p->domains + idx) = WlzAssignDomain(obj2D->domain, NULL); if(val3D.core) { if((obj2D->domain.core != NULL) && (obj2D->values.core == NULL)) { errNum = WLZ_ERR_VALUES_NULL; } else { *(val3D.vox->values + idx) = WlzAssignValues(obj2D->values, NULL); } } } } } if(errNum == WLZ_ERR_NONE) { errNum = WlzStandardPlaneDomain(dom3D.p, val3D.vox); } if(errNum == WLZ_ERR_NONE) { obj3D = WlzMakeMain(WLZ_3D_DOMAINOBJ, dom3D, val3D, NULL, NULL, &errNum); } if(errNum != WLZ_ERR_NONE) { if(dom3D.core) { (void )WlzFreeDomain(dom3D); } if(val3D.core) { (void )WlzFreeValues(val3D); } } if(dstErr) { *dstErr = errNum; } return(obj3D); }
/*! * \ingroup WlzAllocation * \brief Make in interval values table to match the input object The table will have linkcount set to zero. * * \return New interval values table. * \param type Required table type. * \param obj Input object. * \param bckgrnd Values table background value. * \param dstErr Error return. * \par Constraints The woolz object type must resolve to WLZ_GREY_TAB_INTL using WlzGreyTableTypeToTableType()or an error will be reported and NULL returned. For historical reasons the type encodes the table type as well as the grey-value type. * \par Source: * WlzMakeIntervalValues.c */ WlzIntervalValues * WlzMakeIntervalValues(WlzObjectType type, WlzObject *obj, WlzPixelV bckgrnd, WlzErrorNum *dstErr) { WlzValues v; WlzValueIntervalLine *vil; WlzValueLine *val; WlzGreyP g; WlzIntervalWSpace iwsp; WlzIntervalDomain *idom; WlzErrorNum errNum=WLZ_ERR_NONE; /* check the values table type */ v.i = NULL; (void) WlzGreyTableTypeToTableType(type, &errNum); if( errNum == WLZ_ERR_NONE ){ (void) WlzGreyTableTypeToGreyType(type, &errNum); } /* check the object */ if( (errNum == WLZ_ERR_NONE) && (obj == NULL) ){ errNum = WLZ_ERR_OBJECT_NULL; } if( errNum == WLZ_ERR_NONE ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; break; } idom = obj->domain.i; break; case WLZ_EMPTY_OBJ: default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } } /* * allocate space for basic, per line and per interval structures */ if((errNum == WLZ_ERR_NONE) && ((v.i = (WlzIntervalValues *) AlcCalloc(sizeof(WlzIntervalValues) + (idom->lastln - idom->line1 + 1) * sizeof(WlzValueIntervalLine) + WlzIntervalCount(idom, NULL) * sizeof(WlzValueLine), 1)) == NULL) ){ errNum = WLZ_ERR_MEM_ALLOC; } if( errNum == WLZ_ERR_NONE ){ vil = (WlzValueIntervalLine *) (v.i + 1); val = (WlzValueLine *) (vil + idom->lastln - idom->line1 + 1); v.i->bckgrnd = bckgrnd; switch( WlzGreyTableTypeToGreyType(type, NULL) ){ case WLZ_GREY_INT: g.inp = (int *) AlcCalloc(WlzArea(obj, NULL), sizeof(int)); break; case WLZ_GREY_SHORT: g.shp = (short *) AlcCalloc(WlzArea(obj, NULL), sizeof(short)); break; case WLZ_GREY_UBYTE: g.ubp = (WlzUByte *) AlcCalloc(WlzArea(obj, NULL), sizeof(WlzUByte)); break; case WLZ_GREY_FLOAT: g.flp = (float *) AlcCalloc(WlzArea(obj, NULL), sizeof(float)); break; case WLZ_GREY_DOUBLE: g.dbp = (double *) AlcCalloc(WlzArea(obj, NULL), sizeof(double)); break; case WLZ_GREY_RGBA: g.rgbp = (WlzUInt *) AlcCalloc(WlzArea(obj, NULL), sizeof(WlzUInt)); break; default: WlzFreeValues( v ); v.i = NULL; errNum = WLZ_ERR_GREY_TYPE; break; } } if( (errNum == WLZ_ERR_NONE) && (g.inp == NULL) ){ WlzFreeValues( v ); v.i = NULL; errNum = WLZ_ERR_MEM_ALLOC; } /* * fill in structure values and initialise scanning */ if( errNum == WLZ_ERR_NONE ){ v.i->type = type; v.i->freeptr = AlcFreeStackPush(v.i->freeptr, (void *)g.inp, NULL); v.i->line1 = idom->line1; v.i->lastln = idom->lastln; v.i->kol1 = idom->kol1; v.i->width = idom->lastkl - idom->kol1 + 1; v.i->vil = vil; v.i->linkcount = 0; v.i->original_table.core = NULL; vil--; if((errNum = WlzInitRasterScan(obj, &iwsp, WLZ_RASTERDIR_ILIC)) != WLZ_ERR_NONE ){ WlzFreeValues( v ); v.i = NULL; } } /* * fill in the line and interval structures, note grey-type already checked. */ if( errNum == WLZ_ERR_NONE ){ while((errNum == WLZ_ERR_NONE) && (errNum = WlzNextInterval(&iwsp)) == WLZ_ERR_NONE){ if (iwsp.nwlpos != 0) { vil += iwsp.nwlpos; vil->vtbint = val; } vil->nintvs++; val->vkol1 = iwsp.lftpos - v.i->kol1; val->vlastkl = iwsp.rgtpos - v.i->kol1; switch( WlzGreyTableTypeToGreyType(type, NULL) ){ case WLZ_GREY_INT: val->values.inp = g.inp; g.inp += iwsp.colrmn; break; case WLZ_GREY_SHORT: val->values.shp = g.shp; g.shp += iwsp.colrmn; break; case WLZ_GREY_UBYTE: val->values.ubp = g.ubp; g.ubp += iwsp.colrmn; break; case WLZ_GREY_FLOAT: val->values.flp = g.flp; g.flp += iwsp.colrmn; break; case WLZ_GREY_DOUBLE: val->values.dbp = g.dbp; g.dbp += iwsp.colrmn; break; case WLZ_GREY_RGBA: val->values.rgbp = g.rgbp; g.rgbp += iwsp.colrmn; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } val++; } switch( errNum ){ case WLZ_ERR_NONE: case WLZ_ERR_EOO: errNum = WLZ_ERR_NONE; break; default: WlzFreeValues( v ); v.i = NULL; break; } } if( dstErr ){ *dstErr = errNum; } return(v.i); }
/*! * \return New 2D Woolz object or NULL on error. * \ingroup WlzTransform * \brief Creates a new 2D Woolz object with a single line which * is the profile from the given start position to the * given end position. This function assumes that it is * given either a 2 or 3D spatial domain object and that * this object has a non-NULL domain. See WlzProfileLine(). * \param gObj Given Woolz object. * \param sPos Start position. * \param ePos End position. * \param dstErr Destination error pointer, may be NULL. */ static WlzObject *WlzProfileLnSD( WlzObject *gObj, WlzIVertex3 sPos, WlzIVertex3 ePos, WlzErrorNum *dstErr) { WlzDomain rDom = {0}; WlzValues rVal = {0}; WlzObject *rObj = NULL; WlzGreyP rPix = {0}; WlzGreyValueWSpace *gVWSp = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; rDom.i = WlzProfileLineIDom(gObj, sPos, ePos, &errNum); if(errNum == WLZ_ERR_NONE) { if(gObj->values.core) { gVWSp = WlzGreyValueMakeWSp(gObj, &errNum); if(errNum == WLZ_ERR_NONE) { int len; size_t gSz; len = rDom.i->lastkl - rDom.i->kol1 +1; if((gSz = WlzGreySize(gVWSp->gType)) == 0) { errNum = WLZ_ERR_GREY_TYPE; } else if((rPix.v = AlcMalloc(len * gSz)) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } } if(errNum == WLZ_ERR_NONE) { WlzPixelV bgd; WlzObjectType tType; bgd.type = gVWSp->gType; bgd.v = gVWSp->gBkd; tType = WlzGreyValueTableType(0, WLZ_GREY_TAB_RECT, gVWSp->gType, NULL); rVal.r = WlzMakeRectValueTb(tType, rDom.i->line1, rDom.i->lastln, rDom.i->kol1, (rDom.i->lastkl - rDom.i->kol1) + 1, bgd, rPix.inp, &errNum); } } } if(errNum == WLZ_ERR_NONE) { rObj = WlzMakeMain(gObj->type, rDom, rVal, NULL, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { errNum = WlzProfileWalkValues(gObj, rObj, gVWSp, sPos, ePos, &errNum); } if(errNum != WLZ_ERR_NONE) { if(rObj) { (void )WlzFreeObj(rObj); rObj = NULL; } else { if(rVal.core) { (void )WlzFreeDomain(rDom); (void )WlzFreeValues(rVal); } else { AlcFree(rPix.v); } } } 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 New Woolz domain object with maximal domain and grey * values which encode the gradient's direction or NULL * on error. * \ingroup WlzFeatures * \brief Computes the maximal domain and gradient direction of * given Woolz 2D domain object. * \note All the objects domains are known to be the same. * \param grdM Gradient magnitude. * \param grdY Gradient (partial derivative) * through lines. * \param grdX Gradient (partial derivative) * through columns. * \param minThrV Minimum gradient value to * consider. * \param dstErr Destination error pointer, may * be null. */ static WlzObject *WlzNMSuppress2D(WlzObject *grdM, WlzObject *grdY, WlzObject *grdX, WlzPixelV minThrV, WlzErrorNum *dstErr) { int idN, inLen, outLen, inLnIdx = 0; WlzGreyType gType, bufType; WlzIVertex2 bufSz, inPos, outPos, orgPos; WlzValues tmpVal; WlzDomain dstDom, grdDom; WlzIntervalWSpace tmpIWSp = {0}, grdMIWSp = {0}, grdYIWSp = {0}, grdXIWSp = {0}; WlzGreyWSpace tmpGWSp, grdMGWSp, grdYGWSp, grdXGWSp; WlzPixelV zeroV; WlzGreyP grdMBufGP, grdYBufGP, grdXBufGP; WlzDynItvPool pool; WlzObject *dstObj = NULL, *tmpObj = NULL; void *grdYBuf = NULL, *grdXBuf = NULL; void **grdMBuf = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; tmpVal.core = NULL; pool.itvBlock = NULL; dstDom.core = NULL; if((grdM->type != WLZ_2D_DOMAINOBJ) || (grdY->type != WLZ_2D_DOMAINOBJ) || (grdX->type != WLZ_2D_DOMAINOBJ)) { errNum = WLZ_ERR_OBJECT_NULL; } else if((grdM->domain.core == NULL) || (grdY->domain.core == NULL) || (grdX->domain.core == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } else if((grdM->values.core == NULL) || (grdY->values.core == NULL) || (grdX->values.core == NULL)) { errNum = WLZ_ERR_VALUES_NULL; } else { /* Find required buffer type (WLZ_GREY_DOUBLE or WLZ_GREY_INT). */ bufType = WLZ_GREY_INT; gType = WlzGreyTableTypeToGreyType(grdM->values.core->type, &errNum); if(errNum == WLZ_ERR_NONE) { if((gType == WLZ_GREY_FLOAT) || (gType == WLZ_GREY_DOUBLE)) { bufType = WLZ_GREY_DOUBLE; } else { gType = WlzGreyTableTypeToGreyType(grdY->values.core->type, &errNum); if(errNum == WLZ_ERR_NONE) { if((gType == WLZ_GREY_FLOAT) || (gType == WLZ_GREY_DOUBLE)) { bufType = WLZ_GREY_DOUBLE; } else { gType = WlzGreyTableTypeToGreyType(grdX->values.core->type, &errNum); if(errNum == WLZ_ERR_NONE) { if((gType == WLZ_GREY_FLOAT) || (gType == WLZ_GREY_DOUBLE)) { bufType = WLZ_GREY_DOUBLE; } } } } } } } /* Convert minimum gradient threshold value. */ if(errNum == WLZ_ERR_NONE) { if(bufType == WLZ_GREY_INT) { errNum = WlzValueConvertPixel(&minThrV, minThrV, WLZ_GREY_INT); } else /* bufType == WLZ_GREY_DOUBLE */ { errNum = WlzValueConvertPixel(&minThrV, minThrV, WLZ_GREY_DOUBLE); } } if(errNum == WLZ_ERR_NONE) { grdDom = grdM->domain; /* Make destination object with WLZ_GREY_UBYTE greys. */ zeroV.type = WLZ_GREY_UBYTE; zeroV.v.inv = 0; tmpVal.v = WlzNewValueTb(grdM, WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_UBYTE, NULL), zeroV, &errNum); if(errNum == WLZ_ERR_NONE) { /* Use the input domain while calculating the new maximal domain. */ tmpObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, grdM->domain, tmpVal, NULL, NULL, &errNum); } } /* Initialize the memory pool with some size of block. Any +ve number * greater than the maximum number of intervals in any destination line * would work but the fewer allocations then the more efficient the code, * hence this attempt to guess the required number of intervals in the * destination domain. */ if(errNum == WLZ_ERR_NONE) { pool.itvsInBlock = (((grdDom.i->lastkl - grdDom.i->kol1 + 1) * (grdDom.i->lastln - grdDom.i->line1 + 1)) / 64) + grdDom.i->lastkl - grdDom.i->kol1 + 1024; } /* Make gradient buffers. */ if(errNum == WLZ_ERR_NONE) { bufSz.vtY = 3; bufSz.vtX = grdDom.i->lastkl - grdDom.i->kol1 + 1; if(bufType == WLZ_GREY_INT) { if((AlcInt2Malloc((int ***)&grdMBuf, bufSz.vtY, bufSz.vtX) != ALC_ER_NONE) || ((grdYBuf = AlcMalloc(sizeof(int) * bufSz.vtX)) == NULL) || ((grdXBuf = AlcMalloc(sizeof(int) * bufSz.vtX)) == NULL)) { errNum = WLZ_ERR_MEM_ALLOC; } else { grdYBufGP.inp = (int *)grdYBuf; grdXBufGP.inp = (int *)grdXBuf; } } else /* bufType == WLZ_GREY_DOUBLE */ { if((AlcDouble2Malloc((double ***)&grdMBuf, bufSz.vtY, bufSz.vtX) != ALC_ER_NONE) || ((grdYBuf = AlcMalloc(sizeof(double) * bufSz.vtX)) == NULL) || ((grdXBuf = AlcMalloc(sizeof(double) * bufSz.vtX)) == NULL)) { errNum = WLZ_ERR_MEM_ALLOC; } else { grdYBufGP.dbp = (double *)grdYBuf; grdXBufGP.dbp = (double *)grdXBuf; } } } /* Make destination interval domain with interval lines but not intervals. */ if(errNum == WLZ_ERR_NONE) { dstDom.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, grdDom.i->line1, grdDom.i->lastln, grdDom.i->kol1, grdDom.i->lastkl, &errNum); } if(errNum == WLZ_ERR_NONE) { /* Scan down through the gradient objects. */ if(((errNum = WlzInitGreyScan(tmpObj, &tmpIWSp, &tmpGWSp)) == WLZ_ERR_NONE) && ((errNum = WlzInitGreyScan(grdM, &grdMIWSp, &grdMGWSp)) == WLZ_ERR_NONE) && ((errNum = WlzInitGreyScan(grdY, &grdYIWSp, &grdYGWSp)) == WLZ_ERR_NONE) && ((errNum = WlzInitGreyScan(grdX, &grdXIWSp, &grdXGWSp)) == WLZ_ERR_NONE)) { orgPos.vtX = grdDom.i->kol1; orgPos.vtY = grdDom.i->line1; while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&grdMIWSp)) == WLZ_ERR_NONE)) { inLen = grdMIWSp.rgtpos - grdMIWSp.lftpos + 1; inPos.vtX = grdMIWSp.lftpos - orgPos.vtX; /* Process any lines between this and the last by clearing the * gradient magnitude buffer . */ if(grdMIWSp.nwlpos > 0) { idN = (grdMIWSp.nwlpos >= 3)? 3: grdMIWSp.nwlpos; while(--idN >= 0) { inPos.vtY = grdMIWSp.linpos - orgPos.vtY - idN; inLnIdx = (3 + inPos.vtY) % 3; if(bufType == WLZ_GREY_INT) { WlzValueSetInt(*((int **)grdMBuf + inLnIdx), 0, bufSz.vtX); } else /* bufType == WLZ_GREY_DOUBLE */ { WlzValueSetDouble(*((double **)grdMBuf + inLnIdx), 0, bufSz.vtX); } } } /* Copy intervals to values buffers. */ if(bufType == WLZ_GREY_INT) { grdMBufGP.inp = *((int **)grdMBuf + inLnIdx); } else /* bufType == WLZ_GREY_DOUBLE */ { grdMBufGP.dbp = *((double **)grdMBuf + inLnIdx); } WlzValueCopyGreyToGrey(grdMBufGP, inPos.vtX, bufType, grdMGWSp.u_grintptr, 0, grdMGWSp.pixeltype, inLen); if(grdMIWSp.intrmn == 0) { while((errNum == WLZ_ERR_NONE) && (tmpIWSp.linpos < grdMIWSp.linpos)) { outPos.vtY = tmpIWSp.linpos - orgPos.vtY; if(outPos.vtY >= 0) { outLen = tmpIWSp.rgtpos - tmpIWSp.lftpos + 1; outPos.vtX = tmpIWSp.lftpos - orgPos.vtX; WlzValueCopyGreyToGrey(grdYBufGP, 0, bufType, grdYGWSp.u_grintptr, 0, grdYGWSp.pixeltype, outLen); WlzValueCopyGreyToGrey(grdXBufGP, 0, bufType, grdXGWSp.u_grintptr, 0, grdXGWSp.pixeltype, outLen); if(bufType == WLZ_GREY_INT) { errNum = WlzNMSuppress2DBufI(dstDom.i, (int **)grdMBuf, (int *)grdYBuf, (int *)grdXBuf, &pool, tmpGWSp.u_grintptr.ubp, outLen, outPos, orgPos, minThrV.v.inv); } else /* bufType == WLZ_GREY_DOUBLE */ { errNum = WlzNMSuppress2DBufD(dstDom.i, (double **)grdMBuf, (double *)grdYBuf, (double *)grdXBuf, &pool, tmpGWSp.u_grintptr.ubp, outLen, outPos, orgPos, minThrV.v.dbv); } } if(errNum == WLZ_ERR_NONE) { errNum = WlzNextGreyInterval(&tmpIWSp); } if(errNum == WLZ_ERR_NONE) { errNum = WlzNextGreyInterval(&grdYIWSp); } if(errNum == WLZ_ERR_NONE) { errNum = WlzNextGreyInterval(&grdXIWSp); } } } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } } if(tmpIWSp.gryptr == &tmpGWSp) { (void )WlzEndGreyScan(&tmpIWSp, &tmpGWSp); } if(grdMIWSp.gryptr == &grdMGWSp) { (void )WlzEndGreyScan(&grdMIWSp, &grdMGWSp); } if(grdYIWSp.gryptr == &grdYGWSp) { (void )WlzEndGreyScan(&grdYIWSp, &grdYGWSp); } if(grdXIWSp.gryptr == &grdXGWSp) { (void )WlzEndGreyScan(&grdXIWSp, &grdXGWSp); } } if(errNum == WLZ_ERR_NONE) { if((errNum = WlzStandardIntervalDomain(dstDom.i)) == WLZ_ERR_NONE) { dstObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, dstDom, tmpVal, NULL, NULL, &errNum); } } if(tmpObj) { WlzFreeObj(tmpObj); } if(errNum != WLZ_ERR_NONE) { if(tmpObj == NULL) { if(dstDom.core) { (void )WlzFreeDomain(dstDom); } if(tmpVal.core) { (void )WlzFreeValues(tmpVal); } } } if(grdMBuf) { Alc2Free(grdMBuf); } if(grdYBuf) { AlcFree(grdYBuf); } if(grdXBuf) { AlcFree(grdXBuf); } if(dstErr) { *dstErr = errNum; } return(dstObj); }