int main(int argc, char *argv[]) { int tI0, ok = 1, option, usage = 0, nItr = 200, nonMan = 0; unsigned int flags = 0; double lambda, mu, kPB = 0.1000, kSB = 1.0000, dPB = 0.2500, dSB = 0.1000; FILE *fP = NULL; char *inObjFileStr, *outObjFileStr; const char *errMsgStr; WlzErrorNum errNum = WLZ_ERR_NONE; WlzObject *obj = NULL; static char optList[] = "hNo:l:m:n:p:s:P:S:"; const char inObjFileStrDef[] = "-", outObjFileStrDef[] = "-", setMsg[] = "set on command line", notSetMsg[] = "not set / default "; opterr = 0; inObjFileStr = (char *)inObjFileStrDef; outObjFileStr = (char *)outObjFileStrDef; while(ok && ((option = getopt(argc, argv, optList)) != EOF)) { switch(option) { case 'N': nonMan = 1; break; case 'o': outObjFileStr = optarg; break; case 'l': if((sscanf(optarg, "%lg", &lambda) != 1) || (fabs(lambda) < DBL_EPSILON) || (fabs(lambda) > 1.0)) { usage = 1; ok = 0; } flags |= WLZWLZ_CTRFFLAGS_LAMBDA; break; case 'm': if((sscanf(optarg, "%lg", &mu) != 1) || (fabs(mu) < DBL_EPSILON) || (fabs(mu) > 1.0)) { usage = 1; ok = 0; } flags |= WLZWLZ_CTRFFLAGS_MU; break; case 'n': if((sscanf(optarg, "%d", &nItr) != 1) || (nItr < 0)) { usage = 1; ok = 0; } flags |= WLZWLZ_CTRFFLAGS_NITR; break; case 'p': if((sscanf(optarg, "%lg", &kPB) != 1) || (kPB < DBL_EPSILON) || (kPB > 1.0)) { usage = 1; ok = 0; } flags |= WLZWLZ_CTRFFLAGS_KPB; break; case 's': if((sscanf(optarg, "%lg", &kSB) != 1) || (kSB < 1.0) || (kSB > 2.0)) { usage = 1; ok = 0; } flags |= WLZWLZ_CTRFFLAGS_KSB; break; case 'P': if((sscanf(optarg, "%lg", &dPB) != 1) || (dPB < DBL_EPSILON) || (dPB > 1.0)) { usage = 1; ok = 0; } flags |= WLZWLZ_CTRFFLAGS_DPB; break; case 'S': if((sscanf(optarg, "%lg", &dSB) != 1) || (dSB < DBL_EPSILON) || (dSB > 1.0)) { usage = 1; ok = 0; } flags |= WLZWLZ_CTRFFLAGS_DSB; break; case 'h': default: usage = 1; ok = 0; break; } } if(ok) { if((inObjFileStr == NULL) || (*inObjFileStr == '\0') || (outObjFileStr == NULL) || (*outObjFileStr == '\0')) { ok = 0; usage = 1; } if(ok && (optind < argc)) { if((optind + 1) != argc) { usage = 1; ok = 0; } else { inObjFileStr = *(argv + optind); } } } if(ok) { if((inObjFileStr == NULL) || (*inObjFileStr == '\0') || ((fP = (strcmp(inObjFileStr, "-")? fopen(inObjFileStr, "r"): stdin)) == NULL) || ((obj = WlzAssignObject(WlzReadObj(fP, &errNum), NULL)) == NULL) || (errNum != WLZ_ERR_NONE)) { ok = 0; (void )fprintf(stderr, "%s: failed to read object from file %s\n", *argv, inObjFileStr); } if(fP && strcmp(inObjFileStr, "-")) { fclose(fP); } } if(ok) { tI0 = WLZWLZ_CTRFFLAGS_LAMBDA | WLZWLZ_CTRFFLAGS_MU; if((flags & tI0) != tI0) { errNum = WlzGMFilterGeomLPParam(&lambda, &mu, &tI0, kPB, kSB, dPB, dSB); } if((flags & WLZWLZ_CTRFFLAGS_NITR) == 0) { nItr = tI0; } if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsgStr); (void )fprintf(stderr, "%s: Failed to compute filter parameters lambda and mu from the\n" " band pass and band stop frequency parameters (%s).\n", argv[0], errMsgStr); } } if(ok) { if(obj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } if(obj->type != WLZ_CONTOUR) { errNum = WLZ_ERR_OBJECT_TYPE; } else if(obj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else { errNum = WlzGMFilterGeomLPLM(obj->domain.ctr->model, lambda, mu, nItr, nonMan); } if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsgStr); (void )fprintf(stderr, "%s: Failed to filter the geometric model. (%s).\n", argv[0], errMsgStr); } } if(ok) { if((fP = (strcmp(outObjFileStr, "-")? fopen(outObjFileStr, "w"): stdout)) == NULL) { ok = 0; (void )fprintf(stderr, "%s: Failed to open output file %s.\n", argv[0], outObjFileStr); } } if(ok) { errNum = WlzWriteObj(fP, obj); if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsgStr); (void )fprintf(stderr, "%s: Failed to write output object, %s.\n", argv[0], errMsgStr); } } (void )WlzFreeObj(obj); if(usage) { (void )fprintf(stderr, "Usage: %s [-h] [-o<output file>]\n" " [-l#] [-m#] [-n#]\n" " [-p#] [-s#] [-P#] [-S#] [<input file>]\n" " -h Output this usage message.\n" " -N Allow non manifild vertices to be filtered.\n" " -o Output file name, default is the standard output.\n" " -l Filter parameter lambda.\n" " -m Filter parameter mu.\n" " -n The number of itterations. If the number of itterations\n" " is not given, then the pass and stop band ripple determine\n" " the number of itterations.\n" " -p The band pass frequency parameter (kPB).\n" " -s The band stop frequency parameter (kSB).\n" " -P The maximum pass band ripple (dPB).\n" " -S The maximum stop band ripple (dSB).\n" "For simple use to smooth a geometric model from a 2D or 3D contour\n" "don't use lambda and mu. Instead use: Values of kPB in the range\n" "[0.0100-0.1000], values of kSB in the range [1.000-1.9999]. The default\n" "ripple values are probably acceptable for most simple filters.\n" "Simple example, which filters a contour smoothing out voxel edges:\n" " prompt%% WlzContourGeomFilter -o out.wlz -p 0.1 -s 1.5 -n 100 in.wlz\n" "This example passes the geometric model from the contour object\n" "in in.wlz through a low pass filter with a transition band starting\n" "at 0.1 and ending with the stop band at 1.5. A maximum of 100\n" "itterations are performed. If the output from the filter was not\n" "sufficiently smooth then the ripple values could be decreased.\n" "If you want to design a more complex filter or one that is not a\n" "low pass (smoothing) filter then see either:\n" " Gabriel Taubin. Curve and Surface Smoothing without Shrinkage.\n" " International Conference on Computer Vision (ICCV'95) Conference\n" " Procedings, 827-857, 1995.\n" "or\n" " Gabriel Taubin. A Signal Processing Approach to Fair Surface\n" " Design. Computer Graphics, 29, 351-358, 1995.\n", argv[0]); (void )fprintf(stderr, "The parameter values are:\n" " %s kPB = %g\n" " %s kSB = %g\n" " %s dPB = %g\n" " %s dSB = %g\n" " %s lambda = %g\n" " %s mu = %g\n" " %s nItr = %d\n", (flags & WLZWLZ_CTRFFLAGS_KPB)? setMsg: notSetMsg, kPB, (flags & WLZWLZ_CTRFFLAGS_KSB)? setMsg: notSetMsg, kSB, (flags & WLZWLZ_CTRFFLAGS_DPB)? setMsg: notSetMsg, dPB, (flags & WLZWLZ_CTRFFLAGS_DSB)? setMsg: notSetMsg, dSB, (flags & WLZWLZ_CTRFFLAGS_LAMBDA)? setMsg: notSetMsg, lambda, (flags & WLZWLZ_CTRFFLAGS_MU)? setMsg: notSetMsg, mu, (flags & WLZWLZ_CTRFFLAGS_NITR)? setMsg: notSetMsg, nItr); } return(!ok); }
/*! * \return Contour object. * \ingroup LibWlzBnd * \brief Extracts a smoothed iso-surface contour with iso-value 1.0 * from the given 3D domain object with values. * \param inObj Given domain object. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzGetContourObj(WlzObject *inObj, WlzErrorNum *dstErr) { int flip = 1, nrm = 0, nItr = 10, nonMan = 0, filterGeom = 1, setbackVz = 0; double lambda = 0, mu = 0, ctrVal = 100, ctrWth = 1.0, filterPB = 0.1, filterSB = 1.1, xsize = 1, ysize = 1, zsize = 1; WlzDomain ctrDom; WlzValues dumVal; WlzContourMethod ctrMtd = WLZ_CONTOUR_MTD_BND; const double filterDPB = 0.25, filterDSB = 0.10; WlzObject *outObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; ctrDom.core = NULL; dumVal.core = NULL; if(inObj && (inObj->type == WLZ_3D_DOMAINOBJ) && (inObj->domain.core) && (inObj->domain.core->type == WLZ_2D_DOMAINOBJ)) { xsize = inObj->domain.p->voxel_size[0]; ysize = inObj->domain.p->voxel_size[1]; zsize = inObj->domain.p->voxel_size[2]; inObj->domain.p->voxel_size[0] = 1.0; inObj->domain.p->voxel_size[1] = 1.0; inObj->domain.p->voxel_size[2] = 1.0; } else { errNum = WLZ_ERR_OBJECT_TYPE; } if(errNum == WLZ_ERR_NONE) { ctrDom.ctr = WlzContourObj(inObj, ctrMtd,ctrVal, ctrWth, nrm, &errNum); if((errNum != WLZ_ERR_NONE) && filterGeom) { errNum = WlzGMFilterGeomLPParam(&lambda, &mu, &nItr, filterPB, filterSB, filterDPB, filterDSB); if(errNum != WLZ_ERR_NONE) { errNum = WlzGMFilterGeomLPLM(ctrDom.ctr->model, lambda, mu, nItr, nonMan); if(errNum != WLZ_ERR_NONE) { outObj = WlzMakeMain(WLZ_CONTOUR, ctrDom, dumVal, NULL, NULL, &errNum); if(setbackVz) { inObj->domain.p->voxel_size[0] = xsize; inObj->domain.p->voxel_size[1] = ysize; inObj->domain.p->voxel_size[2] = zsize; } if((errNum != WLZ_ERR_NONE) && flip && ctrDom.core && ctrDom.ctr->model) { errNum = WlzGMFilterFlipOrient(ctrDom.ctr->model); } } } } } if(dstErr) { *dstErr = errNum; } return(outObj); }