/*! * \return Error code. * \ingroup AlcArray * \brief Allocates a 1 dimensional zero'd array of pointers to void. * \note Should be free'd using AlcFree(). * \note Array size is limited only by address space. * \param dest Destination for allocated array * pointer. * \param mElem Number of elements in array. */ AlcErrno AlcPtr1Calloc(void ***dest, size_t mElem) { AlcErrno alcErrno = ALC_ER_NONE; /* Template doesn't work for pointer types. */ if((dest) == NULL) { alcErrno = ALC_ER_NULLPTR; } else if(mElem < 1) { alcErrno = ALC_ER_NUMELEM; } else if((*(dest) = (void **)AlcCalloc(mElem, sizeof(void *))) == NULL) { alcErrno = ALC_ER_ALLOC; } if(alcErrno != ALC_ER_NONE) { if(dest) { *(dest) = NULL; } } return(alcErrno); }
/*! * \return New Amira file header data structure or NULLon error. * \ingroup WlzExtFF * \brief Allocates a new Amira file header data structure with * all fields cleared. * \param <void> */ static WlzEffAmHead *WlzEffAmNewHead(void) { WlzEffAmHead *head; head = AlcCalloc(1, sizeof(WlzEffAmHead)); return(head); }
/*! * \return Error code. * \ingroup AlcArray * \brief Allocates a 3 dimensional array of pointers to void. * \note Should be free'd using Alc3Free(). * \note Array size is limited only by address space. * \param dest Destination for allocated array * pointer. * \param mElem Number of 2D arrays. * \param nElem Number of 1D arrays. * \param oElem Number of elements in each 1D * array. */ AlcErrno AlcPtr3Calloc(void *****dest, size_t mElem, size_t nElem, size_t oElem) { size_t index0, index1; void **dump0 = NULL, ***dump1 = NULL, ****dump2 = NULL; AlcErrno alcErrno = ALC_ER_NONE; if((dest) == NULL) { alcErrno = ALC_ER_NULLPTR; } else if((mElem < 1) || (nElem < 1) || (oElem < 1)) { alcErrno = ALC_ER_NUMELEM; } else if(((dump0 = (void **)AlcCalloc(mElem * nElem * oElem, sizeof(void *))) == NULL) || ((dump1 = (void ***)AlcMalloc(mElem * nElem * sizeof(void **))) == NULL) || ((dump2 = (void ****)AlcMalloc(mElem * sizeof(void ***))) == NULL)) { alcErrno = ALC_ER_ALLOC; } if(alcErrno == ALC_ER_NONE) { *(dest) = dump2; for(index0 = 0; index0 < mElem; ++index0) { for(index1=0; index1 < nElem; ++index1) { dump1[index1] = dump0; dump0 += oElem; } (*(dest))[index0] = dump1; dump1 += nElem; } } else { if(dest) { *(dest) = NULL; } AlcFree(dump2); AlcFree(dump1); AlcFree(dump0); } return(alcErrno); }
/*! * \return KD-tree data structure, or NULL on error. * \ingroup AlcKDTree * \brief Creates a KD-tree data structure. * \param type Type of tree node key. * \param dim Dimension of tree (must be >= 1). * \param tol Tollerance for key comparision, * only used if the tree has floating * point keys. If the tolerance is * negative it is set to a default * value. * \param nNodes Expected number of nodes in the * tree, 0 if unknown. This * can be used to optimise node * allocation. * \param dstErr Destination pointer for error * code, may be NULL. */ AlcKDTTree *AlcKDTTreeNew(AlcPointType type, int dim, double tol, size_t nNodes, AlcErrno *dstErr) { size_t keySz; AlcKDTTree *tree = NULL; AlcErrno errNum = ALC_ER_NONE; const size_t minNodeBlockSz = 1024; const double defTol = 1.0E-06; if(dim < 1) { errNum = ALC_ER_PARAM; } else { switch(type) { case ALC_POINTTYPE_INT: keySz = sizeof(int) * dim; break; case ALC_POINTTYPE_DBL: keySz = sizeof(double) * dim; break; default: errNum = ALC_ER_PARAM; break; } } if(errNum == ALC_ER_NONE) { if((tree = (AlcKDTTree *)AlcCalloc(1, sizeof(AlcKDTTree))) == NULL) { errNum = ALC_ER_ALLOC; } else { tree->type = type; tree->dim = dim; tree->keySz = keySz; tree->tol = (tol < 0.0)? defTol: tol; if((tree->nodeBlockSz = nNodes / 10) < minNodeBlockSz) { tree->nodeBlockSz = minNodeBlockSz; } } } if(dstErr) { *dstErr = errNum; } return(tree); }
/*! * \return New affine transform initialized to the identity transform. * \ingroup WlzTransform * \brief Allocates and initialises space for a 2D or 3D affine * transform. Sufficient space is always allocated for a * 3D transform. * The transform should be freed using WlzFreeAffineTransform(). * \param type Transform type. * \param dstErr Destination error pointer, may * be null. */ WlzAffineTransform *WlzMakeAffineTransform(WlzTransformType type, WlzErrorNum *dstErr) { WlzAffineTransform *trans=NULL; WlzErrorNum errNum = WLZ_ERR_NONE; switch(type) { case WLZ_TRANSFORM_2D_AFFINE: case WLZ_TRANSFORM_2D_REG: case WLZ_TRANSFORM_2D_TRANS: case WLZ_TRANSFORM_2D_NOSHEAR: case WLZ_TRANSFORM_3D_AFFINE: case WLZ_TRANSFORM_3D_REG: case WLZ_TRANSFORM_3D_TRANS: case WLZ_TRANSFORM_3D_NOSHEAR: break; default: errNum = WLZ_ERR_TRANSFORM_TYPE; break; } if(errNum == WLZ_ERR_NONE) { if(((trans = (WlzAffineTransform *) AlcCalloc(1, sizeof(WlzAffineTransform))) == NULL) || (AlcDouble2Calloc(&trans->mat, 4, 4) != ALC_ER_NONE)) { if(trans) { AlcFree(trans); trans = NULL; } errNum = WLZ_ERR_MEM_ALLOC; } } if(errNum == WLZ_ERR_NONE) { trans->type = type; /* Initialize to the identity transform */ trans->mat[0][0] = 1.0; trans->mat[1][1] = 1.0; trans->mat[2][2] = 1.0; trans->mat[3][3] = 1.0; } if(dstErr) { *dstErr = errNum; } return(trans); }
/*! * \return Error code. * \ingroup AlcArray * \brief Allocates a 2 dimensional zero'd array of pointers to void. * \note Should be free'd using Alc2Free(). * \note Array size is limited only by address space. * \param dest Destination for allocated array * pointer. * \param mElem Number of 1D arrays. * \param nElem Number of elements in each 1D * array. */ AlcErrno AlcPtr2Calloc(void ****dest, size_t mElem, size_t nElem) { size_t index; void **dump0 = NULL; void ***dump1 = NULL; AlcErrno alcErrno = ALC_ER_NONE; /* Template doesn't work for pointer types. */ if(dest == NULL) { alcErrno = ALC_ER_NULLPTR; } else if((mElem < 1) || (nElem < 1)) { alcErrno = ALC_ER_NUMELEM; } else if(((dump0 = (void **)AlcCalloc(mElem * nElem, sizeof(void *))) == NULL) || ((dump1 = (void ***)AlcMalloc(mElem * sizeof(void **))) == NULL)) { alcErrno = ALC_ER_ALLOC; } if(alcErrno == ALC_ER_NONE) { *dest = dump1; for(index = 0; index < mElem; ++index) { (*dest)[index] = dump0; dump0 += nElem; } } else { if(dest) { *dest = NULL; } if(dump0) { AlcFree(dump0); } if(dump1) { AlcFree(dump1); } } return(alcErrno); }
/*! * \return Duplicated section, NULL on error. * \ingroup Reconstruct * \brief Duplicates the given section. * \param sec Section to be duplicated. */ RecSection *RecSecDup(RecSection *sec) { RecSection *newSec = NULL; WlzErrorNum wlzErr = WLZ_ERR_NONE; REC_DBG((REC_DBG_SEC|REC_DBG_LVL_FN|REC_DBG_LVL_1), ("RecSecDup FE 0x%lx\n", (unsigned long )sec)); if(sec) { if(((newSec = (RecSection *)AlcCalloc(1, sizeof(RecSection))) != NULL) && sec->imageFile && ((newSec->imageFile = AlcStrDup(sec->imageFile)) != NULL) && sec->transform && ((newSec->transform = WlzAssignAffineTransform( WlzAffineTransformFromMatrix(sec->transform->type, sec->transform->mat, &wlzErr), NULL)) != NULL) && (wlzErr == WLZ_ERR_NONE)) { newSec->index = sec->index; newSec->iterations = sec->iterations; newSec->correl = sec->correl; } else { if(newSec) { if(newSec->imageFile) { AlcFree(newSec->imageFile); } AlcFree(newSec); newSec = NULL; } } } REC_DBG((REC_DBG_SEC|REC_DBG_LVL_FN|REC_DBG_LVL_1), ("RecSecDup FX 0x%lx\n", (unsigned long )newSec)); return(newSec); }
/*! * \return New secton list or NULL on error. * \ingroup Reconstruct * \brief Creates a new empty section list with default settings. * \param dstErr Destination error pointer, may * be NULL. */ RecSectionList *RecSecNewSectionList(RecError *dstErr) { RecSectionList *newSecList = NULL; RecError errFlag = REC_ERR_NONE; if((newSecList = (RecSectionList *) AlcCalloc(1, sizeof(RecSectionList))) == NULL) { errFlag = REC_ERR_MALLOC; } else { /* Set fields to default values. */ newSecList->list = NULL; newSecList->attributes.trMode = REC_TRMODE_REL; newSecList->attributes.currentItem = NULL; RecSecRecSetDefaults(&(newSecList->reconstruction)); } if(dstErr) { *dstErr = errFlag; } return(newSecList); }
/*! * \ingroup WlzAllocation * \brief Make in interval values table to match the input object The table will have linkcount set to zero. * * \return New interval values table. * \param type Required table type. * \param obj Input object. * \param bckgrnd Values table background value. * \param dstErr Error return. * \par Constraints The woolz object type must resolve to WLZ_GREY_TAB_INTL using WlzGreyTableTypeToTableType()or an error will be reported and NULL returned. For historical reasons the type encodes the table type as well as the grey-value type. * \par Source: * WlzMakeIntervalValues.c */ WlzIntervalValues * WlzMakeIntervalValues(WlzObjectType type, WlzObject *obj, WlzPixelV bckgrnd, WlzErrorNum *dstErr) { WlzValues v; WlzValueIntervalLine *vil; WlzValueLine *val; WlzGreyP g; WlzIntervalWSpace iwsp; WlzIntervalDomain *idom; WlzErrorNum errNum=WLZ_ERR_NONE; /* check the values table type */ v.i = NULL; (void) WlzGreyTableTypeToTableType(type, &errNum); if( errNum == WLZ_ERR_NONE ){ (void) WlzGreyTableTypeToGreyType(type, &errNum); } /* check the object */ if( (errNum == WLZ_ERR_NONE) && (obj == NULL) ){ errNum = WLZ_ERR_OBJECT_NULL; } if( errNum == WLZ_ERR_NONE ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; break; } idom = obj->domain.i; break; case WLZ_EMPTY_OBJ: default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } } /* * allocate space for basic, per line and per interval structures */ if((errNum == WLZ_ERR_NONE) && ((v.i = (WlzIntervalValues *) AlcCalloc(sizeof(WlzIntervalValues) + (idom->lastln - idom->line1 + 1) * sizeof(WlzValueIntervalLine) + WlzIntervalCount(idom, NULL) * sizeof(WlzValueLine), 1)) == NULL) ){ errNum = WLZ_ERR_MEM_ALLOC; } if( errNum == WLZ_ERR_NONE ){ vil = (WlzValueIntervalLine *) (v.i + 1); val = (WlzValueLine *) (vil + idom->lastln - idom->line1 + 1); v.i->bckgrnd = bckgrnd; switch( WlzGreyTableTypeToGreyType(type, NULL) ){ case WLZ_GREY_INT: g.inp = (int *) AlcCalloc(WlzArea(obj, NULL), sizeof(int)); break; case WLZ_GREY_SHORT: g.shp = (short *) AlcCalloc(WlzArea(obj, NULL), sizeof(short)); break; case WLZ_GREY_UBYTE: g.ubp = (WlzUByte *) AlcCalloc(WlzArea(obj, NULL), sizeof(WlzUByte)); break; case WLZ_GREY_FLOAT: g.flp = (float *) AlcCalloc(WlzArea(obj, NULL), sizeof(float)); break; case WLZ_GREY_DOUBLE: g.dbp = (double *) AlcCalloc(WlzArea(obj, NULL), sizeof(double)); break; case WLZ_GREY_RGBA: g.rgbp = (WlzUInt *) AlcCalloc(WlzArea(obj, NULL), sizeof(WlzUInt)); break; default: WlzFreeValues( v ); v.i = NULL; errNum = WLZ_ERR_GREY_TYPE; break; } } if( (errNum == WLZ_ERR_NONE) && (g.inp == NULL) ){ WlzFreeValues( v ); v.i = NULL; errNum = WLZ_ERR_MEM_ALLOC; } /* * fill in structure values and initialise scanning */ if( errNum == WLZ_ERR_NONE ){ v.i->type = type; v.i->freeptr = AlcFreeStackPush(v.i->freeptr, (void *)g.inp, NULL); v.i->line1 = idom->line1; v.i->lastln = idom->lastln; v.i->kol1 = idom->kol1; v.i->width = idom->lastkl - idom->kol1 + 1; v.i->vil = vil; v.i->linkcount = 0; v.i->original_table.core = NULL; vil--; if((errNum = WlzInitRasterScan(obj, &iwsp, WLZ_RASTERDIR_ILIC)) != WLZ_ERR_NONE ){ WlzFreeValues( v ); v.i = NULL; } } /* * fill in the line and interval structures, note grey-type already checked. */ if( errNum == WLZ_ERR_NONE ){ while((errNum == WLZ_ERR_NONE) && (errNum = WlzNextInterval(&iwsp)) == WLZ_ERR_NONE){ if (iwsp.nwlpos != 0) { vil += iwsp.nwlpos; vil->vtbint = val; } vil->nintvs++; val->vkol1 = iwsp.lftpos - v.i->kol1; val->vlastkl = iwsp.rgtpos - v.i->kol1; switch( WlzGreyTableTypeToGreyType(type, NULL) ){ case WLZ_GREY_INT: val->values.inp = g.inp; g.inp += iwsp.colrmn; break; case WLZ_GREY_SHORT: val->values.shp = g.shp; g.shp += iwsp.colrmn; break; case WLZ_GREY_UBYTE: val->values.ubp = g.ubp; g.ubp += iwsp.colrmn; break; case WLZ_GREY_FLOAT: val->values.flp = g.flp; g.flp += iwsp.colrmn; break; case WLZ_GREY_DOUBLE: val->values.dbp = g.dbp; g.dbp += iwsp.colrmn; break; case WLZ_GREY_RGBA: val->values.rgbp = g.rgbp; g.rgbp += iwsp.colrmn; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } val++; } switch( errNum ){ case WLZ_ERR_NONE: case WLZ_ERR_EOO: errNum = WLZ_ERR_NONE; break; default: WlzFreeValues( v ); v.i = NULL; break; } } if( dstErr ){ *dstErr = errNum; } return(v.i); }
/*! * \return Affine transform which brings the two objects into register. * \ingroup WlzRegistration * \brief Registers the two given 2D domain objects using a * frequency domain cross correlation. An affine transform * is computed, which when applied to the source object * takes it into register with the target object. * A resolution pyramid is built from the given objects * and used to register the objects, progressing from * a low resolution towards the full resolution objects. * \param tObj The target object. Must have * been assigned. * \param sObj The source object to be * registered with target object. * \param initTr Initial affine transform * to be applied to the source * object prior to registration. * Only translations in x and y * and rotation about the z axis * are used. May be NULL which is * equivalent to an identity transform. * \param trType Required transform type. * \param maxTran Maximum translation. * \param maxRot Maximum rotation. * \param maxItr Maximum number of iterations, * if \f$leq\f$ 0 then infinite iterations * are allowed. * \param winFn Window function. * \param noise Use Gaussian noise if non-zero. * \param dstConv Destination ptr for the * convergence flag (non zero * on convergence), may be NULL. * \param dstCCor Destination ptr for the cross * correlation value, may be NULL. * \param dstErr Destination error pointer, * may be NULL. */ static WlzAffineTransform *WlzRegCCorObjs2D(WlzObject *tObj, WlzObject *sObj, WlzAffineTransform *initTr, WlzTransformType trType, WlzDVertex2 maxTran, double maxRot, int maxItr, WlzWindowFnType winFn, int noise, int *dstConv, double *dstCCor, WlzErrorNum *dstErr) { int tI1, samIdx, nSam, conv; double cCor, rot0, rot1, sMaxRot; WlzPixelV gV[4]; WlzIVertex2 tIV0, tIV1; WlzIVertex3 samFacV; WlzDVertex2 tran0, tran1, sMaxTran; WlzIBox2 sBox, tBox; int *samFac = NULL; WlzObject **sTObj = NULL, **sSObj = NULL; WlzAffineTransform *samRegTr0 = NULL, *samRegTr1 = NULL, *regTr = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; WlzAffineTransformPrim trPrim; WlzPixelV zeroBgd; const int samFacStep = 4, maxSam = 16, minSamSz = 100; zeroBgd.type = WLZ_GREY_INT; zeroBgd.v.inv = 0; gV[0].type = gV[1].type = gV[2].type = gV[3].type = WLZ_GREY_DOUBLE; /* Compute the number of x4 subsampling operations to use. */ sBox = WlzBoundingBox2I(sObj, &errNum); if(errNum == WLZ_ERR_NONE) { tBox = WlzBoundingBox2I(tObj, &errNum); } if(errNum == WLZ_ERR_NONE) { tIV0.vtX = sBox.xMax - sBox.xMin + 1; tIV0.vtY = sBox.yMax - sBox.yMin + 1; tIV1.vtX = tBox.xMax - tBox.xMin + 1; tIV1.vtY = tBox.yMax - tBox.yMin + 1; tIV0.vtX = WLZ_MIN(tIV0.vtX, tIV1.vtX); tIV0.vtY = WLZ_MIN(tIV0.vtY, tIV1.vtY); nSam = 1; tI1 = WLZ_MIN(tIV0.vtX, tIV0.vtY); while((nSam < maxSam) && (tI1 > minSamSz)) { ++nSam; tI1 /= samFacStep; } } /* Allocate space for subsampled objects. */ if(errNum == WLZ_ERR_NONE) { if(((samFac = (int *)AlcMalloc(nSam * sizeof(int))) == NULL) || ((sTObj = (WlzObject **)AlcCalloc(nSam, sizeof(WlzObject *))) == NULL) || ((sSObj = (WlzObject **)AlcCalloc(nSam, sizeof(WlzObject *))) == NULL)) { errNum = WLZ_ERR_MEM_ALLOC; } } /* Compute subsampled objects and make sure the background value is zero. */ if(errNum == WLZ_ERR_NONE) { samIdx = 0; *samFac = 1; samFacV.vtX = samFacV.vtY = samFacStep; *(sTObj + 0) = WlzAssignObject(tObj, NULL); *(sSObj + 0) = WlzAssignObject(sObj, NULL); while((errNum == WLZ_ERR_NONE) && (++samIdx < nSam)) { *(samFac + samIdx) = *(samFac + samIdx - 1) * samFacStep; *(sTObj + samIdx) = WlzAssignObject( WlzSampleObj(*(sTObj + samIdx - 1), samFacV, WLZ_SAMPLEFN_GAUSS, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { (void )WlzSetBackground(*(sTObj + samIdx), zeroBgd); *(sSObj + samIdx) = WlzAssignObject( WlzSampleObj(*(sSObj + samIdx - 1), samFacV, WLZ_SAMPLEFN_GAUSS, &errNum), NULL); } if(errNum == WLZ_ERR_NONE) { (void )WlzSetBackground(*(sSObj + samIdx), zeroBgd); } } } /* Register the subsampled objects starting with the lowest resolution * (highest subsampling) and progressing to the unsampled objects. */ if(errNum == WLZ_ERR_NONE) { if(initTr == NULL) { rot0 = 0.0; tran0.vtX = 0.0; tran0.vtY = 0.0; } else { errNum = WlzAffineTransformPrimGet(initTr, &trPrim); rot0 = trPrim.theta; tran0.vtX = trPrim.tx; tran0.vtY = trPrim.ty; } conv = 1; samIdx = nSam - 1; sMaxRot = maxRot; sMaxTran.vtX = maxTran.vtX / *(samFac + nSam - 1); sMaxTran.vtY = maxTran.vtY / *(samFac + nSam - 1); while((errNum == WLZ_ERR_NONE) && conv && (samIdx >= 0)) { /* Compute initial transform. */ rot1 = rot0; tran1.vtX = tran0.vtX / *(samFac + samIdx); tran1.vtY = tran0.vtY / *(samFac + samIdx); samRegTr0 = WlzAffineTransformFromPrimVal(WLZ_TRANSFORM_2D_AFFINE, tran1.vtX, tran1.vtY, 0.0, 1.0, rot1, 0.0, 0.0, 0.0, 0.0, 0, &errNum); /* Compute registration transform. */ if(errNum == WLZ_ERR_NONE) { samRegTr1 = WlzRegCCorObjs2D1(*(sTObj + samIdx), *(sSObj + samIdx), samRegTr0, trType, sMaxTran, sMaxRot, maxItr, winFn, noise, &conv, &cCor, &errNum); } if(samRegTr0) { (void )WlzFreeAffineTransform(samRegTr0); samRegTr0 = NULL; } if(samRegTr1) { samRegTr0 = samRegTr1; samRegTr1 = NULL; } if(errNum == WLZ_ERR_NONE) { errNum = WlzAffineTransformPrimGet(samRegTr0, &trPrim); } if(errNum == WLZ_ERR_NONE) { rot0 = trPrim.theta; tran0.vtX = trPrim.tx * *(samFac + samIdx); tran0.vtY = trPrim.ty * *(samFac + samIdx); } /* Set registration limits. */ sMaxRot = WLZ_M_PI / 24.0; sMaxTran.vtX = samFacStep * 3; sMaxTran.vtY = samFacStep * 3; --samIdx; } } if(errNum == WLZ_ERR_NONE) { if(dstConv) { *dstConv = conv; } if(dstCCor) { *dstCCor = cCor; } regTr = samRegTr0; } AlcFree(samFac); /* Free subsampled objects. */ if(sTObj) { for(samIdx = 0; samIdx < nSam; ++samIdx) { (void )WlzFreeObj(*(sTObj + samIdx)); } AlcFree(sTObj); } if(sSObj) { for(samIdx = 0; samIdx < nSam; ++samIdx) { (void )WlzFreeObj(*(sSObj + samIdx)); } AlcFree(sSObj); } if(dstErr) { *dstErr = errNum; } return(regTr); }
/*! * \return Woolz object read from jpeg image. * \ingroup WlzExtFF * \brief Reads a jpeg image frm the given file stream and returns a * Woolz object. * \param fP Given file stream. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzEffReadObjJpeg( FILE *fP, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ int width, height; /* int depth; */ int wlzDepth; WlzGreyType newpixtype; WlzPixelV bckgrnd; int i, rOff; WlzGreyP wlzData; WlzErrorNum errNum=WLZ_ERR_NONE; /* check input */ if( fP == NULL ){ errNum = WLZ_ERR_PARAM_NULL; } /* We set up the normal JPEG error routines, then override error_exit. */ if( errNum == WLZ_ERR_NONE ){ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ jpeg_destroy_decompress(&cinfo); if( rtnObj ){ WlzFreeObj(rtnObj); rtnObj = NULL; } errNum = WLZ_ERR_READ_INCOMPLETE; } } if( errNum == WLZ_ERR_NONE ){ /* initialize the JPEG decompression object. */ jpeg_create_decompress(&cinfo); /* specify data source (eg, a file) */ jpeg_stdio_src(&cinfo, fP); /* read file parameters with jpeg_read_header() */ (void) jpeg_read_header(&cinfo, TRUE); /* We can ignore the return value from jpeg_read_header since * (a) suspension is not possible with the stdio data source, and * (b) we passed TRUE to reject a tables-only JPEG file as an error. * See libjpeg.doc for more info. */ /* default set parameters for decompression */ (void) jpeg_start_decompress(&cinfo); /* JSAMPLEs per row in output buffer */ row_stride = cinfo.output_width * cinfo.output_components; /* Make a one-row-high sample array that will go away when done with image */ buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); /* create the appropriate woolz object, read scanlines and copy data */ switch( cinfo.jpeg_color_space ){ default: case JCS_UNKNOWN: errNum = WLZ_ERR_READ_INCOMPLETE; break; case JCS_GRAYSCALE: bckgrnd.type = WLZ_GREY_UBYTE; #if BITS_IN_JSAMPLE == 8 if( cinfo.data_precision != 8 ){ errNum = WLZ_ERR_FILE_FORMAT; } else { wlzDepth = sizeof(char); newpixtype = WLZ_GREY_UBYTE; /* depth = cinfo.num_components * 8; */ bckgrnd.v.ubv = 0; } #endif /* BITS_IN_SAMPLE == 8 */ #if BITS_IN_JSAMPLE == 12 if( cinfo.data_precision != 12 ){ errNum = WLZ_ERR_FILE_FORMAT; } else { wlzDepth = sizeof(short); newpixtype = WLZ_GREY_SHORT; /* depth = cinfo.num_components * 12; */ bckgrnd.v.shv = 0; } #endif /* BITS_IN_SAMPLE == 12 */ break; case JCS_YCbCr: case JCS_CMYK: case JCS_YCCK: case JCS_RGB: bckgrnd.type = WLZ_GREY_RGBA; cinfo.out_color_space = JCS_RGB; #if BITS_IN_JSAMPLE == 8 if( cinfo.data_precision != 8 ){ errNum = WLZ_ERR_FILE_FORMAT; } else { wlzDepth = sizeof(int); newpixtype = WLZ_GREY_RGBA; /* depth = cinfo.num_components * 8; */ bckgrnd.v.inv = 0; } #endif /* BITS_IN_SAMPLE == 8 */ #if BITS_IN_JSAMPLE == 12 errNum = WLZ_ERR_UNIMPLEMENTED; #endif /* BITS_IN_SAMPLE == 8 */ break; } if( errNum == WLZ_ERR_NONE ){ /* make the woolz object */ width = cinfo.image_width; height = cinfo.image_height; if((wlzData.ubp = (WlzUByte *)AlcCalloc(width*height, wlzDepth)) != NULL){ if((rtnObj = WlzMakeRect(0, height-1, 0, width-1, newpixtype, wlzData.inp, bckgrnd, NULL, NULL, &errNum)) != NULL){ AlcErrno errAlcNum; rtnObj->values.r->freeptr = AlcFreeStackPush(rtnObj->values.r->freeptr, (void *) wlzData.ubp, &errAlcNum); if( errAlcNum != ALC_ER_NONE ){ errNum = WLZ_ERR_MEM_ALLOC; } } else{ AlcFree((void *) wlzData.ubp); } } else { errNum = WLZ_ERR_MEM_ALLOC; } } } /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. * scan object copying in scanline values */ if( errNum == WLZ_ERR_NONE ){ while (cinfo.output_scanline < cinfo.output_height) { /* jpeg_read_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could ask for * more than one scanline at a time if that's more convenient. */ (void) jpeg_read_scanlines(&cinfo, buffer, 1); /* copy to the woolz object buffer */ switch( newpixtype ){ case WLZ_GREY_UBYTE: memcpy((void *) wlzData.ubp, (const void *) buffer[0], sizeof(char) * width); wlzData.ubp += width; break; case WLZ_GREY_SHORT: memcpy((void *) wlzData.shp, (const void *) buffer[0], sizeof(short) * width); wlzData.shp += width; break; case WLZ_GREY_RGBA: /* this we need to decode */ rOff = 0; for(i=0; i < width; i++, wlzData.rgbp++, rOff += 3){ WLZ_RGBA_RGBA_SET(*wlzData.rgbp, buffer[0][rOff], buffer[0][rOff+1], buffer[0][rOff+2], 255); } break; default: break; } } /* Finish decompression */ (void) jpeg_finish_decompress(&cinfo); /* Release JPEG decompression object */ jpeg_destroy_decompress(&cinfo); } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/* options_menu initialisation procedure */ void options_menu_init( Widget topl) { Widget widget; String filestr, dirstr; char lineBuf[1024], fileBuf[512], dateBuf[64]; char authorBuf[64], stageBuf[16]; MAPaintExpressMapStatus status; MAPaintExpressMapQuality quality; int bibfileStartIndex=0; /* create the tool controls dialog */ tool_controls_dialog = create_tool_controls_dialog( topl ); /* create the surgery controls dialog */ surgeryDialog = createDomainSurgeryDialog( topl ); XtManageChild( surgeryDialog ); HGU_XmSaveRestoreAddWidget( surgeryDialog, NULL, NULL, NULL, NULL ); /* create the review controls dialog */ reviewDialog = createDomainReviewDialog( topl ); XtManageChild( reviewDialog ); HGU_XmSaveRestoreAddWidget( reviewDialog, NULL, NULL, NULL, NULL ); /* create the colormap controls */ colormap_dialog = create_colormap_dialog( topl ); XtManageChild( colormap_dialog ); HGU_XmSaveRestoreAddWidget( colormap_dialog, NULL, NULL, NULL, NULL ); /* get option menu resources */ XtGetApplicationResources(globals.topl, &globals, autosave_res, XtNumber(autosave_res), NULL, 0); /* add an autosave timeout */ filestr = globals.autosave_file; dirstr = globals.autosave_dir; if( strlen(dirstr) < 1 ){ globals.autosave_file = (String) AlcMalloc(sizeof(char) * (strlen(filestr) + 16 )); sprintf(globals.autosave_file, "%s.%d", filestr, getpid()); } else { globals.autosave_file = (String) AlcMalloc(sizeof(char) * (strlen(dirstr) + strlen(filestr) + 16 )); sprintf(globals.autosave_file, "%s/%s.%d", dirstr, filestr, getpid()); } /* no autosave in sectionView mode */ if( globals.sectViewFlg ){ globals.autosavetimeoutID = 0; } else { globals.autosavetimeoutID = XtAppAddTimeOut(globals.app_con, globals.autosave_time*1000, autosavetimeout_cb, NULL); } /* create the autosave controls */ autosave_dialog = create_autosave_dialog( topl ); XtManageChild( autosave_dialog ); HGU_XmSaveRestoreAddWidget( autosave_dialog, NULL, NULL, NULL, NULL ); globals.stipple = (Pixmap) 0; globals.paint_action_quit_flag = 0; globals.currentPaintAction = MAPAINT_PAINT_BALL_2D; globals.currentPaintActionCbFunc = MAPaintPaintBall2DCb; globals.currentPaintActionInitFunc = MAPaintPaintBall2DInit; globals.currentPaintActionQuitFunc = MAPaintPaintBall2DQuit; globals.review_domain_obj = NULL; /* remove the editing options in sectionView mode */ if( globals.sectViewFlg ){ char nameBuf[64]; int i; for(i=0; options_menu_itemsP[i].name != NULL; i++){ if( strstr(options_menu_itemsP[i].name, "colormap") ){ continue; } else if( options_menu_itemsP[i].name ){ sprintf(nameBuf, "*.options_menu*%s", options_menu_itemsP[i].name); if((widget = XtNameToWidget(topl, nameBuf))){ XtSetSensitive(widget, False); } } } } /* create the save sequence controls */ save_seq_dialog = create_save_seq_dialog( topl ); XtManageChild( save_seq_dialog ); HGU_XmSaveRestoreAddWidget( save_seq_dialog, NULL, NULL, NULL, NULL ); /* get the current working directory */ if((dirstr = getcwd(lineBuf, 256))){ globals.origDir = AlcStrDup(dirstr); } else { globals.origDir = NULL; } /* check for rapid-map or express-map */ if( globals.rapidMapFlg || globals.expressMapFlg ){ /* check for bibfile list file */ if( globals.bibfileListFile ){ FILE *fp; int i, j, linecount, csvCount; WlzObject *dummyObj; WlzPixelV bgdV; Widget toggle, notebook, matrix, textField; XmNotebookPageInfo pageInfo; XmToggleButtonCallbackStruct cbs; /* set the default csv file */ if( globals.bibfileListFile[0] == '/' ){ if( strstr(globals.bibfileListFile, ".csv") ){ sprintf(lineBuf, "%s", globals.bibfileListFile); } else { sprintf(lineBuf, "%s.csv", globals.bibfileListFile); } } else { if( strstr(globals.bibfileListFile, ".csv") ){ sprintf(lineBuf, "%s/%s", globals.origDir, globals.bibfileListFile); } else { sprintf(lineBuf, "%s/%s.csv", globals.origDir, globals.bibfileListFile); } } warpGlobals.bibfileListCSVFile = AlcStrDup(lineBuf); /* read file and create lists */ if((fp = fopen(globals.bibfileListFile, "r"))){ /* count lines */ linecount = 1; while( fgets(lineBuf, 1024, fp) ){ linecount++; } warpGlobals.bibfileList = (char **) AlcCalloc(linecount, sizeof(char *)); warpGlobals.statusList = (MAPaintExpressMapStatus *) AlcCalloc(linecount, sizeof(MAPaintExpressMapStatus)); warpGlobals.dateList = (char **) AlcCalloc(linecount, sizeof(char *)); warpGlobals.authorList = (char **) AlcCalloc(linecount, sizeof(char *)); warpGlobals.stageList = (char **) AlcCalloc(linecount, sizeof(char *)); warpGlobals.qualityList = (MAPaintExpressMapQuality *) AlcCalloc(linecount, sizeof(MAPaintExpressMapQuality)); rewind(fp); linecount = 0; while( fgets(lineBuf, 1024, fp) ){ int statusTmp, qualityTmp; csvCount = sscanf(lineBuf, "%[^,\n], %d, %[^,\n], %[^,\n], %[^,\n], %d", fileBuf, &statusTmp, dateBuf, authorBuf, stageBuf, &qualityTmp); status = statusTmp; quality = qualityTmp; if( csvCount > 0 ){ if((fileBuf[0] != '/') && globals.origDir ){ warpGlobals.bibfileList[linecount] = (char *) AlcMalloc(sizeof(char)* (strlen(fileBuf) + strlen(globals.origDir) + 4)); sprintf(warpGlobals.bibfileList[linecount], "%s/%s", globals.origDir, fileBuf); } else { warpGlobals.bibfileList[linecount] = AlcStrDup(fileBuf); } } if( csvCount > 1 ){ warpGlobals.statusList[linecount] = status; } else { warpGlobals.statusList[linecount] = MA_EXPRESSMAP_STATUS_NONE; } if( csvCount > 2 ){ warpGlobals.dateList[linecount] = AlcStrDup(dateBuf); } else { warpGlobals.dateList[linecount] = AlcStrDup("Unknown"); } if( csvCount > 3 ){ warpGlobals.authorList[linecount] = AlcStrDup(authorBuf); } else { warpGlobals.authorList[linecount] = AlcStrDup("Unknown"); } if( csvCount > 4 ){ warpGlobals.stageList[linecount] = AlcStrDup(stageBuf); } else { warpGlobals.stageList[linecount] = AlcStrDup("TS23"); } if( csvCount > 5 ){ warpGlobals.qualityList[linecount] = quality; } else { warpGlobals.qualityList[linecount] = MA_EXPRESSMAP_QUALITY_NONE; } linecount++; } warpGlobals.bibfileListCount = linecount; fclose(fp); } /* create dummy reference object and install */ bgdV.type = WLZ_GREY_UBYTE; bgdV.v.ubv = 255; dummyObj = WlzAssignObject(WlzMakeCuboid(0, 5, 0, 5, 0, 5, WLZ_GREY_UBYTE, bgdV, NULL, NULL, NULL), NULL); set_topl_title("dummy"); globals.file = NULL; globals.origObjType = WLZ_3D_DOMAINOBJ; install_paint_reference_object(dummyObj); WlzFreeObj(dummyObj); /* create warp input dialog */ warpInput2DCb(globals.topl, NULL, NULL); /* get the warp controls toggle */ if((toggle = XtNameToWidget(globals.topl, "*warp_input_2d_frame_title"))){ XtVaSetValues(toggle, XmNset, True, NULL); cbs.set = True; XtCallCallbacks(toggle, XmNvalueChangedCallback, &cbs); } /* set the files names etc in the table widget */ if((matrix = XtNameToWidget(globals.topl, "*expressmap_matrix"))){ String *rows, bibfileStr, tailStr, *labels; int numRows; Boolean *rowButtonLabels; XtVaGetValues(matrix, XmNrows, &numRows, XmNtextField, &textField, NULL); if( numRows > 0 ){ XbaeMatrixDeleteRows(matrix, 0, numRows); } rows = (String *) AlcMalloc(sizeof(String) * warpGlobals.bibfileListCount * 6); labels = (String *) AlcMalloc(sizeof(String) * warpGlobals.bibfileListCount); rowButtonLabels = (Boolean *)AlcMalloc(sizeof(Boolean) * warpGlobals.bibfileListCount); bibfileStartIndex = -1; for(i=0; i < warpGlobals.bibfileListCount; i++){ bibfileStr = tailStr = warpGlobals.bibfileList[i]; for(j=0; j < strlen(bibfileStr); j++){ if( bibfileStr[j] == '/' ){ tailStr = bibfileStr + (j + 1); } } rows[i*6 + 0] = tailStr; rows[i*6 + 1] = expressMapStatusStrs[warpGlobals.statusList[i]]; rows[i*6 + 2] = warpGlobals.dateList[i]; rows[i*6 + 3] = warpGlobals.authorList[i]; rows[i*6 + 4] = warpGlobals.stageList[i]; rows[i*6 + 5] = expressMapQualityStrs[warpGlobals.qualityList[i]]; labels[i] = "->"; rowButtonLabels[i] = True; /* check for first "None" */ if((bibfileStartIndex == -1) && (warpGlobals.statusList[i] == MA_EXPRESSMAP_STATUS_NONE)){ bibfileStartIndex = i; } } XbaeMatrixAddRows(matrix, 0, rows, labels, NULL, i); for(i=0; i < warpGlobals.bibfileListCount; i++){ XbaeMatrixSetRowUserData(matrix, i, (XtPointer) (long) i); } XtVaSetValues(matrix, XmNbuttonLabels, True, XmNrowButtonLabels, rowButtonLabels, XmNrowLabelAlignment, XmALIGNMENT_CENTER, NULL); AlcFree(rows); AlcFree(labels); AlcFree(rowButtonLabels); XtVaSetValues(textField, XmNeditable, False, NULL); } /* set rapidMap mode */ if( globals.rapidMapFlg ){ if((notebook = XtNameToWidget(globals.topl, "*warp_cntrl_notebook"))){ XtVaSetValues(notebook, XmNcurrentPageNumber, 2, NULL); /* call the activate callback */ if( XmNotebookGetPageInfo(notebook, 2, &pageInfo) == XmPAGE_FOUND ){ XmPushButtonCallbackStruct cbs; cbs.reason = XmCR_ACTIVATE; cbs.event = NULL; cbs.click_count = 1; XtCallCallbacks(pageInfo.major_tab_widget, XmNactivateCallback, &cbs); } } } else { if((notebook = XtNameToWidget(globals.topl, "*warp_cntrl_notebook"))){ XtVaSetValues(notebook, XmNcurrentPageNumber, 3, NULL); /* call the activate callback */ if( XmNotebookGetPageInfo(notebook, 3, &pageInfo) == XmPAGE_FOUND ){ XmPushButtonCallbackStruct cbs; cbs.reason = XmCR_ACTIVATE; cbs.event = NULL; cbs.click_count = 1; XtCallCallbacks(pageInfo.major_tab_widget, XmNactivateCallback, &cbs); } } } /* read first bibfile */ warpGlobals.bibfileSavedFlg = 1; if( bibfileStartIndex < 0 ){ bibfileStartIndex = 0; } warpGlobals.bibfileListIndex = bibfileStartIndex - 1; if( globals.rapidMapFlg ){ if((toggle = XtNameToWidget(globals.topl, "*warp_input_rapid_form*next"))){ XtCallCallbacks(toggle, XmNactivateCallback, NULL); } } else { if((toggle = XtNameToWidget(globals.topl, "*warp_input_express_form*next"))){ XtCallCallbacks(toggle, XmNactivateCallback, NULL); } } } else { warpGlobals.bibfileListCSVFile = NULL; /* should report an error here */ } } else { warpGlobals.matrix = NULL; } return; }
/*! * \return Error code. * \ingroup AlgMatrix * \brief Solves the matrix equation A.x = b for x, where A is a * matrix with at least as many rows as columns. * On return the matrix A is overwritten by the matrix U * in the singular value decomposition: * A = U.W.V' * \param aMat Matrix A. * \param bVec Column matrix b, overwritten * by matrix x on return. * \param tol Tolerance for singular values, * 1.0e-06 should be suitable as * a default value. * \param dstIC Destination pointer for * ill-conditioned flag, which may * be NULL, but if not NULL is set * to the number of singular values * which are smaller than the maximum * singular value times the given * threshold. */ AlgError AlgMatrixSVSolve(AlgMatrix aMat, double *bVec, double tol, int *dstIC) { int cnt0 = 0, cntIC = 0; size_t nM, nN; double thresh, wMax = 0.0; double *tDP0, *wVec = NULL; AlgMatrix vMat; AlgError errCode = ALG_ERR_NONE; nM = aMat.core->nR; nN = aMat.core->nC; vMat.core = NULL; if((aMat.core == NULL) || (aMat.core->type != ALG_MATRIX_RECT) || (aMat.core->nR <= 0) || (aMat.core->nR < aMat.core->nC) || (bVec == NULL)) { errCode = ALG_ERR_FUNC; } else if((wVec = (double *)AlcCalloc(sizeof(double), aMat.rect->nC)) == NULL) { errCode = ALG_ERR_MALLOC; } else { vMat.rect = AlgMatrixRectNew(nM, nN, &errCode); } if(errCode == ALG_ERR_NONE) { errCode = AlgMatrixSVDecomp(aMat, wVec, vMat); } if(errCode == ALG_ERR_NONE) { /* Find maximum singular value. */ cnt0 = nN; cntIC = 0; tDP0 = wVec; while(cnt0-- > 0) { if(*tDP0 > wMax) { ++cntIC; wMax = *tDP0; } ++tDP0; } /* Edit the singular values, replacing any less than tol * max singular value with 0.0. */ cnt0 = nN; tDP0 = wVec; thresh = tol * wMax; while(cnt0-- > 0) { if(*tDP0 < thresh) { *tDP0 = 0.0; } ++tDP0; } errCode = AlgMatrixSVBackSub(aMat, wVec, vMat, bVec); } AlcFree(wVec); AlgMatrixRectFree(vMat.rect); if(dstIC) { *dstIC = cntIC; } ALG_DBG((ALG_DBG_LVL_FN|ALG_DBG_LVL_1), ("AlgMatrixSVSolve FX %d\n", (int )errCode)); return(errCode); }
/*! * \return Grey value work space or NULL on error. * \ingroup WlzAccess * \brief Creates a grey value work space from the given object. * The resulting grey value work space should be freed * using WlzGreyValueFreeWSp(). * \param obj Given object. * \param dstErrNum Destination error pointer, may be NULL. */ WlzGreyValueWSpace *WlzGreyValueMakeWSp(WlzObject *obj, WlzErrorNum *dstErrNum) { int planeIdx, numPlanes; WlzDomain *planeDomains; WlzValues *planeValues; WlzObjectType gTabType0, gTabType1 = WLZ_DUMMY_ENTRY; WlzGreyType gType0 = WLZ_GREY_ERROR, gType1 = WLZ_GREY_ERROR; WlzPixelV bkdPix; WlzAffineTransform *trans0, *trans1; WlzGreyValueWSpace *gVWSp = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; bkdPix.v.ubv = 0; bkdPix.type = WLZ_GREY_INT; WLZ_DBG((WLZ_DBG_LVL_1), ("WlzGreyValueMakeWSp FE %p %p\n", obj, dstErrNum)); if(obj == NULL) { errNum = WLZ_ERR_PARAM_DATA; } else { switch(obj->type) { case WLZ_2D_DOMAINOBJ: if(obj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(obj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else if((gVWSp = (WlzGreyValueWSpace *)AlcCalloc(1, sizeof(WlzGreyValueWSpace))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { gVWSp->objType = obj->type; gVWSp->values = obj->values; gVWSp->gType = WlzGreyTableTypeToGreyType(obj->values.core->type, &errNum); if(errNum == WLZ_ERR_NONE) { gVWSp->gTabType = WlzGreyTableTypeToTableType( obj->values.core->type, &errNum); gVWSp->gTabType2D = gVWSp->gTabType; } if(errNum == WLZ_ERR_NONE) { switch(gVWSp->gTabType2D) { case WLZ_GREY_TAB_RAGR: gVWSp->values2D = obj->values; bkdPix = gVWSp->values2D.v->bckgrnd; break; case WLZ_GREY_TAB_RECT: gVWSp->values2D = obj->values; bkdPix = gVWSp->values2D.r->bckgrnd; break; case WLZ_GREY_TAB_INTL: gVWSp->values2D = obj->values; bkdPix = gVWSp->values2D.i->bckgrnd; break; case WLZ_GREY_TAB_TILED: gVWSp->values2D = obj->values; bkdPix = gVWSp->values2D.t->bckgrnd; break; default: errNum = WLZ_ERR_VALUES_TYPE; break; } } if(errNum == WLZ_ERR_NONE) { switch(gVWSp->gType) { case WLZ_GREY_LONG: case WLZ_GREY_INT: case WLZ_GREY_SHORT: case WLZ_GREY_UBYTE: case WLZ_GREY_FLOAT: case WLZ_GREY_DOUBLE: case WLZ_GREY_RGBA: break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } if((gVWSp->gType != bkdPix.type) && (errNum == WLZ_ERR_NONE)) { errNum = WLZ_ERR_VALUES_DATA; } } if(errNum == WLZ_ERR_NONE) { gVWSp->gBkd = bkdPix.v; gVWSp->domain = obj->domain; gVWSp->iDom2D = obj->domain.i; if((gVWSp->iDom2D->type != WLZ_INTERVALDOMAIN_INTVL) && (gVWSp->iDom2D->type != WLZ_INTERVALDOMAIN_RECT)) { errNum = WLZ_ERR_DOMAIN_TYPE; } } break; case WLZ_3D_DOMAINOBJ: if(obj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(obj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else if(obj->domain.core->type != WLZ_PLANEDOMAIN_DOMAIN) { errNum = WLZ_ERR_DOMAIN_TYPE; } else if((gVWSp = (WlzGreyValueWSpace *)AlcCalloc(1, sizeof(WlzGreyValueWSpace))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { gVWSp->objType = obj->type; gVWSp->domain = obj->domain; gVWSp->values = obj->values; if(WlzGreyTableIsTiled(obj->values.core->type) == WLZ_GREY_TAB_TILED) { gVWSp->gTabType = WLZ_GREY_TAB_TILED; gVWSp->gTabType2D = WLZ_GREY_TAB_TILED; gVWSp->gType = WlzGreyTableTypeToGreyType( obj->values.core->type, &errNum); gVWSp->plane = obj->domain.p->plane1; gVWSp->iDom2D = (*(obj->domain.p->domains)).i; gVWSp->gBkd = obj->values.t->bckgrnd.v; if(obj->values.t->bckgrnd.type != gVWSp->gType) { errNum = WLZ_ERR_VALUES_DATA; } } else { gVWSp->gTabType = WLZ_VOXELVALUETABLE_GREY; /* Put in a list of grey-table types - purely for efficiency to avoid re-computing the type for each voxel request. When table types are no longer computed this in principle could go */ numPlanes = obj->domain.p->lastpl - obj->domain.p->plane1 + 1; if((gVWSp->gTabTypes3D = (WlzObjectType *) AlcCalloc(numPlanes, sizeof(WlzObjectType))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } if(errNum == WLZ_ERR_NONE) { WlzObjectType *gTabTypes3D; gVWSp->values2D.core = NULL; planeIdx = obj->domain.p->plane1; planeDomains = obj->domain.p->domains; planeValues = obj->values.vox->values; gTabTypes3D = gVWSp->gTabTypes3D; while((planeIdx <= obj->domain.p->lastpl) && (errNum == WLZ_ERR_NONE)) { if(((*planeValues).core) && ((*planeValues).core->type != WLZ_EMPTY_OBJ)) { gType0 = WlzGreyTableTypeToGreyType( (*planeValues).core->type, &errNum); if(errNum == WLZ_ERR_NONE) { gTabType0 = WlzGreyTableTypeToTableType((*planeValues). core->type, &errNum); *gTabTypes3D = gTabType0; } if(errNum == WLZ_ERR_NONE) { if((gType0 != gType1) && (gType1 != WLZ_GREY_ERROR)) { errNum = WLZ_ERR_VALUES_DATA; } else { gType1 = gType0; gTabType1 = gTabType0; if(gVWSp->values2D.core == NULL) { gVWSp->plane = planeIdx; gVWSp->iDom2D = (*planeDomains).i; gVWSp->values2D = *planeValues; } } } } ++planeIdx; ++planeDomains; ++planeValues; ++gTabTypes3D; } if((gType1 == WLZ_GREY_ERROR) || (gTabType1 == WLZ_DUMMY_ENTRY)) { errNum = WLZ_ERR_VALUES_DATA; } } if(errNum == WLZ_ERR_NONE) { gVWSp->gType = gType0; gVWSp->gTabType2D = gVWSp->gTabTypes3D[0]; switch(gVWSp->gTabType2D) { case WLZ_GREY_TAB_RAGR: bkdPix = gVWSp->values2D.v->bckgrnd; break; case WLZ_GREY_TAB_RECT: bkdPix = gVWSp->values2D.r->bckgrnd; break; case WLZ_GREY_TAB_INTL: bkdPix = gVWSp->values2D.i->bckgrnd; break; case WLZ_GREY_TAB_TILED: bkdPix = gVWSp->values2D.t->bckgrnd; break; default: errNum = WLZ_ERR_VALUES_TYPE; break; } if((gVWSp->gType != bkdPix.type) && (errNum == WLZ_ERR_NONE)) { errNum = WLZ_ERR_VALUES_DATA; } else if((gVWSp->iDom2D->type != WLZ_INTERVALDOMAIN_INTVL) && (gVWSp->iDom2D->type != WLZ_INTERVALDOMAIN_RECT)) { errNum = WLZ_ERR_DOMAIN_TYPE; } else { gVWSp->gBkd = bkdPix.v; } } } } break; case WLZ_TRANS_OBJ: trans0 = NULL; while((errNum == WLZ_ERR_NONE) && (obj->type == WLZ_TRANS_OBJ)) { if(trans0 == NULL) { trans0 = WlzAffineTransformCopy(obj->domain.t, &errNum); } else { if((trans1 = WlzAffineTransformProduct(trans0, obj->domain.t, &errNum)) != NULL) { WlzFreeAffineTransform(trans0); trans0 = trans1; trans1 = NULL; } } if((obj = obj->values.obj) == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } } if(errNum == WLZ_ERR_NONE) { gVWSp = WlzGreyValueMakeWSp(obj, &errNum); } if(errNum == WLZ_ERR_NONE) { gVWSp->invTrans = WlzAffineTransformInverse(trans0, &errNum); } if(trans0) { WlzFreeAffineTransform(trans0); } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if((errNum != WLZ_ERR_NONE) && (gVWSp != NULL)) { WlzGreyValueFreeWSp(gVWSp); gVWSp = NULL; } if(dstErrNum) { *dstErrNum = errNum; } WLZ_DBG((WLZ_DBG_LVL_FN|WLZ_DBG_LVL_1), ("WlzGreyValueMakeWSp FX %p\n", gVWSp)); return(gVWSp); }
/*! * \return Woolz error code. * \ingroup WlzExtFF * \brief Reads the materials list from the file into the file header * data structure. * There are two formats for materials lists: * \verbatim { { Id 0, Name "Exterior" ) { Id 4, Name "Somites" } } \endverbatim * and * \verbatim { Exterior { } Inside { } Somites { Id 4, Color 0.2 0.8 0.4 } Ventricles } \endverbatim * Dispite id's being given in the file they are ignored and * the id's are given values from 0, incrementing by 1 with * each material parsed. * The default colour is 0.0 0.0 0.0 for the first material * and 1.0 1.0 1.0 for all others. * This function has been written to parse either of these * materials formats, to generate a materials list in the * header data structure. * \param fP Given file. * \param buf Buffer for workspace. * \param bufLen Buffer length. * \param head The Amira lattice header data * structure. */ static WlzErrorNum WlzEffAmReadMaterials(FILE *fP, char *buf, const int bufLen, WlzEffAmHead *head) { int tmpI; WlzEffAmToken tok; WlzEffAmMaterial *lastMat = NULL, *newMat = NULL; WlzErrorNum errNum; const char tokSepDQ[] = "\"", tokSepWS[] = " \t\n\r\f\v", tokSepWSC[] = " \t\n,\r\f\v", tokSepWSCQ[] = " \t\n,\"\r\f\v"; errNum = WlzEffAmReadAndCheckAToken(fP, tokSepWS, buf, bufLen, "{"); if(errNum == WLZ_ERR_NONE) { errNum = WlzEffAmReadAToken(fP, tokSepWS, buf, bufLen); } do { if((errNum == WLZ_ERR_NONE) && (strcmp(buf, "}"))) { /* Create a new material and set the defaults. */ if((newMat = (WlzEffAmMaterial *) AlcCalloc(1, sizeof(WlzEffAmMaterial))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else if(head->matCount > 0) { newMat->color[0] = newMat->color[1] = newMat->color[2] = 1.0; } } if(errNum == WLZ_ERR_NONE) { if(strcmp(buf, "{")) { if((newMat->name = AlcStrDup(buf)) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { errNum = WlzEffAmReadAToken(fP, tokSepWS, buf, bufLen); } } } if((errNum == WLZ_ERR_NONE) && strcmp(buf, "{") && strcmp(buf, "}")) { errNum = WLZ_ERR_READ_INCOMPLETE; } if((errNum == WLZ_ERR_NONE) && strcmp(buf, "}")) { do { errNum = WlzEffAmReadAToken(fP, tokSepWS, buf, bufLen); if((errNum == WLZ_ERR_NONE) && (strcmp(buf, "}"))) { tok = WLZEFF_AM_TOKEN_NONE; (void )WlzStringMatchValue((int *)&tok, buf, "Color", WLZEFF_AM_TOKEN_COLOR, "Id", WLZEFF_AM_TOKEN_ID, "Name", WLZEFF_AM_TOKEN_NAME, NULL); switch(tok) { case WLZEFF_AM_TOKEN_COLOR: errNum = WlzEffAmReadAValD(fP, tokSepWS, buf, bufLen, &(newMat->color[0])); if(errNum == WLZ_ERR_NONE) { errNum = WlzEffAmReadAValD(fP, tokSepWS, buf, bufLen, &(newMat->color[1])); } if(errNum == WLZ_ERR_NONE) { errNum = WlzEffAmReadAValD(fP, tokSepWS, buf, bufLen, &(newMat->color[2])); } break; case WLZEFF_AM_TOKEN_ID: errNum = WlzEffAmReadAValI(fP, tokSepWSC, buf, bufLen, &tmpI); if(errNum == WLZ_ERR_NONE) { errNum = WlzEffAmSkip(fP, tokSepWSC); } break; case WLZEFF_AM_TOKEN_NAME: errNum = WlzEffAmSkip(fP, tokSepWS); if(errNum == WLZ_ERR_NONE) { errNum = WlzEffAmReadAToken(fP, tokSepDQ, buf, bufLen); } if(errNum == WLZ_ERR_NONE) { errNum = WlzEffAmSkip(fP, tokSepWSCQ); } if((errNum == WLZ_ERR_NONE) && ((newMat->name = AlcStrDup(buf)) == NULL)) { errNum = WLZ_ERR_MEM_ALLOC; } break; default: errNum = WLZ_ERR_READ_INCOMPLETE; break; } } }while((errNum == WLZ_ERR_NONE) && strcmp(buf, "}")); *buf = '\0'; } if(errNum == WLZ_ERR_NONE) { /* Insert new material into list keeping the order of the materials * in which they were read from the file. */ newMat->id = (head->matCount)++; if(lastMat == NULL) { head->materials = newMat; } else { lastMat->next = newMat; newMat->prev = lastMat; } lastMat = newMat; newMat = NULL; } if((errNum == WLZ_ERR_NONE) && strcmp(buf, "}")) { errNum = WlzEffAmReadAToken(fP, tokSepWS, buf, bufLen); } } while((errNum == WLZ_ERR_NONE) && strcmp(buf, "}")); if(newMat) { AlcFree(newMat->name); AlcFree(newMat); } return(errNum); }
/*! * \return New filtered object with new values or NULL on error. * \ingroup WlzValuesFilters * \brief Applies a seperable filter along the z axis (planes) * to the given object using the given convolution kernel. * \param inObj Input 3D spatial domain object to be * filtered which must have scalar values. * \param bBox Object's bounding box. * \param maxThr Maximum number of threads to use. * \param iBuf Working buffers large enough for any * column in the image with one for each * thread. * \param rBuf Buffers as for iBuf. * \param cBufSz Convolution kernel size. * \param cBuf Convolution kernel buffer. * \param pad Type of padding. * \param padVal Padding value. * \param dstErr Destination error pointer may be NULL. */ static WlzObject *WlzSepFilterZ(WlzObject *inObj, WlzIBox3 bBox, int maxThr, double **iBuf, double **rBuf, int cBufSz, double *cBuf, AlgPadType pad, double padVal, WlzErrorNum *dstErr) { WlzObjectType rGTT; WlzPixelV zV; WlzObject *rnObj = NULL; WlzGreyValueWSpace **iVWSp = NULL, **rVWSp = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; zV.v.dbv = 0.0; zV.type = WLZ_GREY_DOUBLE; rGTT = WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_DOUBLE, NULL); rnObj = WlzNewObjectValues(inObj, rGTT, zV, 1, zV, &errNum); if(errNum == WLZ_ERR_NONE) { if(((iVWSp = (WlzGreyValueWSpace **) AlcCalloc(maxThr, sizeof(WlzGreyValueWSpace *))) == NULL) || ((rVWSp = (WlzGreyValueWSpace **) AlcCalloc(maxThr, sizeof(WlzGreyValueWSpace *))) == NULL)) { errNum = WLZ_ERR_MEM_ALLOC; } } if(errNum == WLZ_ERR_NONE) { int idt; for(idt = 0; (idt < maxThr) && (errNum == WLZ_ERR_NONE); ++idt) { iVWSp[idt] = WlzGreyValueMakeWSp(inObj, &errNum); if(errNum == WLZ_ERR_NONE) { rVWSp[idt] = WlzGreyValueMakeWSp(rnObj, &errNum); } } } if(errNum == WLZ_ERR_NONE) { int idy; #ifdef _OPENMP #pragma omp parallel for num_threads(maxThr) #endif for(idy = bBox.yMin; idy <= bBox.yMax; ++idy) { int idx, thrId = 0; WlzGreyValueWSpace *iVWSpT, *rVWSpT; #ifdef _OPENMP thrId = omp_get_thread_num(); #endif iVWSpT = iVWSp[thrId]; rVWSpT = rVWSp[thrId]; for(idx = bBox.xMin; idx <= bBox.xMax; ++idx) { int z0, z1, idz; WlzUByte in = 0; for(idz = bBox.zMin; idz <= bBox.zMax + 1; ++idz) { WlzGreyValueGet(iVWSpT, idz, idy, idx); if(iVWSpT->bkdFlag == 0) { double *ibp; if(in == 0) { z0 = idz; in = 1; } z1 = idz; ibp = iBuf[thrId] + (z1 - z0); switch(iVWSpT->gType) { case WLZ_GREY_INT: *ibp = iVWSpT->gVal[0].inv; break; case WLZ_GREY_SHORT: *ibp = iVWSpT->gVal[0].shv; break; case WLZ_GREY_UBYTE: *ibp = iVWSpT->gVal[0].ubv; break; case WLZ_GREY_FLOAT: *ibp = iVWSpT->gVal[0].flv; break; case WLZ_GREY_DOUBLE: *ibp = iVWSpT->gVal[0].dbv; break; default: break; } } else if(in) { int idr, len; len = z1 - z0 + 1; AlgConvolveD(len, rBuf[thrId], cBufSz * 2 + 1, cBuf, len, iBuf[thrId], pad, padVal); for(idr = z0; idr <= z1; ++idr) { WlzGreyValueGet(rVWSpT, idr, idy, idx); *(rVWSpT->gPtr[0].dbp) = rBuf[thrId][idr - z0]; } } } } } } if(iVWSp) { int idt; for(idt = 0; idt < maxThr; ++idt) { WlzGreyValueFreeWSp(iVWSp[idt]); } AlcFree(iVWSp); } if(rVWSp) { int idt; for(idt = 0; idt < maxThr; ++idt) { WlzGreyValueFreeWSp(rVWSp[idt]); } AlcFree(rVWSp); } if(errNum != WLZ_ERR_NONE) { (void )WlzFreeObj(rnObj); rnObj = NULL; } if(dstErr) { *dstErr = errNum; } return(rnObj); }
Widget HGU_XmCreateImageView( String name, Widget parent, int mappingDialogFlg) { Widget image_form, form, button, text, scrolled_window, canvas; HGU_XmImageViewDataStruct *data; String titleStr; XmString choiceStr; /* create the top-level form */ image_form = XtVaCreateManagedWidget(name, xmFormWidgetClass, parent, XmNwidth, 400, XmNheight, 400, NULL); data = (HGU_XmImageViewDataStruct *) AlcCalloc(sizeof(HGU_XmImageViewDataStruct), 1); XtVaSetValues(image_form, XmNuserData, data, NULL); data->imageForm = image_form; data->srcMin = -10000; data->srcMax = 10000; data->min = -10000; data->max = 10000; data->Min = 0; data->Max = 255; data->width = 696; data->height = 520; data->depth = 12; data->byteOrder = 1; data->magVal = 1.0; data->transType = WLZ_GREYTRANSFORMTYPE_LINEAR; data->gamma = 1.0; data->invert = 0; data->lut.g = (HGU_XmLutGrey *) AlcMalloc(sizeof(HGU_XmLutGrey)); data->lut.g->lut = NULL; data->lut.g->min = data->Min; data->lut.g->max = data->Max; /* create file-selector dialog */ XtGetApplicationResources(image_form, &titleStr, HGU_XmImageViewReadTitleResources, 1, NULL, 0); data->fileSelector = XmCreateFileSelectionDialog(image_form, "image_select", NULL, 0); XtVaSetValues(XtParent(data->fileSelector), XmNtitle, titleStr, NULL); XtAddCallback(data->fileSelector, XmNokCallback, HGU_XmImageViewReadImageCb, (XtPointer) data); XtAddCallback(data->fileSelector, XmNokCallback, PopdownCallback, NULL); XtAddCallback(data->fileSelector, XmNcancelCallback, PopdownCallback, NULL); form = XtVaCreateManagedWidget("read_file_form", xmFormWidgetClass, data->fileSelector, XmNborderWidth, 0, NULL); /* add a file type selection menu */ XtGetApplicationResources(image_form, &choiceStr, HGU_XmImageViewReadChoiceResources, 1, NULL, 0); data->typeMenu = HGU_XmBuildMenu(form, XmMENU_OPTION, "file_type", 0, XmTEAR_OFF_DISABLED, file_type_menu_itemsP); XtVaSetValues(data->typeMenu, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNlabelString, choiceStr, NULL); XtManageChild(data->typeMenu); /* create the mapping dialog */ XtGetApplicationResources(parent, &titleStr, HGU_XmGreyMappingDialogTitleResources, 1, NULL, 0); data->greyMapping = HGU_XmCreateGreyMappingDialog("grey_mapping", parent, data); XtVaSetValues(XtParent(data->greyMapping), XmNtitle, titleStr, NULL); /* add the button row for mag+, mag-, I/O and re-mapping */ form = XtVaCreateManagedWidget("image_buttons_form", xmFormWidgetClass, image_form, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); button = XtVaCreateManagedWidget("Read", xmPushButtonWidgetClass, form, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); XtAddCallback(button, XmNactivateCallback, HGU_XmMapDialogCb, data->fileSelector); button = XtVaCreateManagedWidget("Mag+", xmPushButtonWidgetClass, form, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); XtAddCallback(button, XmNactivateCallback, HGU_XmImageViewMagPlusCb, data); button = XtVaCreateManagedWidget("Mag-", xmPushButtonWidgetClass, form, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); XtAddCallback(button, XmNactivateCallback, HGU_XmImageViewMagMinusCb, data); text = XtVaCreateManagedWidget("image_fb", xmTextFieldWidgetClass, form, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNcolumns, 10, NULL); button = XtVaCreateManagedWidget("Map greys", xmPushButtonWidgetClass, form, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); XtAddCallback(button, XmNactivateCallback, HGU_XmMapDialogCb, data->greyMapping); /* add scrolling window and canvas */ scrolled_window = XtVaCreateManagedWidget("image_sc", xmScrolledWindowWidgetClass, image_form, XmNscrollingPolicy, XmAUTOMATIC, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, form, NULL); data->width = 512; data->height = 512; canvas = XtVaCreateManagedWidget("canvas", xmDrawingAreaWidgetClass, scrolled_window, XmNwidth, data->width, XmNheight, data->height, NULL); XtAddCallback(canvas, XmNexposeCallback, HGU_XmImageViewCanvasExposeCb, data); XtAddCallback(canvas, XmNinputCallback, HGU_XmImageViewCanvasInputCb, data); XtAddEventHandler(canvas, PointerMotionMask, False, HGU_XmImageViewCanvasMotionEventHandler, data); data->canvas = canvas; return image_form; }
/*! * \return Woolz error code. * \ingroup WlzTransform * \brief Fits a plane to the given vertices using singular value * decomposition. The best fit plane is returned (provided * there is no error) as a unit normal \f$n\f$ and the * centroid of the given vertices ( \f$r_0\f$ ) which in a * point in the plane, with the plane equation * \f[ \vec{n}\cdot(\vec{r} - \vec{r_0}) = \vec{0} \f] * \param vtxType Given vertex type. * \param nVtx Number of given vertices. * \param vtx Given vertices. * \param dstPinP Destination pointer for the return * of the median point (\f$r_0\f$) in * the plane. * \param dstNrm Destination pointer for the unit * normal to the plane (\f$n\f$). */ WlzErrorNum WlzFitPlaneSVD(WlzVertexType vtxType, int nVtx, WlzVertexP vtx, WlzDVertex3 *dstPinP, WlzDVertex3 *dstNrm) { AlgMatrix aMat, vMat; WlzDVertex3 centroid, normal; double *sVec = NULL; AlgError algErr = ALG_ERR_NONE; WlzErrorNum errNum = WLZ_ERR_NONE; aMat.core = NULL; vMat.core = NULL; if(nVtx < 0) { errNum = WLZ_ERR_PARAM_DATA; } else if(vtx.v == NULL) { errNum = WLZ_ERR_PARAM_NULL; } if(errNum == WLZ_ERR_NONE) { if(((sVec = (double *)AlcCalloc(sizeof(double), 3)) == NULL) || ((aMat.rect = AlgMatrixRectNew(nVtx, 3, NULL)) == NULL) || ((vMat.rect = AlgMatrixRectNew(3, 3, NULL)) == NULL)) { errNum = WLZ_ERR_MEM_ALLOC; } } /* Compute a Nx3 matrix from the given vertices then subtract their * centroid. */ if(errNum == WLZ_ERR_NONE) { int i; double *row; WLZ_VTX_3_ZERO(centroid); switch(vtxType) { case WLZ_VERTEX_I3: for(i = 0; i < nVtx; ++i) { WlzIVertex3 *v; v = vtx.i3 + i; row = aMat.rect->array[i]; centroid.vtX += row[0] = v->vtX; centroid.vtY += row[1] = v->vtY; centroid.vtZ += row[2] = v->vtZ; } break; case WLZ_VERTEX_F3: for(i = 0; i < nVtx; ++i) { WlzFVertex3 *v; v = vtx.f3 + i; row = aMat.rect->array[i]; centroid.vtX += row[0] = v->vtX; centroid.vtY += row[1] = v->vtY; centroid.vtZ += row[2] = v->vtZ; } break; case WLZ_VERTEX_D3: for(i = 0; i < nVtx; ++i) { WlzDVertex3 *v; v = vtx.d3 + i; row = aMat.rect->array[i]; centroid.vtX += row[0] = v->vtX; centroid.vtY += row[1] = v->vtY; centroid.vtZ += row[2] = v->vtZ; } break; default: errNum = WLZ_ERR_PARAM_TYPE; break; } if(errNum == WLZ_ERR_NONE) { WLZ_VTX_3_SCALE(centroid, centroid, (1.0 / nVtx)); for(i = 0; i < nVtx; ++i) { row = aMat.rect->array[i]; row[0] -= centroid.vtX; row[1] -= centroid.vtY; row[2] -= centroid.vtZ; } } } /* Compute SVD. */ if(errNum == WLZ_ERR_NONE) { algErr = AlgMatrixSVDecomp(aMat, sVec, vMat); errNum = WlzErrorFromAlg(algErr); } /* Find the vector corresponding to the least singular value. */ if(errNum == WLZ_ERR_NONE) { int i, m; double len; double **ary; const double eps = 1.0e-06; m = 0; for(i = 1; i < 3; ++i) { if(sVec[i] < sVec[m]) { m = i; } } ary = vMat.rect->array; #ifdef WLZ_FITPLANESVD_DEBUG (void )fprintf(stderr, "WlzFitPlaneSVD() singular values = {%lg, %lg, %lg}\n", sVec[0], sVec[1], sVec[2]); (void )fprintf(stderr, "WlzFitPlaneSVD() index of min singular value = %d\n", m); (void )fprintf(stderr, "WlzFitPlaneSVD() singular vectors = \n" "{\n"); for(i = 0; i < 3; ++i) { (void )fprintf(stderr, " {%lg, %lg, %lg}\n", ary[i][0], ary[i][1], ary[i][2]); } (void )fprintf(stderr, "}\n"); #endif /* WLZ_FITPLANESVD_DEBUG */ normal.vtX = ary[0][m]; normal.vtY = ary[1][m]; normal.vtZ = ary[2][m]; len = WLZ_VTX_3_LENGTH(normal); if(len < eps) { errNum = WLZ_ERR_ALG_SINGULAR; } else { WLZ_VTX_3_SCALE(normal, normal, (1.0 / len)); } } AlgMatrixRectFree(aMat.rect); AlgMatrixRectFree(vMat.rect); AlcFree(sVec); if(errNum == WLZ_ERR_NONE) { if(dstNrm) { *dstNrm = normal; } if(dstPinP) { *dstPinP = centroid; } } return(errNum); }
/*! * \return New recursive filter. * \ingroup WlzValueFilters * \brief Creates a new recursive filter. * \param name Name of filter. * \param prm Parameter is alpha for Deriche's * operators and sigma for * Gaussians, must be \f$\geq\f$ 0.0. * \param dstErr Destination error pointer, may * be null. */ WlzRsvFilter *WlzRsvFilterMakeFilter(WlzRsvFilterName name, double prm, WlzErrorNum *dstErr) { int idx; double tD0, tAS, tWS, tExp, tExp2, tNorm, tCos, tSin; WlzRsvFilter *ftr = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; const double cGauss = 2.4726; const double aGauss[3] = { 1.2600, 0.9338, 0.6134}, bGauss[3] = { 0.9629, -0.1051, 1.2280}, gGauss[3] = { 1.9420, 1.8980, -0.2976}, wGauss[3] = { 0.8448, 0.9459, 1.3320}; if((ftr = (WlzRsvFilter *)AlcCalloc(sizeof(WlzRsvFilter), 1)) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else if(name == WLZ_RSVFILTER_NAME_NONE) { ftr->name = WLZ_RSVFILTER_NAME_NONE; } else if(prm < DBL_EPSILON) { errNum = WLZ_ERR_PARAM_DATA; } else { switch(name) { case WLZ_RSVFILTER_NAME_DERICHE_0: /* FALLTHROUGH */ case WLZ_RSVFILTER_NAME_DERICHE_1: /* FALLTHROUGH */ case WLZ_RSVFILTER_NAME_DERICHE_2: tExp = exp(-prm); tExp2 = tExp * tExp; tD0 = 1.0 - tExp; tNorm = (tD0 * tD0) / (1.0 + (2.0 * prm * tExp) - tExp2); ftr->name = name; ftr->b[0] = -2.0 * tExp; ftr->b[1] = tExp2; switch(name) { case WLZ_RSVFILTER_NAME_DERICHE_0: ftr->a[0] = 1.0; ftr->a[1] = (prm - 1.0) * tExp; ftr->a[2] = (prm + 1.0) * tExp; ftr->a[3] = -tExp2; ftr->c = tNorm; break; case WLZ_RSVFILTER_NAME_DERICHE_1: ftr->a[0] = 0.0; tD0 = (prm * prm) * tExp; ftr->a[1] = -tD0; ftr->a[2] = tD0; ftr->a[3] = 0.0; ftr->c = -tNorm; break; case WLZ_RSVFILTER_NAME_DERICHE_2: tD0 = (prm * prm); ftr->a[0] = -tD0; ftr->a[1] = (prm + 1) * tD0 * tExp; ftr->a[2] = (prm - 1) * tD0 * tExp; ftr->a[3] = tD0 * tExp2; ftr->c = tNorm; break; default: break; } break; case WLZ_RSVFILTER_NAME_GAUSS_0: /* FALLTHROUGH */ case WLZ_RSVFILTER_NAME_GAUSS_1: /* FALLTHROUGH */ case WLZ_RSVFILTER_NAME_GAUSS_2: ftr->name = name; switch(name) { case WLZ_RSVFILTER_NAME_GAUSS_0: idx = 0; break; case WLZ_RSVFILTER_NAME_GAUSS_1: idx = 1; break; case WLZ_RSVFILTER_NAME_GAUSS_2: idx = 2; break; default: break; } tWS = wGauss[idx] / prm; tAS = aGauss[idx] / prm; tCos = cos(tWS); tSin = sin(tWS); tExp = exp(-tAS); tExp2 = tExp * tExp; tNorm = 1.0 / (cGauss * prm); ftr->a[0] = bGauss[idx]; tD0 = ((-bGauss[idx] * tCos) + (gGauss[idx] * tSin)) * tExp; ftr->a[1] = tD0; ftr->b[0] = -2.0 * tCos * tExp; ftr->b[1] = tExp2; if(name == WLZ_RSVFILTER_NAME_GAUSS_1) /* Asymetric */ { ftr->a[3] = -(tD0 + (2.0 * bGauss[idx] * tCos * tExp)); ftr->a[2] = bGauss[idx] * tExp2; } else { ftr->a[2] = tD0 + (2.0 * bGauss[idx] * tCos * tExp); ftr->a[3] = -(bGauss[idx] * tExp2); } ftr->c = tNorm; break; default: errNum = WLZ_ERR_PARAM_DATA; break; } } if(dstErr) { *dstErr = errNum; } return(ftr); }
/*! * \return The filtered object, maybe NULL on error. * \ingroup WlzValueFilters * \brief WlzSeqPar performs a sequential or parallel local * transform. A distance transform is an example of a * sequential transform and a laplacian is an example of * a parallel transform. * Only WLZ_2D_DOMAINOBJ objects with values may be passed * to WlzSeqPar(). * \note If the point to be transformed is at line l and col k, * there is an array of pointers spWSpace->adrptr[-7:7], * whose i'th entry gives the address of the point * (l + (i * spWSpace->ldelta), k), but which is only * meaningful for lines within bdrSz of the point. * For example: spWSpace->adrptr[-3] and * spWSpace->adrptr[3] are undefined if bdrSz < 3. * \param srcObj The given WLZ_2D_DOMAINOBJ object. * \param newObjFlag If zero then the given object is * overwritten otherwise a new object is * created. * \param sequentialFlag If non zero the transform is * seqential and transformed * values are used in calculating * the neighbouring values. * If zero the transform always * works on the original grey * values. * \param rasterDir Direction of raster scan. * \param bdrSz Local transform kernel half-size, * must be in range 0 - 7. * The usual 8 immediate neighbors * correspond to bdrSz == 1. * \param bkgVal Background grey value. * \param transformData Data supplied to the transform * function. * \param transformFn Supplied transform function. * \param dstErr Destination error pointer, may * be NULL. */ WlzObject *WlzSeqPar(WlzObject *srcObj, int newObjFlag, int sequentialFlag, WlzRasterDir rasterDir, int bdrSz, int bkgVal, void *transformData, int (*transformFn)(WlzSeqParWSpace *, void *), WlzErrorNum *dstErr) { int tI0, curLine, howManyLn, bdrP1, numBufs, kol, kol1, lineSz, /* lineSz is the maximally sized line, including borders */ lineOffset, /* lineOffset is difference in line numbers between that being transformed and that needed in the input buffer for use in the transform */ nextLine, inLine, needed, idx, itop, minLine; WlzErrorNum errNum = WLZ_ERR_NONE; int *lineBufSpace = NULL, /* lineBufSpace is the current line buffer */ *firstColP, *lastColP, *dstBuf, *lastLnP, *tIP0; WlzIntervalDomain *jdp; WlzObject *dstObj = NULL; WlzSeqParWSpace spWSpace; /* Work space which is passed on to the transform function. */ WlzIntervalWSpace srcIWsp, dstIWsp; WlzGreyWSpace srcGWsp, dstGWsp; int *lineBufs[15], /* lineBufs is the array of line buffers needed to obtain neighbouring points. */ *adrbase[15]; WLZ_DBG((WLZ_DBG_LVL_FN|WLZ_DBG_LVL_1), ("WlzSeqPar FE %p %d %d %d %d %d %p %p %p\n", srcObj, newObjFlag, sequentialFlag, (int )rasterDir, bdrSz, bkgVal, transformData, transformFn, dstErr)); if(srcObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; if(dstErr) { *dstErr = errNum; } return(NULL); } if((srcObj->type != WLZ_2D_DOMAINOBJ) || (srcObj->values.core == NULL) || (srcObj->domain.core == NULL)) { errNum = WLZ_ERR_OBJECT_TYPE; if(dstErr) { *dstErr = errNum; } return(NULL); } /* * Make an array spWSpace.adrptr of pointers with range [-7,7] */ spWSpace.adrptr = adrbase + 7; spWSpace.brdrsz = bdrSz; jdp = srcObj->domain.i; bdrP1 = -bdrSz - 1; /* * The buffer must contain both the current line and bdrSz lines each side. */ numBufs = (bdrSz * 2) + 1; kol1 = kol = jdp->kol1; lineSz = jdp->lastkl - kol + numBufs; /* * Some pointers to first/last line and column positions * to accomodate different rasters */ firstColP = &dstIWsp.lftpos; lastColP = &dstIWsp.rgtpos; lastLnP = &jdp->lastln; /* * spWSpace.kdelta is increment to adrs when processing points * if positive, procede left to right in lines * if negative procede right to left * spWSpace.ldelta is increment to line number * if positive, the raster is proceeding in increasing line numbers * if negative the raster is procceding with decreasing line numbers */ spWSpace.kdelta = 1; spWSpace.ldelta = 1; /* * Alter parameters for right to left rasters */ if(!sequentialFlag) { rasterDir = WLZ_RASTERDIR_ILIC; } if((rasterDir == WLZ_RASTERDIR_ILDC) || (rasterDir == WLZ_RASTERDIR_DLDC)) { tIP0 = firstColP; firstColP = lastColP; lastColP = tIP0; spWSpace.kdelta = -1; } /* * Alter parameters for bottom to top rasters */ if((rasterDir == WLZ_RASTERDIR_DLIC) || (rasterDir == WLZ_RASTERDIR_DLDC)) { spWSpace.ldelta = -1; lastLnP = &jdp->line1; } lineOffset = bdrSz * spWSpace.ldelta; /* * Allocate space to buffers */ lineBufSpace = (int *)AlcCalloc(lineSz * (numBufs + 1), sizeof(int)); for(idx = 0; idx < numBufs; ++idx) { lineBufs[idx] = lineBufSpace + (idx + 1) * lineSz; } /* * Either use existing object or create a new grey table object * according to the newObjFlag. * If a new object is required then it is created with the SAME interval * list and property list and a DIFFERENT but IDENTICAL grey table. */ if(newObjFlag) { dstObj = WlzNewGrey(srcObj, &errNum); } else { dstObj = srcObj; } /* * Use nxxiv in transplant mode, placing and taking grey values * from the line buffers * srcIWsp is the workspace for entering values into the line buffers * dstIWsp is the workspace for processing the intervals and replacing * the transformed values into the grey table */ srcGWsp.gvio = 1; /* output (since we are specifying tranpl) */ dstGWsp.gvio = 0; /* input */ errNum = WlzInitGreyRasterScan(srcObj, &srcIWsp, &srcGWsp, rasterDir, 1); if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyRasterScan(dstObj, &dstIWsp, &dstGWsp, rasterDir, 1); } if(errNum != WLZ_ERR_NONE) { if(dstErr) { *dstErr = errNum; } return(NULL); } /* * curLine is the line currently being processed * inLine is the last line entered into the line buffers * initialize it to an imaginary line just before the first border line */ (void )WlzNextInterval(&srcIWsp); nextLine = srcIWsp.linpos; inLine = srcIWsp.linpos - (spWSpace.ldelta * (bdrSz + 1)); /* * Process the next interval */ while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&dstIWsp)) == WLZ_ERR_NONE)) { /* * When processing curLine, the line buffer must contain * lines upto needed=curLine+border width */ curLine = dstIWsp.linpos; needed = curLine + lineOffset; /* * Next action depends which lines are aleady in the line buffers */ howManyLn = (needed - inLine) * spWSpace.ldelta; WLZ_DBG((WLZ_DBG_LVL_3), ("WlzSeqPar 01 %d %d\n", inLine, curLine)); if(howManyLn < 0) { /* * This is an error it is impossible to have input a line before needed */ errNum = WLZ_ERR_DOMAIN_DATA; if(dstErr) { *dstErr = errNum; } return(NULL); } else if(howManyLn > 0) { /* * If howManyLn > 0 we need to input some lines to input buffer * routine to fill the input buffers used to determine the value * of the transform needed = maximal(minimal)line needed to be filled * into the buffer * if backwards raster, needed = curLine - bdrSz * if forwards raster, needed = curLine + bdrSz * nextLine = line number of the next interval to be filed by nxxiv */ while(1) { if((needed - nextLine) * spWSpace.ldelta < 0) { /* * Next line needed less far away than next line available * from nxxint fill required buffer lines with bkgVal and return * minLine = WlzSeqParPosMod(inLine, numBufs), i.e. the remainder * of inLine when divided by numBufs. * It thus can be used as the offset into the array of * logical line addresses to determine which line in the * circular buffer inLine is being stored */ while(inLine != needed) { inLine += spWSpace.ldelta; minLine = WlzSeqParPosMod(inLine, numBufs); WlzValueSetInt(lineBufs[minLine], bkgVal, lineSz); } break; } /* * Line(s) needed include some real lines, i.e. obtained from nxxiv * first fill buffer with bkgVal */ while(inLine != nextLine) { inLine += spWSpace.ldelta; minLine = WlzSeqParPosMod(inLine, numBufs); WlzValueSetInt(lineBufs[minLine], bkgVal, lineSz); } /* * nxxint interval to be put into buffer calculate adrs in * buffer by adding leftcol to logical adrs stored in * lineBufs[minLine]. then insert with nxxiv */ do { srcGWsp.u_grintptr.inp = lineBufs[minLine] + srcIWsp.lftpos + bdrSz - kol1; WlzGreyInterval(&srcIWsp); /* * Call nxxint to get next interval if in same line store in buffer */ if(WlzNextInterval(&srcIWsp) != 0) { /* * When nxxint has finished all interval set a high value into * nextLine, so all future lines input will be dummy lines */ nextLine = (*lastLnP) - (bdrP1 * spWSpace.ldelta); goto filledLABEL; } } while(srcIWsp.nwlpos == 0); /* * If next interval in new line,store new line number and * jump to start of routine to see what sort of line buffer * processing is required next */ nextLine = srcIWsp.linpos; } } /* * Line buffers filled for processing of this line either from above call * or buffer filled for previous intervals processed on this line * kol is the first point in the interval to be processed * itop is the last point to be processed */ filledLABEL: /* LABEL! see goto above */ kol = *firstColP; itop = *lastColP; /* * First load spWSpace.adrptr with addresses of required neighbors */ idx = bdrP1; while(idx++ < bdrSz) { tI0 = idx * spWSpace.ldelta; spWSpace.adrptr[idx] = lineBufs[WlzSeqParPosMod(curLine + tI0, numBufs)] + kol + bdrSz - kol1; } /* * Then set the pointer where the transformed value will be placed * if parallel mode, adrs is in current line buffer * if sequential mode, adrs is in input buffer * dstGWsp.grintptr is the location in the nxxiv workspace * giving the location from which nxxiv will transplant * values into the grey table */ if(sequentialFlag) { dstBuf = spWSpace.adrptr[0]; } else { dstBuf = lineBufSpace + bdrSz; } dstGWsp.u_grintptr.inp = dstBuf + dstIWsp.lftpos - kol; /* * Procede thru interval,calling the transforming function * at each point and storing the result where required */ kol -= spWSpace.kdelta; while(kol != itop) { kol += spWSpace.kdelta; *dstBuf = (*transformFn)(&spWSpace, transformData); /* * after each point, update the neighbor adrs and the output adrs */ idx = bdrP1; while(idx++ < bdrSz) { spWSpace.adrptr[idx] += spWSpace.kdelta; } dstBuf += spWSpace.kdelta; } /* * Having finished this interval proceed to the next */ } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } if(lineBufSpace) { AlcFree((void *)lineBufSpace); } if(dstErr) { *dstErr = errNum; } WLZ_DBG((WLZ_DBG_LVL_FN|WLZ_DBG_LVL_1), ("WlzSeqPar FX %p\n", dstObj)); return(dstObj); }
/*! * \return Woolz error code. * \ingroup WlzExtFF * \brief Reads an IPL header from the given file stream. * \param header Given header data structure to be * filled in. * \param fP Given input file stream. */ static WlzErrorNum WlzEffHeadReadIPL(WlzEffIPLHeader *header, FILE *fP) { WlzGreyP p; WlzErrorNum errNum = WLZ_ERR_NONE; double dBuf[4]; p.dbp = dBuf; /* version, format and datatype */ if( fread(p.v, sizeof(char), 6, fP) != 6 ){ errNum = WLZ_ERR_READ_INCOMPLETE; } else { /* should test this version */ strncpy(&(header->version[0]), (const char *)(p.ubp), 4); if( (header->format = p.ubp[4]) != 0 ){ errNum = WLZ_ERR_PARAM_TYPE; } switch(p.ubp[5]){ case 0: header->dType = WLZEFF_IPL_TYPE_UBYTE; break; case 1: header->dType = WLZEFF_IPL_TYPE_SHORT; break; case 2: header->dType = WLZEFF_IPL_TYPE_INT; break; case 3: header->dType = WLZEFF_IPL_TYPE_FLOAT; break; case 4: header->dType = WLZEFF_IPL_TYPE_COL_16; break; case 5: header->dType = WLZEFF_IPL_TYPE_COL_24; break; case 6: header->dType = WLZEFF_IPL_TYPE_U_16; break; default: errNum = WLZ_ERR_PARAM_TYPE; break; } } /* height and width */ if( errNum == WLZ_ERR_NONE ){ if( fread(p.v, sizeof(char), 4, fP) != 4 ){ errNum = WLZ_ERR_READ_INCOMPLETE; } header->nWidth = *(p.inp); } if( errNum == WLZ_ERR_NONE ){ if( fread(p.v, sizeof(char), 4, fP) != 4 ){ errNum = WLZ_ERR_READ_INCOMPLETE; } header->nHeight = *(p.inp); } /* various id's and modes */ if( errNum == WLZ_ERR_NONE ){ if( fread(p.v, sizeof(char), 6, fP) != 6 ){ errNum = WLZ_ERR_READ_INCOMPLETE; } header->fileClutID = p.ubp[0]; header->overlayInFile = p.ubp[1]; header->viewMode = p.ubp[4]; } /* number of sections */ if( errNum == WLZ_ERR_NONE ){ if( fread(p.v, sizeof(char), 2, fP) != 2 ){ errNum = WLZ_ERR_READ_INCOMPLETE; } header->nFrames = *(p.shp); } /* delta? plus reserved space */ if( errNum == WLZ_ERR_NONE ){ if( fread(p.v, sizeof(char), 8, fP) != 8 ){ errNum = WLZ_ERR_READ_INCOMPLETE; } header->delta = *(p.dbp); } if( errNum == WLZ_ERR_NONE ){ if( fread(p.v, sizeof(char), 4, fP) != 4 ){ errNum = WLZ_ERR_READ_INCOMPLETE; } } /* units string */ if( errNum == WLZ_ERR_NONE ){ if( fread(p.v, sizeof(char), 10, fP) != 10 ){ errNum = WLZ_ERR_READ_INCOMPLETE; } strncpy(&(header->units[0]), (const char *) p.v, 10); } /* normalisation data */ if( errNum == WLZ_ERR_NONE ){ if( fread(p.v, sizeof(char), 4, fP) != 4 ){ errNum = WLZ_ERR_READ_INCOMPLETE; } header->normType = p.ubp[1]; header->normSource = p.ubp[2]; header->numRegNarks = p.ubp[3]; } if( errNum == WLZ_ERR_NONE ){ if( fread(p.v, sizeof(char), 8, fP) != 8 ){ errNum = WLZ_ERR_READ_INCOMPLETE; } header->normMin = *(p.dbp); } if( errNum == WLZ_ERR_NONE ){ if( fread(p.v, sizeof(char), 4, fP) != 4 ){ errNum = WLZ_ERR_READ_INCOMPLETE; } } if( errNum == WLZ_ERR_NONE ){ if( fread(p.v, sizeof(char), 8, fP) != 8 ){ errNum = WLZ_ERR_READ_INCOMPLETE; } header->normMax = *(p.dbp); } if( errNum == WLZ_ERR_NONE ){ if( fread(p.v, sizeof(char), 4, fP) != 4 ){ errNum = WLZ_ERR_READ_INCOMPLETE; } } /* now read the color table */ if( errNum == WLZ_ERR_NONE ){ if( (header->colorTable = (void *) AlcCalloc(2048, sizeof(char))) == NULL ){ errNum = WLZ_ERR_MEM_ALLOC; } else { if( fread(header->colorTable, sizeof(char), 2048, fP) != 2048 ){ errNum = WLZ_ERR_READ_INCOMPLETE; } } } return(errNum); }
/*! * \return Object with domain equal to the set difference between the * first and second object, with valuetable from the first * object. * \ingroup WlzDomainOps * \brief Calculates the domain difference between two objects. * \param obj1 First object. * \param obj2 Second object. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzDiffDomain( WlzObject *obj1, WlzObject *obj2, WlzErrorNum *dstErr) { WlzIntervalWSpace iwsp2, iwsp1; WlzInterval *intp; WlzInterval *jntp; WlzDomain diffdom; WlzValues values; WlzIntervalDomain *idom1; int k1, dfinished, intervalcount; WlzObject *diff=NULL; WlzErrorNum errNum=WLZ_ERR_NONE; diffdom.core = NULL; /* check object 1 */ if( obj1 == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } if( errNum == WLZ_ERR_NONE ){ switch( obj1->type ){ case WLZ_2D_DOMAINOBJ: case WLZ_3D_DOMAINOBJ: if( obj1->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } break; case WLZ_EMPTY_OBJ: diffdom.i = NULL; values.v = NULL; return WlzMakeMain(WLZ_EMPTY_OBJ, diffdom, values, NULL, NULL, dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* check object 2 - obj2 == NULL is now an error */ if( (errNum == WLZ_ERR_NONE) && (obj2 == NULL) ){ errNum = WLZ_ERR_OBJECT_NULL; } if( errNum == WLZ_ERR_NONE ){ switch( obj2->type ){ case WLZ_2D_DOMAINOBJ: case WLZ_3D_DOMAINOBJ: if( obj2->type != obj1->type ){ errNum = WLZ_ERR_OBJECT_TYPE; break; } if( obj2->domain.core == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; break; } break; case WLZ_EMPTY_OBJ: return WlzMakeMain(obj1->type, obj1->domain, obj1->values, NULL, NULL, dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* switch for 3D objects */ if( (errNum == WLZ_ERR_NONE) && (obj1->type == WLZ_3D_DOMAINOBJ) ){ return WlzDiffDomain3d( obj1, obj2, dstErr ); } /* * make a new interval table that is big enough */ if( errNum == WLZ_ERR_NONE ){ idom1 = obj1->domain.i; k1 = idom1->kol1; if( (intp = (WlzInterval *) AlcCalloc(WlzIntervalCount(idom1, NULL) + WlzIntervalCount(obj2->domain.i, NULL), sizeof(WlzInterval))) == NULL ){ errNum = WLZ_ERR_MEM_ALLOC; } jntp = intp; } if( errNum == WLZ_ERR_NONE ){ if( (diffdom.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, idom1->line1, idom1->lastln, k1, idom1->lastkl, &errNum)) == NULL ){ AlcFree((void *) intp); } else { diffdom.i->freeptr = AlcFreeStackPush(diffdom.i->freeptr, (void *)intp, NULL); } } if( errNum == WLZ_ERR_NONE ){ if( (diff = WlzMakeMain(WLZ_2D_DOMAINOBJ, diffdom, obj1->values, NULL, NULL, &errNum)) == NULL ){ WlzFreeIntervalDomain(diffdom.i); } } /* * initialise interval scanning */ if( errNum == WLZ_ERR_NONE ){ errNum = WlzInitRasterScan(obj1, &iwsp1, WLZ_RASTERDIR_ILIC); } if( errNum == WLZ_ERR_NONE ){ errNum = WlzInitRasterScan(obj2, &iwsp2, WLZ_RASTERDIR_ILIC); dfinished = 0; intervalcount = 0; } /* * scan object constructing intervals after subtraction of obj2 */ if( (errNum == WLZ_ERR_NONE) && ((errNum = WlzNextInterval(&iwsp2)) == WLZ_ERR_NONE) ){ while( (errNum = WlzNextInterval(&iwsp1)) == WLZ_ERR_NONE ){ /* * case 1 - interval in obj1 succedes interval in obj2 - * get next interval of obj2 */ while( (errNum == WLZ_ERR_NONE) && (dfinished == 0) && (iwsp1.linpos > iwsp2.linpos || (iwsp1.linpos == iwsp2.linpos && iwsp1.lftpos > iwsp2.rgtpos))){ switch( errNum = WlzNextInterval(&iwsp2) ){ case WLZ_ERR_NONE: dfinished = 0; break; case WLZ_ERR_EOO: errNum = WLZ_ERR_NONE; dfinished = 1; break; default: break; } } if( errNum != WLZ_ERR_NONE ){ break; } /* * case 2 - interval in obj1 precedes interval in obj2 * or obj2 finished - just copy interval */ if( (dfinished != 0) || (iwsp1.linpos < iwsp2.linpos || ((iwsp1.linpos == iwsp2.linpos) && (iwsp1.rgtpos < iwsp2.lftpos)) ) ){ jntp->ileft = iwsp1.lftpos - k1; jntp->iright = iwsp1.rgtpos - k1; intervalcount++; jntp++; } /* * case 3 - intervals overlap. * there may be more than one obj2 interval. */ else { /* * test left end of obj1 interval < left * end of obj2 interval, when complete * interval can be constructed immediately */ if (iwsp2.lftpos > iwsp1.lftpos) { jntp->ileft = iwsp1.lftpos - k1; jntp->iright = iwsp2.lftpos -1 - k1; intervalcount++; jntp++; } do { /* * if right end of obj2 interval < * right end of obj1 interval can * plant left end of new interval */ if (iwsp2.rgtpos < iwsp1.rgtpos) { jntp->ileft = iwsp2.rgtpos +1 - k1; switch( errNum = WlzNextInterval(&iwsp2) ){ case WLZ_ERR_NONE: dfinished = 0; break; case WLZ_ERR_EOO: errNum = WLZ_ERR_NONE; dfinished = 1; break; default: break; } if( errNum != WLZ_ERR_NONE ){ break; } /* * check if next obj2 interval * still overlaps this obj1 interval */ if( (dfinished == 0) && (iwsp1.linpos == iwsp2.linpos) && (iwsp1.rgtpos >= iwsp2.lftpos)) jntp->iright = iwsp2.lftpos -1 -k1; else jntp->iright = iwsp1.rgtpos - k1; intervalcount++; jntp++; } } while( (dfinished == 0) && (iwsp1.linpos == iwsp2.linpos) && (iwsp1.rgtpos > iwsp2.rgtpos) ); } if( errNum != WLZ_ERR_NONE ){ break; } /* * is this obj1 interval the last in the line ? * if so, load up the new intervals into the * diff domain. */ if (iwsp1.intrmn == 0) { errNum = WlzMakeInterval(iwsp1.linpos, diffdom.i, intervalcount, intp); intervalcount = 0; intp = jntp; } if( errNum != WLZ_ERR_NONE ){ break; } } } if(errNum == WLZ_ERR_EOO) /* Reset error from end of intervals */ { errNum = WLZ_ERR_NONE; } /* this checks the area and returns NULL if zero in principle it should return an "empty object" */ if(errNum == WLZ_ERR_NONE) { if(WlzIntervalCount(diffdom.i, NULL) == 0){ WlzFreeObj(diff); diffdom.i = NULL; values.v = NULL; diff = WlzMakeEmpty(&errNum); } else { WlzStandardIntervalDomain(diff->domain.i); } } else { WlzFreeObj(diff); diff = NULL; } if( dstErr ){ *dstErr = errNum; } return diff; }
/*! * \ingroup WlzBinaryOps * \brief Segment a domain into connected parts. Connectivity is defined by the connect parameter and can be 4- or 8-connected for 2D objects and 6-, 18- or 26-connected for 3D objects. Note this version requires that there is sufficient space in the objects array defined by maxNumObjs and this is not extended. This should be changed in future so that the array is extended as required. * * \return Error number. * \param obj input object to be segmented * \param mm number of objects return * \param dstArrayObjs object array return, allocated in the procedure. * \param maxNumObjs maximum number of object to return (determines the size of the array) * \param ignlns ignore objects with num lines <= ignlns * \param connect connectivity to determine connected regions * \par Source: * WlzLabel.c */ WlzErrorNum WlzLabel( WlzObject *obj, int *mm, WlzObject ***dstArrayObjs, int maxNumObjs, int ignlns, WlzConnectType connect) { WlzIntervalDomain *jdp; WlzRagRValues *jvp; WlzIntervalWSpace iwsp; WlzInterval *itvl; WlzInterval *jtvl; WlzLAllocBuf *crntal, *altemp; WlzLAllocBuf *al, *crntst, *crlast; WlzLAllocBuf *precal, *precst, *prlast; int nints, mkl; int maxinline,nob,line,ended,lend,chainlistsize; WlzLLink *freechain, *alprec, *alloc, *link1, *link2; int lftcrn, lftprc, rtcrn, rtprec; int jrtcrn, mxkl, jl, jr; int oll, ofl, jjj; WlzDomain domain; WlzValues values; int jdqt; WlzErrorNum errNum=WLZ_ERR_NONE; WlzObject **objlist; /* see HISTORY for comments from the FORTRAN version */ /* now we allocate space for the objects */ if( (objlist = (WlzObject **)AlcMalloc(sizeof(WlzObject *) * maxNumObjs)) == NULL ){ errNum = WLZ_ERR_MEM_ALLOC; } else { *dstArrayObjs = objlist; } /* check object note *mm is always set to zero on error return because the "Too many objects" error can return nobj valid objects therefore if *mm != 0 there are valid objects in objlist which must be freed */ if( obj == NULL ){ *mm = 0; return WLZ_ERR_OBJECT_NULL; } /* check types */ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.core == NULL ){ *mm = 0; return WLZ_ERR_DOMAIN_NULL; } switch( obj->domain.core->type ){ case WLZ_INTERVALDOMAIN_INTVL: break; case WLZ_INTERVALDOMAIN_RECT: if( (obj->domain.i->lastln - obj->domain.i->line1) < ignlns ){ *mm = 0; return( WLZ_ERR_NONE ); } if( maxNumObjs < 1 ){ *mm = 0; return( WLZ_ERR_INT_DATA ); } objlist[0] = WlzAssignObject( WlzMakeMain(obj->type, obj->domain, obj->values, NULL, NULL, &errNum), NULL); *mm = 1; return WLZ_ERR_NONE; default: *mm = 0; return WLZ_ERR_DOMAIN_TYPE; } break; case WLZ_3D_DOMAINOBJ: if( obj->domain.core == NULL ){ *mm = 0; return WLZ_ERR_DOMAIN_NULL; } return WlzLabel3d(obj, mm, objlist, maxNumObjs, ignlns, connect); case WLZ_EMPTY_OBJ: *mm = 0; return WLZ_ERR_NONE; case WLZ_TRANS_OBJ: /* should be able to do this quite easily */ default: *mm = 0; return WLZ_ERR_OBJECT_TYPE; } /* check connectivity parameter */ switch( connect ){ default: return WLZ_ERR_INT_DATA; case WLZ_8_CONNECTED: jdqt = 0; break; case WLZ_4_CONNECTED: jdqt = 1; break; } /* * Allocate and initialise the working spaces. * * The chain store size is not easily predictable. * Here we use ((twice the number of lines) plus (one third the * number of intervals)), very much smaller than the * previous allocation, but apparently adequate to * segment both metaphase spreads and single connected objects. * In any case, this version of label can if necessary allocate * more space when the original chain store fills up. */ chainlistsize = mintcount(obj->domain.i, &maxinline) / 3; chainlistsize += (1 + obj->domain.i->lastln - obj->domain.i->line1)*2; if( (freechain = chainalloc(0,chainlistsize)) == NULL ){ *mm = 0; return WLZ_ERR_MEM_ALLOC; } buckle(freechain, freechain, chainlistsize); /* * The allocation list size is determined as twice * (1 + maximum number of intervals in a line of input object). */ if( (al = (WlzLAllocBuf *) AlcCalloc(2 * (maxinline+1), sizeof(WlzLAllocBuf))) == NULL ){ chainFree(); *mm = 0; return WLZ_ERR_MEM_ALLOC; } jvp = obj->values.v; /* initialise interval scanning */ WlzInitRasterScan (obj, &iwsp, WLZ_RASTERDIR_ILIC); line = iwsp.linpos; ended = 0 ; lend = 0 ; WlzNextInterval(&iwsp); crntst = al + 1 + maxinline; nob = 0 ; prlast = al ; precst = al + 1 ; /* commence new line */ while (!ended) { crntal = crntst-1 ; line++; if (lend) { ended = 1 ; lend = 0 ; } else { /* read the intervals into the allocation buffer */ while (iwsp.linpos <= line) { crntal++; crntal->a_int.ileft = iwsp.lftpos; crntal->a_int.iright = iwsp.rgtpos; if (WlzNextInterval(&iwsp) != 0) { lend = 1 ; break ; } } } crlast = crntal ; crntal = crntst ; precal = precst ; alloc = NULL ; /* test whether last interval in current line dealt with */ while (crntal <= crlast) { lftcrn = crntal->a_int.ileft ; jrtcrn = crntal->a_int.iright ; rtcrn = jrtcrn+2 ; alprec = precal->a_link; lftprc = precal->a_int.ileft ; rtprec = precal->a_int.iright +2 ; /* test whether last interval in preceeding line dealt with */ if (precal > prlast || rtcrn <= lftprc + jdqt) { /* is interval in current line already allocated */ if (!alloc) { /* start a new object and allocate this interval to it */ /* interval list */ link1 = newchain2(freechain,lftcrn,jrtcrn); /* line-of-intervals list */ link2 = newchain1(freechain, (unsigned long) link1); /* "object" -- first line, last line, line-of-intervals pointer */ crntal->a_link = newchain1(freechain,line) ; crntal->a_link = addlink1 (freechain, crntal->a_link, (unsigned long)line); crntal->a_link = addlink1 (freechain, crntal->a_link, (unsigned long) link2); } /* move on to next interval in current line */ crntal++ ; alloc = NULL; } else { if (rtprec > lftcrn+ (int )jdqt) { /* case of overlapping intervals: */ /* is intvl in current line already allocated ? */ if (!alloc) { /* allocate this interval and add to object list */ alloc = alprec ; link1 = alloc->l_link ; crntal->a_link = alloc ; /* test whether this line has already been started for this object */ if (link1->l_u.line != line) { /* update last line */ link1->l_u.line = line; /* add a link to the line list for this line */ link1 = newchain2(freechain,lftcrn,jrtcrn); alloc->l_u.u_link = addlink1 (freechain, alloc->l_u.u_link, (unsigned long) link1); } else { /* add interval to interval list for last line */ link1 = alloc->l_u.u_link; link1->l_u.u_link = addlink2 (freechain, link1->l_u.u_link, lftcrn, jrtcrn); } } else { /* merge lists and reallocate intervals */ /* test whether both already allocated to same object */ if (alprec != alloc) { merge (&alprec, &alloc, freechain); /* reallocate intervals in preceding line */ for (altemp = precst; altemp <= prlast; altemp++) { if (altemp->a_link == alloc) { altemp->a_link = alprec ; } } /* reallocate intervals in current line */ for (altemp = crntst; altemp <= crntal; altemp++) { if (altemp->a_link == alloc) { altemp->a_link = alprec ; } } alloc = alprec ; } } if (rtcrn < rtprec) { /* move to next interval in this line */ crntal++; alloc = NULL ; continue; /* the outer while loop */ } } /* move on to next interval in preceding line */ precal++ ; } } /* all intervals in current line dealt with: */ /* find and construct any finished objects */ if (precst <= prlast) { for (precal = precst; precal <= prlast; precal++) { alprec = precal->a_link ; /* has the object to which this interval was allocated been dealt with */ if (alprec) { /* remove any later intervals allocated to the same object */ for (altemp = precal; altemp <= prlast; altemp++) { if (altemp->a_link == alprec) { altemp->a_link = NULL ; } } /* test if this object has intervals in the current line */ /* and if so skip to end of outer loop */ if (crntst <= crlast) { for (altemp = crntst; altemp <= crlast; altemp++) { if (altemp->a_link == alprec) goto loopend; } } /* construct object - first find line and column bounds */ link1 = alprec->l_link; oll = (int) link1->l_u.line; link1 = link1->l_link; ofl = (int) link1->l_u.line; link1 = alprec->l_u.u_link; mkl = 0; /* Just to keep lint happy. */ mxkl = 0; /* Just to keep lint happy. */ nints = 0; for (jjj=ofl; jjj<=oll; jjj++) { link1 = link1->l_link; link2 = link1->l_u.u_link; do { link2 = link2->l_link; jl = link2->l_u.intv.ileft; jr = link2->l_u.intv.iright; if (nints == 0 || jl < mkl) mkl = jl ; if (nints == 0 || jr > mxkl) mxkl = jr ; nints++; /* test for end of line */ } while (link2 != link1->l_u.u_link); } /* test whether object large enough, if not ignore it */ /* test for height or width less than threshold */ if (oll-ofl < ignlns || mxkl-mkl < ignlns) { for (jjj = ofl; jjj <= oll; jjj++) { link1 = link1->l_link; link2 = link1->l_u.u_link; /* recover chain space */ join (freechain, link2) ; } } else { /* test for object array overflow */ if (nob >= maxNumObjs) { AlcFree((void *) al); chainFree(); *mm = nob; return(WLZ_ERR_INT_DATA); } link1 = alprec->l_u.u_link; /* set up domain and object, and update counts need to test successful space allocation here */ jdp = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, ofl,oll,mkl,mxkl, &errNum); domain.i = jdp; values.v = jvp; *objlist = WlzAssignObject( WlzMakeMain(WLZ_2D_DOMAINOBJ, domain,values,NULL,obj,&errNum), NULL); objlist++; nob++; /* get the size correct here !!! */ itvl = (WlzInterval *) AlcMalloc (nints * sizeof(WlzInterval)); jdp->freeptr = AlcFreeStackPush(jdp->freeptr, (void *)itvl, NULL); /* write intervals and interval pointers lists */ for (jjj=ofl; jjj<=oll; jjj++) { jtvl = itvl; nints = 0; link1 = link1->l_link; link2 = link1->l_u.u_link; do { /* * the following increment since the interval * list is circular, monotone increasing, * but link2 originally points at the * rightmost interval (see comment at top). */ link2 = link2->l_link; itvl->ileft = link2->l_u.intv.ileft - mkl; itvl->iright = link2->l_u.intv.iright - mkl; itvl++; nints++; /* test for end of line */ } while (link2 != link1->l_u.u_link); WlzMakeInterval(jjj,jdp,nints,jtvl); join (freechain, link2) ; } } /* return line list etc to free-list store */ join (freechain, alprec->l_u.u_link); join (freechain, alprec) ; } loopend: ; } } /* update pointers - swap the two halves of the allocation list */ /* before getting the intervals in the next line */ altemp = crntst ; crntst = precst ; precst = altemp ; prlast = crlast ; } *mm = nob ; AlcFree((void *) al); chainFree(); return WLZ_ERR_NONE; }
int main(int argc, char *argv[]) { int id0, id1, rpt, option, ok = 1, usage = 0, special = 0, sz = 10, nRpt = 1, itr = 1000, timer = 0, verbose = 0; long seed = 0; double del, tol = 0.000001, zF = 0.9; double *b0 = NULL, *b1 = NULL, *x0 = NULL, *i0 = NULL, *r0 = NULL; AlgMatrix a0, a1, w; AlgMatrixTestMtd mtd = ALG_MATRIX_TST_MTD_CG; AlgMatrixType aType = ALG_MATRIX_RECT; AlgError errCode = ALG_ERR_NONE; struct timeval times[3]; const char *optList = "d:n:r:t:vz:CLPQSRTUY"; a0.core = NULL; a1.core = NULL; w.core = NULL; while((usage == 0) && ((option = getopt(argc, argv, optList)) != -1)) { switch(option) { case 'd': if(sscanf(optarg, "%ld", &seed) != 1) { usage = 1; } case 'n': if((sscanf(optarg, "%d", &sz) != 1) || (sz < 1)) { usage = 1; } break; case 'r': if((sscanf(optarg, "%d", &nRpt) != 1) || (nRpt < 0)) { usage = 1; } break; case 't': if((sscanf(optarg, "%lg", &tol) != 1) || (tol < 0.0) || (tol > 0.1)) { usage = 1; } break; case 'v': verbose = 1; break; case 'z': if((sscanf(optarg, "%lg", &zF) != 1) || (zF < 0.0) || (tol > 1.0)) { usage = 1; } break; case 'C': mtd = ALG_MATRIX_TST_MTD_CG; break; case 'L': aType = ALG_MATRIX_LLR; break; case 'P': special = 1; break; case 'Q': mtd = ALG_MATRIX_TST_MTD_LSQR; break; case 'S': mtd = ALG_MATRIX_TST_MTD_SVD; break; case 'R': aType = ALG_MATRIX_RECT; break; case 'T': timer = 1; break; case 'U': mtd = ALG_MATRIX_TST_MTD_LU; break; case 'Y': aType = ALG_MATRIX_SYM; break; default: usage = 1; break; } } ok = (usage == 0); if(ok) { AlgRandSeed(seed); a0 = AlgMatrixNew(aType, sz, sz, sz * sz, tol, NULL); a1 = AlgMatrixNew(aType, sz, sz, sz * sz, tol, NULL); if(verbose) { r0 = (double *)AlcMalloc(sz * sizeof(double)); } w.rect = AlgMatrixRectNew(4, sz, NULL); b0 = (double *)AlcCalloc(sz, sizeof(double)); b1 = (double *)AlcCalloc(sz, sizeof(double)); x0 = (double *)AlcCalloc(sz, sizeof(double)); i0 = (double *)AlcCalloc(sz, sizeof(double)); for(id1 = 0; id1 < sz; ++id1) { double v; for(id0 = 0; id0 < id1; ++id0) { v = AlgRandUniform(); if((v > zF) && (zF < 0.999999)) { v = 0.5 * (v - zF) / (1.0 - zF); AlgMatrixSet(a0, id1, id0, v); AlgMatrixSet(a0, id0, id1, v); } } v = ((2 * id1) % 5) * 0.2 + 1.0; AlgMatrixSet(a0, id1, id1, v); *(b0 + id1) = ((id1) % 3) * AlgRandUniform(); *(i0 + id1) = 1.0; } if(verbose != 0) { AlgVectorCopy(b1, b0, sz); (void )fprintf(stderr, "A = [\n"); (void )AlgMatrixWriteAscii(a0, stderr); (void )fprintf(stderr, "]\nb = [\n"); for(id0 = 0; id0 < sz; ++id0) { if(id0 < (sz - 1)) { (void )fprintf(stderr, "%g;\n", b0[id0]); } else { (void )fprintf(stderr, "%g]\n", b0[id0]); } } } for(rpt = 0; rpt < nRpt; ++rpt) { long tL; switch(mtd) { case ALG_MATRIX_TST_MTD_CG: del = tol; AlgVectorCopy(x0, i0, sz); gettimeofday(times + 0, NULL); errCode = AlgMatrixCGSolve(a0, x0, b0, w, NULL, NULL, tol, itr, &del, &itr); gettimeofday(times + 1, NULL); break; case ALG_MATRIX_TST_MTD_LSQR: gettimeofday(times + 0, NULL); errCode = AlgMatrixSolveLSQR(a0, b0, x0, 1.0e-10, 1.0e-10, 1.0e-10, itr, 0, NULL, &tL, NULL, NULL, NULL, NULL, NULL); gettimeofday(times + 1, NULL); itr = tL; break; case ALG_MATRIX_TST_MTD_LU: AlgVectorCopy(x0, b0, sz); (void )AlgMatrixCopy(a1, a0); if((special != 0) && ((sz == 3) || (sz == 4)) && (aType == ALG_MATRIX_RECT)) { if(sz == 3) { gettimeofday(times + 0, NULL); errCode = AlgMatrixLUSolveRaw3(a1.rect->array, x0, 1); gettimeofday(times + 1, NULL); } else /* sz == 4 */ { gettimeofday(times + 0, NULL); errCode = AlgMatrixLUSolveRaw4(a1.rect->array, x0, 1); gettimeofday(times + 1, NULL); } } else { gettimeofday(times + 0, NULL); errCode = AlgMatrixLUSolve(a1, x0, 1); gettimeofday(times + 1, NULL); } break; case ALG_MATRIX_TST_MTD_SVD: AlgVectorCopy(x0, b0, sz); (void )AlgMatrixCopy(a1, a0); gettimeofday(times + 0, NULL); errCode = AlgMatrixSVSolve(a1, x0, tol, NULL); gettimeofday(times + 1, NULL); break; default: break; } } if(verbose != 0) { (void )fprintf(stderr, "x = [\n"); for(id1 = 0; id1 < sz; ++id1) { (void )fprintf(stderr, "%g", *(x0 + id1)); if(id1 < (sz - 1)) { (void )fprintf(stderr, ";\n"); } else { (void )fprintf(stderr, "]\n"); } } AlgMatrixVectorMul(r0, a0, x0); AlgVectorSub(r0, r0, b1, sz); (void )fprintf(stderr, "r = [\n"); for(id1 = 0; id1 < sz; ++id1) { (void )fprintf(stderr, "%g", *(r0 + id1)); if(id1 < (sz - 1)) { (void )fprintf(stderr, ";\n"); } else { (void )fprintf(stderr, "]\n"); } } } else { for(id1 = 0; id1 < sz; ++id1) { (void )printf("%g\n", *(x0 + id1)); } } if(timer) { ALC_TIMERSUB(times + 1, times + 0, times + 2); (void )fprintf(stderr, "%s: Elapsed time = %g\n", *argv, times[2].tv_sec + (0.000001 * times[2].tv_usec)); } } else { (void )fprintf(stderr, "Usage: %s [-d#] [-n#] [-r#] [-t#] [-v] [-z#]\n" " [-C] [-S] [-R] [-T] [-Y]\n%s", *argv, "Test for timing solution of Ax = b using the Conjugate\n" "Gradient and Singular Value Decomposition algorithms.\n" " -d Seed value.\n" " -n Matrix size.\n" " -r Number of repeat solutions.\n" " -t Tollerance value.\n" " -v Verbose output (matching MATLAB) with residuals.\n" " -z Fraction of zero entries.\n" " -C Use the Conjugate Gradient algorithm.\n" " -L Use a linked list row matrix.\n" " -P Use special version code.\n" " -Q Use the LSQR algorithm.\n" " -S Use the Singular Value Decomposition algorithm.\n" " -T Time solution.\n" " -R Use a rectangular matrix.\n" " -Y Use a symetric matrix.\n"); } AlgMatrixFree(a0); AlgMatrixFree(a1); AlgMatrixFree(w); AlcFree(b0); AlcFree(b1); AlcFree(i0); AlcFree(r0); AlcFree(x0); exit(errCode); }
/*! * \return Array of interiority scores with a score for each of the * test objects or NULL on error. * \ingroup WlzFeatures * \brief Computes an interiority score for each test object with * respect to the reference object. See WlzInteriority(). This function computes the distance transform for the reference domain once and then uses this for each of the test domains. If not NULL the returned array of scores should be freed using AlcFree(). * \param refObj Given reference object. * \param nTstObj Number of test objects. * \param tstObjs Array of test objects. * \param dstErr Destination error pointer, may be NULL. */ double *WlzInteriorityN( WlzObject *refObj, int nTstObj, WlzObject **tstObjs, WlzErrorNum *dstErr) { WlzObject *dis = NULL; double *scores = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; /* Check given objects. */ if(refObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if((refObj->type != WLZ_2D_DOMAINOBJ) && (refObj->type != WLZ_3D_DOMAINOBJ) && (refObj->type != WLZ_EMPTY_OBJ)) { errNum = WLZ_ERR_OBJECT_TYPE; } else if((refObj->type != WLZ_EMPTY_OBJ) && (refObj->domain.core == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(nTstObj < 0) { errNum = WLZ_ERR_PARAM_DATA; } else if(tstObjs == NULL) { errNum = WLZ_ERR_PARAM_NULL; } else { int i; for(i = 0; (errNum == WLZ_ERR_NONE) && (i < nTstObj); ++i) { if(tstObjs[i] == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } if(tstObjs[i]->type != WLZ_EMPTY_OBJ) { if(tstObjs[i]->type != refObj->type) { errNum = WLZ_ERR_OBJECT_TYPE; } else if(tstObjs[i]->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } } } } /* Allocate the scores array. */ if(errNum == WLZ_ERR_NONE) { if((scores = (double *)AlcCalloc(nTstObj, sizeof(double))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } } /* Compute the boundary distance object. */ if((errNum == WLZ_ERR_NONE) && (refObj->type != WLZ_EMPTY_OBJ)) { dis = WlzAssignObject( WlzInteriorityCompDisObj(refObj, &errNum), NULL); } /* For each test object compute it's interiority score with respect * to the distance object. */ if(errNum == WLZ_ERR_NONE) { int i; #ifdef _OPENMP #pragma omp parallel for #endif for(i = 0; i < nTstObj; ++i) { if(errNum == WLZ_ERR_NONE) { WlzErrorNum errNum2 = WLZ_ERR_NONE; scores[i] = WlzInteriorityPrv(dis, tstObjs[i], &errNum2); if(errNum2 != WLZ_ERR_NONE) { #ifdef _OPENMP #pragma omp critical { #endif errNum = errNum2; #ifdef _OPENMP } #endif } } } } (void )WlzFreeObj(dis); if(errNum != WLZ_ERR_NONE) { AlcFree(scores); scores = NULL; } if(dstErr) { *dstErr = errNum; } return(scores); }
/*! * \return Error code. * \ingroup AlgMatrix * \brief Performs singular value decomposition of the given * matrix (A) and computes two additional matricies * (U and V) such that: * A = U.W.V' * where V' is the transpose of V. * The code for AlgMatrixSVDecomp was derived from: * Numerical Recipies function svdcmp(), EISPACK * subroutine SVD(), CERN subroutine SVD() and ACM * algorithm 358. * See AlgMatrixSVSolve() for a usage example. * \param aMat The given matrix A, and U on * return. * \param wVec The diagonal matrix of singular * values, returned as a vector. * \param vMat The matrix V (not it's * transpose). */ AlgError AlgMatrixSVDecomp(AlgMatrix aMat, double *wVec, AlgMatrix vMat) { int cnt0, flag, idI, idJ, idK, idL = 0, its, nNL, nMI, nNM; double tD0, c, f, h, s, x, y, z, aNorm = 0.0, g = 0.0, scale = 0.0; double *tDP0, *tDP1, *tDVec = NULL; double **tDPP0; const int maxIts = 100; /* Maximum iterations to find singular value. */ const double aScale = 0.01; /* Used with aNorm to test for small values. */ AlgError errCode = ALG_ERR_NONE; ALG_DBG((ALG_DBG_LVL_FN|ALG_DBG_LVL_1), ("AlgMatrixSVDecomp FE\n")); if((aMat.core == NULL) || (aMat.core->type != ALG_MATRIX_RECT) || (vMat.core == NULL) || (aMat.core->type != vMat.core->type) || (aMat.core->nR <= 0) || (aMat.core->nR < aMat.core->nC) || (aMat.core->nR != vMat.core->nR) || (aMat.core->nC != vMat.core->nC) || (wVec == NULL)) { errCode = ALG_ERR_FUNC; } else if((tDVec = (double *)AlcCalloc(sizeof(double), aMat.rect->nC)) == NULL) { errCode = ALG_ERR_MALLOC; } else { int nM, nN; double **aAry, **vAry; nM = aMat.rect->nR; nN = aMat.rect->nC; aAry = aMat.rect->array; vAry = vMat.rect->array; /* Householder reduction to bidiagonal form */ for(idI = 0; idI < nN; ++idI) { idL = idI + 1; nNL = nN - idL; nMI = nM - idI; tDVec[idI] = scale * g; g = s = scale = 0.0; if(idI < nM) { cnt0 = nMI; tDPP0 = aAry + idI; while(cnt0-- > 0) /* for(idK = idI; idK < nM; ++idK) */ { tD0 = *(*tDPP0++ + idI); scale += fabs(tD0); /* scale += fabs(aMat[idK][idI]); */ } if(scale > DBL_EPSILON) /* scale must always >= 0 */ { cnt0 = nMI; tDPP0 = aAry + idI; while(cnt0-- > 0) /* for(idK = idI; idK < nM; ++idK) */ { tDP0 = *tDPP0++ + idI; *tDP0 /= scale; /* aMat[idK][idI] /= scale; */ s += *tDP0 * *tDP0; /* s += aMat[idK][idI] * aMat[idK][idI]; */ } f = aAry[idI][idI]; g = (f > 0.0)? -(sqrt(s)): sqrt(s); h = (f * g) - s; aAry[idI][idI] = f - g; if(idI != (nN - 1)) { for(idJ = idL; idJ < nN; ++idJ) { s = 0.0; cnt0 = nMI; tDPP0 = aAry + idI; while(cnt0-- > 0) /* for(idK = idI; idK < nM; ++idK) */ { s += *(*tDPP0 + idI) * *(*tDPP0 + idJ); ++tDPP0; /* s += aMat[idK][idI] * aMat[idK][idJ]; */ } f = s / h; cnt0 = nMI; tDPP0 = aAry + idI; while(cnt0-- > 0) /* for(idK = idI; idK < nM; ++idK) */ { *(*tDPP0 + idJ) += f * *(*tDPP0 + idI); ++tDPP0; /* aMat[idK][idJ] += f * aMat[idK][idI]; */ } } } cnt0 = nMI; tDPP0 = aAry + idI; while(cnt0-- > 0) /* for(idK = idI; idK < nM; ++idK) */ { *(*tDPP0++ + idI) *= scale; /* aMat[idK][idI] *= scale; */ } } } wVec[idI] = scale * g; g = s = scale = 0.0; if((idI < nM) && (idI != (nN - 1))) { cnt0 = nNL; tDP0 = *(aAry + idI) + idL; while(cnt0-- > 0) /* for(idK = idL; idK < nN; ++idK) */ { scale += fabs(*tDP0++); /* scale += fabs(aMat[idI][idK]); */ } if(scale > DBL_EPSILON) /* scale always >= 0 */ { cnt0 = nNL; tDP0 = *(aAry + idI) + idL; while(cnt0-- > 0) /* for(idK = idL; idK < nN; ++idK) */ { *tDP0 /= scale; /* aMat[idI][idK] /= scale; */ tD0 = *tDP0++; s += tD0 * tD0; /* s += aMat[idI][idK] * aMat[idI][idK]; */ } f = aAry[idI][idL]; g = (f > 0.0)? -(sqrt(s)): sqrt(s); h = (f * g) - s; aAry[idI][idL] = f - g; cnt0 = nNL; tDP0 = *(aAry + idI) + idL; tDP1 = tDVec + idL; while(cnt0-- > 0) /* for(idK = idL; idK < nN; ++idK) */ { *tDP1++ = *tDP0++ / h; /* tDVec[idK] = aMat[idI][idK] / h; */ } if(idI != (nM - 1)) { for(idJ = idL; idJ < nM; ++idJ) { s = 0.0; cnt0 = nNL; tDP0 = *(aAry + idI) + idL; tDP1 = *(aAry + idJ) + idL; while(cnt0-- > 0) /* for(idK = idL; idK < nN; ++idK) */ { s += *tDP1++ * *tDP0++; /* s += aMat[idJ][idK] * aMat[idI][idK]; */ } cnt0 = nNL; tDP0 = tDVec + idL; tDP1 = *(aAry + idJ) + idL; while(cnt0-- > 0) /* for(idK = idL; idK < nN; ++idK) */ { *tDP1++ += s * *tDP0++; /* aMat[idJ][idK] += s * tDVec[idK]; */ } } } cnt0 = nNL; tDP0 = *(aAry + idI) + idL; while(cnt0-- > 0) /* for(idK = idL; idK < nN; ++idK) */ { *tDP0++ *= scale; /* aMat[idI][idK] *= scale; */ } } } if((tD0 = fabs(wVec[idI]) + fabs(tDVec[idI])) > aNorm) { aNorm = tD0; } } /* Accumulate right-hand transformations. */ for(idI = nN - 1; idI >= 0; --idI) { if(idI < (nN - 1)) { nNL = nN - idL; if(fabs(g) > DBL_EPSILON) { cnt0 = nNL; tDP0 = *(aAry + idI) + idL; tD0 = *tDP0; tDPP0 = vAry + idL; while(cnt0-- > 0) /* for(idJ = idL; idJ < nN; ++idJ) */ { /* vMat[idJ][idI] = (aMat[idI][idJ] / aMat[idI][idL]) /g */ *(*tDPP0++ + idI) = (*tDP0++ / tD0) / g; /* Double division to try and avoid underflow */ } for(idJ = idL; idJ < nN; ++idJ) { s = 0.0; cnt0 = nNL; tDP0 = *(aAry + idI) + idL; tDPP0 = vAry + idL; while(cnt0-- > 0) /* for(idK = idL; idK < nN; ++idK) */ { s += *tDP0++ * *(*tDPP0++ + idJ); /* s += aMat[idI][idK] * vMat[idK][idJ]; */ } cnt0 = nNL; tDPP0 = vAry + idL; while(cnt0-- > 0) { tDP0 = *tDPP0++; *(tDP0 + idJ) += s * *(tDP0 + idI); /* vMat[idK][idJ] += s * vMat[idK][idI]; */ } } } cnt0 = nNL; tDP0 = *(vAry + idI) + idL; tDPP0 = vAry + idL; while(cnt0-- > 0) /* for(idJ = idL; idJ < nN; ++idJ) */ { *tDP0++ = 0.0; /* vMat[idI][idJ] = 0.0 */ *(*tDPP0++ + idI) = 0.0; /* vMat[idJ][idI] = 0.0; */ } } vAry[idI][idI] = 1.0; g = tDVec[idI]; idL = idI; } /* Accumulate left-hand transformations. */ for(idI = nN - 1; idI >= 0; --idI) { idL = idI + 1; nNL = nN - idL; nMI = nM - idI; g = wVec[idI]; if(idI < (nN - 1)) { cnt0 = nNL; tDP0 = *(aAry + idI) + idL; while(cnt0-- > 0) /* for(idJ = idL; idJ < nN; ++idJ) */ { *tDP0++ = 0.0; /* aMat[idI][idJ] = 0.0; */ } } if(fabs(g) > DBL_EPSILON) { g = 1.0 / g; if(idI != (nN - 1)) { for(idJ = idL; idJ < nN; ++idJ) { s = 0.0; cnt0 = nMI - 1; tDPP0 = aAry + idL; while(cnt0-- > 0) /* for(idK = idL; idK < nM; ++idK) */ { tDP0 = *tDPP0++; s += *(tDP0 + idI) * *(tDP0 + idJ); /* s += aMat[idK][idI] * aMat[idK][idJ]; */ } f = (s / aAry[idI][idI]) * g; cnt0 = nMI; tDPP0 = aAry + idI; while(cnt0-- > 0) /* for(idK = idI; idK < nM; ++idK) */ { tDP0 = *tDPP0++; *(tDP0 + idJ) += f * *(tDP0 + idI); } } } cnt0 = nMI; tDPP0 = aAry + idI; while(cnt0-- > 0) /* for(idJ = idI; idJ < nM; ++idJ) */ { *(*tDPP0++ + idI) *= g; /* aMat[idJ][idI] *= g; */ } } else { cnt0 = nMI; tDPP0 = aAry + idI; while(cnt0-- > 0) /* for(idJ = idI; idJ < nM; ++idJ) */ { *(*tDPP0++ + idI) = 0.0; /* aMat[idJ][idI] = 0.0; */ } } aAry[idI][idI] += 1.0; } /* Diagonalize the bidiagonal form. */ for(idK = nN - 1; (idK >= 0) && (errCode == ALG_ERR_NONE); --idK) { for(its = 1; its <= maxIts; ++its) { flag = 1; for(idL = idK; idL >= 0; --idL) { nNM = idL - 1; if(fabs((tDVec[idL] * aScale) + aNorm) == aNorm) { flag = 0; break; } if((fabs(wVec[nNM] * aScale) + aNorm) == aNorm) { break; } } if(flag) { c = 0.0; s = 1.0; for(idI = idL; idI <= idK; ++idI) { f = s * tDVec[idI]; if(fabs(f * aScale) + aNorm != aNorm) { g = wVec[idI]; h = AlgMatrixSVPythag(f, g); wVec[idI] = h; h = 1.0 / h; c = g * h; s = (-f * h); cnt0 = nM; tDPP0 = aAry; while(cnt0-- > 0) /* for(idJ = 0; idJ < nM; ++idJ) */ { tDP0 = *tDPP0 + nNM; tDP1 = *tDPP0++ + idI; y = *tDP0; /* y = aMat[idJ][nNM]; */ z = *tDP1; /* z = aMat[idJ][idI]; */ *tDP0 = (y * c) + (z * s); /* aMat[idJ][nNM] = (y * c) + (z * s); */ *tDP1 = (z * c) - (y * s); /* aMat[idJ][idI] = (z * c) - (y * s); */ } } } } /* Test for convergence. */ z = wVec[idK]; if(idL == idK) { if(z < 0.0) { wVec[idK] = -z; cnt0 = nN; tDPP0 = vAry; while(cnt0-- > 0) /* for(idJ = 0; idJ < nN; ++idJ) */ { tDP0 = *tDPP0++ + idK; *tDP0 = -*tDP0; /* vMat[idJ][idK] = -vMat[idJ][idK]; */ } } break; } if(its >= maxIts) { errCode = ALG_ERR_MATRIX_SINGULAR; } else { x = wVec[idL]; nNM = idK - 1; y = wVec[nNM]; g = tDVec[nNM]; h = tDVec[idK]; f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y); g = AlgMatrixSVPythag(f, 1.0); f = (((x - z) * (x + z)) + (h * ((y / (f + ((f > 0)? g: -g))) - h))) / x; c = s = 1.0; for(idJ = idL; idJ <= nNM; ++idJ) { idI = idJ + 1; g = tDVec[idI]; y = wVec[idI]; h = s * g; g = c * g; z = AlgMatrixSVPythag(f, h); tDVec[idJ] = z; c = f / z; s = h / z; f = (x * c) + (g * s); g = (g * c) - (x * s); h = y * s; y = y * c; cnt0 = nN; tDPP0 = vAry; while(cnt0-- > 0) /* for(idM = 0; idM < nN; ++idM) */ { tDP0 = *tDPP0 + idJ; tDP1 = *tDPP0++ + idI; x = *tDP0; /* x = vMat[idM][idJ]; */ z = *tDP1; /* z = vMat[idM][idI]; */ *tDP0 = (x * c) + (z * s); /* vMat[idM][idJ] = (x * c) + (z * s); */ *tDP1 = (z * c) - (x * s); /* vMat[idM][idI] = (z * c) - (x * s); */ } z = AlgMatrixSVPythag(f, h); wVec[idJ] = z; if(z > DBL_EPSILON) /* Can only be >= 0.0 */ { z = 1.0 / z; c = f * z; s = h * z; } f = (c * g) + (s * y); x = (c * y) - (s * g); cnt0 = nM; tDPP0 = aAry; while(cnt0-- > 0) /* for(idM = 0; idM < nM; ++idM) */ { tDP0 = *tDPP0 + idJ; tDP1 = *tDPP0++ + idI; y = *tDP0; /* y = aMat[idM][idJ]; */ z = *tDP1; /* z = aMat[idM][idI]; */ *tDP0 = (y * c) + (z * s); /* aMat[idM][idJ] = (y * c) + (z * s); */ *tDP1 = (z * c) - (y * s); /* aMat[idM][idI] = (z * c) - (y * s); */ } } tDVec[idL] = 0.0; tDVec[idK] = f; wVec[idK] = x; } } } AlcFree(tDVec); } ALG_DBG((ALG_DBG_LVL_FN|ALG_DBG_LVL_1), ("AlgMatrixSVDecomp FX %d\n", (int )errCode)); return(errCode); }
/*! * \return Woolz error code. * \ingroup WlzBinaryOps * \brief Computes a metric which quantifies the extent to which * the domain of one of the given objects is offset from * the domain of the second. This is a symetric metric, ie * \f$OST(\Omega_0, \Omega_1) \equiv OST(\Omega_0, \Omega_1)\f$. * A domain is computed which is equidistant from the domains * of the two given objects, is within maxDist of each object's * domain and is within the convex hull of the union of the * domains of the two given objects. Within this domain the * 1st, 2nd and 3rd quantiles of the distance * (\f$q_0\f$, \f$q_1\f$ and \f$q_2\f$) are found. * The object's domains are classified as offset if * \f[ frac{q_1}{q_1 + (q_1 - q_0) + (q_2 - q_1)} \geq 0.5 \f] * ie * \f[ frac{q_1}{q_1 + q_2 - q_0} \geq 0.5 \f] * Small equi-distant domains with a volume less than half * the maximum distance do not classify the relationship as * an overlap. * \param o Array with the two given spatial * domain objects, must not be NULL * and nor must the objects. * \param t Array of temporary objects as in * WlzRCCTOIdx. * \param maxDist Maximum distance for offset. This * is used to compute a distance object, * large distances will significantly * increase the processing time. * \param dQ0 Destination pointer for 1st quantile * offset distance, must not be NULL. * \param dQ1 Destination pointer for 2nd quantile * (ie median) offset distance, * must not be NULL. * \param dQ2 Destination pointer for 3rd quantile * offset distance, must not be NULL. */ static WlzErrorNum WlzRCCOffset( WlzObject **o, WlzObject **t, int maxDist, int *dQ0, int *dQ1, int *dQ2) { int empty = 0; int q[3] = {0}; int *dHist = NULL; WlzObject *eObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; if(((o[0]->type == WLZ_2D_DOMAINOBJ) && (o[1]->type == WLZ_2D_DOMAINOBJ)) || ((o[0]->type == WLZ_3D_DOMAINOBJ) && (o[1]->type == WLZ_3D_DOMAINOBJ))) { if((o[0]->domain.core == NULL) || (o[1]->domain.core == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } } else { errNum = WLZ_ERR_OBJECT_TYPE; } /* Compute distance transforms of the two given objects out to a given * maximum distance and then using these distances the equi-distant * domain between these two objects. The values of the eqi-distant object * are those of the distance between the objects.*/ if(errNum == WLZ_ERR_NONE) { int i; WlzObject *sObj = NULL, *cObj = NULL; WlzObject *dObj[2]; dObj[0] = dObj[1] = NULL; /* Create structuring element with which to dilate the given object * domains(by maxDist). */ sObj = WlzAssignObject( WlzMakeSphereObject(o[0]->type, maxDist, 0, 0, 0, &errNum), NULL); /* Create domain or convex hull of the union of the two given object * domains. */ if(errNum == WLZ_ERR_NONE) { WlzObject *uObj = NULL, *xObj = NULL; errNum = WlzRCCMakeT(o, t, WLZ_RCCTOIDX_O0O1U); if(errNum == WLZ_ERR_NONE) { uObj = WlzAssignObject(t[WLZ_RCCTOIDX_O0O1U], NULL); } if(errNum == WLZ_ERR_NONE) { xObj = WlzAssignObject( WlzObjToConvexHull(uObj, &errNum), NULL); } if(errNum == WLZ_ERR_NONE) { cObj = WlzAssignObject( WlzConvexHullToObj(xObj, o[0]->type, &errNum), NULL); } (void )WlzFreeObj(xObj); (void )WlzFreeObj(uObj); } /* Dilate the two given objects and find the ntersection of the * dilated domains with each other and the convex hull computed * above. Within his domain compute the distances. */ if(errNum == WLZ_ERR_NONE) { for(i = 0; i < 2; ++i) { WlzObject *tObj = NULL, *rObj = NULL; tObj = WlzAssignObject( WlzStructDilation(o[i], sObj, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { rObj = WlzAssignObject( WlzIntersect2(tObj, cObj, &errNum), NULL); } (void )WlzFreeObj(tObj); if(errNum == WLZ_ERR_NONE) { dObj[i] = WlzAssignObject( WlzDistanceTransform(rObj, o[!i], WLZ_OCTAGONAL_DISTANCE, 0.0, maxDist, &errNum), NULL); } (void )WlzFreeObj(rObj); if(errNum == WLZ_ERR_NONE) { WlzPixelV bgdV; bgdV.type = WLZ_GREY_INT; bgdV.v.inv = maxDist; errNum = WlzSetBackground(dObj[i], bgdV); } if(errNum != WLZ_ERR_NONE) { break; } } } /* Find the domain which is equi-distant from the two given objects, * within the xDist range and within the convex hull of the union of * the two given object's domains. */ (void )WlzFreeObj(sObj); sObj = NULL; if(errNum == WLZ_ERR_NONE) { WlzLong vol = 0; WlzObject *qObj = NULL, *tObj = NULL; qObj = WlzAssignObject( WlzImageArithmetic(dObj[0], dObj[1], WLZ_BO_EQ, 0, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { WlzPixelV thrV; thrV.type = WLZ_GREY_INT; thrV.v.inv = 1; tObj = WlzAssignObject( WlzThreshold(qObj, thrV, WLZ_THRESH_HIGH, &errNum), NULL); } /* Check that the eqi-distant domain is of a reasonable size ie has * a area or volume greater than half the maximum distance. */ if(errNum == WLZ_ERR_NONE) { vol = WlzVolume(tObj, &errNum); if((maxDist / 2) >= vol) { empty = 1; } } if((errNum == WLZ_ERR_NONE) && !empty) { WlzObject *mObj; WlzPixelV tmpV; tmpV.type = WLZ_GREY_INT; tmpV.v.inv = 0; mObj = WlzAssignObject( WlzGreyTemplate(dObj[0], tObj, tmpV, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { tmpV.v.inv = 1; eObj = WlzAssignObject( WlzThreshold(mObj, tmpV, WLZ_THRESH_HIGH, &errNum), NULL); } (void )WlzFreeObj(mObj); } (void )WlzFreeObj(tObj); (void )WlzFreeObj(qObj); if((errNum == WLZ_ERR_NONE) && !empty) { WlzLong vol; vol = WlzVolume(eObj, &errNum); if((maxDist / 2) >= vol) { empty = 1; } } } (void )WlzFreeObj(cObj); (void )WlzFreeObj(sObj); (void )WlzFreeObj(dObj[0]); (void )WlzFreeObj(dObj[1]); } /* Compute a quantised distance histogram in which equi-distant distances * are quantized to integer values. */ if((errNum == WLZ_ERR_NONE) && !empty) { if((dHist = (int *)AlcCalloc(maxDist + 1, sizeof(int))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } } if((errNum == WLZ_ERR_NONE) && !empty) { if(eObj->type == WLZ_2D_DOMAINOBJ) { errNum = WlzRCCCompDistHist2D(maxDist, dHist, eObj); } else { errNum = WlzRCCCompDistHist3D(maxDist, dHist, eObj); } #ifdef WLZ_RCC_DEBUG_OST { FILE *fP; fP = fopen("WLZ_RCC_DEBUG_OST.wlz", "w"); (void )WlzWriteObj(fP, eObj); (void )fclose(fP); } #endif } WlzFreeObj(eObj); if((errNum == WLZ_ERR_NONE) && !empty) { int i, n, s, nq; /* Compute the median, first and third quantile offset distances, * the ratio of median to the median plus inner inter-quantile range. */ n = 0; for(i = 0; i < maxDist; ++i) { n += dHist[i]; } i = 0; s = 0; nq = n / 4; while(s < nq) { s += dHist[i++]; } q[0] = i; nq = n / 2; while(s < nq) { s += dHist[i++]; } q[1] = i; nq = (3 * n) / 4; while(s < nq) { s += dHist[i++]; } q[2] = i; } AlcFree(dHist); *dQ0 = q[0]; *dQ1 = q[1]; *dQ2 = q[2]; return(errNum); }
/*! * \return Error code. * \ingroup AlgMatrix * \brief Solves the set of of linear equations A.x = b where * A is input as its singular value decomposition in * the three matricies U, W and V, as returned by * AlgMatrixSVDecomp(). * The code for AlgMatrixSVBackSub was derived from: * Numerical Recipies function svbksb(). * \param uMat Given matrix U with nM rows and nN * columns.. * \param wVec The diagonal matrix of singular * values, returned as a vector with * nN elements. * \param vMat The matrix V (not it's * transpose) with nN columns. * \param bVec Column matrix b with nM elements, * overwritten by column matrix x on * return. */ AlgError AlgMatrixSVBackSub(AlgMatrix uMat, double *wVec, AlgMatrix vMat, double *bVec) { int cnt0, idJ; double s; double *tDP0, *tDP1, *tDVec = NULL; double **tDPP0; AlgError errCode = ALG_ERR_NONE; ALG_DBG((ALG_DBG_LVL_FN|ALG_DBG_LVL_1), ("AlgMatrixSVBackSub FE\n")); if((uMat.core == NULL) || (uMat.core->type != ALG_MATRIX_RECT) || (vMat.core == NULL) || (vMat.core->type != vMat.core->type) || (uMat.core->nR <= 0) || (uMat.core->nR < uMat.core->nC) || (uMat.core->nR != vMat.core->nR) || (uMat.core->nC != vMat.core->nC) || (wVec == NULL) || (bVec == NULL)) { errCode = ALG_ERR_FUNC; } else if((tDVec = (double *)AlcCalloc(sizeof(double), uMat.rect->nC)) == NULL) { errCode = ALG_ERR_MALLOC; } else { #ifndef ALG_FAST_CODE int idI; #endif int nM, nN; double **uAry, **vAry; nM = uMat.rect->nR; nN = uMat.rect->nC; uAry = uMat.rect->array; vAry = vMat.rect->array; for(idJ = 0; idJ < nN; ++idJ) { s = 0.0; if(fabs(wVec[idJ]) > DBL_EPSILON) { #ifdef ALG_FAST_CODE cnt0 = nM; tDPP0 = uAry; tDP0 = bVec; while(cnt0-- > 0) { s += *(*tDPP0++ + idJ) * *tDP0++; } #else for(idI = 0; idI < nM; ++idI) { s += uAry[idI][idJ] * bVec[idI]; } #endif s /= wVec[idJ]; } tDVec[idJ] = s; } for(idJ = 0; idJ < nN; ++idJ) { s = 0.0; #ifdef ALG_FAST_CODE cnt0 = nN; tDP0 = *(vAry + idJ); tDP1 = tDVec; while(cnt0-- > 0) { s += *tDP0++ * *tDP1++; } #else for(idI = 0; idI < nN; ++idI) { s += vAry[idJ][idI] * tDVec[idI]; } #endif bVec[idJ] = s; } AlcFree(tDVec); } ALG_DBG((ALG_DBG_LVL_FN|ALG_DBG_LVL_1), ("AlgMatrixSVBackSub FX %d\n", (int )errCode)); return(errCode); }
/*! * \return Woolz error code. * \ingroup WlzBinaryOps * \brief Splits the reference object into component objects cliped * from the reference object, with the bounding box of each * of the component objects determined using the pre-processed * object. The component objects are returned in size order. * \param refObj Reference object. * \param ppObj Pre-processed object which is * normalised to values in the range * 0 - 255 as WlzUByte greys. * \param bWidth Border width. * \param bgdFrac Minimum fraction of values which are * background values, with range * [0.0+ - 1.0-]. * \param sigma Histogram smoothing parameter used * by WlzHistogramCnvGauss(). * \param compThrMethod Method for computing threshold, used * in call to WlzCompThresholdVT(). * \param nReqComp Number of required components. * \param dstNComp Destination pointer for the number of * components extracted, must not be NULL. * \param dstComp Destination pointer for the extracted * components, must not be NULL. */ WlzErrorNum WlzSplitObj(WlzObject *refObj, WlzObject *ppObj, int bWidth, double bgdFrac, double sigma, WlzCompThreshType compThrMethod, int nReqComp, int *dstNComp, WlzObject ***dstComp) { int dim, idC; WlzObject *hObj = NULL, *tObj = NULL; WlzObject **comp = NULL; WlzBox box; WlzPixelV tV; WlzSplitObjData split; WlzThresholdType tType; WlzConnectType lCon; WlzErrorNum errNum = WLZ_ERR_NONE; const int maxComp = 1024; split.nLComp = 0; split.compI = NULL; split.lCompSz = NULL; split.lComp = NULL; if((refObj == NULL) || (ppObj == NULL)) { errNum = WLZ_ERR_OBJECT_NULL; } else if((refObj->domain.core == NULL) || (ppObj->domain.core == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } else if((refObj->values.core == NULL) || (ppObj->values.core == NULL)) { errNum = WLZ_ERR_VALUES_NULL; } else if(refObj->type != ppObj->type) { errNum = WLZ_ERR_OBJECT_TYPE; } else if((dstNComp == NULL) || (dstComp == NULL)) { errNum = WLZ_ERR_PARAM_NULL; } else if((bgdFrac < DBL_EPSILON) || (bgdFrac > (1.0 - DBL_EPSILON))) { errNum = WLZ_ERR_PARAM_DATA; } else { switch(refObj->type) { case WLZ_2D_DOMAINOBJ: dim = 2; lCon = WLZ_8_CONNECTED; break; case WLZ_3D_DOMAINOBJ: dim = 3; lCon = WLZ_26_CONNECTED; break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* Compute threshold value and type from histogram. */ if(errNum == WLZ_ERR_NONE) { hObj = WlzAssignObject( WlzHistogramObj(ppObj, 256, 0.0, 1.0, &errNum), NULL); } if(errNum == WLZ_ERR_NONE) { errNum = WlzHistogramCnvGauss(hObj, sigma, 0); } if(errNum == WLZ_ERR_NONE) { errNum = WlzCompThresholdVT(hObj, compThrMethod, bgdFrac, 0.0, 0.0, &tV, &tType); } (void )WlzFreeObj(hObj); hObj = NULL; /* Threshold object. */ if(errNum == WLZ_ERR_NONE) { tObj = WlzAssignObject( WlzThreshold(ppObj, tV, tType, &errNum), NULL); } /* Label to get connected components. */ if(errNum == WLZ_ERR_NONE) { errNum = WlzLabel(tObj, &(split.nLComp), &(split.lComp), maxComp, 0, lCon); } /* Sort connected components by size. */ if(errNum == WLZ_ERR_NONE) { if(split.nLComp < nReqComp) { nReqComp = split.nLComp; } if(((split.compI = (int *)AlcMalloc(sizeof(int) * split.nLComp)) == NULL) || ((split.lCompSz = (int *)AlcMalloc(sizeof(int) * split.nLComp)) == NULL)) { errNum = WLZ_ERR_MEM_ALLOC; } } if(errNum == WLZ_ERR_NONE) { idC = 0; while((errNum == WLZ_ERR_NONE) && (idC < split.nLComp)) { split.compI[idC] = idC; split.lCompSz[idC] = (dim == 2)? WlzArea(split.lComp[idC], &errNum): WlzVolume(split.lComp[idC], &errNum); ++idC; } } if(errNum == WLZ_ERR_NONE) { /* Sort component indices by component size. */ AlgQSort(split.compI, split.nLComp, sizeof(int), &split, WlzSplitObjSortSzFn); /* Allocate array for cliped component objects. */ if((comp = (WlzObject **)AlcCalloc(sizeof(WlzObject *), split.nLComp)) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } } /* Compute bounding box and clip objects from the reference object. */ if(errNum == WLZ_ERR_NONE) { idC = 0; while((errNum == WLZ_ERR_NONE) && (idC < nReqComp)) { if(dim == 2) { box.i2 = WlzBoundingBox2I(split.lComp[split.compI[idC]], &errNum); if(errNum == WLZ_ERR_NONE) { box.i2.xMin -= bWidth; box.i2.yMin -= bWidth; box.i2.xMax += bWidth; box.i2.yMax += bWidth; comp[idC] = WlzClipObjToBox2D(refObj, box.i2, &errNum); } } else /* dim == 3 */ { box.i3 = WlzBoundingBox3I(split.lComp[split.compI[idC]], &errNum); if(errNum == WLZ_ERR_NONE) { box.i3.xMin -= bWidth; box.i3.yMin -= bWidth; box.i3.zMin -= bWidth; box.i3.xMax += bWidth; box.i3.yMax += bWidth; box.i3.zMax += bWidth; comp[idC] = WlzClipObjToBox3D(refObj, box.i3, &errNum); } } ++idC; } } if(errNum == WLZ_ERR_NONE) { *dstNComp = nReqComp; *dstComp = comp; } /* Free temporary storage. */ if(split.lComp) { for(idC = 0; idC < split.nLComp; ++idC) { (void )WlzFreeObj(split.lComp[idC]); } AlcFree(split.lComp); } AlcFree(split.compI); AlcFree(split.lCompSz); (void )WlzFreeObj(tObj); return(errNum); }
/*! * \return New Woolz interval domain or NULL on error. * \ingroup WlzTransform * \brief Creates a new 2D Woolz interval domain with a single line * which is the profile from the given start position to the * given end position for the given spatial domain object. * \param gObj Given Woolz object. * \param sPos Start position. * \param ePos End position. * \param dstErr Destination error pointer, may be NULL. */ WlzIntervalDomain *WlzProfileLineIDom( WlzObject *gObj, WlzIVertex3 sPos, WlzIVertex3 ePos, WlzErrorNum *dstErr) { WlzIntervalDomain *iDom = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; /* Check given object. */ if(gObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else { switch(gObj->type) { case WLZ_2D_DOMAINOBJ: case WLZ_3D_DOMAINOBJ: if(gObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if(errNum == WLZ_ERR_NONE) { int len; WlzIVertex3 dPos; WlzProfileWalkWSp pWSp = {0}; WlzInterval *rItv = NULL; WLZ_VTX_3_SUB(dPos, ePos, sPos); len = (int )ceil(WLZ_VTX_3_LENGTH(dPos)); /* Create return object. */ iDom = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, 0, 0, 0, len - 1, &errNum); if(errNum == WLZ_ERR_NONE) { if((rItv = (WlzInterval *) AlcCalloc((len / 2) + 1, sizeof(WlzInterval))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; (void )WlzFreeIntervalDomain(iDom); iDom = NULL; } } if(errNum == WLZ_ERR_NONE) { WlzIntervalLine *itvLn; iDom->freeptr = AlcFreeStackPush(iDom->freeptr, (void *)rItv, NULL); pWSp.start = sPos; pWSp.end = ePos; pWSp.domain.i = iDom; itvLn = pWSp.domain.i->intvlines + 0; itvLn->intvs = rItv; itvLn->nintvs = 0; errNum = WlzProfileWalk(gObj, WlzProfileSetIDom, &pWSp); } } if(errNum != WLZ_ERR_NONE) { iDom = NULL; } if(dstErr) { *dstErr = errNum; } return(iDom); }