/*! * \return Woolz error code. * \ingroup WlzValuesUtils * \brief Transfers grey values from the 2D source object to the * 2D destination object where both share the same domain. * The objects are assumed valid 2D domain objects from * WlzGreyTransfer(). * \param dObj Destination object. * \param sObj Source object. */ static WlzErrorNum WlzGreyTransfer2D( WlzObject *dObj, WlzObject *sObj) { WlzGreyWSpace sGWSp, dGWSp; WlzIntervalWSpace sIWSp, dIWSp; WlzErrorNum errNum = WLZ_ERR_NONE; if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(sObj, &sIWSp, &sGWSp); } if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(dObj, &dIWSp, &dGWSp); } if(errNum == WLZ_ERR_NONE) { int bub; bub = (sGWSp.pixeltype == dGWSp.pixeltype) && (sGWSp.pixeltype == WLZ_GREY_UBYTE); while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&sIWSp)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&dIWSp)) == WLZ_ERR_NONE)) { if(bub) { /* Avoid switches and function calls for the most common case. */ (void )memcpy(dGWSp.u_grintptr.ubp, sGWSp.u_grintptr.ubp, sIWSp.colrmn * sizeof(WlzUByte)); } else { WlzValueCopyGreyToGrey(dGWSp.u_grintptr, 0, dGWSp.pixeltype, sGWSp.u_grintptr, 0, sGWSp.pixeltype, sIWSp.colrmn); } } } if(errNum == WLZ_ERR_EOO) { (void )WlzEndGreyScan(&sIWSp, &sGWSp); (void )WlzEndGreyScan(&dIWSp, &dGWSp); errNum = WLZ_ERR_NONE; } return(errNum); }
/*! * \return New filtered object with new values or NULL on error. * \ingroup WlzValuesFilters * \brief Applies a seperable filter along the x axis (columns) * to the given object using the given convolution kernel. * \param inObj Input 2 or 3D spatial domain object * to be filtered which must have scalar * values. * \param dim Object's dimension. * \param maxThr Maximum number of threads to use. * \param iBuf Working buffers large enough for any * line 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 *WlzSepFilterX(WlzObject *inObj, int dim, int maxThr, double **iBuf, double **rBuf, int cBufSz, double *cBuf, AlgPadType pad, double padVal, WlzErrorNum *dstErr) { int idp, poff, nPln; WlzObjectType rGTT; WlzDomain *domains; WlzValues *iVal, *rVal; WlzPixelV zV; WlzObject *rnObj = 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); if(dim == 3) { WlzPlaneDomain *pDom; WlzVoxelValues *vVal; pDom = inObj->domain.p; vVal = inObj->values.vox; nPln = pDom->lastpl - pDom->plane1 + 1; domains = pDom->domains; iVal = vVal->values; poff = pDom->plane1 - vVal->plane1; rnObj = WlzNewObjectValues(inObj, rGTT, zV, 1, zV, &errNum); if(errNum == WLZ_ERR_NONE) { rVal = rnObj->values.vox->values; } } else { nPln = 1; poff = 0; domains = &(inObj->domain); iVal = &(inObj->values); rnObj = WlzNewObjectValues(inObj, rGTT, zV, 1, zV, &errNum); if(errNum == WLZ_ERR_NONE) { rVal = &(rnObj->values); } } if(errNum == WLZ_ERR_NONE) { #ifdef _OPENMP #pragma omp parallel for num_threads(maxThr) #endif for(idp = 0; idp < nPln; ++idp) { if(errNum == WLZ_ERR_NONE) { if(domains[idp].core != NULL) { int thrId = 0; WlzObject *iObj = NULL, *rObj = NULL; WlzIntervalWSpace iIWSp, rIWSp; WlzGreyWSpace iGWSp, rGWSp; WlzErrorNum errNum2 = WLZ_ERR_NONE; #ifdef _OPENMP thrId = omp_get_thread_num(); #endif iObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domains[idp], iVal[idp + poff], NULL, NULL, &errNum2); if(errNum2 == WLZ_ERR_NONE) { rObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domains[idp], rVal[idp], NULL, NULL, &errNum2); } if((errNum2 == WLZ_ERR_NONE) && ((errNum2 = WlzInitGreyScan(iObj, &iIWSp, &iGWSp)) == WLZ_ERR_NONE) && ((errNum2 = WlzInitGreyScan(rObj, &rIWSp, &rGWSp)) == WLZ_ERR_NONE)) { while(((errNum2 = WlzNextGreyInterval(&iIWSp)) == WLZ_ERR_NONE) && ((errNum2 = WlzNextGreyInterval(&rIWSp)) == WLZ_ERR_NONE)) { size_t len; WlzGreyP iBufGP; iBufGP.dbp = iBuf[thrId]; len = iIWSp.rgtpos - iIWSp.lftpos + 1; WlzValueCopyGreyToGrey(iBufGP, 0, WLZ_GREY_DOUBLE, iGWSp.u_grintptr, 0, iGWSp.pixeltype, len); AlgConvolveD(len, rBuf[thrId], cBufSz * 2 + 1, cBuf, len, iBuf[thrId], pad, padVal); WlzValueCopyDoubleToDouble(rGWSp.u_grintptr.dbp, rBuf[thrId], len); } (void )WlzEndGreyScan(&iIWSp, &iGWSp); (void )WlzEndGreyScan(&rIWSp, &rGWSp); if(errNum2 == WLZ_ERR_EOO) { errNum2 = WLZ_ERR_NONE; } } (void )WlzFreeObj(iObj); (void )WlzFreeObj(rObj); if(errNum2 != WLZ_ERR_NONE) { #ifdef _OPENMP #pragma omp critical { #endif if(errNum == WLZ_ERR_NONE) { errNum = errNum2; } #ifdef _OPENMP } #endif } } } } } if(errNum != WLZ_ERR_NONE) { (void )WlzFreeObj(rnObj); rnObj = NULL; } if(dstErr) { *dstErr = errNum; } return(rnObj); }
/*! * \return New Woolz domain object with maximal domain and grey * values which encode the gradient's direction or NULL * on error. * \ingroup WlzFeatures * \brief Computes the maximal domain and gradient direction of * given Woolz 2D domain object. * \note All the objects domains are known to be the same. * \param grdM Gradient magnitude. * \param grdY Gradient (partial derivative) * through lines. * \param grdX Gradient (partial derivative) * through columns. * \param minThrV Minimum gradient value to * consider. * \param dstErr Destination error pointer, may * be null. */ static WlzObject *WlzNMSuppress2D(WlzObject *grdM, WlzObject *grdY, WlzObject *grdX, WlzPixelV minThrV, WlzErrorNum *dstErr) { int idN, inLen, outLen, inLnIdx = 0; WlzGreyType gType, bufType; WlzIVertex2 bufSz, inPos, outPos, orgPos; WlzValues tmpVal; WlzDomain dstDom, grdDom; WlzIntervalWSpace tmpIWSp = {0}, grdMIWSp = {0}, grdYIWSp = {0}, grdXIWSp = {0}; WlzGreyWSpace tmpGWSp, grdMGWSp, grdYGWSp, grdXGWSp; WlzPixelV zeroV; WlzGreyP grdMBufGP, grdYBufGP, grdXBufGP; WlzDynItvPool pool; WlzObject *dstObj = NULL, *tmpObj = NULL; void *grdYBuf = NULL, *grdXBuf = NULL; void **grdMBuf = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; tmpVal.core = NULL; pool.itvBlock = NULL; dstDom.core = NULL; if((grdM->type != WLZ_2D_DOMAINOBJ) || (grdY->type != WLZ_2D_DOMAINOBJ) || (grdX->type != WLZ_2D_DOMAINOBJ)) { errNum = WLZ_ERR_OBJECT_NULL; } else if((grdM->domain.core == NULL) || (grdY->domain.core == NULL) || (grdX->domain.core == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } else if((grdM->values.core == NULL) || (grdY->values.core == NULL) || (grdX->values.core == NULL)) { errNum = WLZ_ERR_VALUES_NULL; } else { /* Find required buffer type (WLZ_GREY_DOUBLE or WLZ_GREY_INT). */ bufType = WLZ_GREY_INT; gType = WlzGreyTableTypeToGreyType(grdM->values.core->type, &errNum); if(errNum == WLZ_ERR_NONE) { if((gType == WLZ_GREY_FLOAT) || (gType == WLZ_GREY_DOUBLE)) { bufType = WLZ_GREY_DOUBLE; } else { gType = WlzGreyTableTypeToGreyType(grdY->values.core->type, &errNum); if(errNum == WLZ_ERR_NONE) { if((gType == WLZ_GREY_FLOAT) || (gType == WLZ_GREY_DOUBLE)) { bufType = WLZ_GREY_DOUBLE; } else { gType = WlzGreyTableTypeToGreyType(grdX->values.core->type, &errNum); if(errNum == WLZ_ERR_NONE) { if((gType == WLZ_GREY_FLOAT) || (gType == WLZ_GREY_DOUBLE)) { bufType = WLZ_GREY_DOUBLE; } } } } } } } /* Convert minimum gradient threshold value. */ if(errNum == WLZ_ERR_NONE) { if(bufType == WLZ_GREY_INT) { errNum = WlzValueConvertPixel(&minThrV, minThrV, WLZ_GREY_INT); } else /* bufType == WLZ_GREY_DOUBLE */ { errNum = WlzValueConvertPixel(&minThrV, minThrV, WLZ_GREY_DOUBLE); } } if(errNum == WLZ_ERR_NONE) { grdDom = grdM->domain; /* Make destination object with WLZ_GREY_UBYTE greys. */ zeroV.type = WLZ_GREY_UBYTE; zeroV.v.inv = 0; tmpVal.v = WlzNewValueTb(grdM, WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_UBYTE, NULL), zeroV, &errNum); if(errNum == WLZ_ERR_NONE) { /* Use the input domain while calculating the new maximal domain. */ tmpObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, grdM->domain, tmpVal, NULL, NULL, &errNum); } } /* Initialize the memory pool with some size of block. Any +ve number * greater than the maximum number of intervals in any destination line * would work but the fewer allocations then the more efficient the code, * hence this attempt to guess the required number of intervals in the * destination domain. */ if(errNum == WLZ_ERR_NONE) { pool.itvsInBlock = (((grdDom.i->lastkl - grdDom.i->kol1 + 1) * (grdDom.i->lastln - grdDom.i->line1 + 1)) / 64) + grdDom.i->lastkl - grdDom.i->kol1 + 1024; } /* Make gradient buffers. */ if(errNum == WLZ_ERR_NONE) { bufSz.vtY = 3; bufSz.vtX = grdDom.i->lastkl - grdDom.i->kol1 + 1; if(bufType == WLZ_GREY_INT) { if((AlcInt2Malloc((int ***)&grdMBuf, bufSz.vtY, bufSz.vtX) != ALC_ER_NONE) || ((grdYBuf = AlcMalloc(sizeof(int) * bufSz.vtX)) == NULL) || ((grdXBuf = AlcMalloc(sizeof(int) * bufSz.vtX)) == NULL)) { errNum = WLZ_ERR_MEM_ALLOC; } else { grdYBufGP.inp = (int *)grdYBuf; grdXBufGP.inp = (int *)grdXBuf; } } else /* bufType == WLZ_GREY_DOUBLE */ { if((AlcDouble2Malloc((double ***)&grdMBuf, bufSz.vtY, bufSz.vtX) != ALC_ER_NONE) || ((grdYBuf = AlcMalloc(sizeof(double) * bufSz.vtX)) == NULL) || ((grdXBuf = AlcMalloc(sizeof(double) * bufSz.vtX)) == NULL)) { errNum = WLZ_ERR_MEM_ALLOC; } else { grdYBufGP.dbp = (double *)grdYBuf; grdXBufGP.dbp = (double *)grdXBuf; } } } /* Make destination interval domain with interval lines but not intervals. */ if(errNum == WLZ_ERR_NONE) { dstDom.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, grdDom.i->line1, grdDom.i->lastln, grdDom.i->kol1, grdDom.i->lastkl, &errNum); } if(errNum == WLZ_ERR_NONE) { /* Scan down through the gradient objects. */ if(((errNum = WlzInitGreyScan(tmpObj, &tmpIWSp, &tmpGWSp)) == WLZ_ERR_NONE) && ((errNum = WlzInitGreyScan(grdM, &grdMIWSp, &grdMGWSp)) == WLZ_ERR_NONE) && ((errNum = WlzInitGreyScan(grdY, &grdYIWSp, &grdYGWSp)) == WLZ_ERR_NONE) && ((errNum = WlzInitGreyScan(grdX, &grdXIWSp, &grdXGWSp)) == WLZ_ERR_NONE)) { orgPos.vtX = grdDom.i->kol1; orgPos.vtY = grdDom.i->line1; while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&grdMIWSp)) == WLZ_ERR_NONE)) { inLen = grdMIWSp.rgtpos - grdMIWSp.lftpos + 1; inPos.vtX = grdMIWSp.lftpos - orgPos.vtX; /* Process any lines between this and the last by clearing the * gradient magnitude buffer . */ if(grdMIWSp.nwlpos > 0) { idN = (grdMIWSp.nwlpos >= 3)? 3: grdMIWSp.nwlpos; while(--idN >= 0) { inPos.vtY = grdMIWSp.linpos - orgPos.vtY - idN; inLnIdx = (3 + inPos.vtY) % 3; if(bufType == WLZ_GREY_INT) { WlzValueSetInt(*((int **)grdMBuf + inLnIdx), 0, bufSz.vtX); } else /* bufType == WLZ_GREY_DOUBLE */ { WlzValueSetDouble(*((double **)grdMBuf + inLnIdx), 0, bufSz.vtX); } } } /* Copy intervals to values buffers. */ if(bufType == WLZ_GREY_INT) { grdMBufGP.inp = *((int **)grdMBuf + inLnIdx); } else /* bufType == WLZ_GREY_DOUBLE */ { grdMBufGP.dbp = *((double **)grdMBuf + inLnIdx); } WlzValueCopyGreyToGrey(grdMBufGP, inPos.vtX, bufType, grdMGWSp.u_grintptr, 0, grdMGWSp.pixeltype, inLen); if(grdMIWSp.intrmn == 0) { while((errNum == WLZ_ERR_NONE) && (tmpIWSp.linpos < grdMIWSp.linpos)) { outPos.vtY = tmpIWSp.linpos - orgPos.vtY; if(outPos.vtY >= 0) { outLen = tmpIWSp.rgtpos - tmpIWSp.lftpos + 1; outPos.vtX = tmpIWSp.lftpos - orgPos.vtX; WlzValueCopyGreyToGrey(grdYBufGP, 0, bufType, grdYGWSp.u_grintptr, 0, grdYGWSp.pixeltype, outLen); WlzValueCopyGreyToGrey(grdXBufGP, 0, bufType, grdXGWSp.u_grintptr, 0, grdXGWSp.pixeltype, outLen); if(bufType == WLZ_GREY_INT) { errNum = WlzNMSuppress2DBufI(dstDom.i, (int **)grdMBuf, (int *)grdYBuf, (int *)grdXBuf, &pool, tmpGWSp.u_grintptr.ubp, outLen, outPos, orgPos, minThrV.v.inv); } else /* bufType == WLZ_GREY_DOUBLE */ { errNum = WlzNMSuppress2DBufD(dstDom.i, (double **)grdMBuf, (double *)grdYBuf, (double *)grdXBuf, &pool, tmpGWSp.u_grintptr.ubp, outLen, outPos, orgPos, minThrV.v.dbv); } } if(errNum == WLZ_ERR_NONE) { errNum = WlzNextGreyInterval(&tmpIWSp); } if(errNum == WLZ_ERR_NONE) { errNum = WlzNextGreyInterval(&grdYIWSp); } if(errNum == WLZ_ERR_NONE) { errNum = WlzNextGreyInterval(&grdXIWSp); } } } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } } if(tmpIWSp.gryptr == &tmpGWSp) { (void )WlzEndGreyScan(&tmpIWSp, &tmpGWSp); } if(grdMIWSp.gryptr == &grdMGWSp) { (void )WlzEndGreyScan(&grdMIWSp, &grdMGWSp); } if(grdYIWSp.gryptr == &grdYGWSp) { (void )WlzEndGreyScan(&grdYIWSp, &grdYGWSp); } if(grdXIWSp.gryptr == &grdXGWSp) { (void )WlzEndGreyScan(&grdXIWSp, &grdXGWSp); } } if(errNum == WLZ_ERR_NONE) { if((errNum = WlzStandardIntervalDomain(dstDom.i)) == WLZ_ERR_NONE) { dstObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, dstDom, tmpVal, NULL, NULL, &errNum); } } if(tmpObj) { WlzFreeObj(tmpObj); } if(errNum != WLZ_ERR_NONE) { if(tmpObj == NULL) { if(dstDom.core) { (void )WlzFreeDomain(dstDom); } if(tmpVal.core) { (void )WlzFreeValues(tmpVal); } } } if(grdMBuf) { Alc2Free(grdMBuf); } if(grdYBuf) { AlcFree(grdYBuf); } if(grdXBuf) { AlcFree(grdXBuf); } if(dstErr) { *dstErr = errNum; } return(dstObj); }
/*! * \return New 2D domain object. * \ingroup WlzArithmetic * \brief Computes a new 2D object which shares the domain of the given * object, but which has grey values that are the result of * applying the given function to the grey values of the * given object. * \param sObj Given source domain object with values. * \param fn Scalar function to be applied. * \param dstErr Destination error pointer, may be NULL. */ static WlzObject *WlzScalarFn2D(WlzObject *sObj, WlzFnType fn, WlzErrorNum *dstErr) { WlzGreyType sGType, dGType; WlzPixelV sBgd, dBgd; WlzObjectType dVType; WlzObject *dObj = NULL; WlzValues dVal; WlzIntervalWSpace sIWSp, dIWSp; WlzGreyWSpace sGWSp, dGWSp; WlzErrorNum errNum = WLZ_ERR_NONE; sGType = WlzGreyTypeFromObj(sObj, &errNum); if(errNum == WLZ_ERR_NONE) { dGType = WlzScalarFnPromoteGType(fn, sGType, &errNum); } if(errNum == WLZ_ERR_NONE) { dVType = WlzGreyTableType(WLZ_GREY_TAB_RAGR, dGType, &errNum); } if(errNum == WLZ_ERR_NONE) { sBgd = WlzGetBackground(sObj, &errNum); } if(errNum == WLZ_ERR_NONE) { dBgd = WlzScalarFnPixel(sBgd, fn, &errNum); } if(errNum == WLZ_ERR_NONE) { dVal.v = WlzNewValueTb(sObj, dVType, dBgd, &errNum); } if(errNum == WLZ_ERR_NONE) { dObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, sObj->domain, dVal, NULL, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(sObj, &sIWSp, &sGWSp); } if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(dObj, &dIWSp, &dGWSp); } if(errNum == WLZ_ERR_NONE) { while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&sIWSp)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&dIWSp)) == WLZ_ERR_NONE)) { int len; WlzGreyP dGP, sGP; len = sIWSp.rgtpos - sIWSp.lftpos + 1; dGP = dGWSp.u_grintptr; sGP = sGWSp.u_grintptr; WlzValueCopyGreyToGrey(dGP, 0, dGType, sGP, 0, sGType, len); WlzScalarFnItv(dGP, dGType, len, fn); } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } } if(dstErr) { *dstErr = errNum; } return(dObj); }
/*! * \return New Woolz domain object with gradient grey values or NULL on * error. * \ingroup WlzValuesFilters * \brief Computes the magnitude of the gray values in the * 3 given Woolz 2D domain objects. * \param srcObj0 First object. * \param srcObj1 Second object. * \param srcObj2 Third object. * \param dstErr Destination error pointer, may be null. */ static WlzObject *WlzGreyMagnitude2D3(WlzObject *srcObj0, WlzObject *srcObj1, WlzObject *srcObj2, WlzErrorNum *dstErr) { int idN, itvLen, bufSz; double **iBufA = NULL; WlzObject *tObj0, *istObj = NULL, *dstObj = NULL; WlzObject *iObjA[3], *tObjA[3]; WlzGreyP tGP0; WlzGreyType dstGType = WLZ_GREY_ERROR; WlzGreyType gTypeA[3]; WlzPixelV dstBgd; WlzPixelV bgdA[3]; WlzValues dstVal; WlzIntervalWSpace dstIWSp; WlzGreyWSpace dstGWSp; WlzIntervalWSpace iIWSpA[3]; WlzGreyWSpace iGWSpA[3]; WlzErrorNum errNum = WLZ_ERR_NONE; *(iObjA + 0) = *(iObjA + 1) = *(iObjA + 2) = NULL; /* Check source objects. */ if((srcObj0 == NULL) || (srcObj1 == NULL) ||(srcObj2 == NULL)) { errNum = WLZ_ERR_OBJECT_NULL;; } else if((srcObj0->type != WLZ_2D_DOMAINOBJ) || (srcObj1->type != WLZ_2D_DOMAINOBJ) || (srcObj2->type != WLZ_2D_DOMAINOBJ)) { errNum = WLZ_ERR_OBJECT_TYPE; } else if((srcObj0->domain.core == NULL) || (srcObj1->domain.core == NULL) || (srcObj2->domain.core == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } else if((srcObj0->values.core == NULL) || (srcObj1->values.core == NULL) || (srcObj2->values.core == NULL)) { errNum = WLZ_ERR_VALUES_NULL; } /* Compute the intersection of the source objects. */ if(errNum == WLZ_ERR_NONE) { *(tObjA + 0) = srcObj0; *(tObjA + 1) = srcObj1; *(tObjA + 2) = srcObj2; istObj = WlzIntersectN(3, tObjA, 0, &errNum); } if(errNum == WLZ_ERR_NONE) { *(iObjA + 0) = WlzMakeMain(WLZ_2D_DOMAINOBJ, istObj->domain, srcObj0->values, NULL, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { *(iObjA + 1) = WlzMakeMain(WLZ_2D_DOMAINOBJ, istObj->domain, srcObj1->values, NULL, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { *(iObjA + 2) = WlzMakeMain(WLZ_2D_DOMAINOBJ, istObj->domain, srcObj2->values, NULL, NULL, &errNum); } /* Get background value and grey types */ idN = 0; while((errNum == WLZ_ERR_NONE) && (idN < 3)) { tObj0 = *(iObjA + idN); *(gTypeA + idN) = WlzGreyTableTypeToGreyType(tObj0->values.core->type, &errNum); if(errNum == WLZ_ERR_NONE) { *(bgdA + idN) = WlzGetBackground(tObj0, &errNum); } ++idN; } /* Promote grey types. */ if(errNum == WLZ_ERR_NONE) { if((*(gTypeA + 0) == WLZ_GREY_DOUBLE) || (*(gTypeA + 1) == WLZ_GREY_DOUBLE) || (*(gTypeA + 2) == WLZ_GREY_DOUBLE)) { dstGType = WLZ_GREY_DOUBLE; } else if((*(gTypeA + 0) == WLZ_GREY_FLOAT) || (*(gTypeA + 1) == WLZ_GREY_FLOAT) || (*(gTypeA + 2) == WLZ_GREY_FLOAT)) { dstGType = WLZ_GREY_FLOAT; } else if((*(gTypeA + 0) == WLZ_GREY_INT) || (*(gTypeA + 1) == WLZ_GREY_INT) || (*(gTypeA + 2) == WLZ_GREY_INT)) { dstGType = WLZ_GREY_INT; } else if((*(gTypeA + 0) == WLZ_GREY_SHORT) || (*(gTypeA + 1) == WLZ_GREY_SHORT) || (*(gTypeA + 2) == WLZ_GREY_SHORT)) { dstGType = WLZ_GREY_SHORT; } else if((*(gTypeA + 0) == WLZ_GREY_UBYTE) || (*(gTypeA + 1) == WLZ_GREY_UBYTE) || (*(gTypeA + 2) == WLZ_GREY_UBYTE)) { dstGType = WLZ_GREY_SHORT; } else { /* RGBA to be done RAB */ errNum = WLZ_ERR_GREY_TYPE; } } /* Make destination object with intersection domain and new values. */ if(errNum == WLZ_ERR_NONE) { (void )WlzValueConvertPixel(&dstBgd, *(bgdA + 0), dstGType); dstVal.v = WlzNewValueTb(*(iObjA + 0), WlzGreyValueTableType(0, WLZ_GREY_TAB_RAGR, dstGType, NULL), dstBgd, &errNum); if(errNum == WLZ_ERR_NONE) { dstObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, istObj->domain, dstVal, NULL, NULL, &errNum); } } if(istObj) { WlzFreeObj(istObj); } /* Make buffers. */ if(errNum == WLZ_ERR_NONE) { bufSz = dstObj->domain.i->lastkl - dstObj->domain.i->kol1 + 1; if(AlcDouble2Malloc(&iBufA, 3, bufSz) != ALC_ER_NONE) { errNum = WLZ_ERR_MEM_ALLOC; } } /* Scan through the objects computing the magnitude. */ if(errNum == WLZ_ERR_NONE) { idN = 0; while((errNum == WLZ_ERR_NONE) && (idN < 3)) { errNum = WlzInitGreyScan(*(iObjA + idN), iIWSpA + idN, iGWSpA + idN); ++idN; } if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(dstObj, &dstIWSp, &dstGWSp); } while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(iIWSpA + 0)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(iIWSpA + 1)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(iIWSpA + 2)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&dstIWSp)) == WLZ_ERR_NONE)) { itvLen = dstIWSp.rgtpos - dstIWSp.lftpos + 1; /* Copy intervals to double buffers. */ idN = 0; while(idN < 3) { tGP0.dbp = *(iBufA + idN); WlzValueCopyGreyToGrey(tGP0, 0, WLZ_GREY_DOUBLE, (iGWSpA + idN)->u_grintptr, 0, (iGWSpA + idN)->pixeltype, itvLen); ++idN; } /* Compute magnitude. */ WlzBufMagD3(*(iBufA + 0), *(iBufA + 1), *(iBufA + 2), itvLen); /* Clamp into destination interval. */ tGP0.dbp = *(iBufA + 0); WlzValueClampGreyIntoGrey(dstGWSp.u_grintptr, 0, dstGWSp.pixeltype, tGP0, 0, WLZ_GREY_DOUBLE, itvLen); } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } } /* Free intersection objects. */ idN = 0; while(idN < 3) { if(iObjA[idN]) { WlzFreeObj(iObjA[idN]); } ++idN; } /* Free buffers. */ if(iBufA) { Alc2Free((void **)iBufA); } /* Tidy up on error. */ if(dstObj && (errNum != WLZ_ERR_NONE)) { WlzFreeObj(dstObj); dstObj = NULL; } /* Pass back error status. */ if(dstErr) { *dstErr = errNum; } return(dstObj); }