/*! * \return Convex hull object, NULL on error. * \ingroup WlzConvexHull * \brief Computes the convex hull of the given object. * \param obj Given object. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzObjToConvexHull( WlzObject *obj, WlzErrorNum *dstErr) { WlzObject *cvh=NULL; WlzValues values; WlzErrorNum errNum=WLZ_ERR_NONE; /* the convex hull is a polygon domain with values which are a set of chords with pre-calculated parameters which can be used by other procedures */ if((cvh = WlzObjToConvexPolygon(obj, &errNum)) != NULL){ if((values.c = WlzMakeConvexHullValues(cvh, obj, &errNum)) != NULL){ /* assign values and reset object type which is now WLZ_CONV_HULL rather than WLZ_2D_POLYGON */ cvh->values = WlzAssignValues(values, NULL); if( cvh->type == WLZ_2D_POLYGON ){ cvh->type = WLZ_CONV_HULL; } if( cvh->type == WLZ_3D_DOMAINOBJ ){ cvh->domain.p->type = WLZ_PLANEDOMAIN_CONV_HULL; } } } if( dstErr ){ *dstErr = errNum; } return cvh; }
/*! * \return New convex hull values. * \ingroup WlzConvexHull * \brief Fill in parameters of the convex hull into the values table. * \param cvh Given convex hull. * \param obj Given object. * \param dstErr Destination error pointer, may be NULL. */ static WlzConvHullValues *WlzMakeConvexHullValues3d( WlzObject *cvh, WlzObject *obj, WlzErrorNum *dstErr) { WlzValues rtnvalues, *valuess, values; WlzObject *obj1, *obj2; WlzDomain *domains1, *domains2; WlzPixelV bckgrnd; int p; WlzErrorNum errNum=WLZ_ERR_NONE; /* this is only called after a successful call to WlzObjToConvexPolygon therefore the given convex hull object and object have been checked and match */ rtnvalues.c = NULL; bckgrnd.type = WLZ_GREY_UBYTE; bckgrnd.v.ubv = 0; /* make a voxeltable and calculate the convex hull values for each plane */ if((rtnvalues.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_CONV_HULL, cvh->domain.p->plane1, cvh->domain.p->lastpl, bckgrnd, NULL, &errNum)) != NULL){ domains1 = cvh->domain.p->domains; domains2 = obj->domain.p->domains; valuess = rtnvalues.vox->values; for(p=cvh->domain.p->plane1; p <= cvh->domain.p->lastpl; p++, domains1++, domains2++, valuess++){ if( (*domains1).core != NULL ){ values.core = NULL; obj1 = WlzMakeMain(WLZ_2D_POLYGON, *domains1, values, NULL, NULL, NULL); obj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains2, values, NULL, NULL, NULL); if((values.c = WlzMakeConvexHullValues(obj1, obj2, &errNum)) != NULL){ *valuess = WlzAssignValues(values, NULL); } else { WlzFreeObj(obj2); WlzFreeObj(obj1); WlzFreeVoxelValueTb(rtnvalues.vox); rtnvalues.vox = NULL; break; } WlzFreeObj(obj2); WlzFreeObj(obj1); } } } if( dstErr ){ *dstErr = errNum; } return rtnvalues.c; }
/*! * \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 Distance object which shares the given foreground object's * domain and has integer distance values, null on error. * \ingroup WlzMorphologyOps * \brief Computes the distance of every pixel/voxel in the foreground * object from the reference object. * * A distance transform maps all position within a forground * domain to their distances from a reference domain. * The distance transforms implemented within this function * use efficient morphological primitives. * * Given two domains, * \f$\Omega_r\f$ the reference domain and \f$\Omega_f\f$ * the domain specifying the region of interest, * a domain with a thin shell \f$\Omega_i\f$ * is iteratively expanded from it's initial domain * corresponding to the reference domain \f$\Omega_r\f$. * At each iteration * \f$\Omega_i\f$ is dilated and clipped * by it's intersection with \f$\Omega_f\f$ until \f$\Omega_i\f$ * becomes the null domain \f$\emptyset\f$. * At each iteration the current distance is recorded in a value * table which * covers the domain \f$\Omega_f\f$. * * An octagonal distance scheme may be used in which * the distance metric is alternated between 4 and 8 * connected for 2D and 6 and 26 connectivities in 3D. * See: G. Borgefors. "Distance Transformations in Arbitrary * Dimensions" CVGIP 27:321-345, 1984. * * An approximate Euclidean distance transform may be computed * by: Scaling the given foreground and reference objects using * the given approximation scale parameter, dilating the * reference domain using a sphere with a radius having the same * value as the scale parameter and then finaly sampling the * scaled distances. * \param forObj Foreground object. * \param refObj Reference object. * \param dFn Distance function which must be * appropriate to the dimension of * the foreground and reference objects. * \param dParam Parameter required for distance * function. Currently only * WLZ_APX_EUCLIDEAN_DISTANCE requires a * parameter. In this case the parameter * is the approximation scale. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzDistanceTransform(WlzObject *forObj, WlzObject *refObj, WlzDistanceType dFn, double dParam, WlzErrorNum *dstErr) { int idP, lastP, dim, notDone = 1; double scale; WlzObject *tmpObj, *sObj = NULL, *sForObj = NULL, *sRefObj = NULL, *dilObj = NULL, *dstObj = NULL, *difObj = NULL, *curItrObj = NULL; WlzObject *bothObj[2]; WlzDomain *difDoms; WlzPixelV dstV, bgdV; WlzValues *difVals; WlzAffineTransform *tr = NULL; WlzConnectType con; WlzObjectType dstGType; WlzErrorNum errNum = WLZ_ERR_NONE; WlzValues difVal, dstVal, nullVal; /* By defining WLZ_DIST_TRANSFORM_ENV these normalization parameters * are read from the environment. This is useful for optimization. */ #ifndef WLZ_DIST_TRANSFORM_ENV const #endif /* ! WLZ_DIST_TRANSFORM_ENV */ /* These normalizarion factors have been choosen to minimize the sum of * squares of the deviation of the distance values from Euclidean values * over a radius 100 circle or sphere, where the distances are computed * from the circumference of the sphere towards it's centre. The values * were established by experiment. */ double nrmDist4 = 0.97, nrmDist6 = 0.91, nrmDist8 = 1.36, nrmDist18 = 1.34, nrmDist26 = 1.60; #ifdef WLZ_DIST_TRANSFORM_ENV double val; char *envStr; if(((envStr = getenv("WLZ_DIST_TRANSFORM_NRMDIST4")) != NULL) && (sscanf(envStr, "%lg", &val) == 1)) { nrmDist4 = val; } if(((envStr = getenv("WLZ_DIST_TRANSFORM_NRMDIST6")) != NULL) && (sscanf(envStr, "%lg", &val) == 1)) { nrmDist6 = val; } if(((envStr = getenv("WLZ_DIST_TRANSFORM_NRMDIST8")) != NULL) && (sscanf(envStr, "%lg", &val) == 1)) { nrmDist8 = val; } if(((envStr = getenv("WLZ_DIST_TRANSFORM_NRMDIST18")) != NULL) && (sscanf(envStr, "%lg", &val) == 1)) { nrmDist18 = val; } if(((envStr = getenv("WLZ_DIST_TRANSFORM_NRMDIST26")) != NULL) && (sscanf(envStr, "%lg", &val) == 1)) { nrmDist26 = val; } #endif /* WLZ_DIST_TRANSFORM_ENV */ scale = dParam; nullVal.core = NULL; /* Check parameters. */ if((forObj == NULL) || (refObj == NULL)) { errNum = WLZ_ERR_OBJECT_NULL; } else if(((forObj->type != WLZ_2D_DOMAINOBJ) && (forObj->type != WLZ_3D_DOMAINOBJ)) || ((refObj->type != WLZ_POINTS) && (refObj->type != forObj->type))) { errNum = WLZ_ERR_OBJECT_TYPE; } else if((forObj->domain.core == NULL) || (refObj->domain.core == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } if(errNum == WLZ_ERR_NONE) { bgdV.type = WLZ_GREY_INT; bgdV.v.inv = 0; dstV.type = WLZ_GREY_DOUBLE; dstV.v.dbv = 0.0; switch(forObj->type) { case WLZ_2D_DOMAINOBJ: switch(dFn) { case WLZ_4_DISTANCE: /* FALLTHROUGH */ case WLZ_8_DISTANCE: /* FALLTHROUGH */ case WLZ_OCTAGONAL_DISTANCE: /* FALLTHROUGH */ case WLZ_APX_EUCLIDEAN_DISTANCE: dim = 2; break; default: errNum = WLZ_ERR_PARAM_DATA; break; } break; case WLZ_3D_DOMAINOBJ: switch(dFn) { case WLZ_6_DISTANCE: /* FALLTHROUGH */ case WLZ_18_DISTANCE: /* FALLTHROUGH */ case WLZ_26_DISTANCE: /* FALLTHROUGH */ case WLZ_OCTAGONAL_DISTANCE: /* FALLTHROUGH */ case WLZ_APX_EUCLIDEAN_DISTANCE: dim = 3; break; default: errNum = WLZ_ERR_PARAM_DATA; break; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if(errNum == WLZ_ERR_NONE) { switch(dFn) { case WLZ_4_DISTANCE: con = WLZ_4_CONNECTED; break; case WLZ_6_DISTANCE: con = WLZ_6_CONNECTED; break; case WLZ_8_DISTANCE: con = WLZ_8_CONNECTED; break; case WLZ_18_DISTANCE: con = WLZ_18_CONNECTED; break; case WLZ_26_DISTANCE: con = WLZ_26_CONNECTED; break; case WLZ_OCTAGONAL_DISTANCE: con = (dim == 2)? WLZ_8_CONNECTED: WLZ_26_CONNECTED; break; case WLZ_APX_EUCLIDEAN_DISTANCE: con = (dim == 2)? WLZ_8_CONNECTED: WLZ_26_CONNECTED; if(scale < 1.0) { errNum = WLZ_ERR_PARAM_DATA; } break; case WLZ_EUCLIDEAN_DISTANCE: errNum = WLZ_ERR_UNIMPLEMENTED; break; default: errNum = WLZ_ERR_PARAM_DATA; break; } } /* Create scaled domains and a sphere domain for structual erosion if the * distance function is approximate Euclidean. */ if(errNum == WLZ_ERR_NONE) { if(dFn == WLZ_APX_EUCLIDEAN_DISTANCE) { tr = (dim == 2)? WlzAffineTransformFromScale(WLZ_TRANSFORM_2D_AFFINE, scale, scale, 0.0, &errNum): WlzAffineTransformFromScale(WLZ_TRANSFORM_3D_AFFINE, scale, scale, scale, &errNum); if(errNum == WLZ_ERR_NONE) { tmpObj = WlzMakeMain(forObj->type, forObj->domain, nullVal, NULL, NULL, &errNum); if(tmpObj) { sForObj = WlzAssignObject( WlzAffineTransformObj(tmpObj, tr, WLZ_INTERPOLATION_NEAREST, &errNum), NULL); (void )WlzFreeObj(tmpObj); } } if(errNum == WLZ_ERR_NONE) { if(refObj->type == WLZ_POINTS) { sRefObj = WlzPointsToDomObj(refObj->domain.pts, scale, &errNum); } else /* type == WLZ_2D_DOMAINOBJ || type == WLZ_3D_DOMAINOBJ */ { tmpObj = WlzMakeMain(refObj->type, refObj->domain, nullVal, NULL, NULL, &errNum); if(errNum == WLZ_ERR_NONE) { sRefObj = WlzAssignObject( WlzAffineTransformObj(tmpObj, tr, WLZ_INTERPOLATION_NEAREST, &errNum), NULL); } } (void )WlzFreeObj(tmpObj); } if(errNum == WLZ_ERR_NONE) { sObj = WlzAssignObject( WlzMakeSphereObject(forObj->type, scale, 0.0, 0.0, 0.0, &errNum), NULL); } (void )WlzFreeAffineTransform(tr); } else { sForObj = WlzAssignObject( WlzMakeMain(forObj->type, forObj->domain, nullVal, NULL, NULL, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { if(refObj->type == WLZ_POINTS) { sRefObj = WlzPointsToDomObj(refObj->domain.pts, 1.0, &errNum); } else { sRefObj = WlzAssignObject( WlzMakeMain(refObj->type, refObj->domain, nullVal, NULL, NULL, &errNum), NULL); } } } } /* Create new values for the computed distances. */ if(errNum == WLZ_ERR_NONE) { dstGType = WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_INT, NULL); if(dim == 2) { dstVal.v = WlzNewValueTb(sForObj, dstGType, bgdV, &errNum); } else { dstVal.vox = WlzNewValuesVox(sForObj, dstGType, bgdV, &errNum); } } /* Create a distance object using the foreground object's domain and * the new distance values. */ if(errNum == WLZ_ERR_NONE) { dstObj = WlzMakeMain(sForObj->type, sForObj->domain, dstVal, NULL, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { bothObj[0] = sForObj; errNum = WlzGreySetValue(dstObj, dstV); } /* Dilate the reference object while setting the distances in each * dilated shell. */ while((errNum == WLZ_ERR_NONE) && notDone) { if(dFn == WLZ_APX_EUCLIDEAN_DISTANCE) { dstV.v.dbv += 1.0; } else { switch(con) { case WLZ_4_CONNECTED: dstV.v.dbv += nrmDist4; break; case WLZ_6_CONNECTED: dstV.v.dbv += nrmDist6; break; case WLZ_8_CONNECTED: dstV.v.dbv += nrmDist8; break; case WLZ_18_CONNECTED: dstV.v.dbv += nrmDist18; break; case WLZ_26_CONNECTED: dstV.v.dbv += nrmDist26; break; default: errNum = WLZ_ERR_CONNECTIVITY_TYPE; break; } } if(dFn == WLZ_APX_EUCLIDEAN_DISTANCE) { dilObj = WlzStructDilation(sRefObj, sObj, &errNum); } else { dilObj = WlzDilation(sRefObj, con, &errNum); } if(errNum == WLZ_ERR_NONE) { switch(sForObj->type) { case WLZ_2D_DOMAINOBJ: curItrObj = WlzAssignObject( WlzIntersect2(dilObj, sForObj, &errNum), NULL); break; case WLZ_3D_DOMAINOBJ: bothObj[1] = dilObj; curItrObj = WlzAssignObject( WlzIntersectN(2, bothObj, 1, &errNum), NULL); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } (void)WlzFreeObj(dilObj); /* Create difference object for the expanding shell. */ if(errNum == WLZ_ERR_NONE) { difObj = WlzDiffDomain(curItrObj, sRefObj, &errNum); } if((difObj == NULL) || WlzIsEmpty(difObj, &errNum)) { notDone = 0; } else { /* Assign the distance object's values to the difference object * and set all it's values to the current distance. */ if(errNum == WLZ_ERR_NONE) { switch(sForObj->type) { case WLZ_2D_DOMAINOBJ: difObj->values = WlzAssignValues(dstObj->values, NULL); errNum = WlzGreySetValue(difObj, dstV); break; case WLZ_3D_DOMAINOBJ: /* 3D is more complex than 2D: Need to create a temporary * voxel valuetable and assign the individual 2D values. */ difVal.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, difObj->domain.p->plane1, difObj->domain.p->lastpl, bgdV, NULL, &errNum); if(errNum == WLZ_ERR_NONE) { difObj->values = WlzAssignValues(difVal, NULL); difDoms = difObj->domain.p->domains; difVals = difObj->values.vox->values; idP = difObj->domain.p->plane1; lastP = difObj->domain.p->lastpl; while(idP <= lastP) { if((*difDoms).core) { dstVal = dstObj->values.vox->values[idP - dstObj->domain.p->plane1]; *difVals = WlzAssignValues(dstVal, NULL); } ++idP; ++difDoms; ++difVals; } if(difObj->domain.p->lastpl > difObj->domain.p->plane1) { errNum = WlzGreySetValue(difObj, dstV); } } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } (void )WlzFreeObj(sRefObj); sRefObj = WlzAssignObject(curItrObj, NULL); (void )WlzFreeObj(curItrObj); } (void )WlzFreeObj(difObj); difObj = NULL; if(dFn == WLZ_OCTAGONAL_DISTANCE) { /* Alternate connectivities for octagonal distance. */ if(dim == 2) { con = (con == WLZ_4_CONNECTED)? WLZ_8_CONNECTED: WLZ_4_CONNECTED; } else /* dim == 3 */ { con = (con == WLZ_6_CONNECTED)? WLZ_26_CONNECTED: WLZ_6_CONNECTED; } } } (void )WlzFreeObj(sObj); (void )WlzFreeObj(sForObj); (void )WlzFreeObj(sRefObj); (void )WlzFreeObj(curItrObj); if((errNum == WLZ_ERR_NONE) && (dFn == WLZ_APX_EUCLIDEAN_DISTANCE)) { tmpObj = WlzDistSample(dstObj, dim, scale, &errNum); (void )WlzFreeObj(dstObj); dstObj = tmpObj; } if(errNum != WLZ_ERR_NONE) { (void )WlzFreeObj(dstObj); dstObj = NULL; } if(dstErr) { *dstErr = errNum; } return(dstObj); }
void read_reference_object_cb( Widget w, XtPointer client_data, XtPointer call_data) { XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *) call_data; WlzEffFormat image_type; WlzObject *obj; String icsfile; WlzDomain domain; WlzValues values; WlzObject *newObj; WlzErrorNum errNum=WLZ_ERR_NONE; /* set hour glass cursor */ HGU_XmSetHourGlassCursor(globals.topl); /* read the new reference object note the switch is to allow direct read given the image type to include the model input options */ if( client_data ){ image_type = (WlzEffFormat) client_data; if((icsfile = HGU_XmGetFileStr(globals.topl, cbs->value, cbs->dir))){ obj = WlzEffReadObj(NULL, icsfile, image_type, 0, 0, 0, &errNum); AlcFree(icsfile); } else { obj = NULL; } } else { obj = HGU_XmReadExtFFObject(read_obj_dialog, cbs, &image_type, &errNum); } if( obj == NULL){ HGU_XmUserError(globals.topl, "Read Reference Object:\n" " No reference object read - either the\n" " selected file is empty or it is not the\n" " correct object type - please check the\n" " file or make a new selection", XmDIALOG_FULL_APPLICATION_MODAL); /* set hour glass cursor */ HGU_XmUnsetHourGlassCursor(globals.topl); return; } if( obj->values.core == NULL ){ HGU_XmUserError(globals.topl, "Read Reference Object:\n" " The reference object must have a grey-\n" " value table. Please select an alternate\n" " object", XmDIALOG_FULL_APPLICATION_MODAL); WlzFreeObj( obj ); /* set hour glass cursor */ HGU_XmUnsetHourGlassCursor(globals.topl); return; } /* install the new reference object */ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, 0, 0, obj->domain.i->line1, obj->domain.i->lastln, obj->domain.i->kol1, obj->domain.i->lastkl, &errNum))){ domain.p->domains[0] = WlzAssignDomain(obj->domain, NULL); if((values.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, 0, 0, WlzGetBackground(obj, NULL), NULL, &errNum))){ values.vox->values[0] = WlzAssignValues(obj->values, NULL); newObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, obj->plist, NULL, &errNum); WlzFreeObj(obj); obj = newObj; } } globals.origObjType = WLZ_2D_DOMAINOBJ; break; case WLZ_3D_DOMAINOBJ: globals.origObjType = WLZ_3D_DOMAINOBJ; break; default: HGU_XmUserError(globals.topl, "Read Reference Object:\n" " The reference object must be a 2- or 3-D\n" " grey-level image. Please select an alternate\n" " object", XmDIALOG_FULL_APPLICATION_MODAL); WlzFreeObj( obj ); /* set hour glass cursor */ HGU_XmUnsetHourGlassCursor(globals.topl); return; } globals.origObjExtType = image_type; /* set title and reference file list */ if((icsfile = HGU_XmGetFileStr(globals.topl, cbs->value, cbs->dir))) { Widget cascade; HGU_XmFileListAddFile(globals.fileList, icsfile, image_type); HGU_XmFileListWriteResourceFile(globals.fileList, globals.resourceFile); if((cascade = XtNameToWidget(globals.topl, "*file_menu*_pulldown*Recent"))){ HGU_XmFileListResetMenu(globals.fileList, cascade, referenceFileListCb); } if( XmStringGetLtoR(cbs->value, XmSTRING_DEFAULT_CHARSET, &icsfile) ) { set_topl_title(icsfile); globals.file = icsfile; } } MAPaintLogData("ReferenceFile", globals.file, 0, NULL); /* clear feedback object and install new reference object */ if( errNum == WLZ_ERR_NONE ){ if( globals.fb_obj ){ WlzFreeObj(globals.fb_obj); globals.fb_obj = NULL; } install_paint_reference_object( obj ); } /* set hour glass cursor */ HGU_XmUnsetHourGlassCursor(globals.topl); if( errNum != WLZ_ERR_NONE ){ MAPaintReportWlzError(globals.topl, "read_reference_object_cb", errNum); } return; }
void file_menu_init( Widget topl) { Widget rc, form, toggle; Visual *visual; Arg arg[1]; char fileStr[128]; FILE *fp; WlzEffFormat image_type=WLZEFF_FORMAT_WLZ; /* set the top-level title */ set_topl_title(NULL); /* get the visual explicitly */ visual = HGU_XmWidgetToVisual(topl); XtSetArg(arg[0], XmNvisual, visual); /* create the read-model file selection dialog */ read_model_dialog = XmCreateFileSelectionDialog(topl, "read_model_dialog", arg, 1); XtAddCallback(read_model_dialog, XmNokCallback, read_reference_object_cb, (XtPointer) WLZEFF_FORMAT_WLZ); XtAddCallback(read_model_dialog, XmNokCallback, PopdownCallback, NULL); XtAddCallback( read_model_dialog, XmNcancelCallback, PopdownCallback, NULL); XtAddCallback(read_model_dialog, XmNmapCallback, FSBPopupCallback, NULL); XtManageChild( read_model_dialog ); /* create the read-obj file selection dialog */ read_obj_dialog = HGU_XmCreateExtFFObjectFSB(topl, "read_obj_dialog", read_reference_object_cb, NULL); if((rc = XtNameToWidget(read_obj_dialog, "*.formatFormRC"))){ /* add a form to include file type and fill-blanks toggle */ form = XtVaCreateManagedWidget("read_file_form", xmFormWidgetClass, rc, XmNborderWidth, 0, NULL); /* add a fill-blanks toggles */ toggle = XtVaCreateManagedWidget("fill_blanks", xmToggleButtonGadgetClass, form, XmNindicatorOn, True, XmNindicatorType, XmN_OF_MANY, XmNset, False, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, NULL); toggle = XtVaCreateManagedWidget("min_domain", xmToggleButtonGadgetClass, form, XmNindicatorOn, True, XmNindicatorType, XmN_OF_MANY, XmNset, True, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, toggle, NULL); } HGU_XmExtFFObjectFSBSetType(read_obj_dialog, WLZEFF_FORMAT_WLZ); XtManageChild( read_obj_dialog ); /* add to the save restore list */ HGU_XmSaveRestoreAddWidget( read_obj_dialog, HGU_XmFSD_SaveFunc, (XtPointer) XtName(topl), NULL, NULL ); /* create the write-obj file selection dialog */ write_obj_dialog = HGU_XmCreateExtFFObjectFSB(topl, "write_obj_dialog", write_reference_object_cb, NULL); HGU_XmExtFFObjectFSBSetType(write_obj_dialog, WLZEFF_FORMAT_WLZ); /* initialise the reference file list pulldown */ if( !globals.sectViewFlg ){ Widget cascade; if((cascade = XtNameToWidget(globals.topl, "*file_menu*_pulldown*Recent"))){ globals.resourceFile = (String) AlcMalloc(sizeof(char) * (strlen(getenv("HOME")) + 16)); sprintf(globals.resourceFile, "%s/%s", getenv("HOME"), ".maRecentFiles"); globals.fileList = HGU_XmFileListCreateList(globals.resourceFile, NULL); HGU_XmFileListResetMenu(globals.fileList, cascade, referenceFileListCb); } } /* add to the save restore list */ HGU_XmSaveRestoreAddWidget( write_obj_dialog, HGU_XmFSD_SaveFunc, (XtPointer) XtName(topl), NULL, NULL ); /* create the object properties dialog */ obj_props_dialog_init( topl ); globals.file = NULL; globals.obj = NULL; globals.orig_obj = NULL; globals.fb_obj = NULL; globals.origObjExtType = image_type; /* setup the theiler directory and menu item - check for stage */ XtGetApplicationResources(topl, &globals, set_att_res, XtNumber(set_att_res), NULL, 0); /* check the logfile */ if( globals.logfile ){ if( (globals.logfileFp = fopen(globals.logfile, "w")) == NULL ){ fprintf(stderr, "MAPaint: something wrong with the logfile %s\n" "Please check name and permissions\n" "Logging not enabled\n\007", globals.logfile); } else { char timeBuf[16]; struct hostent *hstnt; fprintf(stderr, "MAPaint: logging enabled to %s\n", globals.logfile); MAPaintLogData("Filename", globals.logfile, 0, NULL); MAPaintLogData("User", getenv("USER"), 0, NULL); #if defined (LINUX2) || defined (DARWIN) strcpy(timeBuf, "00/00/00"); #else tmpTime = time(NULL); cftime(timeBuf, "%d/%m/%Y", &tmpTime); #endif /* LINUX2 */ MAPaintLogData("Date", timeBuf, 0, NULL); #if defined (LINUX2) || defined (DARWIN) strcpy(timeBuf, "00.00"); #else cftime(timeBuf, "%H.%M", &tmpTime); #endif /* LINUX2 */ MAPaintLogData("Time", timeBuf, 0, NULL); hstnt = gethostbyname(getenv("HOST")); MAPaintLogData("Host", getenv("HOST"), 0, NULL); MAPaintLogData("Hostname", hstnt->h_name, 0, NULL); } } else { globals.logfileFp = NULL; } /* check base directory - if the string has come from the resources then we need to duplicate it to allow it to be freed possibly some memory leakage here */ /* note: only non-NULL if set by the user, if NULL then attempt to find the cdrom or copied data */ if( globals.base_theiler_dir ){ globals.base_theiler_dir = AlcStrDup( globals.base_theiler_dir ); } /* else { FILE *pp;*/ /* search for the Theiler mode directory as per the CDROM should search local disc first */ /*#if defined (LINUX2) if((pp = popen("find /mnt -maxdepth 4 -name Models", "r"))){ while( fscanf(pp, "%s", fileStr) != EOF ){ if( strstr(fileStr, "Models") ){ globals.base_theiler_dir = AlcStrDup(fileStr); break; } } pclose(pp); } #elif defined (DARWIN) if( (pp = popen("find /Volumes -maxdepth 4 -name Models", "r")) ){ while( fscanf(pp, "%s", fileStr) != EOF ){ if( strstr(fileStr, "Models") ){ globals.base_theiler_dir = AlcStrDup(fileStr); break; } } pclose(pp); } #elif defined (SUNOS4) || defined (SUNOS5) if( pp = popen("find /cdrom -maxdepth 4 -name Models", "r") ){ while( fscanf(pp, "%s", fileStr) != EOF ){ if( strstr(fileStr, "Models") ){ globals.base_theiler_dir = AlcStrDup(fileStr); break; } } pclose(pp); } #else globals.base_theiler_dir = NULL; #endif }*/ if( globals.theiler_stage ){ char *tStr; if((tStr = theilerString(globals.theiler_stage))){ globals.theiler_stage = AlcStrDup(tStr); } else { globals.theiler_stage = NULL; } } theiler_menu_init( topl ); /* check for an initial reference file else check Theiler stage */ if( initial_reference_file != NULL ){ WlzObject *obj; /* open the reference object file and install */ if( (fp = fopen(initial_reference_file, "r")) ){ HGU_XmSetHourGlassCursor(topl); if((obj = WlzReadObj( fp, NULL ))){ WlzDomain domain; WlzValues values; WlzObject *newObj; switch( obj->type ){ case WLZ_2D_DOMAINOBJ: domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, 0, 0, obj->domain.i->line1, obj->domain.i->lastln, obj->domain.i->kol1, obj->domain.i->lastkl, NULL); domain.p->domains[0] = WlzAssignDomain(obj->domain, NULL); values.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, 0, 0, WlzGetBackground(obj, NULL), NULL, NULL); values.vox->values[0] = WlzAssignValues(obj->values, NULL); newObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, NULL); WlzFreeObj(obj); obj = newObj; globals.origObjType = WLZ_2D_DOMAINOBJ; break; case WLZ_3D_DOMAINOBJ: globals.origObjType = WLZ_3D_DOMAINOBJ; break; default: HGU_XmUserError(globals.topl, "Read Reference Object:\n" " The reference object must be a 2- or 3-D woolz\n" " grey-level image. Please select an alternate\n" " object", XmDIALOG_FULL_APPLICATION_MODAL); WlzFreeObj( obj ); /* set hour glass cursor */ HGU_XmUnsetHourGlassCursor(globals.topl); return; } HGU_XmFileListAddFile(globals.fileList, initial_reference_file, image_type); HGU_XmFileListWriteResourceFile(globals.fileList, globals.resourceFile); MAPaintLogData("ReferenceFile", initial_reference_file, 0, NULL); install_paint_reference_object( obj ); /* set the globals reference file */ globals.file = initial_reference_file; /* set the title of the top-level window */ set_topl_title(globals.file); } else { /* if it fails to read, check the file name or the file content for special options */ if( strstr(initial_reference_file, "MAPaint") ){ /* standard MAPaint startup */ globals.app_name = "MAPaint"; /* set the title of the top-level window */ set_topl_title(globals.file); } else if( strstr(initial_reference_file, "SectionView") ){ /* restricted section view startup */ globals.app_name = "SectionView"; globals.sectViewFlg = 1; /* set the title of the top-level window */ set_topl_title(globals.file); } else if( theilerString(initial_reference_file) ){ /* load in theiler stage anatomy etc. */ globals.app_name = "SectionView"; globals.sectViewFlg = 1; set_theiler_stage_cb(topl, theilerString(initial_reference_file), NULL); } else { char strBuf[33]; /* check the content */ rewind(fp); fscanf(fp, "%32s", strBuf); if( strstr(strBuf, "MAPaint") ){ /* standard MAPaint startup */ globals.app_name = "MAPaint"; /* set the title of the top-level window */ set_topl_title(globals.file); } else if( strstr(strBuf, "SectionView") ){ /* restricted section view startup */ globals.app_name = "SectionView"; globals.sectViewFlg = 1; /* set the title of the top-level window */ set_topl_title(globals.file); } else if( theilerString(strBuf) ){ /* load in theiler stage anatomy etc. */ globals.app_name = "SectionView"; globals.sectViewFlg = 1; set_theiler_stage_cb(topl, theilerString(strBuf), NULL); } } /* set the globals reference file */ globals.file = NULL; } (void) fclose( fp ); HGU_XmUnsetHourGlassCursor(topl); } } else if( globals.theiler_stage ){ globals.app_name = "MAPaint"; set_theiler_stage_cb(topl, theilerString(globals.theiler_stage), NULL); } /* reset the colormap */ if( globals.sectViewFlg == 1 ){ init_paint_cmapstruct(globals.topl); } /* check for an initial domain file */ if( initial_domain_file != NULL ){ WlzObject *obj; /* open the domain object file and put it in as a 3D feedback option */ if( (fp = fopen(initial_domain_file, "rb")) ){ HGU_XmSetHourGlassCursor(topl); if((obj = WlzReadObj( fp, NULL ))){ if( globals.fb_obj ){ WlzFreeObj(globals.fb_obj); } globals.fb_obj = WlzAssignObject(obj, NULL); setup_ref_display_list_cb(read_obj_dialog, NULL, NULL); } (void) fclose( fp ); HGU_XmUnsetHourGlassCursor(topl); } } return; }
/*! * \return Transformed object. * \ingroup WlzTransform * \brief Transform an object using the given view-transform. * Typically this is for mapping section data back into * the 3D space of the reference image/reconstruction. * \param srcObj Given source object. * \param viewStr Given view transform. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *Wlz3DViewTransformObj( WlzObject *srcObj, WlzThreeDViewStruct *viewStr, WlzErrorNum *dstErr) { WlzErrorNum errNum=WLZ_ERR_NONE; AlcErrno alcErr = ALC_ER_NONE; WlzObject *dstObj=NULL; int area; int i, k, p, xp, yp, line; int plane1, lastpl, line1, lastln, kol1, lastkl; WlzIVertex3 *vertices; int numVtxs, vtxIdx; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzDomain domain, tmpDomain; WlzValues values; int numInts, itvlFlg; WlzInterval *itvl; /* check the object */ if( srcObj == NULL ) { errNum = WLZ_ERR_OBJECT_NULL; } else { switch( srcObj->type ) { case WLZ_2D_DOMAINOBJ: if( srcObj->domain.core == NULL ) { errNum = WLZ_ERR_DOMAIN_NULL; } area = WlzArea(srcObj, &errNum); if( area == 0 ) { dstObj = WlzMakeEmpty(&errNum); } break; case WLZ_2D_POLYGON: /* to be done at some time to 3D polyline */ case WLZ_BOUNDLIST: /* convert to 3D polylines */ case WLZ_TRANS_OBJ: errNum = WLZ_ERR_OBJECT_TYPE; break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* create the voxel list */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { numVtxs = sizeof(WlzIVertex3) * (area+4); vertices = AlcMalloc(sizeof(WlzIVertex3) * (area+4)); numVtxs = 0; if( vertices ) { errNum = WlzInitRasterScan(srcObj, &iwsp, WLZ_RASTERDIR_ILIC); } else { errNum = WLZ_ERR_MEM_ALLOC; } if( errNum == WLZ_ERR_NONE ) { while( (errNum = WlzNextInterval(&iwsp)) == WLZ_ERR_NONE ) { float x, y, z; if((iwsp.linpos < (int) viewStr->minvals.vtY) || (iwsp.linpos > (int) viewStr->maxvals.vtY)) { continue; } yp = iwsp.linpos - (int) viewStr->minvals.vtY; for(k=iwsp.lftpos; k <= iwsp.rgtpos; k++) { if((k < (int) viewStr->minvals.vtX) || (k > (int) viewStr->maxvals.vtX)) { continue; } xp = k - (int) viewStr->minvals.vtX; x = (float )(viewStr->xp_to_x[xp] + viewStr->yp_to_x[yp]); y = (float )(viewStr->xp_to_y[xp] + viewStr->yp_to_y[yp]); z = (float )(viewStr->xp_to_z[xp] + viewStr->yp_to_z[yp]); vertices[numVtxs].vtX = WLZ_NINT(x); vertices[numVtxs].vtY = WLZ_NINT(y); vertices[numVtxs].vtZ = WLZ_NINT(z); numVtxs++; } } if(errNum == WLZ_ERR_EOO) /* Reset error from end of object */ { errNum = WLZ_ERR_NONE; } } } /* sort wrt planes, lines, kols */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { qsort((void *) vertices, (size_t) numVtxs, sizeof(WlzIVertex3), compareVtxVal); /* create planedomain */ plane1 = vertices[0].vtZ; lastpl = vertices[numVtxs - 1].vtZ; line1 = vertices[0].vtY; lastln = line1; kol1 = vertices[0].vtX; lastkl = kol1; for(i=1; i < numVtxs; i++) { if( kol1 > vertices[i].vtX ) { kol1 = vertices[i].vtX; } if( lastkl < vertices[i].vtX ) { lastkl = vertices[i].vtX; } if( line1 > vertices[i].vtY ) { line1 = vertices[i].vtY; } if( lastln < vertices[i].vtY ) { lastln = vertices[i].vtY; } } if( (domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, plane1, lastpl, line1, lastln, kol1, lastkl, &errNum)) == NULL ) { AlcFree((void *) vertices); } } /* for each plane count intervals and make domain */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { vtxIdx = 0; for(p=plane1; p <= lastpl; p++) { /* increment vertex index to current plane */ while( vertices[vtxIdx].vtZ < p ) { vtxIdx++; } /* check for empty domain */ if( vertices[vtxIdx].vtZ > p ) { domain.p->domains[p - plane1].i = NULL; continue; } /* estimate intervals - foreach pixel add one, foreach adjacent pixel on the same line subtract one */ numInts = 1; kol1 = vertices[vtxIdx].vtX; lastkl = kol1; for(i=vtxIdx+1; i < numVtxs; i++) { if( vertices[i].vtZ > p ) { break; } numInts++; if((vertices[i].vtY == vertices[i-1].vtY) && ((vertices[i].vtX == (vertices[i-1].vtX)) || (vertices[i].vtX == (vertices[i-1].vtX + 1)) )) { numInts--; } if(kol1 > vertices[i].vtX) { kol1 = vertices[i].vtX; } if(lastkl < vertices[i].vtX) { lastkl = vertices[i].vtX; } } line1 = vertices[vtxIdx].vtY; lastln = vertices[i-1].vtY; /* make the domain and add the intervals pointer */ tmpDomain.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, line1, lastln, kol1, lastkl, &errNum); itvl = (WlzInterval *) AlcMalloc(sizeof(WlzInterval)*numInts); tmpDomain.i->freeptr = AlcFreeStackPush(tmpDomain.i->freeptr, (void *) itvl, &alcErr); if(alcErr != ALC_ER_NONE) { errNum = WLZ_ERR_MEM_ALLOC; } /* one more loop to add the intervals */ itvl->ileft = vertices[vtxIdx].vtX - kol1; line = vertices[vtxIdx].vtY; itvlFlg = 1; /* interval started */ numInts = 1; for(i=vtxIdx+1; i < numVtxs; i++) { /* new plane -> interval finished if started */ if( vertices[i].vtZ > p ) { if( itvlFlg ) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; WlzMakeInterval(line, tmpDomain.i, numInts, itvl); itvl += numInts; itvlFlg = 0; /* interval finished */ numInts = 0; } break; } /* check if new interval */ if( !itvlFlg ) { itvl->ileft = vertices[i].vtX - kol1; line = vertices[i].vtY; itvlFlg = 1; numInts = 1; continue; /* no further tests */ } /* check for gap - increment interval count */ if((vertices[i].vtY == line) && ((vertices[i].vtX - vertices[i-1].vtX) > 1)) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; numInts++; itvl[numInts-1].ileft = vertices[i].vtX - kol1; itvlFlg = 1; } /* check for new-line */ if( line < vertices[i].vtY ) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; WlzMakeInterval(line, tmpDomain.i, numInts, itvl); itvl += numInts; itvl->ileft = vertices[i].vtX - kol1; line = vertices[i].vtY; itvlFlg = 1; numInts = 1; } } /* complete the last interval */ if( itvlFlg ) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; WlzMakeInterval(line, tmpDomain.i, numInts, itvl); itvl += numInts; } /* add the domain to the planedomain */ domain.p->domains[p - plane1] = WlzAssignDomain(tmpDomain, &errNum); (void) WlzIntervalCount(tmpDomain.i, 0); } } /* create the new object */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { values.core = NULL; dstObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } /* check for grey-level data */ if((errNum == WLZ_ERR_NONE) && dstObj && (dstObj->type != WLZ_EMPTY_OBJ) && srcObj->values.core ) { WlzPixelV bckgrnd; WlzObject *tmpObj; WlzValues tmpValues; WlzDVertex3 vtx; WlzGreyValueWSpace *gVWSp = NULL; WlzObjectType valueTbType; /* explicit intialisation to satisfy strict ANSI on SGI */ bckgrnd = WlzGetBackground(srcObj, &errNum); valueTbType = WlzGreyTableType(WLZ_GREY_TAB_RAGR, bckgrnd.type, NULL); /* make a voxel table */ values.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, plane1, lastpl, bckgrnd, NULL, &errNum); dstObj->values = WlzAssignValues(values, &errNum); /* set up grey-value random access to original and loop through planes setting values */ gVWSp = WlzGreyValueMakeWSp(srcObj, NULL); for(p=plane1; p <= lastpl; p++) { /* check for empty domain */ if( domain.p->domains[p-plane1].core == NULL ) { continue; } /* make a value table */ tmpObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain.p->domains[p-plane1], values.vox->values[p-plane1], NULL, NULL, &errNum); tmpValues.v = WlzNewValueTb(tmpObj, valueTbType, bckgrnd, &errNum); values.vox->values[p-plane1] = WlzAssignValues(tmpValues, &errNum); tmpObj->values = WlzAssignValues(tmpValues, &errNum); /* transfer values */ errNum = WlzInitGreyScan(tmpObj, &iwsp, &gwsp); while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE)) { for(i=0; i<iwsp.colrmn; i++) { vtx.vtX = iwsp.colpos + i; vtx.vtY = iwsp.linpos; vtx.vtZ = p; Wlz3DSectionTransformVtx(&vtx, viewStr); WlzGreyValueGet(gVWSp, 0.0, WLZ_NINT(vtx.vtY), WLZ_NINT(vtx.vtX)); switch( gwsp.pixeltype ) { case WLZ_GREY_LONG: *(gwsp.u_grintptr.lnp+i) = gVWSp->gVal[0].lnv; break; case WLZ_GREY_INT: *(gwsp.u_grintptr.inp+i) = gVWSp->gVal[0].inv; break; case WLZ_GREY_SHORT: *(gwsp.u_grintptr.shp+i) = gVWSp->gVal[0].shv; break; case WLZ_GREY_UBYTE: *(gwsp.u_grintptr.ubp+i) = gVWSp->gVal[0].ubv; break; case WLZ_GREY_FLOAT: *(gwsp.u_grintptr.flp+i) = gVWSp->gVal[0].flv; break; case WLZ_GREY_DOUBLE: *(gwsp.u_grintptr.dbp+i) = gVWSp->gVal[0].dbv; break; case WLZ_GREY_RGBA: *(gwsp.u_grintptr.rgbp+i) = gVWSp->gVal[0].rgbv; break; case WLZ_GREY_BIT: /* not sure what to do with these */ default: break; } } } if(errNum == WLZ_ERR_EOO) /* Reset error from end of object */ { errNum = WLZ_ERR_NONE; } WlzFreeObj(tmpObj); } WlzGreyValueFreeWSp(gVWSp); } /* clean temp allocation */ if( vertices ) { AlcFree((void *) vertices); } if( dstErr ) { *dstErr = errNum; } return dstObj; }
/*! * \return Rescaled object. * \ingroup WlzTransform * \brief Rescales the given 2D domain object using an integer scale. * \param obj 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. */ static WlzObject *WlzIntRescaleObj2D( WlzObject *obj, int scale, int expand, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzDomain domain; WlzValues values; WlzInterval *intvls; int k1, kl, l1, ll, l, num_intvls; WlzErrorNum errNum=WLZ_ERR_NONE; /* check expand or contract */ if( expand ) { k1 = obj->domain.i->kol1 * scale; kl = obj->domain.i->lastkl * scale + scale - 1; l1 = obj->domain.i->line1 * scale; ll = obj->domain.i->lastln * scale + scale - 1; } else { k1 = obj->domain.i->kol1 / scale; kl = obj->domain.i->lastkl / scale; l1 = obj->domain.i->line1 / scale; ll = obj->domain.i->lastln / scale; } /* create a new object */ if((domain.i = WlzMakeIntervalDomain(obj->domain.i->type, l1, ll, k1, kl, &errNum)) != NULL){ values.core = NULL; rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain, values, NULL, NULL, NULL); } /* fill in the intervals */ if( errNum == WLZ_ERR_NONE){ if( domain.i->type == WLZ_INTERVALDOMAIN_INTVL ) { int intvline_offset, max_offset; WlzIntervalLine *intvline; num_intvls = WlzIntervalCount(obj->domain.i, NULL); num_intvls = expand ? num_intvls * scale : num_intvls; intvls = (WlzInterval *)AlcMalloc(sizeof(WlzInterval) * num_intvls); domain.i->freeptr = AlcFreeStackPush(domain.i->freeptr, (void *)intvls, NULL); max_offset = obj->domain.i->lastln - obj->domain.i->line1; for(l=l1; l <= ll; l++) { int i; intvline_offset = (expand?l/scale:l*scale) - obj->domain.i->line1; intvline_offset = WLZ_MAX(intvline_offset, 0); intvline_offset = WLZ_MIN(intvline_offset, max_offset); intvline = obj->domain.i->intvlines + intvline_offset; for(i=0; i < intvline->nintvs; i++) { intvls[i].ileft = (intvline->intvs + i)->ileft; intvls[i].iright = (intvline->intvs + i)->iright; if( expand ) { intvls[i].ileft *= scale; intvls[i].iright *= scale; intvls[i].iright += scale - 1; } else { intvls[i].ileft /= scale; intvls[i].iright /= scale; } } i = check_intvs(intvls, i); WlzMakeInterval(l, domain.i, i, intvls); intvls += i; } (void) WlzStandardIntervalDomain( domain.i ); } } /* create the valuetable */ if( (errNum == WLZ_ERR_NONE) && obj->values.core ) { WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzPixelV backgrnd; WlzGreyValueWSpace *gVWSp = NULL; WlzGreyType gtype; backgrnd = WlzGetBackground(obj, NULL); if((values.v = WlzNewValueTb(rtnObj, obj->values.v->type, backgrnd, &errNum)) != NULL){ rtnObj->values = WlzAssignValues(values, NULL); /* fill in the grey-values */ errNum = WlzInitGreyScan(rtnObj, &iwsp, &gwsp); if(errNum == WLZ_ERR_NONE) { gVWSp = WlzGreyValueMakeWSp(obj, &errNum); if(errNum == WLZ_ERR_NONE) { gtype = WlzGreyTableTypeToGreyType(obj->values.v->type, NULL); } while((errNum == WLZ_ERR_NONE) && (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE) { int k; int lp = expand ? iwsp.linpos/scale : iwsp.linpos*scale; for( k=0; k <= (iwsp.rgtpos - iwsp.lftpos); k++ ) { int kp = expand ? (k+iwsp.lftpos)/scale : (k+iwsp.lftpos)*scale; WlzGreyValueGet(gVWSp, 0, (double) lp, (double) kp); switch(gtype) { case WLZ_GREY_INT: gwsp.u_grintptr.inp[k] = (*(gVWSp->gVal)).inv; break; case WLZ_GREY_SHORT: gwsp.u_grintptr.shp[k] = (*(gVWSp->gVal)).shv; break; case WLZ_GREY_UBYTE: gwsp.u_grintptr.ubp[k] = (*(gVWSp->gVal)).ubv; break; case WLZ_GREY_FLOAT: gwsp.u_grintptr.flp[k] = (*(gVWSp->gVal)).flv; break; case WLZ_GREY_DOUBLE: gwsp.u_grintptr.dbp[k] = (*(gVWSp->gVal)).dbv; break; case WLZ_GREY_RGBA: gwsp.u_grintptr.rgbp[k] = (*(gVWSp->gVal)).rgbv; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzGreyValueFreeWSp(gVWSp); (void )WlzEndGreyScan(&iwsp, &gwsp); } } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
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; }
/*! * \ingroup WlzBinaryOps * \brief Calculate the set union of an array of domain objects. Domians only unless uvt non-zero in which case make an average grey table. Note background values are used in the averaging process. All objects must be domain objects of the same type (2D or 3D) unless WLZ_EMPTY_OBJ, NULL input objects are an error. This function may modify the order of the objects in the array it is passed if the array contains empty objects. * * \return Union of the array of object. * \param n number of input objects * \param objs input object array * \param uvt grey-table copy flag, copy if non-zero. * \param dstErr error return. * \par Source: * WlzUnionN.c */ WlzObject *WlzUnionN( int n, WlzObject **objs, int uvt, WlzErrorNum *dstErr) { WlzObject *obj=NULL; WlzDomain domain; WlzValues values; WlzIntervalDomain *idom; WlzInterval *itvl, *jtvl; WlzIntervalWSpace *iwsp; WlzIntervalWSpace *biwsp, *tiwsp, niwsp; WlzGreyWSpace *gwsp, ngwsp; WlzObjectType type; int i, j, k, l; int inttot, numactive, change, lwas, nints, noverlap; WlzPixelV backg; int line1, lastln; int kol1,lastkl; WlzGreyV gv; WlzGreyP greyptr; int **locbuff; int *locbuffs; int span; WlzErrorNum errNum=WLZ_ERR_NONE; /* preliminary stuff - count of non-NULL objects, note WLZ_EMPTY_OBJs are ignored but NULL objects are an error */ if( n < 1 ){ errNum = WLZ_ERR_PARAM_DATA; } else { for (i=0; i<n ; i++ ){ if ( objs[i] == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; break; } if( objs[i]->type == WLZ_EMPTY_OBJ ){ obj = objs[i]; for ( j=i; j<n-1 ; j++ ){ objs[j] = objs[j+1]; } objs[n-1] = obj; n--; i--; } } } /* n has been checked therefore no objects implies all empty */ if( (errNum == WLZ_ERR_NONE) && (n < 1) ){ return WlzMakeEmpty(dstErr); } /* now check they are all of the same type */ if( errNum == WLZ_ERR_NONE ){ for(i=1; i < n; i++){ if( objs[i]->type != objs[0]->type ){ errNum = WLZ_ERR_OBJECT_TYPE; break; } } } /* now test the type note empty objects have been discarded */ if( errNum == WLZ_ERR_NONE ){ switch( objs[0]->type ){ case WLZ_2D_DOMAINOBJ: break; case WLZ_3D_DOMAINOBJ: return WlzUnion3d(n, objs, uvt, dstErr); case WLZ_TRANS_OBJ: default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* now discard empty objects */ if( errNum == WLZ_ERR_NONE ){ for (i=0; i<n ; i++ ){ if( WlzIsEmpty(objs[i], NULL) ){ obj = objs[i]; for ( j=i; j<n-1 ; j++ ){ objs[j] = objs[j+1]; } objs[n-1] = obj; n--; i--; } } } obj = NULL; /* recheck number of objects */ if( (errNum == WLZ_ERR_NONE) && (n < 1) ){ return WlzMakeEmpty(dstErr); } if( (errNum == WLZ_ERR_NONE) && (n == 1) ){ return WlzMakeMain(objs[0]->type, objs[0]->domain, objs[0]->values, NULL, NULL, dstErr); } /* check if grey-value merge is possible */ if( errNum == WLZ_ERR_NONE ){ for (i=0; i<n ; i++ ){ if( objs[i]->values.core == NULL ){ uvt = 0; break; } } } /* * find the line and column bounds of the union. */ if( errNum == WLZ_ERR_NONE ){ 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; } span = lastkl - kol1 +1 ; if( (locbuff = (int **) AlcMalloc((n+1)*sizeof(int *))) == NULL ){ errNum = WLZ_ERR_MEM_ALLOC; } } /* space must be allocated for the largest variety of grey-value */ if( errNum == WLZ_ERR_NONE ){ if( (locbuffs = (int *) AlcMalloc(sizeof(double)*span*(n+1))) == NULL ){ AlcFree((void *) locbuff); errNum = WLZ_ERR_MEM_ALLOC; } else { for(i=0; i <= n; i++){ locbuff[i] = locbuffs + i*span; } } } /* * count the individual intervals so that sufficient space * for the union may be allocated. */ if( errNum == WLZ_ERR_NONE ){ inttot=0; for(i=0; i < n; i++){ inttot += WlzIntervalCount(objs[i]->domain.i, &errNum); } } /* * set up domain, value table structures, and object. */ if( errNum == WLZ_ERR_NONE ){ if( (idom = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, line1,lastln,kol1,lastkl, &errNum)) == NULL ){ AlcFree((void *) locbuffs); AlcFree((void *) locbuff); } else if( (itvl = (WlzInterval *) AlcMalloc(inttot * sizeof(WlzInterval))) == NULL){ AlcFree((void *) locbuffs); AlcFree((void *) locbuff); WlzFreeIntervalDomain(idom); errNum = WLZ_ERR_MEM_ALLOC; } else { 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 ); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); return(NULL); } } } /* * allocate space for workspaces */ if( errNum == WLZ_ERR_NONE ){ if( (iwsp = (WlzIntervalWSpace *) AlcMalloc (n * sizeof (WlzIntervalWSpace))) == NULL ){ WlzFreeObj( obj ); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); errNum = WLZ_ERR_MEM_ALLOC; obj = NULL; } else { biwsp = iwsp; tiwsp = iwsp + n; } } /* * Construct the union object's table of intervals. * Initialise scanning on each object/workspace combination. * Scan synchronously, setting up the union of adjacent and * overlapping intervals. Needs a clear head !! */ if( errNum == WLZ_ERR_NONE ){ for (i=0; i<n; i++) { WlzInitRasterScan(objs[i], iwsp, WLZ_RASTERDIR_ILIC); WlzNextInterval(iwsp++); } numactive = n; /* * find next line and left hand end of next interval of union */ while (numactive > 0) { /* * find first remaining active object */ iwsp = biwsp; while( iwsp->linrmn < 0 ){ iwsp++; } /* * find minimum line number of remaining active intervals */ l = iwsp->linpos; kol1 = iwsp->lftpos; lastkl = iwsp->rgtpos; for (iwsp++; iwsp<tiwsp; iwsp++) if (iwsp->linrmn >= 0 && iwsp->linpos < l) { l = iwsp->linpos; kol1 = iwsp->lftpos; lastkl = iwsp->rgtpos; } /* * find left-most interval in this line */ for (iwsp=biwsp; iwsp<tiwsp; iwsp++) if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos < kol1) { kol1 = iwsp->lftpos; lastkl = iwsp->rgtpos; } /* * construct maximal interval with current left end-point */ do { change = 0; for (iwsp=biwsp; iwsp<tiwsp; iwsp++) { while( iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= lastkl+1 ){ if (iwsp->rgtpos > lastkl) { lastkl = iwsp->rgtpos; change = 1; } if (WlzNextInterval(iwsp) != WLZ_ERR_NONE) { numactive--; } } } } while (change == 1); itvl->ileft = kol1 - idom->kol1; itvl->iright = lastkl - idom->kol1; if (l == lwas) nints++; else { (void) WlzMakeInterval(lwas,idom,nints,jtvl); for (j = lwas+1; j<l; j++) { (void) WlzMakeInterval(j,idom,0,NULL); } lwas = l; nints = 1; jtvl = itvl; } itvl++; } (void) WlzMakeInterval(lwas,idom,nints,jtvl); for (j = lwas+1; j<=lastln; j++) { (void) WlzMakeInterval(j,idom,0,NULL); } } /* now deal with the grey-values if required */ if( (errNum == WLZ_ERR_NONE) && (uvt != 0) ){ WlzGreyType grey_type; if( (gwsp = (WlzGreyWSpace *) AlcMalloc (n * sizeof (WlzGreyWSpace))) == NULL){ WlzFreeObj( obj ); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); AlcFree((void *) biwsp); errNum = WLZ_ERR_MEM_ALLOC; obj = NULL; } /* construct an empty "ragged-rectangle" greytable with appropriate grey-type */ if( errNum == WLZ_ERR_NONE ){ backg = WlzGetBackground(objs[0], NULL); grey_type = WlzGreyTableTypeToGreyType(objs[0]->values.core->type, NULL); type = WlzGreyTableType(WLZ_GREY_TAB_RAGR, grey_type, NULL); if( (values.v = WlzNewValueTb(obj, type, backg, &errNum)) == NULL ){ WlzFreeObj( obj ); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); AlcFree((void *) biwsp); obj = NULL; } else { obj->values = WlzAssignValues(values, NULL); } } /* fill the grey table. Where more than one input objects overlap, take mean of grey values. */ if( errNum == WLZ_ERR_NONE ){ WlzInitGreyScan(obj, &niwsp, &ngwsp); iwsp = biwsp; for (i=0; i<n; i++) { WlzInitGreyScan(objs[i], iwsp, &gwsp[i]); WlzNextGreyInterval(iwsp++); if( gwsp[i].pixeltype != grey_type ){ AlcFree((void *) gwsp); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); AlcFree((void *) biwsp); WlzFreeObj( obj ); obj = NULL; errNum = WLZ_ERR_GREY_TYPE; } } } if( errNum == WLZ_ERR_NONE ){ 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++) { noverlap = 0; 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))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.inv += *(gwsp[i].u_grintptr.inp + k - iwsp->lftpos); } } *greyptr.inp = gv.inv / noverlap; greyptr.inp++; } break; case WLZ_GREY_SHORT: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; 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))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.shv += *(gwsp[i].u_grintptr.shp + k - iwsp->lftpos); } } *greyptr.shp = (short )(gv.shv / noverlap); greyptr.shp++; } break; case WLZ_GREY_UBYTE: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; 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))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.inv += *(gwsp[i].u_grintptr.ubp + k - iwsp->lftpos); } } *greyptr.ubp = (WlzUByte )(gv.inv / noverlap); greyptr.ubp++; } break; case WLZ_GREY_FLOAT: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; 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))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.flv += *(gwsp[i].u_grintptr.flp + k - iwsp->lftpos); } } *greyptr.flp = gv.flv / noverlap; greyptr.flp++; } break; case WLZ_GREY_DOUBLE: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; 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))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.dbv += *(gwsp[i].u_grintptr.dbp + k - iwsp->lftpos); } } *greyptr.dbp = gv.dbv / noverlap; greyptr.dbp++; } break; case WLZ_GREY_RGBA: /* RGBA to be done - do properly RAB */ for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; 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))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.rgbv += *(gwsp[i].u_grintptr.rgbp + k - iwsp->lftpos); } } *greyptr.rgbp = gv.rgbv / noverlap; greyptr.rgbp++; } break; default: break; } } } AlcFree((void *) gwsp); } if( errNum == WLZ_ERR_NONE ){ AlcFree( (void *) biwsp); AlcFree( (void *)locbuff ); AlcFree( (void *)locbuffs ); } if( dstErr ){ *dstErr = errNum; } return( obj ); }
/*! * \return New 3D domain object. * \ingroup WlzArithmetic * \brief Computes a new 3D object which shares the domain of the given * object, but which has grey values that are the result of * applying the given function to the grey values of the * given object. * \param sObj Given source domain object with values. * \param fn Scalar function to be applied. * \param dstErr Destination error pointer, may be NULL. */ static WlzObject *WlzScalarFn3D(WlzObject *sObj, WlzFnType fn, WlzErrorNum *dstErr) { int idx, off; WlzPixelV sBgd, dBgd; WlzValues dVal; WlzObject *sObj2D, *dObj2D, *dObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; if(errNum == WLZ_ERR_NONE) { sBgd = WlzGetBackground(sObj, &errNum); } if(errNum == WLZ_ERR_NONE) { dBgd = WlzScalarFnPixel(sBgd, fn, &errNum); } if(errNum == WLZ_ERR_NONE) { dVal.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, sObj->domain.p->plane1, sObj->domain.p->lastpl, dBgd, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { for(idx = sObj->domain.p->plane1; idx <= sObj->domain.p->lastpl; ++idx) { off = idx - sObj->domain.p->plane1; dObj2D = NULL; sObj2D = WlzMakeMain(WLZ_2D_DOMAINOBJ, *(sObj->domain.p->domains + off), *(sObj->values.vox->values + off), NULL, NULL, &errNum); if(errNum == WLZ_ERR_NONE) { dObj2D = WlzScalarFn2D(sObj2D, fn, &errNum); } WlzFreeObj(sObj2D); if(errNum == WLZ_ERR_NONE) { *(dVal.vox->values + off) = WlzAssignValues(dObj2D->values, NULL); } WlzFreeObj(dObj2D); } } if(errNum == WLZ_ERR_NONE) { dObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, sObj->domain, dVal, NULL, NULL, &errNum); } if(dstErr) { *dstErr = errNum; } return(dObj); }
int main(int argc, char *argv[]) { int option, nReg = 0, tNReg = 0, ok = 1, usage = 0, verbose = 0, threshSet = 0, centreSet = 0; double minArea = 2; char *inExt, *dbgExt, *inDir, *dbgDir, *inFile, *dbgFile, *inPath = NULL, *dbgPath = NULL, *outFile = NULL; WlzRadDistVal distSort = WLZ_RADDISTVAL_AREA; WlzRadDistRec *distData = NULL; WlzPixelV thrVal; WlzDVertex2 centre; WlzCompThreshType thrMtd = WLZ_COMPTHRESH_OTSU; WlzThresholdType thrMod = WLZ_THRESH_HIGH; WlzEffFormat inFmt = WLZEFF_FORMAT_NONE, dbgFmt = WLZEFF_FORMAT_NONE; WlzObject *inObj = NULL, *disObj = NULL, *segObj = NULL; WlzGreyValueWSpace *disGVWSp = NULL; WlzObject **regObjs = NULL; FILE *fP = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; const int maxObj = 1000000; char pathBuf[FILENAME_MAX]; const double eps = 1.0e-06; const char *errMsg; static char optList[] = "hvAGDHELR:c:d:n:o:t:", defFile[] = "-"; thrVal.type = WLZ_GREY_DOUBLE; thrVal.v.dbv = 0.0; outFile = defFile; while((usage == 0) && ok && ((option = getopt(argc, argv, optList)) != -1)) { switch(option) { case 'A': distSort = WLZ_RADDISTVAL_AREA; break; case 'D': distSort = WLZ_RADDISTVAL_DIST; break; case 'G': distSort = WLZ_RADDISTVAL_ANGLE; break; case 'H': thrMod = WLZ_THRESH_HIGH; break; case 'E': thrMod = WLZ_THRESH_EQUAL; break; case 'L': thrMod = WLZ_THRESH_LOW; break; case 'R': distSort = WLZ_RADDISTVAL_RADIUS; break; case 'h': usage = 1; break; case 'v': verbose = 1; break; case 'c': centreSet = 1; if(sscanf(optarg, "%lg,%lg", &(centre.vtX), &(centre.vtY)) != 2) { usage = 1; } break; case 'd': dbgPath = optarg; break; case 'o': outFile = optarg; break; case 'n': if(sscanf(optarg, "%lg", &minArea) != 1) { usage = 1; } break; case 't': threshSet = 1; if(sscanf(optarg, "%lg", &(thrVal.v.dbv)) != 1) { usage = 1; } break; default: usage = 1; break; } } ok = !usage; if(ok) { if((optind + 1) != argc) { usage = 1; ok = 0; } else { inPath = *(argv + optind); } } if(ok && verbose) { (void )fprintf(stderr, "inPath = %s\n", inPath); } /* Parse input file path into path + name + ext. */ if(ok) { ok = (usage = WlzRadDistParsePath(inPath, &inDir, &inFile, &inExt, &inFmt)) == 0; } if(ok && verbose) { (void )fprintf(stderr, "inDir = %s\n", inDir); (void )fprintf(stderr, "inFile = %s\n", inFile); (void )fprintf(stderr, "inExt = %s\n", (inExt)? inExt: "(null)"); (void )fprintf(stderr, "inFmt = %s\n", WlzEffStringFromFormat(inFmt, NULL)); } /* Read image. */ if(ok) { errNum = WLZ_ERR_READ_EOF; if(inExt) { (void )sprintf(pathBuf, "%s/%s.%s", inDir, inFile, inExt); } else { (void )sprintf(pathBuf, "%s/%s", inDir, inFile); } if(((inObj = WlzAssignObject(WlzEffReadObj(NULL, pathBuf, inFmt, 0, 0, 0, &errNum), NULL)) == NULL) || (inObj->type != WLZ_2D_DOMAINOBJ)) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: Failed to read 2D image object from file %s (%s)\n", *argv, pathBuf, errMsg); } } if(ok && verbose) { (void )fprintf(stderr, "read input image ok.\n"); } /* Convert to grey if needed, normalise 0 - 255 if needed and compute * threshold value unless already known. */ if(ok) { if(WlzGreyTypeFromObj(inObj, NULL) == WLZ_GREY_RGBA) { WlzObject *ppObj; ppObj = WlzAssignObject( WlzRGBAToModulus(inObj, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { (void )WlzFreeObj(inObj); inObj = ppObj; } } if(threshSet == 0) { WlzObject *hObj = NULL; errNum = WlzGreyNormalise(inObj, 1); if(errNum == WLZ_ERR_NONE) { hObj = WlzHistogramObj(inObj, 256, 0.0, 1.0, &errNum); } if(errNum == WLZ_ERR_NONE) { threshSet = 1; errNum = WlzCompThreshold(&thrVal.v.dbv, hObj, thrMtd, 0); } (void )WlzFreeObj(hObj); } if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to normalise object (%s)\n", *argv, errMsg); } } /* Segment the object. */ if(ok) { if(inObj->values.core == NULL) { segObj = WlzAssignObject(inObj, NULL); } else { segObj = WlzAssignObject( WlzThreshold(inObj, thrVal, thrMod, &errNum), NULL); if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to segment image (%s)\n", *argv, errMsg); } } } /* Compute object with the same domain as the input object but in which * the values are the minimum distance from an edge. */ if(ok) { WlzObject *bObj = NULL; bObj = WlzBoundaryDomain(inObj, &errNum); if(errNum == WLZ_ERR_NONE) { disObj = WlzAssignObject( WlzDistanceTransform(inObj, bObj, WLZ_OCTAGONAL_DISTANCE, 0.0, 0.0, &errNum), NULL); } if(errNum == WLZ_ERR_NONE) { disGVWSp = WlzGreyValueMakeWSp(disObj, &errNum); } if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to compute distance object (%s)\n", *argv, errMsg); } (void )WlzFreeObj(bObj); } /* Output the debug image if required. */ if(ok && dbgPath) { WlzObject *dbgObj; dbgObj = WlzAssignObject(WlzCopyObject(inObj, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { WlzPixelV iMin, iMax, oMin, oMax; if(dbgObj->values.core == NULL) { WlzValues tmpVal; oMax.type = WLZ_GREY_UBYTE; oMax.v.ubv = 255; tmpVal.v = WlzNewValueTb(dbgObj, WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_UBYTE, NULL), oMax, &errNum); if(errNum == WLZ_ERR_NONE) { dbgObj->values = WlzAssignValues(tmpVal, NULL); } } else { WlzObject *tmpObj = NULL; oMin.type = WLZ_GREY_UBYTE; oMin.v.ubv = 0; oMax.type = WLZ_GREY_UBYTE; oMax.v.ubv = 200; errNum = WlzGreyRange(dbgObj, &iMin, &iMax); if(errNum == WLZ_ERR_NONE) { errNum = WlzGreySetRange(dbgObj, iMin, iMax, oMin, oMax, 0); } if(errNum == WLZ_ERR_NONE) { tmpObj = WlzMakeMain(inObj->type, segObj->domain, dbgObj->values, NULL, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { oMax.v.ubv = 255; errNum = WlzGreySetValue(tmpObj, oMax); } (void )WlzFreeObj(tmpObj); if(errNum == WLZ_ERR_NONE) { tmpObj = WlzConvertPix(dbgObj, WLZ_GREY_UBYTE, &errNum); (void )WlzFreeObj(dbgObj); dbgObj = WlzAssignObject(tmpObj, NULL); } } } if(errNum == WLZ_ERR_NONE) { (void )WlzRadDistParsePath(dbgPath, &dbgDir, &dbgFile, &dbgExt, &dbgFmt); if(dbgExt) { (void )sprintf(pathBuf, "%s/%s.%s", dbgDir, dbgFile, dbgExt); } else { (void )sprintf(pathBuf, "%s/%s", dbgDir, dbgFile); } errNum = WlzEffWriteObj(NULL, pathBuf, dbgObj, dbgFmt); } (void )WlzFreeObj(dbgObj); if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to output the debug image (%s)\n", *argv, errMsg); } } /* Label the segmented object. */ if(ok) { errNum = WlzLabel(segObj, &nReg, ®Objs, maxObj, 0, WLZ_8_CONNECTED); if(errNum != WLZ_ERR_NONE) { ok = 0; errNum = WLZ_ERR_MEM_ALLOC; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to split into components (%s)\n", *argv, errMsg); } if(ok && verbose) { (void )fprintf(stderr, "nReg = %d\n", nReg); } } /* Compute centre of mass if not known. */ if(ok) { if(centreSet == 0) { centre = WlzCentreOfMass2D(inObj, 1, NULL, &errNum); if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to compute centre of mass (%s)\n", *argv, errMsg); } } if(ok && verbose) { (void )fprintf(stderr, "centre = %lg,%lg\n", centre.vtX, centre.vtY); } } /* Allocate a radial distribution table. */ if(ok) { if((distData = (WlzRadDistRec *) AlcCalloc(nReg, sizeof(WlzRadDistRec))) == NULL) { ok = 0; errNum = WLZ_ERR_MEM_ALLOC; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to allocate result lable (%s)\n", *argv, errMsg); } } /* Compute the redial distribution data. */ if(ok) { int idR = 0, idS = 0; while((errNum == WLZ_ERR_NONE) && (idR < nReg)) { double mass; WlzDVertex2 com; com = WlzCentreOfMass2D(regObjs[idR], 1, &mass, NULL); if(mass > minArea - eps) { WlzGreyValueGet(disGVWSp, 0.0, com.vtY, com.vtX); distData[idS].pos = com; distData[idS].area = mass; WLZ_VTX_2_SUB(com, centre, com); distData[idS].radius = WLZ_VTX_2_LENGTH(com); distData[idS].angle = ALG_M_PI + atan2(com.vtY, com.vtX); switch(disGVWSp->gType) { case WLZ_GREY_LONG: distData[idS].dist = *(disGVWSp->gPtr[0].lnp); break; case WLZ_GREY_INT: distData[idS].dist = *(disGVWSp->gPtr[0].inp); break; case WLZ_GREY_SHORT: distData[idS].dist = *(disGVWSp->gPtr[0].shp); break; case WLZ_GREY_UBYTE: distData[idS].dist = *(disGVWSp->gPtr[0].ubp); break; case WLZ_GREY_FLOAT: distData[idS].dist = *(disGVWSp->gPtr[0].flp); break; case WLZ_GREY_DOUBLE: distData[idS].dist = *(disGVWSp->gPtr[0].dbp); break; default: distData[idS].dist = 0.0; break; } ++idS; } ++idR; } tNReg = idS; switch(distSort) { case WLZ_RADDISTVAL_AREA: (void )qsort(distData, tNReg, sizeof(WlzRadDistRec), WlzRadDistRecSortArea); break; case WLZ_RADDISTVAL_ANGLE: (void )qsort(distData, tNReg, sizeof(WlzRadDistRec), WlzRadDistRecSortAngle); break; case WLZ_RADDISTVAL_RADIUS: (void )qsort(distData, tNReg, sizeof(WlzRadDistRec), WlzRadDistRecSortRadius); break; case WLZ_RADDISTVAL_DIST: (void )qsort(distData, tNReg, sizeof(WlzRadDistRec), WlzRadDistRecSortDist); break; } } /* Output the sorted radial distribution table. */ if(ok) { if(((fP = strcmp(outFile, "-")? fopen(outFile, "w"): stdout)) == NULL) { ok = 0; (void )fprintf(stderr, "%s: failed to open output file %s\n", *argv, outFile); } } if(ok) { int idR; for(idR = 0; idR < tNReg; ++idR) { double a; a = (distData[idR].angle > 0.0)? 0 + (180 * distData[idR].angle / ALG_M_PI): 360 + (180 * distData[idR].angle / ALG_M_PI); (void )fprintf(fP, "%g %g %g %g,%g %g\n", a, distData[idR].radius, distData[idR].area, distData[idR].pos.vtX, distData[idR].pos.vtY, distData[idR].dist); } } if(strcmp(outFile, "-")) { (void )fclose(fP); } /* Tidy up. */ AlcFree(distData); WlzGreyValueFreeWSp(disGVWSp); (void )WlzFreeObj(inObj); (void )WlzFreeObj(disObj); (void )WlzFreeObj(segObj); if(regObjs) { int idR; for(idR = 0; idR < nReg; ++idR) { (void )WlzFreeObj(regObjs[idR]); } AlcFree(regObjs); } if(usage) { (void )fprintf(stderr, "Usage: %s [-h] [-v] [-A] [-D] [-G] [-H] [-E] [-L] [-R]\n" "\t\t[-c #,#] [-d <debug image>] [-n #] [-o <out file>]\n" "\t\t[-t #] [<input image>]\n" "Segments the given object using a threshold value and outputs the \n" "radial distribution of the thresholded components.\n" "Version: %s\n" "Options:\n" " -h Help - prints this usage masseage.\n" " -v Verbose output.\n" " -A Sort output by area (default).\n" " -D Sort output by distance from boundary.\n" " -G Sort output by angle.\n" " -H Threshold high, use pixels at or above threshold (default).\n" " -E Threshold equal, use pixels at threshold.\n" " -L Threshold low, use pixels below threshold.\n" " -R Sort output by radial distance from centre.\n" " -c Centre (default is image centre).\n" " -d Debug image.\n" " -n Minimum area (default %g).\n" " -t Threshold value (default is to compute using Otsu's method).\n" "By default the input image object is read from the standard input and\n" "the radial distribution is written to the standard output.\n" "The image formats understood include wlz, jpg and tif.\n" "The output format is:\n" " <angle> <dist from centre> <area> <x pos>,<y pos> <dist form boundary>\n" "Example:\n" " %s -o out.txt -d debug.jpg in.tif\n" "The input image is read from in.tif, a debug image showing the\n" "segmented regions is written to debug.jpg and the radial distribution\n" "statistics are written to the file out.txt. With the output in\n" "out.txt, the following R code would plot the data as a set of circles\n" "with radius proportional to the square root of the component area:\n" " data <- read.table(\"out.txt\")\n" " attach(data)\n" " symbols(x=data$V1, y=data$V2, circles=sqrt(data$V3))\n", argv[0], WlzVersion(), minArea, argv[0]); } return(!ok); }
static WlzObject *WlzIndexToRGBA3D( WlzObject *obj, unsigned char colormap[3][256], 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 WlzIndexToRGBA. The domain and valuetable must be checked however */ obj1 = NULL; if( obj->domain.p == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if( obj->values.vox == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } /* 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]; } } /* convert 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 ){ if((obj1 = WlzIndexToRGBA(temp, colormap, &errNum)) != NULL){ if( obj1->type == WLZ_2D_DOMAINOBJ ){ *ndomains = WlzAssignDomain(obj1->domain, NULL); *nvalues = WlzAssignValues(obj1->values, NULL); } else { (*ndomains).core = NULL; (*nvalues).core = NULL; } WlzFreeObj(obj1); } } else { (*ndomains).core = NULL; (*nvalues).core = NULL; } } else { WlzFreePlaneDomain(npdom); WlzFreeVoxelValueTb( nvoxtab ); break; } domains++; ndomains++; values++; nvalues++; } /* 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 3D domain object with corresponding WLZ_GREY_RGBA values. * \ingroup WlzValuesUtils * \brief Creates a WLZ_GREY_RGBA valued object from the given compound * array. This is a static function which will always be called * with valid parameters so they aren't checked. * \param cObj Compound array object. * \param cSpc The colour space. * \param dstErr Destination error pointer may be NULL. */ static WlzObject *WlzCompoundToRGBA3D(WlzCompoundArray *cObj, WlzRGBAColorSpace cSpc, WlzErrorNum *dstErr) { WlzIBox3 bBox; WlzDomain dom; WlzValues val; WlzPixelV bgd; WlzObject *rObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; dom.core = NULL; val.core = NULL; bgd.v.rgbv = 0; bgd.type = WLZ_GREY_RGBA; bBox = WlzBoundingBox3I((WlzObject *)cObj, &errNum); if(errNum == WLZ_ERR_NONE) { dom.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, bBox.zMin, bBox.zMax, bBox.yMin, bBox.yMax, bBox.xMin, bBox.xMax, &errNum); } if(errNum == WLZ_ERR_NONE) { val.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, bBox.zMin, bBox.zMax, bgd, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { rObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, dom, val, NULL, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { int idP, nPl; nPl = bBox.zMax - bBox.zMin + 1; for(idP = 0; idP < nPl; ++idP) { if(errNum == WLZ_ERR_NONE) { int idC; WlzObject *rObj2 = NULL; WlzCompoundArray *cObj2 = NULL; WlzErrorNum errNum2 = WLZ_ERR_NONE; cObj2 = WlzMakeCompoundArray(WLZ_COMPOUND_ARR_2, 1, cObj->n, NULL, WLZ_2D_DOMAINOBJ, &errNum2); idC = 0; while((errNum2 == WLZ_ERR_NONE) && (idC < cObj->n)) { int idP2, nPl2; WlzDomain dom2; WlzValues val2; dom2.core = NULL; val2.core = NULL; if((cObj->o[idC] != NULL) && (cObj->o[idC]->type == WLZ_3D_DOMAINOBJ)) { idP2 = bBox.zMin + idP - cObj->o[idC]->domain.p->plane1; nPl2 = cObj->o[idC]->domain.p->lastpl - cObj->o[idC]->domain.p->plane1 + 1; if((idP2 >= 0) && (idP2 <= nPl2)) { dom2 = *(cObj->o[idC]->domain.p->domains + idP2); val2 = *(cObj->o[idC]->values.vox->values + idP2); } } cObj2->o[idC] = (dom2.core == NULL)? WlzMakeEmpty(&errNum2): WlzMakeMain(WLZ_2D_DOMAINOBJ, dom2, val2, NULL, NULL, &errNum2); ++idC; } if(errNum2 == WLZ_ERR_NONE) { rObj2 = WlzCompoundToRGBA2D(cObj2, cSpc, &errNum2); } if(errNum2 == WLZ_ERR_NONE) { dom.p->domains[idP] = WlzAssignDomain(rObj2->domain, NULL); val.vox->values[idP] = WlzAssignValues(rObj2->values, NULL); } (void )WlzFreeObj(rObj2); (void )WlzFreeObj((WlzObject *)cObj2); if(errNum2 != WLZ_ERR_NONE) { errNum = errNum2; } } } } if(errNum != WLZ_ERR_NONE) { if(rObj != NULL) { (void )WlzFreeObj(rObj); rObj = NULL; } else { (void )WlzFreePlaneDomain(dom.p); (void )WlzFreeVoxelValueTb(val.vox); } } if(dstErr) { *dstErr = errNum; } return(rObj); }
/*! * \return New 3D domain object with corresponding WLZ_GREY_RGBA values. * \ingroup WlzValuesUtils * \brief Creates a WLZ_GREY_RGBA valued object from the given compound * array. This is a static function which will always be called * with valid parameters so they aren't checked. * \param cObj Compound array object. * \param cSpc The colour space. * \param dstErr Destination error pointer may be NULL. */ static WlzObject *WlzCompoundToRGBA2D(WlzCompoundArray *cObj, WlzRGBAColorSpace cSpc, WlzErrorNum *dstErr) { int i, j; WlzObject *rtnObj=NULL; WlzPixelV bckgrnd; WlzObject *objs[4]; WlzObjectType vType; WlzUInt b[4]; WlzErrorNum errNum=WLZ_ERR_NONE; /* Make a copy of the object pointers because WlzUnionN() modifies the * array if it contains empty objects. */ for(i = 0; i < 3; ++i) { objs[i] = cObj->o[i]; } rtnObj = WlzUnionN(3, objs, 0, &errNum); if(errNum == WLZ_ERR_NONE) { /* Add an RGBA valuetable, extract background for each channel */ vType = WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_RGBA, &errNum); for(i=0; (errNum == WLZ_ERR_NONE) && (i < 3); i++) { bckgrnd = WlzGetBackground(cObj->o[i], &errNum); if(errNum == WLZ_ERR_NONE) { errNum = WlzValueConvertPixel(&bckgrnd, bckgrnd, WLZ_GREY_UBYTE); b[i] = bckgrnd.v.ubv; } } } if(errNum == WLZ_ERR_NONE) { WlzValues values; bckgrnd.type = WLZ_GREY_RGBA; WLZ_RGBA_RGBA_SET(bckgrnd.v.rgbv, b[0], b[1], b[2], 255); values.v = WlzNewValueTb(rtnObj, vType, bckgrnd, &errNum); if(values.v != NULL) { rtnObj->values = WlzAssignValues(values, &errNum); } else { (void )WlzFreeObj(rtnObj); rtnObj = NULL; } } /* Transfer values */ if( errNum == WLZ_ERR_NONE) { WlzGreyValueWSpace *gValWSpc[4]; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyV gval; /* do it dumb fashion for now, rgb only */ gValWSpc[0] = gValWSpc[1] = gValWSpc[2] = gValWSpc[3] = NULL; for(i=0; i < 3; i++) { if((cObj->o[i] != NULL) && (cObj->o[i]->type != WLZ_EMPTY_OBJ)) { gValWSpc[i] = WlzGreyValueMakeWSp(cObj->o[i], &errNum); if(errNum != WLZ_ERR_NONE) { break; } } } if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(rtnObj, &iwsp, &gwsp); } while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE)) { WlzPixelV pix; for(j = iwsp.lftpos; j <= iwsp.rgtpos; j++) { for(i = 0; i < 3; i++) { if(gValWSpc[i] == NULL) { pix.v.ubv = (i < 2)? 0: 255; } else { WlzGreyValueGet(gValWSpc[i], 0, iwsp.linpos, j); pix.type = gValWSpc[i]->gType; pix.v = gValWSpc[i]->gVal[0]; WlzValueConvertPixel(&pix, pix, WLZ_GREY_UBYTE); } b[i] = pix.v.ubv; } WLZ_RGBA_RGBA_SET(gval.rgbv, b[0], b[1], b[2], b[3]); *gwsp.u_grintptr.rgbp = gval.rgbv; gwsp.u_grintptr.rgbp++; } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } for(i=0; i < 3; i++) { WlzGreyValueFreeWSp(gValWSpc[i]); } } if(dstErr != NULL) { *dstErr = errNum; } return(rtnObj); }
static WlzObject *WlzGreyMask3d( WlzObject *obj, WlzObject *mask, WlzPixelV maskVal, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzObject *tmpMask, *obj1, *obj2; WlzDomain *domains; WlzValues values, *valuess, *newvaluess; 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; } break; case WLZ_EMPTY_DOMAIN: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } } /* check the mask */ if( errNum == WLZ_ERR_NONE ){ if( mask == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { /* set some local variables */ pdom = obj->domain.p; domains = obj->domain.p->domains; valuess = obj->values.vox->values; /* create a new voxel object, initially no values */ values.vox = WlzMakeVoxelValueTb(obj->values.vox->type, obj->values.vox->plane1, obj->values.vox->lastpl, obj->values.vox->bckgrnd, obj, NULL); rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, obj->domain, values, NULL, NULL, NULL); newvaluess = rtnObj->values.vox->values; /* switch on mask type - a 2D mask is applied to each plane */ switch( mask->type ){ case WLZ_2D_DOMAINOBJ: case WLZ_2D_POLYGON: case WLZ_BOUNDLIST: case WLZ_EMPTY_OBJ: for(p=pdom->plane1; p <= pdom->lastpl; p++, domains++, valuess++){ if( (*domains).core ){ obj1 = WlzAssignObject( WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains, *valuess, NULL, NULL, NULL), NULL); if((obj2 = WlzGreyMask(obj1, mask, maskVal, &errNum)) != NULL){ newvaluess[p - pdom->plane1] = WlzAssignValues(obj->values, NULL); WlzFreeObj(obj2); } WlzFreeObj(obj1); } } break; case WLZ_3D_DOMAINOBJ: /* switch on plane domain type - polygon and boundlist are legal but need transforming first. */ switch( obj->domain.p->type ){ WlzDomain *maskDoms; case WLZ_PLANEDOMAIN_DOMAIN: maskDoms = mask->domain.p->domains; for(p=pdom->plane1; p <= pdom->lastpl; p++, domains++, valuess++){ if(((*domains).core)){ if((p >= mask->domain.p->plane1) && (p <= mask->domain.p->lastpl) && (maskDoms[p - mask->domain.p->plane1].core) ){ values.core = NULL; tmpMask = WlzMakeMain(WLZ_2D_DOMAINOBJ, maskDoms[p - mask->domain.p->plane1], values, NULL, NULL, NULL); } else { tmpMask = WlzMakeEmpty(NULL); } obj1 = WlzAssignObject( WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains, *valuess, NULL, NULL, NULL), NULL); if((obj2 = WlzGreyMask(obj1, tmpMask, maskVal, &errNum)) != NULL){ newvaluess[p - pdom->plane1] = WlzAssignValues(obj2->values, NULL); WlzFreeObj(obj2); } WlzFreeObj(obj1); WlzFreeObj(tmpMask); } } break; case WLZ_PLANEDOMAIN_POLYGON: maskDoms = mask->domain.p->domains; for(p=pdom->plane1; p <= pdom->lastpl; p++, domains++, valuess++){ if(((*domains).core)){ if((p >= mask->domain.p->plane1) && (p <= mask->domain.p->lastpl) && (maskDoms[p - mask->domain.p->plane1].core) ){ values.core = NULL; tmpMask = WlzMakeMain(WLZ_2D_POLYGON, maskDoms[p - mask->domain.p->plane1], values, NULL, NULL, NULL); } else { tmpMask = WlzMakeEmpty(NULL); } obj1 = WlzAssignObject( WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains, *valuess, NULL, NULL, NULL), NULL); if((obj2 = WlzGreyMask(obj1, tmpMask, maskVal, &errNum)) != NULL){ newvaluess[p - pdom->plane1] = WlzAssignValues(obj2->values, NULL); WlzFreeObj(obj2); } WlzFreeObj(obj1); WlzFreeObj(tmpMask); } } break; case WLZ_PLANEDOMAIN_BOUNDLIST: maskDoms = mask->domain.p->domains; for(p=pdom->plane1; p <= pdom->lastpl; p++, domains++, valuess++){ if(((*domains).core)){ if((p >= mask->domain.p->plane1) && (p <= mask->domain.p->lastpl) && (maskDoms[p - mask->domain.p->plane1].core) ){ values.core = NULL; tmpMask = WlzMakeMain(WLZ_BOUNDLIST, maskDoms[p - mask->domain.p->plane1], values, NULL, NULL, NULL); } else { tmpMask = WlzMakeEmpty(NULL); } obj1 = WlzAssignObject( WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains, *valuess, NULL, NULL, NULL), NULL); if((obj2 = WlzGreyMask(obj1, tmpMask, maskVal, &errNum)) != NULL){ newvaluess[p - pdom->plane1] = WlzAssignValues(obj2->values, NULL); WlzFreeObj(obj2); } WlzFreeObj(obj1); WlzFreeObj(tmpMask); } } break; default: errNum = WLZ_ERR_DOMAIN_TYPE; WlzFreeObj(rtnObj); rtnObj = NULL; break; } break; default: errNum = WLZ_ERR_OBJECT_NULL; WlzFreeObj(rtnObj); rtnObj = NULL; break; } } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \ingroup WlzValuesUtils * \brief Set the value maskVal within the domain given by the * mask object. The mask object can be a 2D, 3D, polygon * or boundary object. A 3D mask with a 2D object is an * error. A 2D mask with a 3D object will be applied to * each plane in turn. * * \return New object with the same domain as the input object but with values in the intersection with the mask domain set to the mask value. NULL on error. * \param obj Input object * \param mask Mask object. * \param maskVal mask value. * \param dstErr Error return. * \par Source: * WlzGreyMask.c */ WlzObject *WlzGreyMask( WlzObject *obj, WlzObject *mask, WlzPixelV maskVal, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzObject *tmpMask, *obj1; WlzValues values; WlzPixelV tmpMaskval; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyP gptr; int i; 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; } break; case WLZ_3D_DOMAINOBJ: return WlzGreyMask3d(obj, mask, maskVal, dstErr); case WLZ_TRANS_OBJ: if((values.obj = WlzGreyMask(obj->values.obj, mask, maskVal, &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 mask */ if( errNum == WLZ_ERR_NONE ){ if( mask == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { values.core = NULL; switch( mask->type ){ case WLZ_2D_DOMAINOBJ: tmpMask = WlzMakeMain(WLZ_2D_DOMAINOBJ, mask->domain, values, NULL, NULL, &errNum); break; case WLZ_TRANS_OBJ: tmpMask = WlzMakeMain(WLZ_2D_DOMAINOBJ, mask->values.obj->domain, values, NULL, NULL, &errNum); break; case WLZ_EMPTY_OBJ: return WlzMakeMain(WLZ_2D_DOMAINOBJ, obj->domain, obj->values, NULL, NULL, dstErr); case WLZ_2D_POLYGON: tmpMask = WlzPolyToObj(mask->domain.poly, WLZ_SIMPLE_FILL, &errNum); break; case WLZ_BOUNDLIST: tmpMask = WlzBoundToObj(mask->domain.b, WLZ_SIMPLE_FILL, &errNum); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } if( errNum == WLZ_ERR_NONE ){ tmpMask = WlzAssignObject(tmpMask, NULL); } } } /* copy input obj and setvalues in the intersection */ if(errNum == WLZ_ERR_NONE){ if((rtnObj = WlzNewGrey(obj, &errNum)) != NULL){ if((obj1 = WlzIntersect2(obj, tmpMask, &errNum)) != NULL){ obj1->values = WlzAssignValues(rtnObj->values, NULL); errNum = WlzInitGreyScan(obj1, &iwsp, &gwsp); WlzValueConvertPixel(&tmpMaskval, maskVal, gwsp.pixeltype); 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++){ *gptr.inp = tmpMaskval.v.inv; } break; case WLZ_GREY_SHORT: for(i=0; i<iwsp.colrmn; i++, gptr.shp++){ *gptr.shp = tmpMaskval.v.shv; } break; case WLZ_GREY_UBYTE: for(i=0; i<iwsp.colrmn; i++, gptr.ubp++){ *gptr.ubp = tmpMaskval.v.ubv; } break; case WLZ_GREY_FLOAT: for(i=0; i<iwsp.colrmn; i++, gptr.flp++){ *gptr.flp = tmpMaskval.v.flv; } break; case WLZ_GREY_DOUBLE: for(i=0; i<iwsp.colrmn; i++, gptr.dbp++){ *gptr.dbp = tmpMaskval.v.dbv; } break; case WLZ_GREY_RGBA: for(i=0; i<iwsp.colrmn; i++, gptr.rgbp++){ *gptr.rgbp = tmpMaskval.v.rgbv; } break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzFreeObj(obj1); } else { WlzFreeObj(rtnObj); rtnObj = NULL; } } WlzFreeObj(tmpMask); } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \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; }
/*! * \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); }
/*! * \return Object with transformed grey-values. * \ingroup WlzArithmetic * \brief Apply a binary operation (add subtract etc) to * each pixel value in the given object. The operand value * is in <tt>pval</tt>. * \param o1 Input object * \param pval Pixel value for binary operation. * \param op Opertor * \param dstErr Error return. * \par Source: * WlzScalarArithmeticOp.c */ WlzObject *WlzScalarBinaryOp2( WlzObject *o1, WlzPixelV pval, WlzBinaryOperatorType op, WlzErrorNum *dstErr) { WlzObject *obj=NULL, *tmp3; WlzErrorNum errNum=WLZ_ERR_NONE; WlzValues values; WlzPixelV old_bckgrnd, new_bckgrnd; WlzGreyType new_grey_type; int p; /* check object pointers */ if( (o1 == NULL) ){ errNum = WLZ_ERR_OBJECT_NULL; } /* check object types - WLZ_EMPTY_OBJ is legal */ if( errNum == WLZ_ERR_NONE ){ switch( o1->type ){ case WLZ_2D_DOMAINOBJ: /* FALLTHROUGH */ case WLZ_3D_DOMAINOBJ: /* FALLTHROUGH */ case WLZ_TRANS_OBJ: break; case WLZ_EMPTY_OBJ: obj = WlzMakeEmpty(&errNum); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* check domains and valuetables */ if( (errNum == WLZ_ERR_NONE) && (obj == NULL) ){ switch( o1->type ){ case WLZ_2D_DOMAINOBJ: if( (o1->domain.core == NULL) ){ errNum = WLZ_ERR_DOMAIN_NULL; break; } if( (o1->values.core == NULL) ){ errNum = WLZ_ERR_VALUES_NULL; break; } break; case WLZ_3D_DOMAINOBJ: if( (o1->domain.core == NULL) ){ errNum = WLZ_ERR_DOMAIN_NULL; break; } if( (o1->domain.p->type != WLZ_PLANEDOMAIN_DOMAIN) ){ errNum = WLZ_ERR_PLANEDOMAIN_TYPE; break; } if( (o1->values.core == NULL) ){ errNum = WLZ_ERR_VALUES_NULL; break; } if( (o1->values.vox->type != WLZ_VOXELVALUETABLE_GREY) ){ errNum = WLZ_ERR_VOXELVALUES_TYPE; break; } break; case WLZ_TRANS_OBJ: if( (o1->domain.core == NULL) ){ errNum = WLZ_ERR_DOMAIN_NULL; break; } if( (o1->values.core == NULL) ){ errNum = WLZ_ERR_VALUES_NULL; break; } if((values.obj = WlzScalarBinaryOp2(o1->values.obj, pval, op, &errNum)) != NULL){ obj = WlzMakeMain(WLZ_TRANS_OBJ, o1->domain, values, NULL, NULL, &errNum); break; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* set up temporary object */ if((errNum == WLZ_ERR_NONE) && (obj == NULL)){ switch( o1->type ){ case WLZ_2D_DOMAINOBJ: values.core = NULL; if( (tmp3 = WlzMakeMain(WLZ_2D_DOMAINOBJ, o1->domain, values, NULL, NULL, &errNum)) == NULL ){ break; } old_bckgrnd = WlzGetBackground(o1, NULL); switch( WlzGreyTableTypeToGreyType(o1->values.core->type, NULL) ){ case WLZ_GREY_INT: /* FALLTHROUGH */ case WLZ_GREY_SHORT: /* FALLTHROUGH */ case WLZ_GREY_FLOAT: /* FALLTHROUGH */ case WLZ_GREY_DOUBLE: new_grey_type = WlzGreyTableTypeToGreyType(o1->values.core->type, NULL); new_bckgrnd = old_bckgrnd; break; case WLZ_GREY_UBYTE: new_grey_type = WLZ_GREY_SHORT; new_bckgrnd.type = WLZ_GREY_SHORT; new_bckgrnd.v.shv = old_bckgrnd.v.ubv; break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } if(errNum == WLZ_ERR_NONE){ values.v = WlzNewValueTb(tmp3, WlzGreyTableType(WLZ_GREY_TAB_RAGR, new_grey_type, NULL), new_bckgrnd, &errNum); tmp3->values = WlzAssignValues( values, NULL ); } break; case WLZ_3D_DOMAINOBJ: values.core = NULL; if((tmp3 = WlzMakeMain(WLZ_3D_DOMAINOBJ, o1->domain, values, NULL, NULL, &errNum)) == NULL){ break; } /* now a new destination voxeltable */ old_bckgrnd = WlzGetBackground(o1, NULL); switch( old_bckgrnd.type ){ case WLZ_GREY_INT: /* FALLTHROUGH */ case WLZ_GREY_SHORT: /* FALLTHROUGH */ case WLZ_GREY_FLOAT: /* FALLTHROUGH */ case WLZ_GREY_DOUBLE: new_grey_type = old_bckgrnd.type; new_bckgrnd = old_bckgrnd; break; case WLZ_GREY_UBYTE: new_grey_type = WLZ_GREY_SHORT; new_bckgrnd.type = WLZ_GREY_SHORT; new_bckgrnd.v.shv = old_bckgrnd.v.ubv; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } if(errNum == WLZ_ERR_NONE){ values.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, tmp3->domain.p->plane1, tmp3->domain.p->lastpl, new_bckgrnd, NULL, &errNum); if( values.vox == NULL ){break;} for(p=tmp3->domain.p->plane1; p <= tmp3->domain.p->lastpl; p++){ WlzValues values2d; /* currently test for NULL domain to imply WLZ_EMPTY_DOMAIN */ if( tmp3->domain.p->domains[p-tmp3->domain.p->plane1].core == NULL ){ values2d.core = NULL; } else { WlzObject *tmp2d; values2d.core = NULL; if((tmp2d = WlzMakeMain(WLZ_2D_DOMAINOBJ, tmp3->domain.p->domains[p-tmp3->domain.p->plane1], values2d, NULL, NULL, &errNum)) != NULL){ values2d.v = WlzNewValueTb( tmp2d, WlzGreyTableType(WLZ_GREY_TAB_RAGR, new_grey_type, NULL), new_bckgrnd, &errNum); WlzFreeObj( tmp2d ); } } values.vox->values[p-tmp3->domain.p->plane1] = WlzAssignValues(values2d, NULL); } tmp3->values = WlzAssignValues(values, NULL); } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* apply operation and free space */ if((errNum == WLZ_ERR_NONE) && (obj == NULL)){ if((errNum = WlzScalarBinaryOp(o1, pval, tmp3, op)) != WLZ_ERR_NONE){ WlzFreeObj( tmp3 ); } else { obj = tmp3; } } if( dstErr ){ *dstErr = errNum; } return obj; }
void warpSetSignalDomain( WlzIVertex2 *selVtx) { WlzErrorNum errNum=WLZ_ERR_NONE; WlzPixelV threshV, threshV1; WlzObject *obj, *obj1; WlzUInt combineMode; /* image processing sequence */ if( warpGlobals.sgnlThreshObj == NULL ){ warpSetSignalThreshObj(); } if( warpGlobals.sgnlThreshObj ){ obj1 = WlzAssignObject(warpGlobals.sgnlThreshObj, &errNum); } else { return; } /* threshold the resultant image */ if( errNum == WLZ_ERR_NONE ){ switch( warpGlobals.thresholdType ){ case WLZ_RGBA_THRESH_NONE: break; case WLZ_RGBA_THRESH_SINGLE: threshV.type = WLZ_GREY_INT; threshV.v.inv = warpGlobals.threshRangeLow; if( obj1 ){ /* clear signal object */ if( warpGlobals.sgnlObj ){ WlzFreeObj(warpGlobals.sgnlObj); } if((obj = WlzThreshold(obj1, threshV, WLZ_THRESH_HIGH, &errNum)) && (WlzVolume(obj, &errNum) > 0)){ obj = WlzAssignObject(obj, &errNum); WlzFreeObj(obj1); threshV.v.inv = warpGlobals.threshRangeHigh + 1; if((obj1 = WlzThreshold(obj, threshV, WLZ_THRESH_LOW, &errNum)) && (WlzVolume(obj1, &errNum) > 0)){ warpGlobals.sgnlObj = WlzAssignObject(obj1, &errNum); } else { if( obj1 ){ WlzFreeObj(obj1); } warpGlobals.sgnlObj = NULL; } WlzFreeObj(obj); } else { if( obj ) { WlzFreeObj(obj); } WlzFreeObj(obj1); warpGlobals.sgnlObj = NULL; } } break; case WLZ_RGBA_THRESH_MULTI: /* clear signal object */ if( warpGlobals.sgnlObj ){ WlzFreeObj(warpGlobals.sgnlObj); } /* set the thresholds and combine mode */ threshV.type = WLZ_GREY_RGBA; WLZ_RGBA_RGBA_SET(threshV.v.rgbv, warpGlobals.threshRangeRGBLow[0], warpGlobals.threshRangeRGBLow[1], warpGlobals.threshRangeRGBLow[2], 255); threshV1.type = WLZ_GREY_RGBA; WLZ_RGBA_RGBA_SET(threshV1.v.rgbv, warpGlobals.threshRangeRGBHigh[0], warpGlobals.threshRangeRGBHigh[1], warpGlobals.threshRangeRGBHigh[2], 255); WLZ_RGBA_RGBA_SET(combineMode, WLZ_BO_AND, WLZ_BO_AND, WLZ_BO_AND, 255); /* use multi-threshold */ if((obj = WlzRGBAMultiThreshold(obj1, threshV, threshV1, combineMode, &errNum))){ if( WlzIsEmpty(obj, &errNum) ){ WlzFreeObj(obj); warpGlobals.sgnlObj = NULL; } else { warpGlobals.sgnlObj = WlzAssignObject(obj, &errNum); } } else { warpGlobals.sgnlObj = NULL; } WlzFreeObj(obj1); break; case WLZ_RGBA_THRESH_BOX: /* clear signal object */ if( warpGlobals.sgnlObj ){ WlzFreeObj(warpGlobals.sgnlObj); } /* use box-threshold */ if((obj = WlzRGBABoxThreshold(obj1, warpGlobals.lowRGBPoint, warpGlobals.highRGBPoint, &errNum))){ if( WlzIsEmpty(obj, &errNum) ){ WlzFreeObj(obj); warpGlobals.sgnlObj = NULL; } else { warpGlobals.sgnlObj = WlzAssignObject(obj, &errNum); } } else { warpGlobals.sgnlObj = NULL; } WlzFreeObj(obj1); break; case WLZ_RGBA_THRESH_SLICE: /* clear signal object */ if( warpGlobals.sgnlObj ){ WlzFreeObj(warpGlobals.sgnlObj); } /* use slice-threshold */ if((obj = WlzRGBASliceThreshold(obj1, warpGlobals.lowRGBPoint, warpGlobals.highRGBPoint, &errNum))){ if( WlzIsEmpty(obj, &errNum) ){ WlzFreeObj(obj); warpGlobals.sgnlObj = NULL; } else { warpGlobals.sgnlObj = WlzAssignObject(obj, &errNum); } } else { warpGlobals.sgnlObj = NULL; } WlzFreeObj(obj1); break; case WLZ_RGBA_THRESH_SPHERE: /* clear signal object */ if( warpGlobals.sgnlObj ){ WlzFreeObj(warpGlobals.sgnlObj); } /* use Ellipsoid-threshold */ if((obj = WlzRGBAEllipsoidThreshold(obj1, warpGlobals.lowRGBPoint, warpGlobals.highRGBPoint, warpGlobals.colorEllipseEcc, &errNum))){ if( WlzIsEmpty(obj, &errNum) ){ WlzFreeObj(obj); warpGlobals.sgnlObj = NULL; } else { warpGlobals.sgnlObj = WlzAssignObject(obj, &errNum); } } else { warpGlobals.sgnlObj = NULL; } WlzFreeObj(obj1); break; default: errNum = WLZ_ERR_PARAM_DATA; if( obj1 ){ WlzFreeObj(obj1); } if( warpGlobals.sgnlObj ){ WlzFreeObj(warpGlobals.sgnlObj); warpGlobals.sgnlObj = NULL; } break; } } /* check for local mode */ if( warpGlobals.sgnlObj && !warpGlobals.globalThreshFlg ){ if( selVtx != NULL ){ warpGlobals.globalThreshVtx = *selVtx; } /* extract a local domain if the vertex is sensible */ if( warpGlobals.globalThreshVtx.vtX != -10000 ){ WlzObject **objs=NULL; int i, numObjs; double x, y; obj1 = NULL; x = warpGlobals.globalThreshVtx.vtX; y = warpGlobals.globalThreshVtx.vtY; errNum = WlzLabel(warpGlobals.sgnlObj, &numObjs, &objs, 8192, 0, WLZ_4_CONNECTED); if( (errNum == WLZ_ERR_INT_DATA) && (numObjs == 8192) ){ WlzObject *tmpObj1, *tmpObj2; WlzDomain domain; WlzValues values; /* try again, smaller domain */ for(i=0; i < numObjs; i++){ WlzFreeObj( objs[i] ); } AlcFree((void *) objs); objs = NULL; numObjs = 0; domain.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_RECT, y - 80, y + 80, x - 80, x + 80, &errNum); values.core = NULL; if((tmpObj1 = WlzMakeMain(warpGlobals.sgnlObj->type, domain, values, NULL, NULL, &errNum))){ if((tmpObj2 = WlzIntersect2(warpGlobals.sgnlObj, tmpObj1, &errNum))){ tmpObj2->values = WlzAssignValues(warpGlobals.sgnlObj->values, NULL); errNum = WlzLabel(warpGlobals.sgnlObj, &numObjs, &objs, 8192, 0, WLZ_4_CONNECTED); WlzFreeObj(tmpObj2); if((errNum == WLZ_ERR_INT_DATA) && (numObjs == 8192) ){ errNum = WLZ_ERR_NONE; } } WlzFreeObj(tmpObj1); } } if( errNum == WLZ_ERR_NONE ){ for(i=0; i < numObjs; i++){ if( WlzInsideDomain( objs[i], 0.0, y, x, NULL ) ){ obj1 = WlzMakeMain(objs[i]->type, objs[i]->domain, objs[i]->values, NULL, NULL, NULL); obj1 = WlzAssignObject(obj1, NULL); } WlzFreeObj( objs[i] ); } AlcFree((void *) objs); } if( obj1 ){ WlzFreeObj(warpGlobals.sgnlObj); warpGlobals.sgnlObj = obj1; } } else { WlzFreeObj(warpGlobals.sgnlObj); warpGlobals.sgnlObj = NULL; } } /* check for increment mode */ if( warpGlobals.incrThreshFlg && sgnlIncrObj() ){ if( warpGlobals.sgnlObj ){ if((obj1 = WlzUnion2(warpGlobals.sgnlObj, sgnlIncrObj(), &errNum))){ WlzFreeObj(warpGlobals.sgnlObj); warpGlobals.sgnlObj = WlzAssignObject(obj1, &errNum); } } else { warpGlobals.sgnlObj = WlzAssignObject(sgnlIncrObj(), &errNum); } } if( errNum != WLZ_ERR_NONE ){ MAPaintReportWlzError(globals.topl, "warpSetSignalDomain", errNum); } return; }
/*! * \return New woolz object or NULL on error. * \ingroup WlzArithmetic * \brief Scales the values of the given 3D Woolz object so that * \f$v_{new} = m v_{given} + a.\f$ The input object is known * to be a valid 3D domain object with grey values. * \param iObj Given object. * \param m Value to multiply object values by. * \param a Value to add to product. * \param rGType Required grey type for returned object. * \param dstErr Destination error pointer, may be NULL. */ static WlzObject *WlzScalarMulAdd3D(WlzObject *iObj, WlzPixelV m, WlzPixelV a, WlzGreyType rGType, WlzErrorNum *dstErr) { WlzValues rValues; WlzObjectType rVType; WlzPixelV bgdV; WlzObject *rObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; rValues.core = NULL; bgdV = WlzGetBackground(iObj, &errNum); if(errNum == WLZ_ERR_NONE) { rVType = WlzGreyTableType(WLZ_GREY_TAB_RAGR, rGType, &errNum); } if(errNum == WLZ_ERR_NONE) { rValues.vox = WlzNewValuesVox(iObj, rVType, bgdV, &errNum); } if(errNum == WLZ_ERR_NONE) { int idP, plMin, plMax; WlzPlaneDomain *iPDom; WlzVoxelValues *iVox, *rVox; iPDom = iObj->domain.p; iVox = iObj->values.vox; rVox = rValues.vox; plMin = iPDom->plane1; plMax = iPDom->lastpl; #ifdef _OPENMP #pragma omp parallel for #endif for(idP = plMin; idP <= plMax; ++idP) { WlzErrorNum errNum2D = WLZ_ERR_NONE; if(errNum == WLZ_ERR_NONE) { int idO; WlzDomain *iDom2D; WlzValues *iVal2D, *rVal2D; idO = idP - iPDom->plane1; iDom2D = iPDom->domains + idO; iVal2D = iVox->values + idO; rVal2D = rVox->values + idO; if(((*iDom2D).core != NULL) && ((*iVal2D).core != NULL) && ((*rVal2D).core != NULL)) { WlzObject *iObj2D = NULL, *rObj2D = NULL; if((iObj2D = WlzMakeMain(WLZ_2D_DOMAINOBJ, *iDom2D, *iVal2D, NULL, NULL, &errNum2D)) != NULL) { rObj2D = WlzScalarMulAdd2D(iObj2D, m, a, rGType, &errNum2D); } if(errNum2D == WLZ_ERR_NONE) { *rVal2D = WlzAssignValues(rObj2D->values, NULL); } (void )WlzFreeObj(iObj2D); (void )WlzFreeObj(rObj2D); } } if(errNum2D != WLZ_ERR_NONE) { #ifdef _OPENMP #pragma omp critical { #endif if(errNum == WLZ_ERR_NONE) { errNum = errNum2D; } #ifdef _OPENMP } #endif } } } if(errNum == WLZ_ERR_NONE) { rObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, iObj->domain, rValues, iObj->plist, iObj->assoc, &errNum); } if(errNum != WLZ_ERR_NONE) { if(rObj == NULL) { (void )WlzFreeVoxelValueTb(rValues.vox); } else { (void )WlzFreeObj(rObj); rObj = NULL; } } if(dstErr != NULL) { *dstErr = errNum; } return(rObj); }
void referenceFileListCb( Widget w, XtPointer client_data, XtPointer call_data) { HGU_XmFileListCallbackStruct *cbs= (HGU_XmFileListCallbackStruct *) client_data; WlzObject *obj; Widget cascade; WlzErrorNum errNum=WLZ_ERR_NONE; HGU_XmSetHourGlassCursor(globals.topl); if( cbs == NULL ){ /* clear list selection */ HGU_XmFileListClearList(globals.fileList); HGU_XmFileListWriteResourceFile(globals.fileList, globals.resourceFile); if((cascade = XtNameToWidget(globals.topl, "*file_menu*_pulldown*Recent"))){ HGU_XmFileListResetMenu(globals.fileList, cascade, referenceFileListCb); } } else if((obj = HGU_XmFileListReadObject(w, cbs, &errNum))){ WlzDomain domain; WlzValues values; WlzObject *newObj; switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, 0, 0, obj->domain.i->line1, obj->domain.i->lastln, obj->domain.i->kol1, obj->domain.i->lastkl, &errNum))){ domain.p->domains[0] = WlzAssignDomain(obj->domain, NULL); if((values.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, 0, 0, WlzGetBackground(obj, NULL), NULL, &errNum))){ values.vox->values[0] = WlzAssignValues(obj->values, NULL); newObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, NULL); WlzFreeObj(obj); obj = newObj; } } globals.origObjType = WLZ_2D_DOMAINOBJ; break; case WLZ_3D_DOMAINOBJ: globals.origObjType = WLZ_3D_DOMAINOBJ; break; default: HGU_XmUserError(globals.topl, "Read Reference Object:\n" " The reference object must be a 2- or 3-D\n" " grey-level image. Please select an alternate\n" " object", XmDIALOG_FULL_APPLICATION_MODAL); WlzFreeObj( obj ); /* set hour glass cursor */ HGU_XmUnsetHourGlassCursor(globals.topl); return; } MAPaintLogData("ReferenceFile", refFileList[0], 0, NULL); install_paint_reference_object( obj ); /* set the title of the top-level window */ set_topl_title(cbs->file); globals.file = AlcStrDup(cbs->file); globals.origObjExtType = cbs->format; /* add to the file list and write file */ HGU_XmFileListAddFile(globals.fileList, cbs->file, cbs->format); HGU_XmFileListWriteResourceFile(globals.fileList, globals.resourceFile); if((cascade = XtNameToWidget(globals.topl, "*file_menu*_pulldown*Recent"))){ HGU_XmFileListResetMenu(globals.fileList, cascade, referenceFileListCb); } } HGU_XmUnsetHourGlassCursor(globals.topl); if( errNum != WLZ_ERR_NONE ){ MAPaintReportWlzError(globals.topl, "ReferenceFileListCb", errNum); } return; }
static WlzObject *WlzSelect1InN( WlzObject *obj, int first_pl, int last_pl, int step, WlzErrorNum *dstErr) { WlzObject *nobj=NULL; int p, new_p, new_plane1, new_lastpl; WlzDomain domain; WlzValues values; WlzErrorNum errNum=WLZ_ERR_NONE; /* check the object */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } if( errNum == WLZ_ERR_NONE ){ domain.core = NULL; values.core = NULL; switch( obj->type ){ case WLZ_3D_DOMAINOBJ: if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; break; } if( obj->domain.core->type == WLZ_EMPTY_DOMAIN ){ return WlzMakeEmpty(dstErr); } break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* check the parameters */ if( errNum == WLZ_ERR_NONE ){ if( first_pl > last_pl ){ errNum = WLZ_ERR_PARAM_DATA; } else if( step <= 0 ){ errNum = WLZ_ERR_PARAM_DATA; } /* check for empty object */ else if((first_pl > obj->domain.p->lastpl) || (last_pl < obj->domain.p->plane1) ){ return WlzMakeEmpty(dstErr); } } /* make a new planedomain and voxel table as required */ if( errNum == WLZ_ERR_NONE ){ for(p=first_pl; p <= last_pl; p += step){ if( p >= obj->domain.p->plane1 ){ new_plane1 = p / step; break; } } for(;p <= last_pl; p += step){ if( p > obj->domain.p->lastpl ){ break; } new_lastpl = p / step; } if((domain.p = WlzMakePlaneDomain(obj->domain.p->type, new_plane1, new_lastpl, obj->domain.p->line1, obj->domain.p->lastln, obj->domain.p->kol1, obj->domain.p->lastkl, &errNum)) != NULL){ domain.p->voxel_size[0] = obj->domain.p->voxel_size[0]; domain.p->voxel_size[1] = obj->domain.p->voxel_size[1]; domain.p->voxel_size[2] = step * (obj->domain.p->voxel_size[2]); if( obj->values.core != NULL ){ if( (values.vox = WlzMakeVoxelValueTb(obj->values.vox->type, new_plane1, new_lastpl, obj->values.vox->bckgrnd, obj, &errNum)) == NULL ){ (void) WlzFreePlaneDomain(domain.p); } } } } /* set domain and voxel values */ if( errNum == WLZ_ERR_NONE ){ for(p=first_pl; p <= last_pl; p += step){ if( p < obj->domain.p->plane1 ){ continue; } if( p > obj->domain.p->lastpl ){ break; } new_p = (p / step) - domain.p->plane1; domain.p->domains[new_p] = WlzAssignDomain(obj->domain.p->domains[p - obj->domain.p->plane1], NULL); if( obj->values.core != NULL ){ values.vox->values[new_p] = WlzAssignValues( obj->values.vox->values[p - obj->domain.p->plane1], NULL); } } } if( errNum == WLZ_ERR_NONE ){ nobj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } if( dstErr ){ *dstErr = errNum; } return nobj; }
/*! * \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); }
double WlzMixtureValue( WlzObject *obj1, WlzObject *obj2, int numCatRows, int numCatCols, double **mixing, double **contrib, WlzErrorNum *dstErr) { double val, con; WlzObject *tmpObj, *tmpObj1, *tmpObj2; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyP gptr; WlzGreyValueWSpace *gVWSp; WlzPixelV minP, maxP; int i; WlzErrorNum errNum=WLZ_ERR_NONE; /* objects must be same type with grey-values */ if( (obj1 == NULL) || (obj2 == NULL) ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( obj1->type ){ case WLZ_2D_DOMAINOBJ: if( obj2->type != obj1->type ){ errNum = WLZ_ERR_OBJECT_TYPE; } else { if((obj1->values.core == NULL) || (obj2->values.core == NULL)){ errNum = WLZ_ERR_VALUES_NULL; } else { /* convert to int and check range */ if((tmpObj1 = WlzConvertPix(obj1, WLZ_GREY_INT, &errNum)) != NULL){ errNum = WlzGreyRange(tmpObj1, &minP, &maxP); if( errNum == WLZ_ERR_NONE ){ if((minP.v.inv < 1) || (minP.v.inv > numCatRows) || (maxP.v.inv < 1) || (maxP.v.inv > numCatRows)){ errNum = WLZ_ERR_OBJECT_DATA; WlzFreeObj(tmpObj1); } } else { WlzFreeObj(tmpObj1); } } if((errNum == WLZ_ERR_NONE) && (tmpObj2 = WlzConvertPix(obj2, WLZ_GREY_INT, &errNum)) ){ errNum = WlzGreyRange(tmpObj2, &minP, &maxP); if( errNum == WLZ_ERR_NONE ){ if((minP.v.inv < 1) || (minP.v.inv > numCatCols) || (maxP.v.inv < 1) || (maxP.v.inv > numCatCols)){ errNum = WLZ_ERR_OBJECT_DATA; WlzFreeObj(tmpObj1); WlzFreeObj(tmpObj2); } } else { WlzFreeObj(tmpObj1); WlzFreeObj(tmpObj2); } } } } break; case WLZ_3D_DOMAINOBJ: default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* get the intersection region */ if( errNum == WLZ_ERR_NONE ){ if((tmpObj = WlzIntersect2(tmpObj1, tmpObj2, &errNum)) != NULL){ tmpObj->values = WlzAssignValues(tmpObj1->values, &errNum); } else { WlzFreeObj(tmpObj1); WlzFreeObj(tmpObj2); } } /* now calculate the mixture value */ if( errNum == WLZ_ERR_NONE ){ errNum = WlzInitGreyScan(tmpObj, &iwsp, &gwsp); gVWSp = WlzGreyValueMakeWSp(tmpObj2, &errNum); val = 0.0; con = 0.0; while((errNum == WLZ_ERR_NONE) && (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE ){ gptr = gwsp.u_grintptr; for (i=0; i<iwsp.colrmn; i++, gptr.inp++){ WlzGreyValueGet(gVWSp, 0, iwsp.linpos, iwsp.colpos+i); val += mixing[(*gptr.inp)-1][gVWSp->gVal[0].inv-1]; con += contrib[(*gptr.inp)-1][gVWSp->gVal[0].inv-1]; } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzGreyValueFreeWSp(gVWSp); WlzFreeObj(tmpObj); WlzFreeObj(tmpObj1); WlzFreeObj(tmpObj2); } if( dstErr ){ *dstErr = errNum; } if( con > 0.0 ){ return val/con; } else { return 0.0; } }
/*! * \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); }
/*! * \return New Woolz object. * \ingroup WlzAllocation * \brief Creates a new or adds to an existing 3D spatial domain * object using a rectangular buffer of values to a single * plane of the given current object (which may be NULL or * empty if the object is to be created). * The returned object will share domains and values of * planes other than the given plane with the current object. * \param cObj Given current object. * \param og Origin of rectangular buffer. * \param sz Buffer size (note 2D). * \param gType Grey type which must be consistent * with the current object (if it is * valid) and the buffer of values. * \param bufSz Number of values in the buffer * (ie sz.vtX * sz.vtY). * \param bufP Given buffer of values. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzBuildObj3(WlzObject *cObj, WlzIVertex3 og, WlzIVertex2 sz, WlzGreyType gType, int bufSz, WlzGreyP bufP, WlzErrorNum *dstErr) { int nPlnReq = 1; WlzDomain cDom, nDom; WlzValues cVal, nVal; WlzObject *nObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; cDom.core = NULL; nDom.core = NULL; cVal.core = NULL; nVal.core = NULL; if(cObj) { WlzGreyType cGType = WLZ_GREY_ERROR;; switch(cObj->type) { case WLZ_EMPTY_OBJ: cObj = NULL; break; case WLZ_3D_DOMAINOBJ: if(cObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(cObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else { cDom = cObj->domain; cVal = cObj->values; cGType = WlzGreyTypeFromObj(cObj, &errNum); } if((errNum == WLZ_ERR_NONE) && (cGType != gType)) { errNum = WLZ_ERR_GREY_TYPE; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* Create a new object with new plane domain and voxel values. */ if(errNum == WLZ_ERR_NONE) { WlzIBox3 nBox; WlzPixelV bgdV; float vxSz[3]; nBox.xMin = og.vtX; nBox.yMin = og.vtY; nBox.zMin = og.vtZ; nBox.xMax = og.vtX + sz.vtX - 1; nBox.yMax = og.vtY + sz.vtY - 1; nBox.zMax = og.vtZ; if(cObj) { nPlnReq = (og.vtZ < cDom.p->plane1) || (og.vtZ > cDom.p->lastpl) || ((*(cDom.p->domains + og.vtZ - cDom.p->plane1)).core == NULL); nBox.xMin = ALG_MIN(nBox.xMin, cDom.p->kol1); nBox.yMin = ALG_MIN(nBox.yMin, cDom.p->line1); nBox.zMin = ALG_MIN(nBox.zMin, cDom.p->plane1); nBox.xMax = ALG_MAX(nBox.xMax, cDom.p->lastkl); nBox.yMax = ALG_MAX(nBox.yMax, cDom.p->lastln); nBox.zMax = ALG_MAX(nBox.zMax, cDom.p->lastpl); vxSz[0] = cDom.p->voxel_size[0]; vxSz[1] = cDom.p->voxel_size[1]; vxSz[2] = cDom.p->voxel_size[2]; bgdV = WlzGetBackground(cObj, &errNum); } else { vxSz[0] = vxSz[1] = vxSz[2] = 1.0f; bgdV.type = WLZ_GREY_INT; bgdV.v.inv = 0; } if(errNum == WLZ_ERR_NONE) { nDom.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, nBox.zMin, nBox.zMax, nBox.yMin, nBox.yMax, nBox.xMin, nBox.xMax, &errNum); } if(errNum == WLZ_ERR_NONE) { nVal.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, nBox.zMin, nBox.zMax, bgdV, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { nDom.p->voxel_size[0] = vxSz[0]; nDom.p->voxel_size[1] = vxSz[1]; nDom.p->voxel_size[2] = vxSz[2]; nObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, nDom, nVal, NULL, NULL, &errNum); } } /* Set the domain and values on each plane for the new object. */ if(errNum == WLZ_ERR_NONE) { int idZ; for(idZ = nDom.p->plane1; idZ <= nDom.p->lastpl; ++idZ) { int idP; WlzDomain nDom2; WlzValues nVal2; nDom2.core = NULL; nVal2.core = NULL; idP = idZ - nDom.p->plane1; if(idZ == og.vtZ) { /* Plane with buffer. */ WlzIVertex2 og2, sz2; WlzObject *cObj2 = NULL, *nObj2 = NULL; og2.vtX = og.vtX; og2.vtY = og.vtY; sz2.vtX = sz.vtX; sz2.vtY = sz.vtY; if(nPlnReq == 0) { int idP; idP = idZ - cDom.p->plane1; cObj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, *(cDom.p->domains + idP), *(cVal.vox->values + idP), NULL, NULL, &errNum); } nObj2 = WlzBuildObj2(cObj2, og2, sz2, gType, bufSz, bufP, &errNum); if(errNum == WLZ_ERR_NONE) { nDom2 = WlzAssignDomain(nObj2->domain, NULL); nVal2 = WlzAssignValues(nObj2->values, NULL); } (void )WlzFreeObj(cObj2); (void )WlzFreeObj(nObj2); } else if((idZ >= cDom.p->plane1) && (idZ <= cDom.p->lastpl)) { /* Not buffer plane, but previously existing plane. */ int idQ; idQ = idZ - cDom.p->plane1; nDom2 = WlzAssignDomain(*(cDom.p->domains + idQ), NULL); nVal2 = WlzAssignValues(*(cVal.vox->values + idQ), NULL); } if(errNum == WLZ_ERR_NONE) { *(nDom.p->domains + idP) = nDom2; *(nVal.vox->values + idP) = nVal2; } else { break; } } } if(dstErr) { *dstErr = errNum; } return(nObj); }
/*! * \return New Woolz object without holes or NULL on error. * \ingroup WlzDomainOps * \brief Fills the holes in the given object's domain (which are by * definition not connected to the outside). When the given * object's domain has more than one component part, the * object should first be labeled, this function should then be * called for each of the labeled parts and then the union of * the filled domains should be formed. * \param srcObj Given 3D domain object. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzDomainFill3D( WlzObject *srcObj, WlzErrorNum *dstErr) { int nPln = 0; WlzObject *bndObj = NULL, *filObj = NULL, *gvnObj = NULL, *sedObj = NULL, *shlObj = NULL; WlzPixelV zeroV; WlzValues nullVal; WlzErrorNum errNum = WLZ_ERR_NONE; nullVal.core = NULL; zeroV.type = WLZ_GREY_UBYTE; zeroV.v.ubv = 0; if(srcObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(srcObj->type != WLZ_3D_DOMAINOBJ) { errNum = WLZ_ERR_OBJECT_TYPE; } else if(srcObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else { gvnObj = WlzMakeMain(srcObj->type, srcObj->domain, nullVal, NULL, NULL, &errNum); } /* Create a then shell 1 voxel thick just inside the given objects's * domain. */ if(errNum == WLZ_ERR_NONE) { WlzObject *difObj = NULL; difObj = WlzAssignObject( WlzBoundaryDomain(gvnObj, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { WlzIBox3 clipBox; /* Clip the dilated shell domain to make sure it stays within the * bounding box of the given object then all planes will align. */ clipBox.xMin = gvnObj->domain.p->kol1; clipBox.yMin = gvnObj->domain.p->line1; clipBox.zMin = gvnObj->domain.p->plane1; clipBox.xMax = gvnObj->domain.p->lastkl; clipBox.yMax = gvnObj->domain.p->lastln; clipBox.zMax = gvnObj->domain.p->lastpl; shlObj = WlzAssignObject( WlzClipObjToBox3D(difObj, clipBox, &errNum), NULL); } (void )WlzFreeObj(difObj); } /* Make sure that the bounding box of the thin shell domain fits it and * that it's first and last planes have interrvals. */ if(errNum == WLZ_ERR_NONE) { errNum = WlzStandardPlaneDomain(shlObj->domain.p, NULL); } /* Create a value table for the shell object with values set to zero. */ if(errNum == WLZ_ERR_NONE) { WlzValues val; WlzObjectType tType; tType = WlzGreyTableType(WLZ_GREY_TAB_INTL, WLZ_GREY_UBYTE, NULL); val.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, shlObj->domain.p->plane1, shlObj->domain.p->lastpl, zeroV, NULL, &errNum); if(errNum == WLZ_ERR_NONE) { int p; nPln = shlObj->domain.p->lastpl - shlObj->domain.p->plane1 + 1; shlObj->values = WlzAssignValues(val, NULL); #ifdef _OPENMP #pragma omp parallel for shared(shlObj) #endif for(p = 0; p < nPln; ++p) { if(errNum == WLZ_ERR_NONE) { WlzDomain dom2; WlzErrorNum errNum2; dom2 = shlObj->domain.p->domains[p]; if(dom2.core) { WlzValues val2; WlzObject *shlObj2; shlObj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, dom2, nullVal, NULL, NULL, &errNum2); if(errNum2 == WLZ_ERR_NONE) { val2.i = WlzMakeIntervalValues(tType, shlObj2, zeroV, &errNum2); /* WlzMakeIntervalValues() sets all values to zero. */ } if(errNum2 == WLZ_ERR_NONE) { shlObj->values.vox->values[p] = WlzAssignValues(val2, NULL); } (void )WlzFreeObj(shlObj2); if(errNum2 == WLZ_ERR_NONE) { #ifdef _OPENMP #pragma omp critical { #endif if((errNum == WLZ_ERR_NONE) && (errNum2 != WLZ_ERR_NONE)) { errNum = errNum2; } #ifdef _OPENMP } #endif } } } } } } /* Compute the (plane-wise) boundary list for the given object. */ if(errNum == WLZ_ERR_NONE) { bndObj = WlzObjToBoundary(gvnObj, 0, &errNum); } /* Sweep down through the boundary object setting the values of * those voxels in the shell object to a non zero value when they * correspond to top level boundaries. */ if(errNum == WLZ_ERR_NONE) { int p; #ifdef _OPENMP #pragma omp parallel for shared(bndObj,shlObj) #endif for(p = 0; p < nPln; ++p) { if(errNum == WLZ_ERR_NONE) { WlzDomain bDom2; bDom2 = bndObj->domain.p->domains[p]; if(bDom2.core) { WlzDomain iDom2; WlzValues iVal2; WlzObject *iObj2 = NULL; WlzGreyValueWSpace *gVWSp = NULL; WlzErrorNum errNum2 = WLZ_ERR_NONE; iDom2 = shlObj->domain.p->domains[p]; iVal2 = shlObj->values.vox->values[p]; iObj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, iDom2, iVal2, NULL, NULL, &errNum2); if(errNum == WLZ_ERR_NONE) { gVWSp = WlzGreyValueMakeWSp(iObj2, &errNum2); } if(errNum2 == WLZ_ERR_NONE) { WlzBoundList *bnd, *bnd2; bnd2 = bDom2.b; for(bnd = bnd2; bnd != NULL; bnd = bnd->next) { if(bnd->poly != NULL) { WlzPolygonDomain *ply; ply = bnd->poly; if(ply) { int i; WlzIVertex2 *vtx; vtx = ply->vtx; for(i = 0; i < ply->nvertices; ++i) { WlzGreyValueGet(gVWSp, 0, vtx[i].vtY, vtx[i].vtX); *(gVWSp->gPtr[0].ubp) = 255; } } } } } else { #ifdef _OPENMP #pragma omp critical { #endif if(errNum == WLZ_ERR_NONE) { errNum = errNum2; } #ifdef _OPENMP } #endif } (void )WlzFreeObj(iObj2); WlzGreyValueFreeWSp(gVWSp); } } } } /* Threshold the shell object, throwing away all but where the voxels * are set to create a seed domain. Then remove the value table from * the shell object and free it as it's no longer needed. */ if(errNum == WLZ_ERR_NONE) { WlzObject *tObj = NULL; WlzPixelV tV; tV.type = WLZ_GREY_UBYTE; tV.v.ubv = 1; tObj = WlzAssignObject( WlzThreshold(shlObj, tV, WLZ_THRESH_HIGH, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { sedObj = WlzAssignObject( WlzMakeMain(tObj->type, tObj->domain, nullVal, NULL, NULL, &errNum), NULL); } (void )WlzFreeObj(tObj); tObj = NULL; if(errNum == WLZ_ERR_NONE) { tObj = WlzAssignObject( WlzMakeMain(shlObj->type, shlObj->domain, nullVal, NULL, NULL, &errNum), NULL); } (void )WlzFreeObj(shlObj); shlObj = NULL; if(errNum == WLZ_ERR_NONE) { shlObj = tObj; tObj = NULL; } (void )WlzFreeObj(tObj); #ifdef WLZ_DOMOMAINFILL3D_DEBUG { FILE *fP; fP = fopen("debug-shlObj-00.wlz", "w"); (void )WlzWriteObj(fP, shlObj); (void )fclose(fP); } #endif } /* Label the shell domain using 26-connectivity in 3D and then * keep only those component objects which intersect the seed domain. * Then free the shell and seed domains replacing the shell domain * with the union of the intersecting labeled component objects. * Finaly free the intersecting component objects, keeping only the * new shell domain. */ if(errNum == WLZ_ERR_NONE) { int i, j, nCSObj = 0; WlzIBox3 bBox; WlzObject **csObj = NULL; bBox = WlzBoundingBox3I(shlObj, &errNum); if(errNum == WLZ_ERR_NONE) { int maxCSObj; maxCSObj = ((bBox.xMax - bBox.xMin + 1) * (bBox.yMax - bBox.yMin + 1) * (bBox.zMax - bBox.zMin + 1)) / 8; if(maxCSObj < 8) { maxCSObj = 8; } errNum = WlzLabel(shlObj, &nCSObj, &csObj, maxCSObj, 0, WLZ_26_CONNECTED); } if(errNum == WLZ_ERR_NONE) { for(i = 0; i < nCSObj; ++i) { if(!WlzHasIntersection(csObj[i], sedObj, &errNum)) { (void )WlzFreeObj(csObj[i]); csObj[i] = NULL; } } } if(errNum == WLZ_ERR_NONE) { /* Squeeze out any NULL objects reseting their number.*/ for(i = 0, j = 0; i < nCSObj; ++i) { if(csObj[i]) { csObj[j++] = csObj[i]; } } nCSObj = j; } if(errNum == WLZ_ERR_NONE) { WlzObject *iObj = NULL, *uObj = NULL; uObj = WlzAssignObject( WlzUnionN(nCSObj, csObj, 0, &errNum), NULL); iObj = WlzAssignObject( WlzIntersect2(uObj, shlObj, &errNum), NULL); (void )WlzFreeObj(uObj); (void )WlzFreeObj(shlObj); shlObj = iObj; #ifdef WLZ_DOMOMAINFILL3D_DEBUG { FILE *fP; fP = fopen("debug-shlObj-01.wlz", "w"); (void )WlzWriteObj(fP, shlObj); (void )fclose(fP); } #endif } if(csObj) { for(i = 0; i < nCSObj; ++i) { (void )WlzFreeObj(csObj[i]); } (void )AlcFree(csObj); } } /* Sweep down through the boundary lists again creating new boundary lists * which do not have boundaries that do not intersect the new shell domain. * Then create a new filled object from these boundary lists. */ if(errNum == WLZ_ERR_NONE) { int p, nPlnFil; WlzDomain filDom; nPlnFil = shlObj->domain.p->lastpl - shlObj->domain.p->plane1 + 1; filDom.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, shlObj->domain.p->plane1, shlObj->domain.p->lastpl, shlObj->domain.p->line1, shlObj->domain.p->lastln, shlObj->domain.p->kol1, shlObj->domain.p->lastkl, &errNum); #ifdef _OPENMP #pragma omp parallel for shared(bndObj,shlObj) #endif for(p = 0; p < nPlnFil; ++p) { if(errNum == WLZ_ERR_NONE) { WlzDomain bDom2; bDom2 = bndObj->domain.p->domains[p]; if(bDom2.core) { WlzDomain sDom2; WlzObject *fObj2 = NULL; WlzBoundList *newBnd = NULL; WlzErrorNum errNum2 = WLZ_ERR_NONE; sDom2 = shlObj->domain.p->domains[p]; if(sDom2.core) { newBnd = WlzDomFill3DDoBound2D(bDom2.b, sDom2, &errNum2); if(newBnd != NULL) { fObj2 = WlzBoundToObj(newBnd, WLZ_SIMPLE_FILL, &errNum2); (void )WlzFreeBoundList(newBnd); } if(errNum2 == WLZ_ERR_NONE) { if(fObj2) { filDom.p->domains[p] = WlzAssignDomain(fObj2->domain, NULL); } } else { #ifdef _OPENMP #pragma omp critical { #endif if(errNum == WLZ_ERR_NONE) { errNum = errNum2; } #ifdef _OPENMP } #endif } (void )WlzFreeObj(fObj2); } } } } if(errNum == WLZ_ERR_NONE) { errNum = WlzStandardPlaneDomain(filDom.p, NULL); } if(errNum == WLZ_ERR_NONE) { WlzObject *tObj0 = NULL, *tObj1 = NULL; /* Put back any isolated voxels this function has removed. */ tObj0 = WlzAssignObject( WlzMakeMain(srcObj->type, filDom, nullVal, NULL, NULL, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { tObj1 = WlzUnion2(gvnObj, tObj0, &errNum); } if(errNum == WLZ_ERR_NONE) { filObj = WlzMakeMain(tObj1->type, tObj1->domain, nullVal, NULL, NULL, &errNum); } (void )WlzFreeObj(tObj0); (void )WlzFreeObj(tObj1); } } (void )WlzFreeObj(bndObj); (void )WlzFreeObj(gvnObj); (void )WlzFreeObj(shlObj); (void )WlzFreeObj(sedObj); if((errNum != WLZ_ERR_NONE) && (filObj != NULL)) { (void )WlzFreeObj(filObj); filObj = NULL; } if(dstErr) { *dstErr = errNum; } return(filObj); }
/*! * \return New Woolz object. * \ingroup WlzAllocation * \brief Creates a new 2D spatial domain object by adding a * rectangular buffer of values to the given current * object (which may be NULL or empty). * \param cObj Given current object. * \param og Origin of rectangular buffer. * \param sz Buffer size. * \param gType Grey type which must be consistent * with the current object and the * buffer of values. * \param bufSz Number of values in the buffer. * \param bufP Given buffer of values. * \param dstErr Destination error pointer, may be NULL. */ static WlzObject *WlzBuildObj2(WlzObject *cObj, WlzIVertex2 og, WlzIVertex2 sz, WlzGreyType gType, int bufSz, WlzGreyP bufP, WlzErrorNum *dstErr) { WlzDomain bDom; WlzValues bVal, nVal; WlzObject *bObj = NULL, *nObj = NULL; WlzPixelV bgdV; WlzErrorNum errNum = WLZ_ERR_NONE; bDom.core = NULL; bVal.core = NULL; nVal.core = NULL; bgdV.type = WLZ_GREY_INT; bgdV.v.inv = 0; if(cObj) { WlzGreyType cGType = WLZ_GREY_ERROR;; switch(cObj->type) { case WLZ_EMPTY_OBJ: cObj = NULL; break; case WLZ_2D_DOMAINOBJ: if(cObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(cObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else { cGType = WlzGreyTypeFromObj(cObj, &errNum); bgdV = WlzGetBackground(cObj, &errNum); } if((errNum == WLZ_ERR_NONE) && (cGType != gType)) { errNum = WLZ_ERR_GREY_TYPE; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* Create new object with domain and values of given rectangular buffer. */ if(errNum == WLZ_ERR_NONE) { bDom.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_RECT, og.vtY, og.vtY + sz.vtY - 1, og.vtX, og.vtX + sz.vtX - 1, &errNum); } if(errNum == WLZ_ERR_NONE) { WlzObjectType gTT; gTT = WlzGreyTableType(WLZ_GREY_TAB_RECT, gType, NULL); bVal.r = WlzMakeRectValueTb(gTT, bDom.i->line1, bDom.i->lastln, bDom.i->kol1, sz.vtX, bgdV, bufP.inp, &errNum); } if(errNum == WLZ_ERR_NONE) { bObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, bDom, bVal, NULL, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { if(cObj == NULL) { /* Just copy the buffer object. */ nObj = WlzCopyObject(bObj, &errNum); } else { /* Compute union of current and buffer objects. */ nObj = (cObj)? WlzUnion2(cObj, bObj, &errNum): WlzMakeMain(WLZ_2D_DOMAINOBJ, bDom, nVal, NULL, NULL, &errNum); /* Create new value table. */ if(errNum == WLZ_ERR_NONE) { WlzObjectType gTT; gTT = WlzGreyTableType(WLZ_GREY_TAB_RAGR, gType, NULL); nVal.v = WlzNewValueTb(nObj, gTT, bgdV, &errNum); } if(errNum == WLZ_ERR_NONE) { nObj->values = WlzAssignValues(nVal, NULL); } if(errNum == WLZ_ERR_NONE) { WlzObject *tObj; /* Copy existing values to new object. */ tObj = WlzGreyTransfer(nObj, cObj, &errNum); (void )WlzFreeObj(nObj); nObj = tObj; /* Then copy buffer values to new object. */ if(errNum == WLZ_ERR_NONE) { tObj = WlzGreyTransfer(nObj, bObj, &errNum); (void )WlzFreeObj(nObj); nObj = tObj; } } } } (void )WlzFreeObj(bObj); if(dstErr) { *dstErr = errNum; } return(nObj); }