/*! * \return Returns a preprocessed object for registration. * \ingroup WlzRegistration * \brief * \param obj Given object. * \param inv Flag, non zero if object values are * to be inverted. * \param dstErr Destination error pointer, * may be NULL. */ static WlzObject *WlzRegCCorNormaliseObj2D(WlzObject *obj, int inv, WlzErrorNum *dstErr) { WlzGreyType gType; WlzPixelV min, max, mean, minN, maxN, zero; WlzObject *obj0 = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; /* Normalise the object inverting the grey values if required -> obj0. */ minN.v.ubv = 0; maxN.v.ubv = 255; zero.v.ubv = 0; min.type = WLZ_GREY_DOUBLE; max.type = WLZ_GREY_DOUBLE; mean.type = WLZ_GREY_UBYTE; minN.type = WLZ_GREY_UBYTE; maxN.type = WLZ_GREY_UBYTE; zero.type = WLZ_GREY_UBYTE; mean.v.ubv = 128; if(inv) { minN.v.ubv = 255; maxN.v.ubv = 0; } (void )WlzGreyStats(obj, &gType, &(min.v.dbv), &(max.v.dbv), NULL, NULL, NULL, NULL, &errNum); if(errNum == WLZ_ERR_NONE) { WlzValueConvertPixel(&min, min, gType); WlzValueConvertPixel(&max, max, gType); WlzValueConvertPixel(&minN, minN, gType); WlzValueConvertPixel(&maxN, maxN, gType); obj0 = WlzCopyObject(obj, &errNum); } if(errNum == WLZ_ERR_NONE) { errNum = WlzSetBackground(obj0, zero); errNum = WlzGreySetRange(obj0, min, max, minN, maxN, 0); } if(errNum != WLZ_ERR_NONE) { (void )WlzFreeObj(obj0); obj0 = NULL; } if(dstErr) { *dstErr = errNum; } return(obj0); }
/*! * - Function: WlzEffWriteMeshTransform3DWithoutDisplacementVTK * - Returns: none * - Purpose: output the orginal mesh. * - Parameters: * -# *fp: pointer pointing to a specific file. * -# wmt3D: mesh transform. * - Author: J. Rao, R. Baldock and B. Hill */ static void OutPutSectionsForTest( WlzObject *WObjS, WlzObject *WObj2D, /* FILE *outFile; */ char *outFileStr, int iloop, WlzErrorNum *errNum){ WlzGreyValueWSpace *gVWSp; WlzErrorNum wErrN = WLZ_ERR_NONE; WlzGMModel *gM; WlzGMShell *cS, *fS; WlzGMLoopT *cLT, *fLT; WlzGMEdgeT *cET, *fET; WlzDVertex2 *v1, *v2; WlzIBox2 bBoxT; WlzObject *tObj; int ix, jy, kt, intensity; if( ( (WObjS->type) != WLZ_CONTOUR ) ) { wErrN = WLZ_ERR_DOMAIN_TYPE; } if( ( WObj2D->type != WLZ_2D_DOMAINOBJ ) ) { wErrN = WLZ_ERR_DOMAIN_TYPE; } if( ( WObj2D->domain.core == NULL ) ) { wErrN = WLZ_ERR_DOMAIN_NULL; } if(wErrN == WLZ_ERR_NONE) { /* copy it */ tObj = WlzCopyObject(WObj2D, &wErrN); if( wErrN != WLZ_ERR_NONE) { printf("Something wrong with when copy obj "); exit(1); } /* get the bounding box */ bBoxT = WlzBoundingBox2I(tObj, &wErrN); if( wErrN != WLZ_ERR_NONE) { printf("Something wrong with getting bounding box of obj "); exit(1); } /* revise the grey value of it */ gVWSp = WlzGreyValueMakeWSp(tObj, &wErrN); if( wErrN != WLZ_ERR_NONE) { printf("Something wrong with when make warped obj Wsp"); exit(1); } for(ix = bBoxT.xMin; ix <bBoxT.xMax; ix++) { kt = 0; for(jy= bBoxT.yMin; jy< bBoxT.yMax; jy++) { /* GetGreyValue(gVWSp, 0, jy, ix, &intensity, &errNum); */ intensity = 255; FillGreyValue(gVWSp, 0, jy, ix, intensity, &wErrN); } } } /* visualize the data: */ if( wErrN == WLZ_ERR_NONE) { iloop = 1; kt = 0; gM = WObjS->domain.ctr->model; /* For each shell of the model. */ cS = fS = (WlzGMShell *) gM->child; do { printf("Shell %d Shell index %d\n", kt, cS->idx); /* For each loop topology element of the model. */ cLT = fLT = (WlzGMLoopT *) cS->child; kt++; do { printf("Loop index %d\n", cLT->idx); /* For each edge topology element of the model. */ cET = fET = cLT->edgeT; do { if(cET == cET->edge->edgeT) /* Print edge end points */ { v1 = (WlzDVertex2 *) cET->vertexT->diskT->vertex->geo.vg2D; v2 = (WlzDVertex2 *) cET->opp->vertexT->diskT->vertex->geo.vg2D; /* printf("%lg %lg\n",cET->vertexT->diskT->vertex->geo.vg2D->vtx.vtX, \ cET->vertexT->diskT->vertex->geo.vg2D->vtx.vtY ); printf("%lg %lg\n",cET->opp->vertexT->diskT->vertex->geo.vg2D->vtx.vtX, \ cET->opp->vertexT->diskT->vertex->geo.vg2D->vtx.vtY ); */ /* if(kt%3 == iloop) */ { ix = (int) cET->vertexT->diskT->vertex->geo.vg2D->vtx.vtX; jy = (int) cET->vertexT->diskT->vertex->geo.vg2D->vtx.vtY; printf("idx %d ix %d iy %d\n", cET->vertexT->diskT->vertex->idx, ix, jy); intensity = kt * 40; FillGreyValue(gVWSp, 0, jy, ix, intensity, &wErrN); ix = (int) cET->opp->vertexT->diskT->vertex->geo.vg2D->vtx.vtX; jy = (int) cET->opp->vertexT->diskT->vertex->geo.vg2D->vtx.vtY; printf("idx %d ix %d iy %d\n", cET->opp->vertexT->diskT->vertex->idx, ix, jy); FillGreyValue(gVWSp, 0, jy, ix, intensity, &wErrN); } } cET = cET->next; } while (cET != fET); cLT = cLT->next; } while(cLT != fLT); cS = cS->next; } while(cS != fS ); } if((outFile = fopen(outFileStr, "w")) == NULL ) { printf("cannot open the output woolz file.\n"); exit(1); } if( ( wErrN = WlzWriteObj(outFile, tObj) ) != WLZ_ERR_NONE ) { printf("output Woolz Object Error.\n"); fclose(outFile); exit(1); } fclose(outFile); outFile = NULL; WlzGreyValueFreeWSp(gVWSp); }
/*! * \return Object containing the point (x,y). * \ingroup WlzBinaryOps * \brief Takes a WLZ_2D_DOMAINOBJ, calls WlzLabel to split the domain * and returns the one containing point(x,y). * \param obj Given WLZ_2D_DOMAINOBJ object. * \param x Column coordinate. * \param y Line coordinate. * \param dstErr Destination error code pointer, may be NULL. */ WlzObject *Wlz2DContains(WlzObject *obj, double x, double y, WlzErrorNum *dstErr) { WlzObject *retObj = NULL; WlzObject **objArray; int i, nobjs; /* int maxNobjs=1024; */ int maxNobjs=2048; int found = 0; WlzErrorNum errNum=WLZ_ERR_NONE; WlzConnectType connectivity = WLZ_8_CONNECTED; /* fprintf(stderr, "entering Wlz2DContains %f,%f\n", x,y); fflush(stderr); */ if(obj->type != WLZ_2D_DOMAINOBJ) return (NULL); /* get array of domains */ if(obj != NULL) { errNum = WlzLabel(obj, &nobjs, &objArray, maxNobjs, 0, connectivity); } /* fprintf(stderr, "got array of %d objects\n", nobjs); fflush(stderr); */ /* select the required domain */ /* ie the one which contains clicked point */ if((errNum == WLZ_ERR_NONE) && (nobjs > 0)) { for(i=0; i<nobjs; i++) { /* fprintf(stderr, "checking domain # %d\n", i); fflush(stderr); */ if(WlzInsideDomain(objArray[i], 0.0, y, x, &errNum)) { if(errNum == WLZ_ERR_NONE) { found = 1; /* fprintf(stderr, "domain # %d contains point\n", i); fflush(stderr); */ break; } else { (void )fprintf(stderr, "WlzInsideDomain, Wlz error: %d\n", (int )errNum); fflush(stderr); } } else { WlzFreeObj(objArray[i]); } } if((found == 1) && (errNum == WLZ_ERR_NONE)) { /* retObj = objArray[i]; */ retObj = WlzCopyObject(objArray[i], &errNum); WlzFreeObj(objArray[i]); if(errNum != WLZ_ERR_NONE) { (void )fprintf(stderr, "WlzCopyObject, Wlz error: %d\n", (int )errNum); fflush(stderr); } } } *dstErr = errNum; /* fprintf(stderr, "leaving Wlz2DContains\n"); fflush(stderr); */ return retObj; }
/*! * \return New object or NULL on error. * \ingroup WlzValuesUtils * \brief Transfers grey values from the source object to the * destination object within the intersection of the source * and destination. Grey values within the destination * object outside of the source object are unchanged. * It is an error if either object has a different dimension * or grey value type, except for when either is an empty * object. * \param dObj Destination object which may be * empty, but otherwise should be of the * same dimension as the source object * with valid values.. * \param sObj Source object which if not empty must * have both a valid domain and valid * values. * \param inplace Overwrite the destination object's * values if non zero. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzGreyTransfer( WlzObject *dObj, WlzObject *sObj, int inplace, WlzErrorNum *dstErr) { WlzObject *rObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; if((dObj == NULL) || (sObj == NULL)) { errNum = WLZ_ERR_OBJECT_NULL; } else if(WlzIsEmpty(dObj, NULL)) { rObj = WlzMakeEmpty(&errNum); } else if(WlzIsEmpty(sObj, NULL)) { rObj = WlzMakeMain(dObj->type, dObj->domain, dObj->values, dObj->plist, NULL, &errNum); } else if(dObj->type != sObj->type) { errNum = WLZ_ERR_OBJECT_TYPE; } else if((dObj->domain.core == NULL) || (sObj->domain.core == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(sObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else { switch(sObj->type) { case WLZ_2D_DOMAINOBJ: case WLZ_3D_DOMAINOBJ: /* FALLTHROUGH */ { WlzObject *rIObj = NULL; rIObj = WlzIntersect2(dObj, sObj, &errNum); if((errNum == WLZ_ERR_NONE) && (WlzIsEmpty(rIObj, NULL) == 0)) { rObj = (inplace)? WlzMakeMain(dObj->type, dObj->domain, dObj->values, dObj->plist, NULL, &errNum): WlzCopyObject(dObj, &errNum); if(errNum == WLZ_ERR_NONE) { /* If the destination object does not have values then * create them to match the domain of the destination * object. */ if((sObj->values.core != NULL) && (rObj->values.core == NULL)) { WlzPixelV bgdV; WlzGreyType gType; WlzObjectType gTT; WlzValues newVal; newVal.core = NULL; bgdV = WlzGetBackground(sObj, &errNum); if(errNum == WLZ_ERR_NONE) { gType = WlzGreyTypeFromObj(sObj, &errNum); } if(errNum == WLZ_ERR_NONE) { gTT = WlzGreyTableType(WLZ_GREY_TAB_RAGR, gType, NULL); if(rObj->type == WLZ_2D_DOMAINOBJ) { newVal.v = WlzNewValueTb(rObj, gTT, bgdV, &errNum); } else /* rObj->type == WLZ_3D_DOMAINOBJ */ { newVal.vox = WlzNewValuesVox(rObj, gTT, bgdV, &errNum); } } if(errNum == WLZ_ERR_NONE) { rObj->values = WlzAssignValues(newVal, NULL); } if(errNum == WLZ_ERR_NONE) { errNum = WlzGreySetValue(rObj, bgdV); } } } if(errNum == WLZ_ERR_NONE) { if(sObj->type == WLZ_2D_DOMAINOBJ) { WlzObject *sIObj; rIObj->values = WlzAssignValues(rObj->values, NULL); sIObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, rIObj->domain, sObj->values, NULL, NULL, &errNum); if(errNum == WLZ_ERR_NONE) { errNum = WlzGreyTransfer2D(rIObj, sIObj); } (void )WlzFreeObj(sIObj); } else /* sObj->type == WLZ_3D_DOMAINOBJ */ { int p, rTiled, sTiled, nPlanes; rTiled = WlzGreyTableIsTiled(rObj->values.core->type); sTiled = WlzGreyTableIsTiled(sObj->values.core->type); nPlanes = rIObj->domain.p->lastpl - rIObj->domain.p->plane1 + 1; #ifdef _OPENMP #pragma omp parallel for #endif for(p = 0; p < nPlanes; ++p) { if(errNum == WLZ_ERR_NONE) { int pln; WlzDomain dom; WlzValues val; WlzObject *rIObj2D = NULL, *sIObj2D = NULL; WlzErrorNum errNum2D = WLZ_ERR_NONE; pln = p + rIObj->domain.p->plane1; dom = rIObj->domain.p->domains[p]; val = (rTiled)? rObj->values: rObj->values.vox->values[pln - rObj->values.vox->plane1]; rIObj2D = WlzMakeMain(WLZ_2D_DOMAINOBJ, dom, val, NULL, NULL, &errNum2D); if(errNum2D == WLZ_ERR_NONE) { val = (sTiled)? sObj->values: sObj->values.vox->values[pln - sObj->values.vox->plane1]; sIObj2D = WlzMakeMain(WLZ_2D_DOMAINOBJ, dom, val, NULL, NULL, &errNum2D); } if(errNum2D == WLZ_ERR_NONE) { errNum2D = WlzGreyTransfer2D(rIObj2D, sIObj2D); } (void )WlzFreeObj(rIObj2D); (void )WlzFreeObj(sIObj2D); #ifdef _OPENMP #pragma omp critical { #endif if((errNum == WLZ_ERR_NONE) && (errNum2D != WLZ_ERR_NONE)) { errNum = errNum2D; } #ifdef _OPENMP } #endif } } } } } (void )WlzFreeObj(rIObj); } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if(errNum != WLZ_ERR_NONE) { WlzFreeObj(rObj); rObj = NULL; } if(dstErr) { *dstErr = errNum; } return(rObj); }
/*! * \return 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); }
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); }
/*! * \return New contour object. * \brief Create a contour object from a 2D domain object with values, * together with a set of parameters. * \param gObj Given 2D domain object. * \param binFlg Generate contours from binary * (thresholded) image. * \param thrType Threshold type. * \param thrVal Threshold value. * \param medianSz Median filter size if > 0. * \param smooth Gaussian smoothing value. * \param cThr Contour threshold value. * \param minSpx Minimum number of simplicies per shell. * \param objDbgFileName If non-null used as the name of a * file for the image object just prior * to computing the geometric model. * \param dstErr Destination ptr for error, may be NULL. */ static WlzObject *WlzMatchICPPlaneCreateContourObj(WlzObject *gObj, int binFlg, WlzThresholdType thrType, double thrVal, int medianSz, double smooth, double cThr, int minSpx, int debug, char *objDbgFileName, WlzErrorNum *dstErr) { WlzObject *tObj0 = NULL, *cObj = NULL; WlzDomain tDom; WlzValues tVal; FILE *dFP = NULL; WlzPixelV thrV; WlzErrorNum errNum = WLZ_ERR_NONE; const int nrmFlg = 1; tVal.core = NULL; if(binFlg) { thrV.type = WLZ_GREY_DOUBLE; thrV.v.dbv = thrVal; tObj0 = WlzThreshold(gObj, thrV, thrType, &errNum); if(errNum == WLZ_ERR_NONE) { thrV.v.dbv = 0.0; errNum = WlzGreySetValue(gObj, thrV); } if(errNum == WLZ_ERR_NONE) { thrV.v.dbv = 255.0; errNum = WlzGreySetValue(tObj0, thrV); } (void )WlzFreeObj(tObj0); tObj0 = NULL; } if(medianSz > 0) { errNum = WlzRankFilter(gObj, medianSz, 0.5); } if(errNum == WLZ_ERR_NONE) { if(smooth > DBL_EPSILON) { tObj0 = WlzAssignObject( WlzGauss2(gObj, smooth, smooth, 0, 0, &errNum), NULL); } else { tObj0 = WlzAssignObject(gObj, NULL); } } if(errNum == WLZ_ERR_NONE) { if(objDbgFileName) { if((dFP = fopen(objDbgFileName, "w")) != NULL) { (void )WlzWriteObj(dFP, tObj0); (void )fclose(dFP); } } tDom.ctr = WlzContourObj(tObj0, WLZ_CONTOUR_MTD_GRD, cThr, 1.0, nrmFlg, &errNum); } WlzFreeObj(tObj0); if(errNum == WLZ_ERR_NONE) { cObj = WlzMakeMain(WLZ_CONTOUR, tDom, tVal, NULL, NULL, &errNum); } /* There's a bug somewhere in the deletion of small shells. Delete small * shells and then copy the contours. */ if(debug && (errNum == WLZ_ERR_NONE)) { errNum = WlzGMVerifyModel(cObj->domain.ctr->model, NULL); } if(errNum == WLZ_ERR_NONE) { errNum = WlzGMFilterRmSmShells(cObj->domain.ctr->model, minSpx * 3); } if(debug && (errNum == WLZ_ERR_NONE)) { errNum = WlzGMVerifyModel(cObj->domain.ctr->model, NULL); } if(errNum == WLZ_ERR_NONE) { tObj0 = WlzAssignObject(WlzCopyObject(cObj, &errNum), NULL); WlzFreeObj(cObj); if(errNum == WLZ_ERR_NONE) { cObj = tObj0; } tObj0 = NULL; } if(debug && (errNum == WLZ_ERR_NONE)) { errNum = WlzGMVerifyModel(cObj->domain.ctr->model, NULL); } return(cObj); }
/*! * \ingroup WlzValuesUtils * \brief Transfer grey values from the source object to the destination object. Currently it is assumed that the objects are of the same type (2D/3D) and have the same grey-value type. * * \return Woolz object with transferred grey values * \param obj destination object * \param srcObj source object * \param dstErr error return * \par Source: * WlzGreyTransfer.c */ WlzObject *WlzGreyTransfer( WlzObject *obj, WlzObject *srcObj, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzObject *obj1, *obj2; WlzValues values; WlzIntervalWSpace iwsp1, iwsp2; WlzGreyWSpace gwsp1, gwsp2; int size; WlzErrorNum errNum=WLZ_ERR_NONE; /* check destination obj */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if(WlzGreyTableIsTiled(obj->values.core->type)) { errNum = WLZ_ERR_VALUES_TYPE; } else { rtnObj = WlzCopyObject(obj, &errNum); } break; case WLZ_3D_DOMAINOBJ: return WlzGreyTransfer3d(obj, srcObj, dstErr); case WLZ_TRANS_OBJ: if((values.obj = WlzGreyTransfer(obj->values.obj, srcObj, &errNum)) != NULL){ return WlzMakeMain(WLZ_TRANS_OBJ, obj->domain, values, NULL, NULL, dstErr); } break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* check the source object */ if( errNum == WLZ_ERR_NONE ){ if( srcObj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( srcObj->type ){ case WLZ_2D_DOMAINOBJ: break; case WLZ_TRANS_OBJ: srcObj = srcObj->values.obj; break; case WLZ_EMPTY_OBJ: if( dstErr ){ *dstErr = errNum; } return rtnObj; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } } /* copy source obj values within the intersection */ if( errNum == WLZ_ERR_NONE ){ if((srcObj->type != WLZ_EMPTY_OBJ) ){ if( (obj1 = WlzIntersect2(srcObj, rtnObj, &errNum)) ){ obj1->values = WlzAssignValues(rtnObj->values, NULL); obj2 = WlzMakeMain(obj1->type, obj1->domain, srcObj->values, NULL, NULL, NULL); errNum = WlzInitGreyScan(obj1, &iwsp1, &gwsp1); errNum = WlzInitGreyScan(obj2, &iwsp2, &gwsp2); switch( gwsp1.pixeltype ){ case WLZ_GREY_INT: size = sizeof(int); break; case WLZ_GREY_SHORT: size = sizeof(short); break; case WLZ_GREY_UBYTE: size = sizeof(WlzUByte); break; case WLZ_GREY_FLOAT: size = sizeof(float); break; case WLZ_GREY_DOUBLE: size = sizeof(double); break; case WLZ_GREY_RGBA: size = sizeof(WlzUInt); break; default: errNum = WLZ_ERR_GREY_TYPE; break; } while((errNum == WLZ_ERR_NONE) && (errNum = WlzNextGreyInterval(&iwsp1)) == WLZ_ERR_NONE){ (void) WlzNextGreyInterval(&iwsp2); memcpy((void *) gwsp1.u_grintptr.inp, (const void *) gwsp2.u_grintptr.inp, size * iwsp1.colrmn); } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzFreeObj(obj2); WlzFreeObj(obj1); } else { WlzFreeObj(rtnObj); rtnObj = NULL; } } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \ingroup WlzValuesUtils * \brief static function to implement WlzGreyTransfer for 3D objects. * * \return woolz object * \param obj destination object * \param srcObj source object * \param dstErr error return * \par Source: * WlzGreyTransfer.c */ static WlzObject *WlzGreyTransfer3d( WlzObject *obj, WlzObject *srcObj, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzObject *obj1, *obj2, *tmpObj; WlzDomain *domains; WlzValues values, *valuess; WlzPlaneDomain *pdom; int p; WlzErrorNum errNum=WLZ_ERR_NONE; /* check the object - it is non-NULL and 3D but the domain needs checking */ if( obj->domain.p == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else { switch( obj->domain.p->type ){ case WLZ_2D_DOMAINOBJ: /* check there is a valuetable */ if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if(WlzGreyTableIsTiled(obj->values.core->type)) { errNum = WLZ_ERR_VALUES_TYPE; } break; default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } } /* check the source object */ if( errNum == WLZ_ERR_NONE ){ if( srcObj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( srcObj->type ){ case WLZ_3D_DOMAINOBJ: if( srcObj->domain.p ){ switch( srcObj->domain.p->type ){ case WLZ_2D_DOMAINOBJ: break; default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } } else { errNum = WLZ_ERR_DOMAIN_NULL; } break; case WLZ_EMPTY_OBJ: return WlzCopyObject(obj, dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } } /* now we have a 3D obj and 3D srcObject so run through the source and map values as required */ if( errNum == WLZ_ERR_NONE ){ WlzDomain *objDoms; WlzValues *objVals; /* attach a voxel table with empty values list */ values.vox = WlzMakeVoxelValueTb(obj->values.vox->type, obj->domain.p->plane1, obj->domain.p->lastpl, obj->values.vox->bckgrnd, NULL, NULL); rtnObj = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); /* set some local variables */ pdom = rtnObj->domain.p; domains = rtnObj->domain.p->domains; valuess = rtnObj->values.vox->values; objDoms = obj->domain.p->domains; objVals = obj->values.vox->values; /* calculate the new valuetables */ for(p=pdom->plane1; p <= pdom->lastpl; p++, domains++, valuess++, objDoms++, objVals++){ if(((*domains).core)){ obj1 = WlzMakeMain(WLZ_2D_DOMAINOBJ, *objDoms, *objVals, NULL, NULL, &errNum); obj1 = WlzAssignObject(obj1, &errNum); if((p >= srcObj->domain.p->plane1) && (p <= srcObj->domain.p->lastpl) && (srcObj->domain.p->domains[p-srcObj->domain.p->plane1].core)){ obj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, srcObj->domain.p->domains[p-srcObj->domain.p->plane1], srcObj->values.vox->values[p-srcObj->domain.p->plane1], NULL, NULL, &errNum); } else { obj2 = WlzMakeEmpty(NULL); } obj2 = WlzAssignObject(obj2, &errNum); tmpObj = WlzGreyTransfer(obj1, obj2, &errNum); *valuess = WlzAssignValues(tmpObj->values, &errNum); WlzFreeObj(obj1); WlzFreeObj(obj2); WlzFreeObj(tmpObj); } } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }