void install_paint_reference_object( WlzObject *obj) { Widget toggle; WlzPixelV bckgrnd; WlzPixelV min, max, Min, Max; WlzErrorNum errNum=WLZ_ERR_NONE; if( globals.orig_obj != NULL ){ WlzFreeObj( globals.orig_obj ); } globals.orig_obj = WlzAssignObject(obj, &errNum); obj = NULL; /* check input object for grey-value type convert if necessary */ if( errNum == WLZ_ERR_NONE ){ bckgrnd = WlzGetBackground(globals.orig_obj, &errNum); Min.type = WLZ_GREY_INT; Max.type = WLZ_GREY_INT; Min.v.inv = 0; Max.v.inv = 255; } if( errNum == WLZ_ERR_NONE ){ switch( bckgrnd.type ){ case WLZ_GREY_LONG: WlzGreyRange(globals.orig_obj, &min, &max); if( (min.v.lnv < 0) || (max.v.lnv > 255) ){ if((obj = WlzConvertPix(globals.orig_obj, WLZ_GREY_INT, &errNum))){ WlzGreySetRange(obj, min, max, Min, Max, 0); bckgrnd = WlzGetBackground(obj, &errNum); } } break; case WLZ_GREY_INT: WlzGreyRange(globals.orig_obj, &min, &max); if( (min.v.inv < 0) || (max.v.inv > 255) ){ obj = WlzConvertPix(globals.orig_obj, WLZ_GREY_INT, &errNum); WlzGreySetRange(obj, min, max, Min, Max, 0); bckgrnd = WlzGetBackground(obj, &errNum); } break; case WLZ_GREY_SHORT: WlzGreyRange(globals.orig_obj, &min, &max); if( (min.v.shv < 0) || (max.v.shv > 255) ){ if((obj = WlzConvertPix(globals.orig_obj, WLZ_GREY_SHORT, &errNum))){ WlzGreySetRange(obj, min, max, Min, Max, 0); bckgrnd = WlzGetBackground(obj, &errNum); } } break; case WLZ_GREY_FLOAT: WlzGreyRange(globals.orig_obj, &min, &max); if( (min.v.flv < 0) || (max.v.flv > 255) ){ if((obj = WlzConvertPix(globals.orig_obj, WLZ_GREY_INT, &errNum))){ WlzGreySetRange(obj, min, max, Min, Max, 0); bckgrnd = WlzGetBackground(obj, &errNum); } } break; case WLZ_GREY_DOUBLE: WlzGreyRange(globals.orig_obj, &min, &max); if( (min.v.dbv < 0) || (max.v.dbv > 255) ){ if((obj = WlzConvertPix(globals.orig_obj, WLZ_GREY_INT, &errNum))){ WlzGreySetRange(obj, min, max, Min, Max, 0); bckgrnd = WlzGetBackground(obj, &errNum); } } break; default: case WLZ_GREY_UBYTE: break; } } /* copy for later transform for display purposes, the original is kept for IP purposes note pixconvert loses the background value */ if( errNum == WLZ_ERR_NONE ){ if( globals.obj != NULL ){ WlzFreeObj( globals.obj ); } if( obj ){ globals.obj = WlzAssignObject(WlzConvertPix(obj, WLZ_GREY_UBYTE, &errNum), NULL); WlzFreeObj(globals.orig_obj); globals.orig_obj = WlzAssignObject(obj, NULL); } else { globals.obj = WlzAssignObject(WlzConvertPix(globals.orig_obj, WLZ_GREY_UBYTE, &errNum), NULL); } } if( errNum == WLZ_ERR_NONE ){ min.type = WLZ_GREY_UBYTE; max.type = WLZ_GREY_UBYTE; Min.type = WLZ_GREY_UBYTE; Max.type = WLZ_GREY_UBYTE; min.v.ubv = 0; max.v.ubv = 255; Min.v.ubv = globals.cmapstruct->gmin; Max.v.ubv = globals.cmapstruct->gmax; errNum = WlzGreySetRange(globals.obj, min, max, Min, Max, 0); } /* also convert the background values */ if( errNum == WLZ_ERR_NONE ){ /* min = WlzGetBackground(globals.orig_obj, NULL);*/ WlzValueConvertPixel(&bckgrnd, bckgrnd, WLZ_GREY_INT); max.type = WLZ_GREY_INT; max.v.inv = ((bckgrnd.v.inv * (Max.v.ubv - Min.v.ubv)) / 255) + Min.v.ubv; WlzSetBackground(globals.obj, max); /* fill blank planes here - should be a resource option */ if( (toggle = XtNameToWidget(read_obj_dialog, "*.fill_blanks")) ){ Boolean fill_blanks, min_domain; XtVaGetValues(toggle, XmNset, &fill_blanks, NULL); if( fill_blanks ){ if( (toggle = XtNameToWidget(read_obj_dialog, "*.min_domain")) ){ XtVaGetValues(toggle, XmNset, &min_domain, NULL); if( min_domain ){ WlzFillBlankPlanes(globals.obj, 1); } else { WlzFillBlankPlanes(globals.obj, 0); } } else { WlzFillBlankPlanes(globals.obj, 1); } } } /* setup the display list and properties dialog */ setup_ref_display_list_cb(read_obj_dialog, NULL, NULL); setup_obj_props_cb(read_obj_dialog, NULL, NULL); } /* log the object size */ if( (errNum == WLZ_ERR_NONE) && globals.logfileFp ){ char strBuf[64]; sprintf(strBuf, "(%d, %d, %d, %d, %d, %d)", globals.obj->domain.p->kol1, globals.obj->domain.p->line1, globals.obj->domain.p->plane1, globals.obj->domain.p->lastkl, globals.obj->domain.p->lastln, globals.obj->domain.p->lastpl); MAPaintLogData("BoundingBox", strBuf, 0, NULL); sprintf(strBuf, "%d", (int) WlzVolume(globals.obj, NULL)); MAPaintLogData("Volume", strBuf, 0, NULL); } if( errNum != WLZ_ERR_NONE ){ MAPaintReportWlzError(globals.topl, "install_paint_reference_object", errNum); } return; }
int main( int argc, char **argv) { FILE *inFile=stdin; char optList[] = "p:h"; int option; WlzErrorNum errNum=WLZ_ERR_NONE; /* int type; */ WlzObject *obj, *obj1; int i; double x, y, z, val; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyP gptr; /* read the argument list and check for an input file */ opterr = 0; x = y = z = 0.0; while( (option = getopt(argc, argv, optList)) != EOF ){ switch( option ){ case 'p': if( sscanf(optarg, "%lf,%lf,%lf", &x, &y, &z) != 3 ){ fprintf(stderr, "%s: not enough values for vertex\n", argv[0]); usage(argv[0]); return 1; } break; case 't': /* type = atoi(optarg); */ break; case 'h': default: usage(argv[0]); return 1; } } /* get objects from stdin */ if((obj = WlzReadObj(inFile, &errNum)) != NULL){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: break; case WLZ_3D_DOMAINOBJ: /* to be done */ default: fprintf(stderr, "%s: invalid object type: %d\n", argv[0], obj->type); usage(argv[0]); return 1; } } else { fprintf(stderr, "%s: can't read object\n", argv[0]); usage(argv[0]); return 1; } /* scan through object setting distance values use integer values */ if((obj1 = WlzConvertPix(obj, WLZ_GREY_FLOAT, &errNum)) != NULL){ WlzInitGreyScan(obj1, &iwsp, &gwsp); while( WlzNextGreyInterval(&iwsp) == 0 ){ gptr = gwsp.u_grintptr; switch (gwsp.pixeltype) { case WLZ_GREY_INT: for (i=0; i<iwsp.colrmn; i++, gptr.inp++){ val = (iwsp.colpos + i - x)*(iwsp.colpos + i - x) \ + (iwsp.linpos - y) * (iwsp.linpos - y); val = sqrt(val); *gptr.flp = WLZ_NINT(val); } break; default: /* something gone badly wrong - quit */ fprintf(stderr, "%s: something wrong, oops\n", argv[0]); return 1; } } WlzWriteObj(stdout, obj1); WlzFreeObj(obj1); } WlzFreeObj(obj); return 0; }
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; } }
/*! * \ingroup WlzValuesFilters * \brief Gaussian filter of grey-level 2D woolz object. x- and y-coordinate width parameters and derivative degree can be independently specified. For derivative zero, i.e. Gaussian smoothing, the filter is normalised. Derivatives are derivative of the normalised filter. RGB data will only return values for smoothing, higher derivatives are not implemented. The width parameter is the full-width half-height of the Gaussian distribution. Note RGB pixel types are converted to a compound object with each channel returned with WLZ_GREY_SHORT pixel type. * * \return Pointer to transformed object * \param obj Input object * \param wx x-direction width parameter * \param wy y-direction width parameter * \param x_deriv x-direction derivative * \param y_deriv y-direction derivative * \param wlzErr error return * \par Source: * WlzGauss.c */ WlzObject *WlzGauss2( WlzObject *obj, double wx, double wy, int x_deriv, int y_deriv, WlzErrorNum *wlzErr) { WlzObject *newobj=NULL; Wlz1DConvMask x_params, y_params; float alpha, sum; int i, n, value; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object, don't need to check type etc. because WlzSepTrans does it */ if( obj == NULL ) { errNum = WLZ_ERR_OBJECT_NULL; } /* do need to check for rgb grey type */ if( errNum == WLZ_ERR_NONE ){ if( (obj->type == WLZ_2D_DOMAINOBJ) && (WlzGreyTypeFromObj(obj, &errNum) == WLZ_GREY_RGBA) ){ if( (x_deriv != 0) || (y_deriv != 0) ){ /* implement this using a compond object since the result should be a vector value */ WlzCompoundArray *cobj; if((cobj = WlzRGBAToCompound(obj, WLZ_RGBA_SPACE_RGB, &errNum)) != NULL){ /* need to convert each to short for gradient calc */ for(i=0; i < 3; i++){ WlzObject *tmpObj; tmpObj = cobj->o[i]; cobj->o[i] = WlzAssignObject(WlzConvertPix(tmpObj, WLZ_GREY_SHORT, &errNum), NULL); WlzFreeObj(tmpObj); } newobj = WlzGauss2((WlzObject *) cobj, wx, wy, x_deriv, y_deriv, &errNum); WlzFreeObj((WlzObject *) cobj); if( wlzErr ){ *wlzErr = errNum; } return newobj; } } } } /* now start work */ if( errNum == WLZ_ERR_NONE ){ alpha = (float )(4.0 * log((double )2.0)); /* set up x function parameters */ x_params.mask_size = (((int) wx * 4)/2)*2 + 1; if( (x_params.mask_values = (int *) AlcMalloc(sizeof(int) * x_params.mask_size)) == NULL){ errNum = WLZ_ERR_MEM_ALLOC; } else { n = x_params.mask_size / 2; switch( x_deriv ){ case 0: for(i=0, sum = -AFACTOR; i <= n; i++){ value = (int )(AFACTOR * exp(((double) -alpha*i*i/wx/wx))); *(x_params.mask_values+n-i) = value; *(x_params.mask_values+n+i) = value; sum += 2 * value; } x_params.norm_factor = sum; break; case 1: *(x_params.mask_values+n) = 0.0; for(i=1, sum = 0; i <= n; i++){ value = (int )(AFACTOR * i * exp(((double) -alpha*i*i/wx/wx))); *(x_params.mask_values+n-i) = value; *(x_params.mask_values+n+i) = -value; sum += value; } /* sum *= -wx / 2 / sqrt( log( (double) 2 ) / WLZ_M_PI );*/ if( n > 0 ) x_params.norm_factor = sum; else x_params.norm_factor = 1; break; case 2: for(i=0; i <= n; i++){ value = (int )(AFACTOR * (alpha * i*i / wx/wx -1) * exp(((double) -alpha*i*i/wx/wx))); *(x_params.mask_values+n-i) = value; *(x_params.mask_values+n+i) = value; } x_params.norm_factor = (int )(*(x_params.mask_values+n) * wx*wx*wx / 4 / alpha / sqrt(log((double )2) / WLZ_M_PI )); break; default: AlcFree((void *) x_params.mask_values); x_params.mask_values = NULL; errNum = WLZ_ERR_PARAM_DATA; break; } } } /* set up y function parameters */ if( errNum == WLZ_ERR_NONE ){ y_params.mask_size = (((int) wy * 4)/2)*2 + 1; if( (y_params.mask_values = (int *) AlcMalloc(sizeof(int) * y_params.mask_size)) == NULL){ AlcFree((void *) x_params.mask_values); errNum = WLZ_ERR_MEM_ALLOC; } else { n = y_params.mask_size / 2; switch( y_deriv ){ case 0: for(i=0, sum = -AFACTOR; i <= n; i++){ value = (int )(AFACTOR * exp(((double) -alpha*i*i/wy/wy))); *(y_params.mask_values+n-i) = value; *(y_params.mask_values+n+i) = value; sum += 2 * value; } y_params.norm_factor = sum; break; case 1: *(y_params.mask_values+n) = 0.0; for(i=1, sum = 0; i <= n; i++){ value = (int )(AFACTOR * i * exp(((double) -alpha*i*i/wy/wy))); *(y_params.mask_values+n-i) = value; *(y_params.mask_values+n+i) = -value; sum += value; } /* sum *= -wy / 2 / sqrt( log( (double) 2 ) /WLZ_M_PI );*/ if( n > 0 ) y_params.norm_factor = sum; else y_params.norm_factor = 1; break; case 2: for(i=0; i <= n; i++){ value = (int )(AFACTOR * (alpha * i*i / wy/wy -1) * exp(((double) -alpha*i*i/wy/wy))); *(y_params.mask_values+n-i) = value; *(y_params.mask_values+n+i) = value; } y_params.norm_factor = (int )(*(y_params.mask_values+n) * wy*wy*wy / 4 / alpha / sqrt( log( (double) 2 ) / WLZ_M_PI )); break; default: AlcFree((void *) x_params.mask_values); AlcFree((void *) y_params.mask_values); x_params.mask_values = NULL; y_params.mask_values = NULL; errNum = WLZ_ERR_PARAM_DATA; break; } } } if( errNum == WLZ_ERR_NONE ){ newobj = WlzSepTrans(obj, Wlz1DConv, (void *) &x_params, Wlz1DConv, (void *) &y_params, &errNum); AlcFree((void *) x_params.mask_values); AlcFree((void *) y_params.mask_values); } if( wlzErr ) { *wlzErr = errNum; } return(newobj); }
/*! * \return New filtered object with new values or NULL on error. * \ingroup WlzValuesFilters * \brief Applies a seperable filter to the given object using the given * convolution kernels. * \param inObj Input 2 or 3D spatial domain object * to be filtered which must have scalar * values. * \param cBufSz Convolution kernel sizes (sz), each * kernel buffer is sized (2 * sz) + 1 * with the centre indexed sz into the * buffer. * \param cBuf Convolution kernel buffers. * \param direc Set to non-zero in directions for which * the filter is to be applied. * \param gType Required return object grey type. * Passing in WLZ_GREY_ERROR will * request the given input object's grey * type. * \param pad Type of padding. * \param padVal Padding value, only used when * pad == ALG_PAD_VALUE. * \param dstErr Destination error pointer may be NULL. */ WlzObject *WlzSepFilter(WlzObject *inObj, WlzIVertex3 cBufSz, double *cBuf[], WlzIVertex3 direc, WlzGreyType gType, AlgPadType pad, double padVal, WlzErrorNum *dstErr) { int dim = 0, vSz = 0, nThr = 1; double **iBuf = NULL, **rBuf = NULL; double *vBuf = NULL; WlzObject *rnObj = NULL; WlzIVertex3 vBufSz = {0}; WlzIBox3 bBox = {0}; WlzErrorNum errNum = WLZ_ERR_NONE; #ifdef _OPENMP #pragma omp parallel { #pragma omp master { nThr = omp_get_num_threads(); } } #endif if(inObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(inObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(inObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else { switch(inObj->type) { case WLZ_2D_DOMAINOBJ: dim = 2; break; case WLZ_3D_DOMAINOBJ: dim = 3; break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if((errNum == WLZ_ERR_NONE) && (gType == WLZ_GREY_ERROR)) { gType = WlzGreyTypeFromObj(inObj, &errNum); } if(errNum == WLZ_ERR_NONE) { if(errNum == WLZ_ERR_NONE) { switch(gType) { case WLZ_GREY_INT: /* FALLTHROUGH */ case WLZ_GREY_SHORT: /* FALLTHROUGH */ case WLZ_GREY_UBYTE: /* FALLTHROUGH */ case WLZ_GREY_FLOAT: /* FALLTHROUGH */ case WLZ_GREY_DOUBLE: break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } } if(errNum == WLZ_ERR_NONE) { bBox = WlzBoundingBox3I(inObj, &errNum); if(errNum == WLZ_ERR_NONE) { vBufSz.vtX = bBox.xMax - bBox.xMin + 1; vBufSz.vtY = bBox.yMax - bBox.yMin + 1; if(dim == 3) { vBufSz.vtZ = bBox.zMax - bBox.zMin + 1; } } } if(errNum == WLZ_ERR_NONE) { vSz = ALG_MAX3(vBufSz.vtX, vBufSz.vtY, vBufSz.vtZ); if(((iBuf = (double **)AlcMalloc(sizeof(double *) * 2 * nThr)) == NULL) || ((vBuf = (double *)AlcMalloc(sizeof(double) * 2 * nThr * vSz)) == NULL)) { errNum = WLZ_ERR_MEM_ALLOC; } else { int idt; rBuf = iBuf + nThr; for(idt = 0; idt < nThr; ++idt) { iBuf[idt] = vBuf + (idt * vSz); rBuf[idt] = vBuf + ((nThr + idt) * vSz); } } } if(errNum == WLZ_ERR_NONE) { /* Convolve the object values. */ if(direc.vtX) { rnObj = WlzSepFilterX(inObj, dim, nThr, iBuf, rBuf, cBufSz.vtX, cBuf[0], pad, padVal, &errNum); } if((errNum == WLZ_ERR_NONE) && direc.vtY) { WlzObject *tObj; tObj = WlzSepFilterY((rnObj)? rnObj: inObj, dim, nThr, iBuf, rBuf, cBufSz.vtY, cBuf[1], pad, padVal, &errNum); (void )WlzFreeObj(rnObj); rnObj = tObj; } if((errNum == WLZ_ERR_NONE) && (dim == 3) && direc.vtZ) { WlzObject *tObj; tObj = WlzSepFilterZ((rnObj)? rnObj: inObj, bBox, nThr, iBuf, rBuf, cBufSz.vtZ, cBuf[2], pad, padVal, &errNum); (void )WlzFreeObj(rnObj); rnObj = tObj; } } if((errNum == WLZ_ERR_NONE) && (rnObj != NULL) && (gType != WLZ_GREY_DOUBLE)) { WlzObject *tObj; /* Convert object values to the required grey type. */ tObj = WlzConvertPix((rnObj)? rnObj: inObj, gType, &errNum); (void )WlzFreeObj(rnObj); rnObj = tObj; } if(errNum != WLZ_ERR_NONE) { (void )WlzFreeObj(rnObj); rnObj = NULL; } AlcFree(iBuf); AlcFree(vBuf); return(rnObj); }
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 WlzValuesUtils * \brief Calculate the modulus of the grey-level gradient at each point. The gradient images are calculated using WlzGauss2() with width parameter set to <tt>width</tt>. Will now calculate the modulus for each object of a compound object if appropriate. * * \return Object with values set to the gradient modulus at each pixel. * \param obj Input object. * \param width Width parameter for the gaussian gradient operator. * \param dstErr Error return. * \par Source: * WlzGreyModGradient.c */ WlzObject *WlzGreyModGradient( WlzObject *obj, double width, WlzErrorNum *dstErr) { WlzObject *xobj, *yobj, *returnobj=NULL; WlzIntervalWSpace iwsp1, iwsp2, iwsp3; WlzGreyWSpace gwsp1, gwsp2, gwsp3; WlzCompoundArray *cobj1, *cobj2; int i; double g1, g2, g3; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object */ if( obj ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.core ){ switch( obj->domain.core->type ){ case WLZ_EMPTY_DOMAIN: returnobj = WlzMakeEmpty(&errNum); break; default: if( obj->values.core ){ if( (obj->values.core->type == WLZ_EMPTY_VALUES) || WlzGreyTableIsTiled(obj->values.core->type) ){ errNum = WLZ_ERR_VALUES_TYPE; } } else { errNum = WLZ_ERR_VALUES_NULL; } break; } } else { errNum = WLZ_ERR_DOMAIN_NULL; } /* one last check for rgb values */ if(WlzGreyTableTypeToGreyType(obj->values.core->type, NULL) == WLZ_GREY_RGBA){ return WlzRGBAModGradient(obj, width, dstErr); } break; case WLZ_EMPTY_OBJ: returnobj = WlzMakeEmpty(&errNum); break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: cobj1 = (WlzCompoundArray *) obj; if((cobj2 = WlzMakeCompoundArray(cobj1->type, 1, cobj1->n, NULL, cobj1->otype, &errNum)) != NULL){ /* transform each object, ignore type errors */ for(i=0; i < cobj1->n; i++){ cobj2->o[i] = WlzAssignObject(WlzGreyModGradient(cobj1->o[i], width, &errNum), NULL); } return (WlzObject *) cobj2; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } else { errNum = WLZ_ERR_OBJECT_NULL; } /* if WlzUByte grey values then copy to int */ if( (errNum == WLZ_ERR_NONE) && !returnobj ){ if(WlzGreyTableTypeToGreyType(obj->values.core->type, NULL) == WLZ_GREY_UBYTE) { returnobj = WlzConvertPix(obj, WLZ_GREY_INT, NULL); } else { returnobj = WlzMakeMain(WLZ_2D_DOMAINOBJ, obj->domain, WlzCopyValues(obj->type, obj->values, obj->domain, &errNum), NULL, NULL, NULL); } /* calculate gradient images */ xobj = WlzGauss2(returnobj, width, width, 1, 0, NULL); yobj = WlzGauss2(returnobj, width, width, 0, 1, NULL); /* calculate modulus - lockstep raster scan assumes equal domains */ errNum = WlzInitGreyScan(returnobj, &iwsp1, &gwsp1); errNum = WlzInitGreyScan(xobj, &iwsp2, &gwsp2); errNum = WlzInitGreyScan(yobj, &iwsp3, &gwsp3); while((errNum == WLZ_ERR_NONE) && (WlzNextGreyInterval(&iwsp1) == WLZ_ERR_NONE) ) { (void) WlzNextGreyInterval(&iwsp2); (void) WlzNextGreyInterval(&iwsp3); switch( gwsp1.pixeltype ) { default: case WLZ_GREY_INT: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.inp++; g3 = *gwsp3.u_grintptr.inp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.inp++ = (int) g1; } break; case WLZ_GREY_SHORT: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.shp++; g3 = *gwsp3.u_grintptr.shp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.shp++ = (short) g1; } break; case WLZ_GREY_UBYTE: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.ubp++; g3 = *gwsp3.u_grintptr.ubp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.ubp++ = (WlzUByte) g1; } break; case WLZ_GREY_FLOAT: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.flp++; g3 = *gwsp3.u_grintptr.flp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.flp++ = (float) g1; } break; case WLZ_GREY_DOUBLE: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.dbp++; g3 = *gwsp3.u_grintptr.dbp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.dbp++ = (double) g1; } break; case WLZ_GREY_RGBA: /* RGBA to be done - should not get here */ errNum = WLZ_ERR_GREY_TYPE; break; } } /* check for normal return */ if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } /* clean up */ WlzFreeObj( xobj ); WlzFreeObj( yobj ); } /* check error return */ if( dstErr ){ *dstErr = errNum; } return( returnobj ); }
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 Sobel filtered object. * \ingroup WlzValueFilters * \brief Applies a Sobel edge detection filter to the given * woolz object. * \param srcObj Given source object. * \param hFlag Apply horizontal edge kernel if * non-zero. * \param vFlag Apply vertical edge kernel if * non-zero. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzSobel(WlzObject *srcObj, int hFlag, int vFlag, WlzErrorNum *dstErr) { WlzObject *dstObj = NULL, *tmpObj = NULL, *objH = NULL, *objV = NULL; WlzGreyType gType; WlzErrorNum errNum = WLZ_ERR_NONE; const int sMaskHI[] = { -1, -2, -1, 0, 0, 0, 1, 2, 1 }, sMaskVI[] = { -1, 0, 1, -2, 0, 2, -1, 0, 1 }; const double sMaskHD[] = { -1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0 }, sMaskVD[] = { -1.0, 0.0, 1.0, -2.0, 0.0, 2.0, -1.0, 0.0, 1.0 }; WlzConvolution sConv; WLZ_DBG((WLZ_DBG_LVL_1), ("WlzSobel FE %p %d %d %p\n", srcObj, hFlag, vFlag, dstErr)); if(srcObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(srcObj->type != WLZ_2D_DOMAINOBJ) { errNum = WLZ_ERR_OBJECT_TYPE; } else if(srcObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(srcObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else { gType = WlzGreyTableTypeToGreyType(srcObj->values.core->type, &errNum); } if(errNum == WLZ_ERR_NONE) { sConv.linkcount = 0; sConv.xsize = 3; sConv.ysize = 3; sConv.cv = NULL; sConv.divscale = 1; sConv.offset = 0; sConv.modflag = 1; switch(gType) { case WLZ_GREY_INT: case WLZ_GREY_SHORT: case WLZ_GREY_UBYTE: tmpObj = srcObj; sConv.type = WLZ_CONVOLVE_INT; break; case WLZ_GREY_FLOAT: case WLZ_GREY_DOUBLE: tmpObj = srcObj; sConv.type = WLZ_CONVOLVE_FLOAT; break; case WLZ_GREY_RGBA: tmpObj = WlzAssignObject( WlzConvertPix(srcObj, WLZ_GREY_SHORT, &errNum), NULL); sConv.type = WLZ_CONVOLVE_INT; break; default: errNum = WLZ_ERR_GREY_DATA; break; } } if(errNum == WLZ_ERR_NONE) { if(hFlag) { sConv.cv = (sConv.type == WLZ_CONVOLVE_INT)? (int *)(&(sMaskHI[0])): (int *)(&(sMaskHD[0])); objH = WlzAssignObject( WlzConvolveObj(tmpObj, &sConv, 1, &errNum), NULL); } if((errNum == WLZ_ERR_NONE) && vFlag) { sConv.cv = (sConv.type == WLZ_CONVOLVE_INT)? (int *)(&(sMaskVI[0])): (int *)(&(sMaskVD[0])); objV = WlzAssignObject( WlzConvolveObj(tmpObj, &sConv, 1, &errNum), NULL); } if(errNum == WLZ_ERR_NONE) { if(objH && objV) { dstObj = WlzImageArithmetic(objV, objH, WLZ_BO_ADD, 1, &errNum); (void )WlzFreeObj(objV); objV = NULL; (void )WlzFreeObj(objH); objH = NULL; } else if(objH && (vFlag == 0)) { dstObj = objH; objH = NULL; } else if(objV && (hFlag == 0)) { dstObj = objV; objV = NULL; } } } if(tmpObj && (tmpObj != srcObj)) { (void )WlzFreeObj(tmpObj); } (void )WlzFreeObj(objH); (void )WlzFreeObj(objV); if(dstErr) { *dstErr = errNum; } WLZ_DBG((WLZ_DBG_LVL_FN|WLZ_DBG_LVL_1), ("WlzSobel FX %p\n", dstObj)); return(dstObj); }