/*! * \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); }
/*! * \ingroup WlzValuesFilters * \brief Set new grey-range by simple linear interpolation. It assumes that the min and max values enclose the true range of grey-values in the object. Failure to check this could result in a segmentation fault. The transform function is: \f[g' = \frac{(gMax - gMin)}{(gmax - gmin)} (g - gmin) + gMin + \delta \f] Here \f$\delta\f$ is the dither value. * * \return Woolz error number * \param obj Input grey-level object whose values are to be reset. * \param min Initial minimum value * \param max Initial maximum value * \param Min Final minimum value * \param Max Final maximum value * \param Dither values if destination range is greater than source range * and this flag is non-zero. * \par Source: * WlzGreySetRange.c */ WlzErrorNum WlzGreySetRange( WlzObject *obj, WlzPixelV min, WlzPixelV max, WlzPixelV Min, WlzPixelV Max, int dither) { double gMin = 0.0, gMax = 0.0, sigma = 0.0, factor, val; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyP gptr; WlzObject *tempobj; WlzValues *values; WlzDomain *domains; int i, j, nplanes; WlzErrorNum errNum = WLZ_ERR_NONE; /* check object */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } if( errNum == WLZ_ERR_NONE ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.i == NULL ){ return WLZ_ERR_DOMAIN_NULL; } if( obj->values.core == NULL ){ return WLZ_ERR_VALUES_NULL; } if( WlzGreyTableIsTiled(obj->values.core->type) ){ return WLZ_ERR_VALUES_TYPE; } break; case WLZ_3D_DOMAINOBJ: /* check planedomain and voxeltable */ if( obj->domain.p == NULL ){ return WLZ_ERR_DOMAIN_NULL; } if( obj->domain.p->type != WLZ_PLANEDOMAIN_DOMAIN ){ return WLZ_ERR_PLANEDOMAIN_TYPE; } if( obj->values.vox == NULL ){ return WLZ_ERR_VALUES_NULL; } if( obj->values.vox->type != WLZ_VOXELVALUETABLE_GREY ){ return WLZ_ERR_VOXELVALUES_TYPE; } /* set range of each plane if non-empty - indicated by NULL */ domains = obj->domain.p->domains; values = obj->values.vox->values; nplanes = obj->domain.p->lastpl - obj->domain.p->plane1 + 1; for(i=0; i < nplanes; i++, domains++, values++){ if( (*domains).core == NULL || (*values).core == NULL ){ continue; } tempobj = WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains, *values, NULL, NULL, &errNum); if((tempobj == NULL) && (errNum == WLZ_ERR_NONE) ){ errNum = WLZ_ERR_UNSPECIFIED; break; } errNum = WlzGreySetRange(tempobj, min, max, Min, Max, dither); WlzFreeObj( tempobj ); if( errNum != WLZ_ERR_NONE ){ break; } } return errNum; case WLZ_TRANS_OBJ: return WlzGreySetRange(obj->values.obj, min, max, Min, Max, dither); case WLZ_EMPTY_OBJ: return errNum; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if( errNum == WLZ_ERR_NONE ){ /* get conversion function - should use LUT use 4 LUTS for rgb type since bounded */ if( WlzGreyTypeFromObj(obj, &errNum) == WLZ_GREY_RGBA ){ WlzUByte rgbaLut[4][256]; WlzUInt rgbamin[4], rgbaMin[4]; double rgbaFactor[4], val1; WlzUInt red, green, blue, alpha; rgbamin[0] = WLZ_RGBA_RED_GET(min.v.rgbv); rgbaMin[0] = WLZ_RGBA_RED_GET(Min.v.rgbv); if(WLZ_RGBA_RED_GET(max.v.rgbv) > WLZ_RGBA_RED_GET(min.v.rgbv)){ rgbaFactor[0] = (((double) WLZ_RGBA_RED_GET(Max.v.rgbv) - WLZ_RGBA_RED_GET(Min.v.rgbv))/ (WLZ_RGBA_RED_GET(max.v.rgbv) - WLZ_RGBA_RED_GET(min.v.rgbv))); } else { rgbaFactor[0] = 0.0; } rgbamin[1] = WLZ_RGBA_GREEN_GET(min.v.rgbv); rgbaMin[1] = WLZ_RGBA_GREEN_GET(Min.v.rgbv); if(WLZ_RGBA_GREEN_GET(max.v.rgbv) > WLZ_RGBA_GREEN_GET(min.v.rgbv)){ rgbaFactor[1] = (((double) WLZ_RGBA_GREEN_GET(Max.v.rgbv) - WLZ_RGBA_GREEN_GET(Min.v.rgbv))/ (WLZ_RGBA_GREEN_GET(max.v.rgbv) - WLZ_RGBA_GREEN_GET(min.v.rgbv))); } else { rgbaFactor[1] = 0.0; } rgbamin[2] = WLZ_RGBA_BLUE_GET(min.v.rgbv); rgbaMin[2] = WLZ_RGBA_BLUE_GET(Min.v.rgbv); if(WLZ_RGBA_BLUE_GET(max.v.rgbv) > WLZ_RGBA_BLUE_GET(min.v.rgbv)){ rgbaFactor[2] = (((double) WLZ_RGBA_BLUE_GET(Max.v.rgbv) - WLZ_RGBA_BLUE_GET(Min.v.rgbv))/ (WLZ_RGBA_BLUE_GET(max.v.rgbv) - WLZ_RGBA_BLUE_GET(min.v.rgbv))); } else { rgbaFactor[2] = 0.0; } rgbamin[3] = WLZ_RGBA_ALPHA_GET(min.v.rgbv); rgbaMin[3] = WLZ_RGBA_ALPHA_GET(Min.v.rgbv); if(WLZ_RGBA_ALPHA_GET(max.v.rgbv) > WLZ_RGBA_ALPHA_GET(min.v.rgbv)){ rgbaFactor[3] = (((double) WLZ_RGBA_ALPHA_GET(Max.v.rgbv) - WLZ_RGBA_ALPHA_GET(Min.v.rgbv))/ (WLZ_RGBA_ALPHA_GET(max.v.rgbv) - WLZ_RGBA_ALPHA_GET(min.v.rgbv))); } else { rgbaFactor[3] = 0.0; } /* now set up the LUTS */ for(i=0; i < 4; i++){ for(j=0; j < 256; j++){ val1 = rgbaFactor[i] * (j - rgbamin[i]) + rgbaMin[i]; rgbaLut[i][j] = (WlzUByte )WLZ_CLAMP(val1, 0, 255); } } /* set values - can assume rgba grey-type */ errNum = WlzInitGreyScan(obj, &iwsp, &gwsp); if(errNum == WLZ_ERR_NONE) { while( WlzNextGreyInterval(&iwsp) == WLZ_ERR_NONE ){ gptr = gwsp.u_grintptr; for (i=0; i<iwsp.colrmn; i++, gptr.rgbp++){ red = rgbaLut[0][WLZ_RGBA_RED_GET(*gptr.rgbp)]; green = rgbaLut[0][WLZ_RGBA_GREEN_GET(*gptr.rgbp)]; blue = rgbaLut[0][WLZ_RGBA_BLUE_GET(*gptr.rgbp)]; alpha = rgbaLut[0][WLZ_RGBA_ALPHA_GET(*gptr.rgbp)]; WLZ_RGBA_RGBA_SET(*gptr.rgbp, red, green, blue, alpha); } } (void )WlzEndGreyScan(&iwsp, &gwsp); if(errNum == WLZ_ERR_EOO){ errNum = WLZ_ERR_NONE; } } } else { WlzValueConvertPixel(&min, min, WLZ_GREY_DOUBLE); WlzValueConvertPixel(&max, max, WLZ_GREY_DOUBLE); WlzValueConvertPixel(&Min, Min, WLZ_GREY_DOUBLE); WlzValueConvertPixel(&Max, Max, WLZ_GREY_DOUBLE); if( fabs(max.v.dbv - min.v.dbv) < DBL_EPSILON ){ return WLZ_ERR_FLOAT_DATA; } errNum = WlzInitGreyScan(obj, &iwsp, &gwsp); if(errNum == WLZ_ERR_NONE) { factor = (Max.v.dbv - Min.v.dbv) / (max.v.dbv - min.v.dbv); if(dither) { if(fabs(factor) < 1.0 + DBL_EPSILON) { dither = 0; } else { sigma = fabs(2.0 / factor); AlgRandSeed(101); switch(gwsp.pixeltype) { case WLZ_GREY_INT: gMin = ALG_MAX(Min.v.dbv, INT_MIN); gMax = ALG_MIN(Max.v.dbv, INT_MAX); break; case WLZ_GREY_SHORT: gMin = ALG_MAX(Min.v.dbv, SHRT_MIN); gMax = ALG_MIN(Max.v.dbv, SHRT_MAX); break; case WLZ_GREY_UBYTE: gMin = ALG_MAX(Min.v.dbv, 0); gMax = ALG_MIN(Max.v.dbv, 255); break; case WLZ_GREY_FLOAT: gMin = ALG_MAX(Min.v.dbv, FLT_MIN); gMax = ALG_MIN(Max.v.dbv, FLT_MAX); break; case WLZ_GREY_DOUBLE: gMin = Min.v.dbv; gMax = Max.v.dbv; break; default: break; } } } while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE)){ gptr = gwsp.u_grintptr; switch (gwsp.pixeltype) { case WLZ_GREY_INT: for (i=0; i<iwsp.colrmn; i++, gptr.inp++){ if(dither){ val = factor * (*gptr.inp + AlgRandZigNormal(0.0, sigma) - min.v.dbv) + Min.v.dbv; val = WLZ_CLAMP(val, gMin, gMax); } else { val = factor * (*gptr.inp - min.v.dbv) + Min.v.dbv; } *gptr.inp = WLZ_NINT(val); } break; case WLZ_GREY_SHORT: for (i=0; i<iwsp.colrmn; i++, gptr.shp++){ if(dither){ val = factor * (*gptr.shp + AlgRandZigNormal(0.0, sigma) - min.v.dbv) + Min.v.dbv; val = WLZ_CLAMP(val, gMin, gMax); } else { val = factor * (*gptr.shp - min.v.dbv) + Min.v.dbv; } *gptr.shp = (short )WLZ_NINT(val); } break; case WLZ_GREY_UBYTE: for (i=0; i<iwsp.colrmn; i++, gptr.ubp++){ if(dither){ val = factor * (*gptr.ubp + AlgRandZigNormal(0.0, sigma) - min.v.dbv) + Min.v.dbv; val = WLZ_CLAMP(val, gMin, gMax); } else { val = factor * (*gptr.ubp - min.v.dbv) + Min.v.dbv; } *gptr.ubp = (WlzUByte )WLZ_NINT(val); } break; case WLZ_GREY_FLOAT: for (i=0; i<iwsp.colrmn; i++, gptr.flp++){ if(dither){ val = factor * (*gptr.flp + AlgRandZigNormal(0.0, sigma) - min.v.dbv) + Min.v.dbv; val = WLZ_CLAMP(val, gMin, gMax); } else { val = factor * (*gptr.flp - min.v.dbv) + Min.v.dbv; } *gptr.flp = (float )val; } break; case WLZ_GREY_DOUBLE: for (i=0; i<iwsp.colrmn; i++, gptr.dbp++){ if(dither){ val = factor * (*gptr.dbp + AlgRandZigNormal(0.0, sigma) - min.v.dbv) + Min.v.dbv; val = WLZ_CLAMP(val, gMin, gMax); } else { val = factor * (*gptr.dbp - min.v.dbv) + Min.v.dbv; } *gptr.dbp = val; } break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } (void )WlzEndGreyScan(&iwsp, &gwsp); if(errNum == WLZ_ERR_EOO){ 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 Rescaled object. * \ingroup WlzTransform * \brief Rescales the given 2D domain object using an integer scale. * \param obj Given object. * \param scale Integer scale factor. * \param expand If zero use \f$\frac{1}{scale}\f$. * \param dstErr Destination error pointer, may be NULL. */ static WlzObject *WlzIntRescaleObj2D( WlzObject *obj, int scale, int expand, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzDomain domain; WlzValues values; WlzInterval *intvls; int k1, kl, l1, ll, l, num_intvls; WlzErrorNum errNum=WLZ_ERR_NONE; /* check expand or contract */ if( expand ) { k1 = obj->domain.i->kol1 * scale; kl = obj->domain.i->lastkl * scale + scale - 1; l1 = obj->domain.i->line1 * scale; ll = obj->domain.i->lastln * scale + scale - 1; } else { k1 = obj->domain.i->kol1 / scale; kl = obj->domain.i->lastkl / scale; l1 = obj->domain.i->line1 / scale; ll = obj->domain.i->lastln / scale; } /* create a new object */ if((domain.i = WlzMakeIntervalDomain(obj->domain.i->type, l1, ll, k1, kl, &errNum)) != NULL){ values.core = NULL; rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain, values, NULL, NULL, NULL); } /* fill in the intervals */ if( errNum == WLZ_ERR_NONE){ if( domain.i->type == WLZ_INTERVALDOMAIN_INTVL ) { int intvline_offset, max_offset; WlzIntervalLine *intvline; num_intvls = WlzIntervalCount(obj->domain.i, NULL); num_intvls = expand ? num_intvls * scale : num_intvls; intvls = (WlzInterval *)AlcMalloc(sizeof(WlzInterval) * num_intvls); domain.i->freeptr = AlcFreeStackPush(domain.i->freeptr, (void *)intvls, NULL); max_offset = obj->domain.i->lastln - obj->domain.i->line1; for(l=l1; l <= ll; l++) { int i; intvline_offset = (expand?l/scale:l*scale) - obj->domain.i->line1; intvline_offset = WLZ_MAX(intvline_offset, 0); intvline_offset = WLZ_MIN(intvline_offset, max_offset); intvline = obj->domain.i->intvlines + intvline_offset; for(i=0; i < intvline->nintvs; i++) { intvls[i].ileft = (intvline->intvs + i)->ileft; intvls[i].iright = (intvline->intvs + i)->iright; if( expand ) { intvls[i].ileft *= scale; intvls[i].iright *= scale; intvls[i].iright += scale - 1; } else { intvls[i].ileft /= scale; intvls[i].iright /= scale; } } i = check_intvs(intvls, i); WlzMakeInterval(l, domain.i, i, intvls); intvls += i; } (void) WlzStandardIntervalDomain( domain.i ); } } /* create the valuetable */ if( (errNum == WLZ_ERR_NONE) && obj->values.core ) { WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzPixelV backgrnd; WlzGreyValueWSpace *gVWSp = NULL; WlzGreyType gtype; backgrnd = WlzGetBackground(obj, NULL); if((values.v = WlzNewValueTb(rtnObj, obj->values.v->type, backgrnd, &errNum)) != NULL){ rtnObj->values = WlzAssignValues(values, NULL); /* fill in the grey-values */ errNum = WlzInitGreyScan(rtnObj, &iwsp, &gwsp); if(errNum == WLZ_ERR_NONE) { gVWSp = WlzGreyValueMakeWSp(obj, &errNum); if(errNum == WLZ_ERR_NONE) { gtype = WlzGreyTableTypeToGreyType(obj->values.v->type, NULL); } while((errNum == WLZ_ERR_NONE) && (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE) { int k; int lp = expand ? iwsp.linpos/scale : iwsp.linpos*scale; for( k=0; k <= (iwsp.rgtpos - iwsp.lftpos); k++ ) { int kp = expand ? (k+iwsp.lftpos)/scale : (k+iwsp.lftpos)*scale; WlzGreyValueGet(gVWSp, 0, (double) lp, (double) kp); switch(gtype) { case WLZ_GREY_INT: gwsp.u_grintptr.inp[k] = (*(gVWSp->gVal)).inv; break; case WLZ_GREY_SHORT: gwsp.u_grintptr.shp[k] = (*(gVWSp->gVal)).shv; break; case WLZ_GREY_UBYTE: gwsp.u_grintptr.ubp[k] = (*(gVWSp->gVal)).ubv; break; case WLZ_GREY_FLOAT: gwsp.u_grintptr.flp[k] = (*(gVWSp->gVal)).flv; break; case WLZ_GREY_DOUBLE: gwsp.u_grintptr.dbp[k] = (*(gVWSp->gVal)).dbv; break; case WLZ_GREY_RGBA: gwsp.u_grintptr.rgbp[k] = (*(gVWSp->gVal)).rgbv; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzGreyValueFreeWSp(gVWSp); (void )WlzEndGreyScan(&iwsp, &gwsp); } } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \return Woolz error code. * \ingroup WlzArithmetic * \brief Increments all values within the given object. * \param obj Given object. */ WlzErrorNum WlzGreyIncValues2D(WlzObject *obj) { WlzGreyWSpace gWSp; WlzIntervalWSpace iWSp; WlzErrorNum errNum = WLZ_ERR_NONE; errNum = WlzInitGreyScan(obj, &iWSp, &gWSp); if(errNum == WLZ_ERR_NONE) { while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iWSp)) == WLZ_ERR_NONE)) { int i, len; WlzGreyP gP; gP = gWSp.u_grintptr; len = iWSp.rgtpos - iWSp.lftpos + 1; switch(gWSp.pixeltype) { case WLZ_GREY_INT: for(i = 0; i < len; ++i) { *(gP.inp)++ += 1; } break; case WLZ_GREY_SHORT: for(i = 0; i < len; ++i) { *(gP.shp)++ += 1; } break; case WLZ_GREY_UBYTE: for(i = 0; i < len; ++i) { *(gP.ubp)++ += 1; } break; case WLZ_GREY_FLOAT: for(i = 0; i < len; ++i) { *(gP.flp)++ += 1.0f; } break; case WLZ_GREY_DOUBLE: for(i = 0; i < len; ++i) { *(gP.dbp)++ += 1.0; } break; default: break; } } (void )WlzEndGreyScan(&iWSp, &gWSp); if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } } return(errNum); }
/*! * \return Woolz error code. * \ingroup WlzArithmetic * \brief Sets the values of the return object from the input object * using simple linear scaling, see WlzScalarMulAdd(). The * objects are known to be 2D, have the same domain. * \param rObj * \param iObj * \param m * \param a */ static WlzErrorNum WlzScalarMulAddSet2D(WlzObject *rObj, WlzObject *iObj, double m, double a) { int bufLen; WlzGreyWSpace iGWSp, rGWSp; WlzIntervalWSpace iIWSp = {0}, rIWSp = {0}; WlzErrorNum errNum = WLZ_ERR_NONE; bufLen = iObj->domain.i->lastkl - iObj->domain.i->kol1 + 1; if((bufLen != iObj->domain.i->lastkl - iObj->domain.i->kol1 + 1) || (bufLen < 0)) { errNum = WLZ_ERR_DOMAIN_DATA; } else if(bufLen > 0) { if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(iObj, &iIWSp, &iGWSp); } if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(rObj, &rIWSp, &rGWSp); } if(errNum == WLZ_ERR_NONE) { double *buf = NULL; if((buf = AlcMalloc(sizeof(double) * bufLen)) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { while((errNum = WlzNextGreyInterval(&iIWSp)) == WLZ_ERR_NONE) { int t, idN, itvLen; double f; itvLen = iIWSp.colrmn; (void )WlzNextGreyInterval(&rIWSp); switch(iGWSp.pixeltype) { case WLZ_GREY_INT: WlzValueCopyIntToDouble(buf, iGWSp.u_grintptr.inp, itvLen); break; case WLZ_GREY_SHORT: WlzValueCopyShortToDouble(buf, iGWSp.u_grintptr.shp, itvLen); break; case WLZ_GREY_UBYTE: WlzValueCopyUByteToDouble(buf, iGWSp.u_grintptr.ubp, itvLen); break; case WLZ_GREY_FLOAT: WlzValueCopyFloatToDouble(buf, iGWSp.u_grintptr.flp, itvLen); break; case WLZ_GREY_DOUBLE: WlzValueCopyDoubleToDouble(buf, iGWSp.u_grintptr.dbp, itvLen); break; case WLZ_GREY_RGBA: WlzValueCopyRGBAToDouble(buf, iGWSp.u_grintptr.rgbp, itvLen); break; default: break; } switch(rGWSp.pixeltype) { case WLZ_GREY_UBYTE: for(idN = 0; idN < itvLen; ++idN) { f = (buf[idN] * m) + a; f = WLZ_CLAMP(f, 0, 255); rGWSp.u_grintptr.ubp[idN] = WLZ_NINT(f); } break; case WLZ_GREY_SHORT: for(idN = 0; idN < itvLen; ++idN) { f = (buf[idN] * m) + a; f = WLZ_CLAMP(f, SHRT_MIN, SHRT_MAX); rGWSp.u_grintptr.shp[idN] = WLZ_NINT(f); } break; case WLZ_GREY_INT: for(idN = 0; idN < itvLen; ++idN) { f = (buf[idN] * m) + a; f = WLZ_CLAMP(f, INT_MIN, INT_MAX); rGWSp.u_grintptr.inp[idN] = WLZ_NINT(f); } break; case WLZ_GREY_RGBA: for(idN = 0; idN < itvLen; ++idN) { WlzUInt u; f = (buf[idN] * m) + a; f = WLZ_CLAMP(f, 0, 255); t = WLZ_NINT(f); WLZ_RGBA_RGBA_SET(u, t, t, t, 255); rGWSp.u_grintptr.inp[idN] = u; } case WLZ_GREY_FLOAT: for(idN = 0; idN < itvLen; ++idN) { double t; t = (buf[idN] * m) + a; rGWSp.u_grintptr.flp[idN] = WLZ_CLAMP(t, -(FLT_MAX), FLT_MAX); } break; case WLZ_GREY_DOUBLE: for(idN = 0; idN < itvLen; ++idN) { rGWSp.u_grintptr.dbp[idN] = (buf[idN] * m) + a; } break; default: break; } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } } AlcFree(buf); } (void )WlzEndGreyScan(&iIWSp, &iGWSp); (void )WlzEndGreyScan(&rIWSp, &rGWSp); } return(errNum); }
/*! * \return Coordinates of center of mass. * \ingroup WlzFeatures * \brief Calculates the centre of mass of a WLZ_2D_DOMAIN_OBJ. * If the object has values and the binary object flag is * not set then the centre of mass is calculated using * the grey level information. * \f[ C_x = \frac{\sum_x{\sum_y{x G(x,y)}}} {\sum_x{\sum_y{G(x,y)}}} , C_y = \frac{\sum_x{\sum_y{y G(x,y)}}} {\sum_x{\sum_y{G(x,y)}}} \f] * Where \f$(C_x,C_y)\f$ are the coordinates of the centre of * mass. * If the given object does not have grey values or the * binary object flag is set (ie non zero) then every * pixel within the objects domain has the same mass. * \param srcObj Given object. * \param binObjFlag Binary object flag. * \param dstMass Destination pointer for mass, may be * NULL. * \param dstErr Destination pointer for error, may be * NULL. */ static WlzDVertex2 WlzCentreOfMassDom2D(WlzObject *srcObj, int binObjFlag, double *dstMass, WlzErrorNum *dstErr) { int iCount; double mass = 0.0, tmpD; WlzIntervalWSpace iWsp; WlzGreyWSpace gWsp; WlzGreyP gPix; WlzIVertex2 pos; WlzDVertex2 cMass, sum; WlzErrorNum errNum = WLZ_ERR_NONE; sum.vtX = 0.0; sum.vtY = 0.0; cMass.vtX = 0.0; cMass.vtY = 0.0; if(srcObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if((srcObj->domain.core->type != WLZ_INTERVALDOMAIN_INTVL) && (srcObj->domain.core->type != WLZ_INTERVALDOMAIN_RECT)) { errNum = WLZ_ERR_DOMAIN_TYPE; } else { if((srcObj->values.core == NULL) || (srcObj->values.core->type == WLZ_EMPTY_OBJ)) { binObjFlag = 1; } if(binObjFlag) { errNum = WlzInitRasterScan(srcObj, &iWsp, WLZ_RASTERDIR_ILIC); } else { errNum = WlzInitGreyScan(srcObj, &iWsp, &gWsp); } } if(errNum == WLZ_ERR_NONE) { if(binObjFlag) { while((errNum = WlzNextInterval(&iWsp)) == WLZ_ERR_NONE) { iCount = iWsp.rgtpos - iWsp.lftpos + 1; mass += iCount; sum.vtX += ((iWsp.rgtpos * (iWsp.rgtpos + 1)) - (iWsp.lftpos * (iWsp.lftpos - 1))) / 2.0; sum.vtY += iWsp.linpos * iCount; } if(errNum == WLZ_ERR_EOO) /* Reset error from end of intervals */ { errNum = WLZ_ERR_NONE; } } else { if((gWsp.pixeltype != WLZ_GREY_INT) && (gWsp.pixeltype != WLZ_GREY_SHORT) && (gWsp.pixeltype != WLZ_GREY_UBYTE) && (gWsp.pixeltype != WLZ_GREY_FLOAT) && (gWsp.pixeltype != WLZ_GREY_DOUBLE) && (gWsp.pixeltype != WLZ_GREY_RGBA)) { errNum = WLZ_ERR_GREY_TYPE; } if(errNum == WLZ_ERR_NONE) { while((errNum = WlzNextGreyInterval(&iWsp)) == WLZ_ERR_NONE) { pos.vtX = iWsp.lftpos; pos.vtY = iWsp.linpos; gPix = gWsp.u_grintptr; iCount = iWsp.rgtpos - iWsp.lftpos + 1; switch(gWsp.pixeltype) { case WLZ_GREY_INT: while(iCount-- > 0) { tmpD = *(gPix.inp); sum.vtY += pos.vtY * tmpD; sum.vtX += pos.vtX * tmpD; mass += tmpD; ++(gPix.inp); ++(pos.vtX); } break; case WLZ_GREY_SHORT: while(iCount-- > 0) { tmpD = *(gPix.shp); sum.vtY += pos.vtY * tmpD; sum.vtX += pos.vtX * tmpD; mass += tmpD; ++(gPix.shp); ++(pos.vtX); } break; case WLZ_GREY_UBYTE: while(iCount-- > 0) { tmpD = *(gPix.ubp); sum.vtY += pos.vtY * tmpD; sum.vtX += pos.vtX * tmpD; mass += tmpD; ++(gPix.ubp); ++(pos.vtX); } break; case WLZ_GREY_FLOAT: while(iCount-- > 0) { tmpD = *(gPix.flp); sum.vtY += pos.vtY * tmpD; sum.vtX += pos.vtX * tmpD; mass += tmpD; ++(gPix.flp); ++(pos.vtX); } break; case WLZ_GREY_DOUBLE: while(iCount-- > 0) { tmpD = *(gPix.dbp); sum.vtY += pos.vtY * tmpD; sum.vtX += pos.vtX * tmpD; mass += tmpD; ++(gPix.dbp); ++(pos.vtX); } break; case WLZ_GREY_RGBA: while(iCount-- > 0) { tmpD = WLZ_RGBA_MODULUS(*(gPix.rgbp)); sum.vtY += pos.vtY * tmpD; sum.vtX += pos.vtX * tmpD; mass += tmpD; ++(gPix.rgbp); ++(pos.vtX); } break; default: break; } } if(errNum == WLZ_ERR_EOO) /* Reset error from end of intervals */ { errNum = WLZ_ERR_NONE; } } (void )WlzEndGreyScan(&iWsp, &gWsp); } } if(errNum == WLZ_ERR_NONE) { if((mass > DBL_EPSILON) || (mass < (-(DBL_EPSILON)))) { cMass.vtX = sum.vtX / mass; cMass.vtY = sum.vtY / mass; } if(dstMass) { *dstMass = mass; } } if(dstErr) { *dstErr = errNum; } return(cMass); }
/*! * \return Centrality feature value in range [0.0-1.0]. * \ingroup WlzFeatures * \brief Computes the centrality of a feature domain with respect * to a boundary domain, where the domains are 2D. See * WlzCentrality(). * \param fObj Feature domain object. * \param bObj Boundary domain object. * \param nRay Number of equally spaced rays projected * from the centre of mass. * \param binFlg Treat as binary object if non-zero. * \param dstMaxR Destination pointer for maximum * boundary radius, may be NULL. * \param dstErr Destination error pointer, may be NULL. */ static double WlzCentrality2D(WlzObject *fObj, WlzObject *bObj, int nRay, int binFlg, double *dstMaxR, WlzErrorNum *dstErr) { int idx; double cent = 0.0, fNum = 0.0, fDnm = 0.0, maxR = 0.0; WlzIVertex2 pos; WlzDVertex2 cmV; double *pTbl = NULL; WlzObject *tmpObj, *bndObj = NULL; WlzGreyP gPix; WlzGreyWSpace gWsp; WlzIntervalWSpace iWsp; WlzErrorNum errNum = WLZ_ERR_NONE; /* Get centre of mass of the boundary object. */ cmV = WlzCentreOfMass2D(bObj, 1, NULL, &errNum); /* Get boundary of the boundary domain. */ if(errNum == WLZ_ERR_NONE) { bndObj = WlzObjToBoundary(bObj, 0, &errNum); } /* Make sure the boundary is 8-connected. */ if(errNum == WLZ_ERR_NONE) { tmpObj = WlzBoundTo8Bound(bndObj, &errNum); (void )WlzFreeObj(bndObj); bndObj = tmpObj; } /* Compute polar maximum boundary table. */ if(errNum == WLZ_ERR_NONE) { if((pTbl = (double *)AlcMalloc(nRay * sizeof(double))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } } if(errNum == WLZ_ERR_NONE) { WlzCentralityCompPolarTbl2D(cmV, nRay, pTbl, bndObj); if(dstMaxR != NULL) { for(idx = 0; idx < nRay; ++idx) { if(pTbl[idx] > maxR) { maxR = pTbl[idx]; } } } } (void )WlzFreeObj(bndObj); /* Scan through feature domain adding to feature values. */ if(errNum == WLZ_ERR_NONE) { if(binFlg != 0) { errNum = WlzInitRasterScan(fObj, &iWsp, WLZ_RASTERDIR_ILIC); while((errNum = WlzNextInterval(&iWsp)) == WLZ_ERR_NONE) { pos.vtY = iWsp.linpos; for(pos.vtX = iWsp.lftpos; pos.vtX <= iWsp.rgtpos; ++pos.vtX) { WlzCentralityUpdate2D(&fNum, &fDnm, cmV, nRay, pTbl, 1.0, pos); } } } else { errNum = WlzInitGreyScan(fObj, &iWsp, &gWsp); if(errNum == WLZ_ERR_NONE) { while((errNum = WlzNextGreyInterval(&iWsp)) == WLZ_ERR_NONE) { gPix = gWsp.u_grintptr; pos.vtY = iWsp.linpos; for(pos.vtX = iWsp.lftpos; pos.vtX <= iWsp.rgtpos; ++pos.vtX) { switch(gWsp.pixeltype) { case WLZ_GREY_INT: WlzCentralityUpdate2D(&fNum, &fDnm, cmV, nRay, pTbl, *(gPix.inp)++, pos); break; case WLZ_GREY_SHORT: WlzCentralityUpdate2D(&fNum, &fDnm, cmV, nRay, pTbl, *(gPix.shp)++, pos); break; case WLZ_GREY_UBYTE: WlzCentralityUpdate2D(&fNum, &fDnm, cmV, nRay, pTbl, *(gPix.ubp)++, pos); break; case WLZ_GREY_FLOAT: WlzCentralityUpdate2D(&fNum, &fDnm, cmV, nRay, pTbl, *(gPix.flp)++, pos); break; case WLZ_GREY_DOUBLE: WlzCentralityUpdate2D(&fNum, &fDnm, cmV, nRay, pTbl, *(gPix.dbp)++, pos); break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } } (void )WlzEndGreyScan(&iWsp, &gWsp); } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } } if(errNum == WLZ_ERR_NONE) { cent = (fabs(fDnm) > DBL_EPSILON)? fNum / fDnm: DBL_MAX; if(dstMaxR != NULL) { *dstMaxR = maxR; } } AlcFree(pTbl); if(dstErr) { *dstErr = errNum; } return(cent); }
/*! * \return Angle in radians. * \ingroup WlzRegistration * \brief Calculates the angle which the long principal axis * makes with the x-axis in the given object. * \f[ \theta = \frac{1}{2} \arctan{(2 \frac{I_{xy}}{I_{yy}-I_{xx}})} \f] * where * \f[ I_{xx} = \sum_y \sum_x ((y - C_y) (y - C_y) G(x, y)) \f] * \f[ I_{yy} = \sum_y \sum_x ((x - C_x) (x - C_x) G(x, y)) \f] * \f[ I_{xy} = - \sum_y \sum_x (((x - C x) (y - C_y) G(x, y)) \f] * and \f$(C_x, C_y)\f$ are the coordinates of the centre of * mass. * \param srcObj Given object. * \param cMass Center of mass of given object. * \param binObjFlag Given object is binary if non * zero. * \param dstErrNum Destination pointer for error * number, may be NULL if not * required. */ double WlzPrincipalAngle(WlzObject *srcObj, WlzDVertex2 cMass, int binObjFlag, WlzErrorNum *dstErrNum) { int tI0, tI1, iCount; double tD0, tD1, root0, root1, ixx = 0.0, iyy = 0.0, ixy = 0.0, pAngle = 0.0; WlzIVertex2 delta; WlzIntervalWSpace iWsp = {0}; WlzGreyWSpace gWsp; WlzGreyP gPix; WlzErrorNum errNum = WLZ_ERR_NONE; WLZ_DBG((WLZ_DBG_LVL_FN|WLZ_DBG_LVL_1), ("WlzPrincipalAngle FE %p {%d %d} %d\n", srcObj, cMass.vtX, cMass.vtY, binObjFlag)); if(srcObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(srcObj->type != WLZ_2D_DOMAINOBJ) { errNum = WLZ_ERR_OBJECT_TYPE; } else if(srcObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if((srcObj->domain.core->type != WLZ_INTERVALDOMAIN_INTVL) && (srcObj->domain.core->type != WLZ_INTERVALDOMAIN_RECT)) { errNum = WLZ_ERR_DOMAIN_TYPE; } else { if((srcObj->values.core == NULL) || (srcObj->values.core->type == WLZ_EMPTY_OBJ)) { binObjFlag = 1; } if(binObjFlag) { errNum = WlzInitRasterScan(srcObj, &iWsp, WLZ_RASTERDIR_ILIC); } else { errNum = WlzInitGreyScan(srcObj, &iWsp, &gWsp); } } if(errNum == WLZ_ERR_NONE) { if(binObjFlag) { while((errNum = WlzNextInterval(&iWsp)) == WLZ_ERR_NONE) { delta.vtY = (int )(iWsp.linpos - cMass.vtY); delta.vtX = (int )(iWsp.lftpos - cMass.vtX); iCount = iWsp.rgtpos - iWsp.lftpos + 1; tI0 = iCount * (iCount - 1); ixx += iCount * delta.vtY * delta.vtY; iyy += (iCount * delta.vtX * delta.vtX) + (tI0 * delta.vtX) + (tI0 * ((2 * iCount) - 1) / 6); ixy -= (iCount * delta.vtX * delta.vtY) + (tI0 * delta.vtY / 2); } if(errNum == WLZ_ERR_EOO) /* Reset error from end of intervals */ { errNum = WLZ_ERR_NONE; } } else { while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iWsp)) == WLZ_ERR_NONE)) { gPix = gWsp.u_grintptr; delta.vtX = (int )(iWsp.lftpos - cMass.vtX); delta.vtY = (int )(iWsp.linpos - cMass.vtY); iCount = iWsp.rgtpos - iWsp.lftpos; switch(gWsp.pixeltype) { case WLZ_GREY_INT: while(iCount-- >= 0) { tI0 = *gPix.inp; tI1 = delta.vtX * tI0; ixx += delta.vtY * delta.vtY * tI0; iyy += delta.vtX * tI1; ixy -= delta.vtY * tI1; ++gPix.inp; ++delta.vtX; } break; case WLZ_GREY_SHORT: while(iCount-- >= 0) { tI0 = *gPix.shp; tI1 = delta.vtX * tI0; ixx += delta.vtY * delta.vtY * tI0; iyy += delta.vtX * tI1; ixy -= delta.vtY * tI1; ++gPix.inp; ++delta.vtX; } break; case WLZ_GREY_UBYTE: while(iCount-- >= 0) { tI0 = *gPix.ubp; tI1 = delta.vtX * tI0; ixx += delta.vtY * delta.vtY * tI0; iyy += delta.vtX * tI1; ixy -= delta.vtY * tI1; ++gPix.ubp; ++delta.vtX; } break; case WLZ_GREY_FLOAT: while(iCount-- >= 0) { tD0 = *gPix.flp; tD1 = delta.vtX * tD0; ixx += delta.vtY * delta.vtY * tD0; iyy += delta.vtX * tD1; ixy -= delta.vtY * tD1; ++gPix.flp; ++delta.vtX; } break; case WLZ_GREY_DOUBLE: while(iCount-- >= 0) { tD0 = *gPix.dbp; tD1 = delta.vtX * tD0; ixx += delta.vtY * delta.vtY * tD0; iyy += delta.vtX * tD1; ixy -= delta.vtY * tD1; ++gPix.dbp; ++delta.vtX; } break; case WLZ_GREY_RGBA: while(iCount-- >= 0) { tI0 = (WlzUInt )WLZ_RGBA_MODULUS(*gPix.rgbp); tI1 = delta.vtX * tI0; ixx += delta.vtY * delta.vtY * tI0; iyy += delta.vtX * tI1; ixy -= delta.vtY * tI1; ++gPix.rgbp; ++delta.vtX; } break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } (void )WlzEndGreyScan(&iWsp, &gWsp); if(errNum == WLZ_ERR_EOO) /* Reset error from end of intervals */ { errNum = WLZ_ERR_NONE; } } } if(errNum == WLZ_ERR_NONE) { tD0 = ixx + iyy; tD1 = sqrt((tD0 * tD0) - (4.0 * ((ixx * iyy) - (ixy * ixy)))); root0 = (tD0 - tD1) / 2.0; root1 = (tD0 + tD1) / 2.0; if(WLZ_ABS(root0) > WLZ_ABS(root1)) { root0 = root1; } if(WLZ_ABS(root0 - ixx) < DBL_EPSILON) { pAngle = 0.0; } else if(WLZ_ABS(ixy) < DBL_EPSILON) { pAngle = WLZ_M_PI_2; } else { pAngle = atan((root0 - ixx) / ixy); } } if(dstErrNum) { *dstErrNum = errNum; } WLZ_DBG((WLZ_DBG_LVL_FN|WLZ_DBG_LVL_1), ("WlzPrincipalAngle FX %d\n", pAngle)); return(pAngle); }
/*! * \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); }
WlzObject *WlzCbThreshold( WlzObject *obj, WlzThreshCbFn threshCb, void *clientData, WlzErrorNum *dstErr) { WlzObject *nobj=NULL; WlzIntervalDomain *idom = NULL; WlzGreyP g; WlzThreshCbStr callData; int colno, nints; int over; int nl1,nll,nk1,nkl; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzInterval *itvl = NULL, *jtvl = NULL; WlzDomain domain; WlzValues values; WlzErrorNum errNum=WLZ_ERR_NONE; /* check the object */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( obj->type ){ case WLZ_2D_DOMAINOBJ: /* check object 2D domain and valuetable */ if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; break; } if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; break; } break; case WLZ_3D_DOMAINOBJ: return WlzCbThreshold3d(obj, threshCb, clientData, dstErr); case WLZ_TRANS_OBJ: if((nobj = WlzCbThreshold(obj->values.obj, threshCb, clientData, &errNum)) != NULL){ values.obj = nobj; return WlzMakeMain(obj->type, obj->domain, values, NULL, obj, dstErr); } break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; } } /* * first pass - find line and column bounds of thresholded * object and number of intervals. */ if( errNum == WLZ_ERR_NONE ){ idom = obj->domain.i; nl1 = idom->lastln; nll = idom->line1; nk1 = idom->lastkl; nkl = idom->kol1; callData.pix.type = gwsp.pixeltype; (void) WlzInitGreyScan(obj, &iwsp, &gwsp); } if( errNum == WLZ_ERR_NONE ){ nints = 0; while( (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE ){ callData.pos.vtY = iwsp.linpos; g = gwsp.u_grintptr; over = 0; for (colno = iwsp.lftpos; colno <= iwsp.rgtpos; colno++) { callData.pix.p = g; callData.pos.vtX = colno; if((*threshCb)(obj, clientData, &callData) ){ if (over == 0) { over = 1; if (iwsp.linpos < nl1) nl1 = iwsp.linpos; if (iwsp.linpos > nll) nll = iwsp.linpos; if (colno < nk1) nk1 = colno; } } else { if (over == 1) { if (colno > nkl) nkl = colno; over = 0; nints++; } } switch( gwsp.pixeltype ){ case WLZ_GREY_INT: g.inp++; break; case WLZ_GREY_SHORT: g.shp++; break; case WLZ_GREY_UBYTE: g.ubp++; break; case WLZ_GREY_FLOAT: g.flp++; break; case WLZ_GREY_DOUBLE: g.dbp++; break; case WLZ_GREY_RGBA: g.rgbp++; break; default: break; } } if (over == 1) { if (colno > nkl) nkl = colno; over = 0; nints++; } } nkl--; /* since we have looked at points beyond interval ends */ (void )WlzEndGreyScan(&iwsp, &gwsp); if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } } /* domain structure */ if( errNum == WLZ_ERR_NONE ){ if( nints > 0 ){ if((idom = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, nl1, nll, nk1, nkl, &errNum)) != NULL){ if( (itvl = (WlzInterval *) AlcMalloc(nints * sizeof(WlzInterval))) == NULL ){ errNum = WLZ_ERR_MEM_ALLOC; WlzFreeIntervalDomain(idom); } else { idom->freeptr = AlcFreeStackPush(idom->freeptr, (void *)itvl, NULL); } } /* * second pass - construct intervals */ if( errNum == WLZ_ERR_NONE ){ errNum = WlzInitGreyScan(obj, &iwsp, &gwsp); callData.pix.type = gwsp.pixeltype; nints = 0; jtvl = itvl; } /* find thresholded endpoints */ if( errNum == WLZ_ERR_NONE ){ while( (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE ){ if( iwsp.linpos < nl1 || iwsp.linpos > nll ){ continue; } callData.pos.vtY = iwsp.linpos; g = gwsp.u_grintptr; over = 0; for (colno = iwsp.lftpos; colno <= iwsp.rgtpos; colno++) { callData.pix.p = g; callData.pos.vtX = colno; if((*threshCb)(obj, clientData, &callData) ){ if (over == 0) { over = 1; itvl->ileft = colno - nk1; } } else { if (over == 1) { over = 0; itvl->iright = colno - nk1 - 1; nints++; itvl++; } } switch( gwsp.pixeltype ){ case WLZ_GREY_INT: g.inp++; break; case WLZ_GREY_SHORT: g.shp++; break; case WLZ_GREY_UBYTE: g.ubp++; break; case WLZ_GREY_FLOAT: g.flp++; break; case WLZ_GREY_DOUBLE: g.dbp++; break; case WLZ_GREY_RGBA: g.rgbp++; break; default: break; } } if (over == 1) { over = 0; itvl->iright = colno - nk1 - 1; nints++; itvl++; } /* * end of line ? */ if (iwsp.intrmn == 0) { WlzMakeInterval(iwsp.linpos, idom, nints, jtvl); jtvl = itvl; nints = 0; } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } } } else { /* no thresholded points - make a dummy domain anyway */ return WlzMakeEmpty(dstErr); } } /* main object */ if( errNum == WLZ_ERR_NONE ){ domain.i = idom; nobj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain, obj->values, obj->plist, obj, &errNum); } if( dstErr ){ *dstErr = errNum; } return(nobj); }
/*! * \return projection object * \ingroup WlzTransform * \brief Use the view transform to define a projection from * 3D to 2D. Currently only the domain is projected as * an opaque shadow. * This is old code temporarily kept for compatibility. * \param obj source 3D object * \param viewStr view structure defining the projection * \param intFunc grey-value summation function * \param intFuncData data to be passed to the integration function * \param dstErr error return */ WlzObject *WlzGetProjectionFromObject( WlzObject *obj, WlzThreeDViewStruct *viewStr, Wlz3DProjectionIntFn intFunc, void *intFuncData, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL, *obj1; WlzThreeDViewStruct *viewStr1=NULL; WlzDomain domain; WlzValues values; WlzGreyType srcGType = WLZ_GREY_UBYTE, dstGType = WLZ_GREY_UBYTE; WlzPixelV pixval; WlzPixelP pixptr; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyValueWSpace *gVWSp = NULL; WlzDVertex3 vtx, vtx1; double x, y, z; double *s_to_x=NULL; double *s_to_y=NULL; double *s_to_z=NULL; int k, xp, yp, s, sp; int length = 0, size = 0, occupiedFlg; WlzErrorNum errNum=WLZ_ERR_NONE; /* check inputs */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else if( obj->type != WLZ_3D_DOMAINOBJ ){ errNum = WLZ_ERR_OBJECT_TYPE; } else if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if( obj->domain.core->type != WLZ_PLANEDOMAIN_DOMAIN ){ errNum = WLZ_ERR_DOMAIN_TYPE; } if( (errNum == WLZ_ERR_NONE) && (viewStr == NULL) ){ errNum = WLZ_ERR_OBJECT_NULL; } /* create new view transform */ if( errNum == WLZ_ERR_NONE ){ if((viewStr1 = WlzMake3DViewStruct(WLZ_3D_VIEW_STRUCT, &errNum)) != NULL){ /* need to worry about fixed line mode here sometime */ viewStr1->fixed = viewStr->fixed; viewStr1->theta = viewStr->theta; viewStr1->phi = viewStr->phi; viewStr1->zeta = viewStr->zeta; viewStr1->dist = viewStr->dist; viewStr1->scale = viewStr->scale; viewStr1->voxelSize[0] = viewStr->voxelSize[0]; viewStr1->voxelSize[1] = viewStr->voxelSize[1]; viewStr1->voxelSize[2] = viewStr->voxelSize[2]; viewStr1->voxelRescaleFlg = viewStr->voxelRescaleFlg; viewStr1->interp = viewStr->interp; viewStr1->view_mode = viewStr->view_mode; viewStr1->up = viewStr->up; /* now intialize it */ /* could optimise by setting fixed point to object centre */ if( (errNum = WlzInit3DViewStruct(viewStr1, obj)) != WLZ_ERR_NONE ){ WlzFree3DViewStruct(viewStr1); viewStr1 = NULL; } } } /* set up orthogonal line parameters & luts */ if( errNum == WLZ_ERR_NONE ){ length = WLZ_NINT(viewStr1->maxvals.vtZ) - WLZ_NINT(viewStr1->minvals.vtZ) + 1; s_to_x = (double *) AlcMalloc(sizeof(double) * length ); s_to_y = (double *) AlcMalloc(sizeof(double) * length ); s_to_z = (double *) AlcMalloc(sizeof(double) * length ); /* transform a perpendicular vector */ vtx.vtX = 0.0; vtx.vtY = 0.0; vtx.vtZ = 1.0; Wlz3DSectionTransformInvVtx(&vtx, viewStr1); vtx1.vtX = 0.0; vtx1.vtY = 0.0; vtx1.vtZ = 0.0; Wlz3DSectionTransformInvVtx(&vtx1, viewStr1); vtx.vtX -= vtx1.vtX; vtx.vtY -= vtx1.vtY; vtx.vtZ -= vtx1.vtZ; /* assign lut values */ s = (int )(WLZ_NINT(viewStr1->minvals.vtZ) - viewStr1->dist); for(sp=0; sp < length; sp++, s++){ s_to_x[sp] = s * vtx.vtX; s_to_y[sp] = s * vtx.vtY; s_to_z[sp] = s * vtx.vtZ; } } /* if there is an integration function then allocate space for the grey-level array */ if( (errNum == WLZ_ERR_NONE) && (intFunc) ){ srcGType = WlzGreyTypeFromObj(obj, &errNum); switch( srcGType ){ case WLZ_GREY_LONG: size = sizeof(WlzLong)*length; break; case WLZ_GREY_INT: size = sizeof(int)*length; break; case WLZ_GREY_SHORT: size = sizeof(short)*length; break; case WLZ_GREY_UBYTE: size = sizeof(WlzUByte)*length; break; case WLZ_GREY_FLOAT: size = sizeof(float)*length; break; case WLZ_GREY_DOUBLE: size = sizeof(double)*length; break; case WLZ_GREY_RGBA: size = sizeof(int)*length; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } if( (pixptr.p.inp = (int *) AlcMalloc(size)) == NULL ){ errNum = WLZ_ERR_MEM_ALLOC; } pixptr.type = srcGType; /* set up the grey-value workspace for random access */ gVWSp = WlzGreyValueMakeWSp(obj, &errNum); } /* create rectangular projection image */ if( errNum == WLZ_ERR_NONE ){ if((domain.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_RECT, WLZ_NINT(viewStr1->minvals.vtY), WLZ_NINT(viewStr1->maxvals.vtY), WLZ_NINT(viewStr1->minvals.vtX), WLZ_NINT(viewStr1->maxvals.vtX), &errNum)) != NULL){ values.core = NULL; if((rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain, values, NULL, NULL, &errNum)) != NULL){ /* note the grey-values required are determined by the integration function. Here we use WlzUByte and reset later if needed */ dstGType = WLZ_GREY_UBYTE; pixval.type = WLZ_GREY_UBYTE; pixval.v.ubv = (WlzUByte )0; if((values.v = WlzNewValueTb(rtnObj, WlzGreyTableType(WLZ_GREY_TAB_RECT, dstGType, NULL), pixval, &errNum)) != NULL){ rtnObj->values = WlzAssignValues(values, &errNum); } else { WlzFreeObj(rtnObj); rtnObj = NULL; } } else { WlzFreeDomain(domain); domain.core = NULL; } } } /* scan image setting values */ if( errNum == WLZ_ERR_NONE ){ errNum = WlzInitGreyScan(rtnObj, &iwsp, &gwsp); } if( errNum == WLZ_ERR_NONE ){ while( (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE ){ yp = iwsp.linpos - WLZ_NINT(viewStr1->minvals.vtY); for(k=iwsp.lftpos; k <= iwsp.rgtpos; k++){ xp = k - WLZ_NINT(viewStr1->minvals.vtX); vtx.vtX = viewStr1->xp_to_x[xp] + viewStr1->yp_to_x[yp]; vtx.vtY = viewStr1->xp_to_y[xp] + viewStr1->yp_to_y[yp]; vtx.vtZ = viewStr1->xp_to_z[xp] + viewStr1->yp_to_z[yp]; /* get the projection values */ /* if no function then just check for occupancy */ if( intFunc == NULL ){ occupiedFlg = 0; sp = (int )(viewStr1->dist - WLZ_NINT(viewStr1->minvals.vtZ)); for(; !occupiedFlg && (sp < length); sp++){ x = vtx.vtX + s_to_x[sp]; y = vtx.vtY + s_to_y[sp]; z = vtx.vtZ + s_to_z[sp]; if( WlzInsideDomain(obj, z, y, x, &errNum) ){ occupiedFlg = 1; } } sp = (int )(viewStr1->dist - WLZ_NINT(viewStr1->minvals.vtZ) - 1); for(; !occupiedFlg && (sp >= 0); sp--){ x = vtx.vtX + s_to_x[sp]; y = vtx.vtY + s_to_y[sp]; z = vtx.vtZ + s_to_z[sp]; if( WlzInsideDomain(obj, z, y, x, &errNum) ){ occupiedFlg = 1; } } /* set the integrated value - only WlzUByte at the moment */ *(gwsp.u_grintptr.ubp) = (WlzUByte )occupiedFlg; gwsp.u_grintptr.ubp++; } /* use integration function */ else { /* set array of pixel values */ for(sp=0; sp < length; sp++){ x = vtx.vtX + s_to_x[sp]; y = vtx.vtY + s_to_y[sp]; z = vtx.vtZ + s_to_z[sp]; WlzGreyValueGet(gVWSp, WLZ_NINT(z), WLZ_NINT(y), WLZ_NINT(x)); switch( srcGType ){ case WLZ_GREY_LONG: pixptr.p.lnp[sp] = gVWSp->gVal[0].lnv; break; case WLZ_GREY_INT: pixptr.p.inp[sp] = gVWSp->gVal[0].inv; break; case WLZ_GREY_SHORT: pixptr.p.shp[sp] = gVWSp->gVal[0].shv; break; case WLZ_GREY_UBYTE: pixptr.p.ubp[sp] = gVWSp->gVal[0].ubv; break; case WLZ_GREY_FLOAT: pixptr.p.flp[sp] = gVWSp->gVal[0].flv; break; case WLZ_GREY_DOUBLE: pixptr.p.dbp[sp] = gVWSp->gVal[0].dbv; break; case WLZ_GREY_RGBA: pixptr.p.rgbp[sp] = gVWSp->gVal[0].rgbv; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } /* call integration function and seet value */ intFunc(pixptr, length, (int )(viewStr1->dist - WLZ_NINT(viewStr1->minvals.vtZ)), intFuncData, &errNum); } } } (void )WlzEndGreyScan(&iwsp, &gwsp); if(errNum == WLZ_ERR_EOO) /* Reset error from end of intervals */ { errNum = WLZ_ERR_NONE; } /* if no integration function then threshold - binary only */ if( intFunc == NULL ){ pixval.v.ubv = 1; rtnObj = WlzAssignObject(rtnObj, NULL); if((obj1 = WlzThreshold(rtnObj, pixval, WLZ_THRESH_HIGH, &errNum)) != NULL){ WlzFreeObj(rtnObj); values.core = NULL; rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, obj1->domain, values, NULL, NULL, &errNum); WlzFreeObj(obj1); } else { WlzFreeObj(rtnObj); rtnObj = NULL; } } } /* clear space */ if( viewStr1 ){ errNum = WlzFree3DViewStruct(viewStr1); } if( s_to_x ){ AlcFree( s_to_x ); } if( s_to_y ){ AlcFree( s_to_y ); } if( s_to_z ){ AlcFree( s_to_z ); } /* check error and return */ if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \return New object with the rojection. * \ingroup WlzTransform * \brief Use the view transform to define a projection from * 3D to 2D and then project the object onto this plane. * The object supplied to this function must be a 3D * spatial domain object (WLZ_3D_DOMAINOBJ) with either * no values or for integration WLZ_GREY_UBYTE values. * Integration will assign each output pixel the sum of * all input voxels mapped via either the domain density * or the voxel density. * The integration is controled by the integrate parameter * with valid values: * WLZ_PROJECT_INT_MODE_NONE - a "shadow domain" without values * is computed, * WLZ_PROJECT_INT_MODE_DOMAIN - the voxels of the domain are * integrated using * \f[ p = \frac{1}{255} n d \f] * WLZ_PROJECT_INT_MODE_VALUES - the voxel values are integrated * using * \f[ p = \frac{1}{255} \sum{l\left[v\right]}. \f] * Where * \f$p\f$ is the projected image value, * \f$n\f$ is the number of voxels projected for \f$p\f$, * \f$d\f$ is the density of domain voxels, * \f$l\f$ is the voxel value density look up table and * \f$v\f$ is a voxel value. * \param obj The given object. * \param vStr Given view structure defining the * projection plane. * \param intMod This may take three values: * WLZ_PROJECT_INT_MODE_NONE, * WLZ_PROJECT_INT_MODE_DOMAIN or * WLZ_PROJECT_INT_MODE_VALUES. * \param denDom Density of domain voxels this value * is not used unless the integration * mode is WLZ_PROJECT_INT_MODE_DOMAIN. * \param denVal Density look up table for object * voxel density values which must be * an array of 256 values. This may be * NULL if the integration mode is not * WLZ_PROJECT_INT_MODE_VALUES. * \param depth If greater than zero, the projection * depth perpendicular to the viewing * plane. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzProjectObjToPlane(WlzObject *obj, WlzThreeDViewStruct *vStr, WlzProjectIntMode intMod, WlzUByte denDom, WlzUByte *denVal, double depth, WlzErrorNum *dstErr) { int nThr = 1, itvVal = 0; WlzIVertex2 prjSz; WlzIBox2 prjBox = {0}; double pln[4]; WlzObject *bufObj = NULL, *prjObj = NULL; WlzThreeDViewStruct *vStr1 = NULL; double **vMat = NULL; WlzValues nullVal; WlzErrorNum errNum = WLZ_ERR_NONE; WlzAffineTransform *rescaleTr = NULL; WlzGreyValueWSpace **gVWSp = NULL; void ***prjAry = NULL; const double eps = 0.000001; #ifdef WLZ_DEBUG_PROJECT3D_TIME struct timeval times[3]; #endif /* WLZ_DEBUG_PROJECT3D_TIME */ nullVal.core = NULL; if(obj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(obj->type != WLZ_3D_DOMAINOBJ) { errNum = WLZ_ERR_OBJECT_TYPE; } else if(obj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(obj->domain.core->type != WLZ_PLANEDOMAIN_DOMAIN) { errNum = WLZ_ERR_DOMAIN_TYPE; } else if(vStr == NULL) { errNum = WLZ_ERR_TRANSFORM_NULL; } else if((intMod == WLZ_PROJECT_INT_MODE_VALUES) && (obj->values.core == NULL)) { errNum = WLZ_ERR_VALUES_NULL; } #ifdef WLZ_DEBUG_PROJECT3D_TIME gettimeofday(times + 0, NULL); #endif /* WLZ_DEBUG_PROJECT3D_TIME */ /* Create new view transform without voxel scaling. The voxel scaling * is done after the projection. */ if(errNum == WLZ_ERR_NONE) { if((vStr1 = WlzMake3DViewStruct(WLZ_3D_VIEW_STRUCT, &errNum)) != NULL) { vStr1->fixed = vStr->fixed; vStr1->theta = vStr->theta; vStr1->phi = vStr->phi; vStr1->zeta = vStr->zeta; vStr1->dist = vStr->dist; vStr1->scale = vStr->scale; vStr1->voxelSize[0] = 1.0; vStr1->voxelSize[1] = 1.0; vStr1->voxelSize[2] = 1.0; vStr1->voxelRescaleFlg = 0; vStr1->interp = vStr->interp; vStr1->view_mode = vStr->view_mode; vStr1->up = vStr->up; vStr1->initialised = WLZ_3DVIEWSTRUCT_INIT_NONE; vMat = vStr1->trans->mat; errNum = WlzInit3DViewStructAffineTransform(vStr1); if(errNum == WLZ_ERR_NONE) { errNum = Wlz3DViewStructTransformBB(obj, vStr1); } if(errNum != WLZ_ERR_NONE) { WlzFree3DViewStruct(vStr1); vStr1 = NULL; } } } /* Compute bounding box of the projection. */ if(errNum == WLZ_ERR_NONE) { prjBox.xMin = WLZ_NINT(vStr1->minvals.vtX); prjBox.yMin = WLZ_NINT(vStr1->minvals.vtY); prjBox.xMax = WLZ_NINT(vStr1->maxvals.vtX); prjBox.yMax = WLZ_NINT(vStr1->maxvals.vtY); prjSz.vtX = prjBox.xMax - prjBox.xMin + 1; prjSz.vtY = prjBox.yMax - prjBox.yMin + 1; } /* Compute post projection scaling. */ if((errNum == WLZ_ERR_NONE) && (vStr->voxelRescaleFlg != 0)) { WlzIBox2 sBox; WlzIVertex2 sSz; WlzThreeDViewStruct *vStr2; vStr2 = WlzMake3DViewStruct(WLZ_3D_VIEW_STRUCT, &errNum); if(errNum == WLZ_ERR_NONE) { vStr2->fixed = vStr->fixed; vStr2->theta = vStr->theta; vStr2->phi = vStr->phi; vStr2->zeta = vStr->zeta; vStr2->dist = vStr->dist; vStr2->scale = vStr->scale; vStr2->voxelSize[0] = vStr->voxelSize[0]; vStr2->voxelSize[1] = vStr->voxelSize[1]; vStr2->voxelSize[2] = vStr->voxelSize[2]; vStr2->voxelRescaleFlg = vStr->voxelRescaleFlg; vStr2->interp = vStr->interp; vStr2->view_mode = vStr->view_mode; vStr2->up = vStr->up; vStr2->initialised = WLZ_3DVIEWSTRUCT_INIT_NONE; errNum = WlzInit3DViewStructAffineTransform(vStr2); if(errNum == WLZ_ERR_NONE) { errNum = Wlz3DViewStructTransformBB(obj, vStr2); } if(errNum == WLZ_ERR_NONE) { sBox.xMin = WLZ_NINT(vStr2->minvals.vtX); sBox.yMin = WLZ_NINT(vStr2->minvals.vtY); sBox.xMax = WLZ_NINT(vStr2->maxvals.vtX); sBox.yMax = WLZ_NINT(vStr2->maxvals.vtY); sSz.vtX = sBox.xMax - sBox.xMin + 1; sSz.vtY = sBox.yMax - sBox.yMin + 1; rescaleTr = WlzMakeAffineTransform(WLZ_TRANSFORM_2D_AFFINE, &errNum); } if(errNum == WLZ_ERR_NONE) { double **m; m = rescaleTr->mat; m[0][0] = (sSz.vtX * eps) / (prjSz.vtX * eps); m[1][1] = (sSz.vtY * eps) / (prjSz.vtY * eps); m[0][2] = sBox.xMin - WLZ_NINT(m[0][0] * prjBox.xMin); m[1][2] = sBox.yMin - WLZ_NINT(m[1][1] * prjBox.yMin); } (void )WlzFree3DViewStruct(vStr2); } } /* Compute plane equation, used to clip intervals if depth was given. */ if((errNum == WLZ_ERR_NONE) && (depth > eps)) { Wlz3DViewGetPlaneEqn(vStr1, pln + 0, pln + 1, pln + 2, pln + 3); } /* Create rectangular projection array buffers, one for each thread, * also if integrating values create a grey value workspace per thread. */ if(errNum == WLZ_ERR_NONE) { int idB; #ifdef _OPENMP #pragma omp parallel { #pragma omp master { nThr = omp_get_num_threads(); } } #endif if((prjAry = (void ***)AlcCalloc(nThr, sizeof(void **))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { if(intMod == WLZ_PROJECT_INT_MODE_NONE) { for(idB = 0; idB < nThr; ++idB) { if(AlcUnchar2Calloc((WlzUByte ***)&(prjAry[idB]), prjSz.vtY, prjSz.vtX) != ALC_ER_NONE) { errNum = WLZ_ERR_MEM_ALLOC; break; } } } else { for(idB = 0; idB < nThr; ++idB) { if(AlcInt2Calloc((int ***)&(prjAry[idB]), prjSz.vtY, prjSz.vtX) != ALC_ER_NONE) { errNum = WLZ_ERR_MEM_ALLOC; break; } } } } if((errNum == WLZ_ERR_NONE) && (intMod == WLZ_PROJECT_INT_MODE_VALUES)) { itvVal = (WlzGreyTableIsTiled(obj->values.core->type) == 0); if(itvVal == 0) { if((gVWSp = AlcCalloc(nThr, sizeof(WlzGreyValueWSpace *))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { for(idB = 0; idB < nThr; ++idB) { gVWSp[idB] = WlzGreyValueMakeWSp(obj, &errNum); if(gVWSp[idB]->gType != WLZ_GREY_UBYTE) { errNum = WLZ_ERR_GREY_TYPE; break; } } } } } } /* Scan through the 3D domain setting value in the projection array. */ if(errNum == WLZ_ERR_NONE) { int pIdx, pCnt; WlzDomain *doms; WlzValues *vals = NULL; doms = obj->domain.p->domains; if(itvVal) { vals = obj->values.vox->values; } pCnt = obj->domain.p->lastpl - obj->domain.p->plane1 + 1; #ifdef _OPENMP #pragma omp parallel for #endif for(pIdx = 0; pIdx < pCnt; ++pIdx) { int thrId = 0; if((errNum == WLZ_ERR_NONE) && (doms[pIdx].core != NULL)) { WlzObject *obj2; WlzGreyWSpace gWSp; WlzIntervalWSpace iWSp; WlzErrorNum errNum2 = WLZ_ERR_NONE; #ifdef _OPENMP thrId = omp_get_thread_num(); #endif obj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, doms[pIdx], (vals)? vals[pIdx]: nullVal, NULL, NULL, &errNum2); if(errNum2 == WLZ_ERR_NONE) { if(itvVal) { errNum2 = WlzInitGreyScan(obj2, &iWSp, &gWSp); } else { errNum2 = WlzInitRasterScan(obj2, &iWSp, WLZ_RASTERDIR_ILIC); } } if(errNum2 == WLZ_ERR_NONE) { double plnZ, vMZX, vMZY; WlzIVertex3 p0, p1; p0.vtZ = p1.vtZ = obj->domain.p->plane1 + pIdx; vMZX = (vMat[0][2] * p0.vtZ) + vMat[0][3] - prjBox.xMin; vMZY = (vMat[1][2] * p0.vtZ) + vMat[1][3] - prjBox.yMin; plnZ = (pln[2] * p0.vtZ) + pln[3]; while(((itvVal == 0) && ((errNum2 = WlzNextInterval(&iWSp)) == WLZ_ERR_NONE)) || ((itvVal != 0) && ((errNum2 = WlzNextGreyInterval(&iWSp)) == WLZ_ERR_NONE))) { int skip = 0; WlzDVertex2 q0, q1; p0.vtX = iWSp.lftpos; p1.vtX = iWSp.rgtpos; p0.vtY = p1.vtY = iWSp.linpos; if(depth > eps) { int c; double d0, d1, plnYZ; /* Clip the 3D line segment p0,p1 using the plane equation. */ plnYZ = (pln[1] * p0.vtY) + plnZ; d0 = (pln[0] * p0.vtX) + plnYZ; d1 = (pln[0] * p1.vtX) + plnYZ; c = ((d1 > depth) << 3) | ((d0 > depth) << 2) | ((d1 < -depth) << 1) | (d0 < -depth); if(c) { if((c == 3) || (c == 12)) /* 00-- or ++00 */ { /* Both out of range, so don't render. */ skip = 1; } else { if(fabs(pln[0]) > eps) { double plnX; plnX = -1.0 / pln[0]; if((c & 1) != 0) /* x0x- */ { p0.vtX = plnX * (plnYZ + depth); } else if((c & 4) != 0) /* x+x0 */ { p0.vtX = plnX * (plnYZ - depth); } if((c & 2) != 0) /* 0x-x */ { p1.vtX = plnX * (plnYZ + depth); } else if((c & 8) != 0) /* +x0x */ { p1.vtX = plnX * (plnYZ - depth); } } } } } if(skip == 0) { q0.vtX = (vMat[0][0] * p0.vtX) + (vMat[0][1] * p0.vtY) + vMZX; q0.vtY = (vMat[1][0] * p0.vtX) + (vMat[1][1] * p0.vtY) + vMZY; q1.vtX = (vMat[0][0] * p1.vtX) + (vMat[0][1] * p1.vtY) + vMZX; q1.vtY = (vMat[1][0] * p1.vtX) + (vMat[1][1] * p1.vtY) + vMZY; switch(intMod) { case WLZ_PROJECT_INT_MODE_NONE: { WlzIVertex2 u0, u1; WLZ_VTX_2_NINT(u0, q0); WLZ_VTX_2_NINT(u1, q1); WlzProjectObjLine((WlzUByte **)(prjAry[thrId]), u0, u1); } break; case WLZ_PROJECT_INT_MODE_DOMAIN: { int np, nq; WlzDVertex3 dq; WlzIVertex2 u0, u1; WLZ_VTX_2_NINT(u0, q0); WLZ_VTX_2_NINT(u1, q1); WLZ_VTX_2_SUB(dq, q0, q1); np = denDom * (iWSp.rgtpos - iWSp.lftpos + 1); nq = (int )ceil(WLZ_VTX_2_LENGTH(dq) + eps); WlzProjectObjLineDom((int **)(prjAry[thrId]), np / nq, u0, u1); } break; case WLZ_PROJECT_INT_MODE_VALUES: if(itvVal) { WlzProjectObjLineVal((int **)(prjAry[thrId]), denVal, gWSp.u_grintptr.ubp, NULL, vMat, vMZX, vMZY, p0, p1); } else { WlzProjectObjLineVal((int **)(prjAry[thrId]), denVal, NULL, gVWSp[thrId], vMat, vMZX, vMZY, p0, p1); } break; } } } (void )WlzEndGreyScan(&iWSp, &gWSp); if(errNum2 == WLZ_ERR_EOO) { errNum2 = WLZ_ERR_NONE; } } (void )WlzFreeObj(obj2); if(errNum2 != WLZ_ERR_NONE) { #ifdef _OPENMP #pragma omp critical { #endif if(errNum == WLZ_ERR_NONE) { errNum = errNum2; } #ifdef _OPENMP } #endif } } } } /* Free grey value workspaces if they were created. */ if(gVWSp) { int idB; for(idB = 0; idB < nThr; ++idB) { WlzGreyValueFreeWSp(gVWSp[idB]); } AlcFree(gVWSp); } if(errNum == WLZ_ERR_NONE) { int idB; size_t idC, bufSz; WlzGreyP buf0, buf1; WlzIVertex2 prjOrg; prjOrg.vtX = prjBox.xMin; prjOrg.vtY = prjBox.yMin; bufSz = prjSz.vtX * prjSz.vtY; for(idB = 1; idB < nThr; ++idB) { if(intMod == WLZ_PROJECT_INT_MODE_NONE) { buf0.ubp = ((WlzUByte ***)(prjAry))[0][0], buf1.ubp = ((WlzUByte ***)(prjAry))[idB][0]; for(idC = 0; idC < bufSz; ++idC) { buf0.ubp[idC] += buf1.ubp[idC]; } } else { buf0.inp = ((int ***)(prjAry))[0][0], buf1.inp = ((int ***)(prjAry))[idB][0]; for(idC = 0; idC < bufSz; ++idC) { buf0.inp[idC] += buf1.inp[idC]; } } } switch(intMod != WLZ_PROJECT_INT_MODE_NONE) { buf0.inp = ((int ***)(prjAry))[0][0]; for(idC = 0; idC < bufSz; ++idC) { buf0.inp[idC] /= 256; } } if(intMod == WLZ_PROJECT_INT_MODE_NONE) { bufObj = WlzAssignObject( WlzFromArray2D((void **)(prjAry[0]), prjSz, prjOrg, WLZ_GREY_UBYTE, WLZ_GREY_UBYTE, 0.0, 1.0, 1, 0, &errNum), NULL); } else { bufObj = WlzAssignObject( WlzFromArray2D((void **)(prjAry[0]), prjSz, prjOrg, WLZ_GREY_INT, WLZ_GREY_INT, 0.0, 1.0, 1, 0, &errNum), NULL); } } /* Free the projection array(s). */ if(prjAry) { int idB; for(idB = 0; idB < nThr; ++idB) { (void )Alc2Free((prjAry[idB])); } AlcFree(prjAry); } /* Make return object using threshold. */ if(errNum == WLZ_ERR_NONE) { WlzPixelV tV; WlzObject *tObj = NULL; tV.type = WLZ_GREY_UBYTE; tV.v.ubv = 1; tObj = WlzAssignObject( WlzThreshold(bufObj, tV, WLZ_THRESH_HIGH, &errNum), NULL); if(tObj) { if(intMod == WLZ_PROJECT_INT_MODE_NONE) { prjObj = WlzMakeMain(tObj->type, tObj->domain, nullVal, NULL, NULL, &errNum); } else { prjObj = WlzMakeMain(tObj->type, tObj->domain, tObj->values, NULL, NULL, &errNum); } } (void )WlzFreeObj(tObj); } (void )WlzFreeObj(bufObj); (void )WlzFree3DViewStruct(vStr1); /* Scale image. */ if(rescaleTr != NULL) { if(errNum == WLZ_ERR_NONE) { WlzObject *tObj = NULL; tObj = WlzAffineTransformObj(prjObj, rescaleTr, WLZ_INTERPOLATION_NEAREST, &errNum); (void )WlzFreeObj(prjObj); prjObj = tObj; } (void )WlzFreeAffineTransform(rescaleTr); } #ifdef WLZ_DEBUG_PROJECT3D_TIME gettimeofday(times + 1, NULL); ALC_TIMERSUB(times + 1, times + 0, times + 2); (void )fprintf(stderr, "WlzGetProjectionFromObject: Elapsed time = %g\n", times[2].tv_sec + (0.000001 * times[2].tv_usec)); #endif /* WLZ_DEBUG_PROJECT3D_TIME */ if(dstErr) { *dstErr = errNum; } return(prjObj); }