/*! * \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 Woolz error code. * \ingroup WlzBinaryOps * \brief For each value in the given 2D distance object the count in * the given distance histogram (array) is incremented. The * distance if clipped to the range [0-maxDist]. * \param maxDist Maximum distance value. * \param dHist Distance histogram (array). * \param dObj Given 2D distance object. */ static WlzErrorNum WlzRCCCompDistHist2D( int maxDist, int *dHist, WlzObject *dObj) { WlzGreyWSpace gWSp; WlzIntervalWSpace iWSp; WlzErrorNum errNum = WLZ_ERR_NONE; errNum = WlzInitGreyScan(dObj, &iWSp, &gWSp); if(errNum == WLZ_ERR_NONE) { while((errNum = WlzNextGreyInterval(&iWSp)) == WLZ_ERR_NONE) { int i; int *p; p = gWSp.u_grintptr.inp; for(i = iWSp.lftpos; i <= iWSp.rgtpos; ++i) { int d; d = *p++; d = WLZ_CLAMP(d, 0, maxDist); ++(dHist[d]); } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } } return(errNum); }
/*! * \return Woolz error code. * \ingroup WlzValueUtils * \brief Sets a portion of a value array using the iven 2D domain * object. * \param ary Current pointer within the array. * \param obj Given object which must be a valid 2D * domain object with integer values. * \param pln The plane coordinate. Not used for * 2D. * \param dim The dimension of the object that the * array is being filled from (2 or 3). */ static WlzErrorNum WlzCompDispSetAry(int **ary, WlzObject *obj, int pln, int dim) { int idV, iWidth; int *valP; WlzIntervalWSpace iWSp; WlzGreyWSpace gWSp; WlzErrorNum errNum = WLZ_ERR_NONE; errNum = WlzInitGreyScan(obj, &iWSp, &gWSp); if(errNum == WLZ_ERR_NONE) { while((errNum = WlzNextGreyInterval(&iWSp)) == WLZ_ERR_NONE) { valP = gWSp.u_grintptr.inp; iWidth = iWSp.rgtpos - iWSp.lftpos + 1; for(idV = 0; idV < iWidth; ++idV) { *(*ary)++ = *valP++; *(*ary)++ = iWSp.colpos + idV; *(*ary)++ = iWSp.linpos; if(dim == 3) { *(*ary)++ = pln; } } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } } return(errNum); }
/*! * \ingroup WlzValuesUtils * \brief Convert a RGBA image to a compound object. The RGBA * channels are at array indices 0,1,2,3 respectively * and the sub-object grey types will be WLZ_GREY_UBYTE. * * \return Compound array of rgba values * \param obj Input domain object with value type * WLZ_GREY_RGBA * \param colSpc The colour space. * \param dstErr Destination error ponyer, may be NULL. */ WlzCompoundArray *WlzRGBAToCompound( WlzObject *obj, WlzRGBAColorSpace colSpc, WlzErrorNum *dstErr) { WlzCompoundArray *cobj=NULL; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object type, and value type */ if( obj ){ 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( WlzGreyTypeFromObj(obj, &errNum) != WLZ_GREY_RGBA ){ errNum = WLZ_ERR_VALUES_TYPE; } break; case WLZ_3D_DOMAINOBJ: if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if( obj->domain.p->type != WLZ_PLANEDOMAIN_DOMAIN ){ errNum = WLZ_ERR_DOMAIN_TYPE; } else if ( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( obj->values.vox->type != WLZ_VOXELVALUETABLE_GREY ){ errNum = WLZ_ERR_VALUES_TYPE; } else if( WlzGreyTypeFromObj(obj, &errNum) != WLZ_GREY_RGBA ){ errNum = WLZ_ERR_VALUES_TYPE; } return WlzRGBAToCompound3D(obj, colSpc, dstErr); case WLZ_TRANS_OBJ: /* not difficult, do it later */ errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: /* bit recursive this ! */ errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_EMPTY_OBJ: return (WlzCompoundArray *) WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; } } else { errNum = WLZ_ERR_OBJECT_NULL; } /* check colour space */ if( errNum == WLZ_ERR_NONE ){ switch( colSpc ){ case WLZ_RGBA_SPACE_RGB: case WLZ_RGBA_SPACE_HSB: case WLZ_RGBA_SPACE_CMY: break; default: errNum = WLZ_ERR_PARAM_DATA; break; } } /* create compound object return */ if( errNum == WLZ_ERR_NONE ){ WlzValues values; WlzObject *objs[4]; WlzObjectType type; WlzPixelV oldBck, newBck; type = WlzGreyTableType( WlzGreyTableTypeToTableType(obj->values.core->type, &errNum), WLZ_GREY_UBYTE, &errNum); oldBck = WlzGetBackground(obj, &errNum); /* red */ newBck.type = WLZ_GREY_UBYTE; newBck.v.ubv = (WlzUByte )WLZ_RGBA_RED_GET(oldBck.v.rgbv); values.v = WlzNewValueTb(obj, type, newBck, &errNum); objs[0] = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); /* green */ newBck.v.ubv = (WlzUByte )WLZ_RGBA_GREEN_GET(oldBck.v.rgbv); values.v = WlzNewValueTb(obj, type, newBck, &errNum); objs[1] = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); /* blue */ newBck.v.ubv = (WlzUByte )WLZ_RGBA_BLUE_GET(oldBck.v.rgbv); values.v = WlzNewValueTb(obj, type, newBck, &errNum); objs[2] = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); /* alpha */ newBck.v.ubv = (WlzUByte )WLZ_RGBA_ALPHA_GET(oldBck.v.rgbv); values.v = WlzNewValueTb(obj, type, newBck, &errNum); objs[3] = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); /* create compound object, object pointers are assigned for mode=3 so no need to free objects */ cobj = WlzMakeCompoundArray(WLZ_COMPOUND_ARR_1, 3, 4, &(objs[0]), obj->type, &errNum); } /* iterate through objects setting values */ if( errNum == WLZ_ERR_NONE ){ WlzIntervalWSpace iwsp0, iwsp[4]; WlzGreyWSpace gwsp0, gwsp[4]; int i, j, k; int a, col[3]; errNum = WlzInitGreyScan(obj, &iwsp0, &gwsp0); for(i=0; i < 4; i++){ errNum = WlzInitGreyScan(cobj->o[i], &(iwsp[i]), &(gwsp[i])); } while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp0)) == WLZ_ERR_NONE)){ for(i=0; i < 4; i++){ errNum = WlzNextGreyInterval(&(iwsp[i])); } switch( colSpc ){ case WLZ_RGBA_SPACE_RGB: for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++, gwsp0.u_grintptr.rgbp++){ *(gwsp[0].u_grintptr.ubp++) = (WlzUByte )WLZ_RGBA_RED_GET(*(gwsp0.u_grintptr.rgbp)); *(gwsp[1].u_grintptr.ubp++) = (WlzUByte )WLZ_RGBA_GREEN_GET(*(gwsp0.u_grintptr.rgbp)); *(gwsp[2].u_grintptr.ubp++) = (WlzUByte )WLZ_RGBA_BLUE_GET(*(gwsp0.u_grintptr.rgbp)); *(gwsp[3].u_grintptr.ubp++) = (WlzUByte )WLZ_RGBA_ALPHA_GET(*(gwsp0.u_grintptr.rgbp)); } break; case WLZ_RGBA_SPACE_HSB: /* each normalised to [0,255] */ for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++, gwsp0.u_grintptr.rgbp++){ col[0] = WLZ_RGBA_RED_GET(*(gwsp0.u_grintptr.rgbp)); col[1] = WLZ_RGBA_GREEN_GET(*(gwsp0.u_grintptr.rgbp)); col[2] = WLZ_RGBA_BLUE_GET(*(gwsp0.u_grintptr.rgbp)); a = WLZ_RGBA_ALPHA_GET(*(gwsp0.u_grintptr.rgbp)); WlzRGBAConvertRGBToHSV_UBYTENormalised(col); *(gwsp[0].u_grintptr.ubp++) = (WlzUByte )(col[0]); *(gwsp[1].u_grintptr.ubp++) = (WlzUByte )(col[1]); *(gwsp[2].u_grintptr.ubp++) = (WlzUByte )(col[2]); *(gwsp[3].u_grintptr.ubp++) = (WlzUByte )a; } break; case WLZ_RGBA_SPACE_CMY: for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++, gwsp0.u_grintptr.rgbp++){ col[0] = WLZ_RGBA_RED_GET(*(gwsp0.u_grintptr.rgbp)); col[1] = WLZ_RGBA_GREEN_GET(*(gwsp0.u_grintptr.rgbp)); col[2] = WLZ_RGBA_BLUE_GET(*(gwsp0.u_grintptr.rgbp)); a = WLZ_RGBA_ALPHA_GET(*(gwsp0.u_grintptr.rgbp)); *(gwsp[0].u_grintptr.ubp++) = (WlzUByte )((col[1] + col[2]) / 2); *(gwsp[1].u_grintptr.ubp++) = (WlzUByte )((col[2] + col[0]) / 2); *(gwsp[2].u_grintptr.ubp++) = (WlzUByte )((col[0] + col[1]) / 2); *(gwsp[3].u_grintptr.ubp++) = (WlzUByte )a; } break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } } if( dstErr ){ *dstErr = errNum; } return cobj; }
double WlzMixtureValue( WlzObject *obj1, WlzObject *obj2, int numCatRows, int numCatCols, double **mixing, double **contrib, WlzErrorNum *dstErr) { double val, con; WlzObject *tmpObj, *tmpObj1, *tmpObj2; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyP gptr; WlzGreyValueWSpace *gVWSp; WlzPixelV minP, maxP; int i; WlzErrorNum errNum=WLZ_ERR_NONE; /* objects must be same type with grey-values */ if( (obj1 == NULL) || (obj2 == NULL) ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( obj1->type ){ case WLZ_2D_DOMAINOBJ: if( obj2->type != obj1->type ){ errNum = WLZ_ERR_OBJECT_TYPE; } else { if((obj1->values.core == NULL) || (obj2->values.core == NULL)){ errNum = WLZ_ERR_VALUES_NULL; } else { /* convert to int and check range */ if((tmpObj1 = WlzConvertPix(obj1, WLZ_GREY_INT, &errNum)) != NULL){ errNum = WlzGreyRange(tmpObj1, &minP, &maxP); if( errNum == WLZ_ERR_NONE ){ if((minP.v.inv < 1) || (minP.v.inv > numCatRows) || (maxP.v.inv < 1) || (maxP.v.inv > numCatRows)){ errNum = WLZ_ERR_OBJECT_DATA; WlzFreeObj(tmpObj1); } } else { WlzFreeObj(tmpObj1); } } if((errNum == WLZ_ERR_NONE) && (tmpObj2 = WlzConvertPix(obj2, WLZ_GREY_INT, &errNum)) ){ errNum = WlzGreyRange(tmpObj2, &minP, &maxP); if( errNum == WLZ_ERR_NONE ){ if((minP.v.inv < 1) || (minP.v.inv > numCatCols) || (maxP.v.inv < 1) || (maxP.v.inv > numCatCols)){ errNum = WLZ_ERR_OBJECT_DATA; WlzFreeObj(tmpObj1); WlzFreeObj(tmpObj2); } } else { WlzFreeObj(tmpObj1); WlzFreeObj(tmpObj2); } } } } break; case WLZ_3D_DOMAINOBJ: default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* get the intersection region */ if( errNum == WLZ_ERR_NONE ){ if((tmpObj = WlzIntersect2(tmpObj1, tmpObj2, &errNum)) != NULL){ tmpObj->values = WlzAssignValues(tmpObj1->values, &errNum); } else { WlzFreeObj(tmpObj1); WlzFreeObj(tmpObj2); } } /* now calculate the mixture value */ if( errNum == WLZ_ERR_NONE ){ errNum = WlzInitGreyScan(tmpObj, &iwsp, &gwsp); gVWSp = WlzGreyValueMakeWSp(tmpObj2, &errNum); val = 0.0; con = 0.0; while((errNum == WLZ_ERR_NONE) && (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE ){ gptr = gwsp.u_grintptr; for (i=0; i<iwsp.colrmn; i++, gptr.inp++){ WlzGreyValueGet(gVWSp, 0, iwsp.linpos, iwsp.colpos+i); val += mixing[(*gptr.inp)-1][gVWSp->gVal[0].inv-1]; con += contrib[(*gptr.inp)-1][gVWSp->gVal[0].inv-1]; } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzGreyValueFreeWSp(gVWSp); WlzFreeObj(tmpObj); WlzFreeObj(tmpObj1); WlzFreeObj(tmpObj2); } if( dstErr ){ *dstErr = errNum; } if( con > 0.0 ){ return val/con; } else { return 0.0; } }
/*! * \return WlzErrorNum. * \ingroup WlzTransform * \brief Outputs displacements to a file in VTK format. * \param outFile VTK format file. * \param objX X displacement object. * \param objY Y displacement object. */ static WlzErrorNum WlzDisplacementsToVtk(FILE *outFile, WlzObject *objX, WlzObject *objY) { WlzIntervalWSpace iWspX, iWspY; WlzGreyWSpace gWspX, gWspY; WlzGreyP gPixX, gPixY; WlzErrorNum errNum = WLZ_ERR_NONE; int numpoints, k, l; float m; /* initialise workspaces */ if ((errNum = WlzInitGreyScan(objX, &iWspX, &gWspX)) == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(objY, &iWspY, &gWspY); } /* Calculate number of points */ if (errNum == WLZ_ERR_NONE) { numpoints = 0; while((errNum = WlzNextGreyInterval(&iWspX)) == WLZ_ERR_NONE) { for (k = iWspX.lftpos; k <= iWspX.rgtpos; k++) { numpoints++; } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } } if (errNum == WLZ_ERR_NONE) { fprintf(outFile, "# vtk DataFile Version 4.0\n"); fprintf(outFile, "Displacements of an MAPaint mapping\n"); fprintf(outFile, "ASCII\n"); fprintf(outFile, "DATASET POLYDATA\n"); fprintf(outFile, "%s %d %s\n","POINTS",numpoints," float"); } /* now output pixel locations */ if (errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(objX, &iWspX, &gWspX); } if (errNum == WLZ_ERR_NONE) { while((errNum = WlzNextGreyInterval(&iWspX)) == WLZ_ERR_NONE) { l = iWspX.linpos; for (k = iWspX.lftpos; k <= iWspX.rgtpos; k++) { fprintf(outFile, "%lf %lf 0.0\n", (float)k, (float)l); } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } } /* output displacement vectors */ if (errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(objX, &iWspX, &gWspX); } if (errNum == WLZ_ERR_NONE) { fprintf(outFile, "%s %d\n","POINT_DATA", numpoints); fprintf(outFile, "%s %s %s\n","VECTORS","vectors", "float" ); while(((errNum = WlzNextGreyInterval(&iWspX)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iWspY)) == WLZ_ERR_NONE)) { gPixX = gWspX.u_grintptr; gPixY = gWspY.u_grintptr; l = iWspX.linpos; for (k = iWspX.lftpos; k <= iWspX.rgtpos; k++) { fprintf(outFile, "%lf %lf 0.0\n", *(gPixX.flp), *(gPixY.flp)); ++(gPixX.flp); ++(gPixY.flp); } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } } /* output scalars */ if (errNum == WLZ_ERR_NONE) { if ((errNum = WlzInitGreyScan(objX, &iWspX, &gWspX)) == WLZ_ERR_NONE) errNum = WlzInitGreyScan(objY, &iWspY, &gWspY); } if (errNum == WLZ_ERR_NONE) { fprintf(outFile, "%s %s %s\n","SCALARS","scalars", "float" ); fprintf(outFile, "%s %s\n","LOOKUP_TABLE","default"); while(((errNum = WlzNextGreyInterval(&iWspX)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iWspY)) == WLZ_ERR_NONE)) { gPixX = gWspX.u_grintptr; gPixY = gWspY.u_grintptr; l = iWspX.linpos; for (k = iWspX.lftpos; k <= iWspX.rgtpos; k++) { m = sqrt(pow(*(gPixX.flp),2) + pow(*(gPixY.flp),2)); fprintf(outFile, "%lf\n", m); ++(gPixX.flp); ++(gPixY.flp); } } } if(errNum == WLZ_ERR_EOO) { 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 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 WlzExtFF * \brief Writes the given object to a jpeg image. * \param fP Given file stream. * \param obj Given object to be written. * \param params Jpeg parameters string, currently this * is a single ascii integer, which should * have the range 1 - 100 and rpresents * the image quality with 100 being * lossless. */ WlzErrorNum WlzEffWriteObjJpeg( FILE *fP, WlzObject *obj, char *params) { WlzErrorNum errNum=WLZ_ERR_NONE; struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; JSAMPARRAY buffer = NULL; /* Output row buffer */ int quality = 100; /* Output quality. */ int row_stride; /* physical row width in input buffer */ int width, height; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; int i, j; WlzObject *rectObj=NULL; WlzGreyType gType = WLZ_GREY_ERROR; /* check input */ if( fP == NULL ){ errNum = WLZ_ERR_PARAM_NULL; } if( obj ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.core ){ if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else { WlzIBox2 cutBox; cutBox.xMin = obj->domain.i->kol1; cutBox.yMin = obj->domain.i->line1; cutBox.xMax = obj->domain.i->lastkl; cutBox.yMax = obj->domain.i->lastln; gType = WlzGreyTypeFromObj(obj, &errNum); if((rectObj = WlzCutObjToBox2D(obj, cutBox, gType, 0, 0.0, 0.0, &errNum)) != NULL){ width = rectObj->domain.i->lastkl - rectObj->domain.i->kol1 + 1; height = rectObj->domain.i->lastln - rectObj->domain.i->line1 + 1; } } } else { errNum = WLZ_ERR_DOMAIN_NULL; } break; case WLZ_TRANS_OBJ: errNum = WlzEffWriteObjJpeg(fP, obj->values.obj, params); break; case WLZ_EMPTY_OBJ: return WLZ_ERR_NONE; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } else { errNum = WLZ_ERR_OBJECT_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_compress(&cinfo); if( rectObj ){ WlzFreeObj(rectObj); } errNum = WLZ_ERR_WRITE_INCOMPLETE; } } if( errNum == WLZ_ERR_NONE ){ jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, fP); /* set the image parameters */ width = obj->domain.i->lastkl - obj->domain.i->kol1 + 1; height = obj->domain.i->lastln - obj->domain.i->line1 + 1; cinfo.image_width = width; cinfo.image_height = height; switch( gType ){ case WLZ_GREY_INT: case WLZ_GREY_SHORT: case WLZ_GREY_FLOAT: case WLZ_GREY_DOUBLE: errNum = WLZ_ERR_UNIMPLEMENTED; break; case WLZ_GREY_UBYTE: cinfo.input_components = 1; cinfo.in_color_space = JCS_GRAYSCALE; break; case WLZ_GREY_RGBA: cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; break; default: break; } if( errNum == WLZ_ERR_NONE ){ /* set the default parameters */ jpeg_set_defaults(&cinfo); /* check for other parameters */ if( params ){ sscanf(params, "%d", &quality); } jpeg_set_quality(&cinfo, quality, TRUE); /* JSAMPLEs per row in output buffer */ row_stride = cinfo.image_width * cinfo.input_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); } else { jpeg_destroy_compress(&cinfo); if( rectObj ){ WlzFreeObj(rectObj); } } } if( errNum == WLZ_ERR_NONE ){ jpeg_start_compress(&cinfo, TRUE); /* loop through the woolz object setting the output buffer note this is the "input" to the compressor */ if((errNum = WlzInitGreyScan(rectObj, &iwsp, &gwsp)) == WLZ_ERR_NONE){ while((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE){ WlzUInt val; switch( gType ){ case WLZ_GREY_UBYTE: for(i=0, j=0; i < width; i++){ buffer[0][j++] = gwsp.u_grintptr.ubp[i]; } break; case WLZ_GREY_RGBA: for(i=0, j=0; i < width; i++){ val = gwsp.u_grintptr.rgbp[i]; buffer[0][j++] = WLZ_RGBA_RED_GET(val); buffer[0][j++] = WLZ_RGBA_GREEN_GET(val); buffer[0][j++] = WLZ_RGBA_BLUE_GET(val); } break; default: break; } (void) jpeg_write_scanlines(&cinfo, buffer, 1); } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); WlzFreeObj(rectObj); } 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); }
/*! * \ingroup WlzValuesUtils * \brief Set the value maskVal within the domain given by the * mask object. The mask object can be a 2D, 3D, polygon * or boundary object. A 3D mask with a 2D object is an * error. A 2D mask with a 3D object will be applied to * each plane in turn. * * \return New object with the same domain as the input object but with values in the intersection with the mask domain set to the mask value. NULL on error. * \param obj Input object * \param mask Mask object. * \param maskVal mask value. * \param dstErr Error return. * \par Source: * WlzGreyMask.c */ WlzObject *WlzGreyMask( WlzObject *obj, WlzObject *mask, WlzPixelV maskVal, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzObject *tmpMask, *obj1; WlzValues values; WlzPixelV tmpMaskval; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyP gptr; int i; WlzErrorNum errNum=WLZ_ERR_NONE; /* check obj */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } break; case WLZ_3D_DOMAINOBJ: return WlzGreyMask3d(obj, mask, maskVal, dstErr); case WLZ_TRANS_OBJ: if((values.obj = WlzGreyMask(obj->values.obj, mask, maskVal, &errNum)) != NULL){ return WlzMakeMain(WLZ_TRANS_OBJ, obj->domain, values, NULL, NULL, dstErr); } break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* check the mask */ if( errNum == WLZ_ERR_NONE ){ if( mask == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { values.core = NULL; switch( mask->type ){ case WLZ_2D_DOMAINOBJ: tmpMask = WlzMakeMain(WLZ_2D_DOMAINOBJ, mask->domain, values, NULL, NULL, &errNum); break; case WLZ_TRANS_OBJ: tmpMask = WlzMakeMain(WLZ_2D_DOMAINOBJ, mask->values.obj->domain, values, NULL, NULL, &errNum); break; case WLZ_EMPTY_OBJ: return WlzMakeMain(WLZ_2D_DOMAINOBJ, obj->domain, obj->values, NULL, NULL, dstErr); case WLZ_2D_POLYGON: tmpMask = WlzPolyToObj(mask->domain.poly, WLZ_SIMPLE_FILL, &errNum); break; case WLZ_BOUNDLIST: tmpMask = WlzBoundToObj(mask->domain.b, WLZ_SIMPLE_FILL, &errNum); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } if( errNum == WLZ_ERR_NONE ){ tmpMask = WlzAssignObject(tmpMask, NULL); } } } /* copy input obj and setvalues in the intersection */ if(errNum == WLZ_ERR_NONE){ if((rtnObj = WlzNewGrey(obj, &errNum)) != NULL){ if((obj1 = WlzIntersect2(obj, tmpMask, &errNum)) != NULL){ obj1->values = WlzAssignValues(rtnObj->values, NULL); errNum = WlzInitGreyScan(obj1, &iwsp, &gwsp); WlzValueConvertPixel(&tmpMaskval, maskVal, gwsp.pixeltype); 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++){ *gptr.inp = tmpMaskval.v.inv; } break; case WLZ_GREY_SHORT: for(i=0; i<iwsp.colrmn; i++, gptr.shp++){ *gptr.shp = tmpMaskval.v.shv; } break; case WLZ_GREY_UBYTE: for(i=0; i<iwsp.colrmn; i++, gptr.ubp++){ *gptr.ubp = tmpMaskval.v.ubv; } break; case WLZ_GREY_FLOAT: for(i=0; i<iwsp.colrmn; i++, gptr.flp++){ *gptr.flp = tmpMaskval.v.flv; } break; case WLZ_GREY_DOUBLE: for(i=0; i<iwsp.colrmn; i++, gptr.dbp++){ *gptr.dbp = tmpMaskval.v.dbv; } break; case WLZ_GREY_RGBA: for(i=0; i<iwsp.colrmn; i++, gptr.rgbp++){ *gptr.rgbp = tmpMaskval.v.rgbv; } break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzFreeObj(obj1); } else { WlzFreeObj(rtnObj); rtnObj = NULL; } } WlzFreeObj(tmpMask); } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \ingroup WlzValuesUtils * \brief Calculate the modulus of the grey-level gradient at each point. The gradient images are calculated using WlzGauss2() with width parameter set to <tt>width</tt>. Will now calculate the modulus for each object of a compound object if appropriate. * * \return Object with values set to the gradient modulus at each pixel. * \param obj Input object. * \param width Width parameter for the gaussian gradient operator. * \param dstErr Error return. * \par Source: * WlzGreyModGradient.c */ WlzObject *WlzGreyModGradient( WlzObject *obj, double width, WlzErrorNum *dstErr) { WlzObject *xobj, *yobj, *returnobj=NULL; WlzIntervalWSpace iwsp1, iwsp2, iwsp3; WlzGreyWSpace gwsp1, gwsp2, gwsp3; WlzCompoundArray *cobj1, *cobj2; int i; double g1, g2, g3; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object */ if( obj ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.core ){ switch( obj->domain.core->type ){ case WLZ_EMPTY_DOMAIN: returnobj = WlzMakeEmpty(&errNum); break; default: if( obj->values.core ){ if( (obj->values.core->type == WLZ_EMPTY_VALUES) || WlzGreyTableIsTiled(obj->values.core->type) ){ errNum = WLZ_ERR_VALUES_TYPE; } } else { errNum = WLZ_ERR_VALUES_NULL; } break; } } else { errNum = WLZ_ERR_DOMAIN_NULL; } /* one last check for rgb values */ if(WlzGreyTableTypeToGreyType(obj->values.core->type, NULL) == WLZ_GREY_RGBA){ return WlzRGBAModGradient(obj, width, dstErr); } break; case WLZ_EMPTY_OBJ: returnobj = WlzMakeEmpty(&errNum); break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: cobj1 = (WlzCompoundArray *) obj; if((cobj2 = WlzMakeCompoundArray(cobj1->type, 1, cobj1->n, NULL, cobj1->otype, &errNum)) != NULL){ /* transform each object, ignore type errors */ for(i=0; i < cobj1->n; i++){ cobj2->o[i] = WlzAssignObject(WlzGreyModGradient(cobj1->o[i], width, &errNum), NULL); } return (WlzObject *) cobj2; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } else { errNum = WLZ_ERR_OBJECT_NULL; } /* if WlzUByte grey values then copy to int */ if( (errNum == WLZ_ERR_NONE) && !returnobj ){ if(WlzGreyTableTypeToGreyType(obj->values.core->type, NULL) == WLZ_GREY_UBYTE) { returnobj = WlzConvertPix(obj, WLZ_GREY_INT, NULL); } else { returnobj = WlzMakeMain(WLZ_2D_DOMAINOBJ, obj->domain, WlzCopyValues(obj->type, obj->values, obj->domain, &errNum), NULL, NULL, NULL); } /* calculate gradient images */ xobj = WlzGauss2(returnobj, width, width, 1, 0, NULL); yobj = WlzGauss2(returnobj, width, width, 0, 1, NULL); /* calculate modulus - lockstep raster scan assumes equal domains */ errNum = WlzInitGreyScan(returnobj, &iwsp1, &gwsp1); errNum = WlzInitGreyScan(xobj, &iwsp2, &gwsp2); errNum = WlzInitGreyScan(yobj, &iwsp3, &gwsp3); while((errNum == WLZ_ERR_NONE) && (WlzNextGreyInterval(&iwsp1) == WLZ_ERR_NONE) ) { (void) WlzNextGreyInterval(&iwsp2); (void) WlzNextGreyInterval(&iwsp3); switch( gwsp1.pixeltype ) { default: case WLZ_GREY_INT: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.inp++; g3 = *gwsp3.u_grintptr.inp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.inp++ = (int) g1; } break; case WLZ_GREY_SHORT: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.shp++; g3 = *gwsp3.u_grintptr.shp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.shp++ = (short) g1; } break; case WLZ_GREY_UBYTE: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.ubp++; g3 = *gwsp3.u_grintptr.ubp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.ubp++ = (WlzUByte) g1; } break; case WLZ_GREY_FLOAT: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.flp++; g3 = *gwsp3.u_grintptr.flp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.flp++ = (float) g1; } break; case WLZ_GREY_DOUBLE: for(i=0; i < iwsp1.colrmn; i++) { g2 = *gwsp2.u_grintptr.dbp++; g3 = *gwsp3.u_grintptr.dbp++; g1 = sqrt( g2*g2 + g3*g3 ); *gwsp1.u_grintptr.dbp++ = (double) g1; } break; case WLZ_GREY_RGBA: /* RGBA to be done - should not get here */ errNum = WLZ_ERR_GREY_TYPE; break; } } /* check for normal return */ if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } /* clean up */ WlzFreeObj( xobj ); WlzFreeObj( yobj ); } /* check error return */ if( dstErr ){ *dstErr = errNum; } return( returnobj ); }
/*! * \ingroup WlzValuesUtils * \brief * * \return New object with the same domain <tt>tmpl</tt> but values in the intersection with <tt>obj</tt> set to those of the object. Returns NULL on error. * \param obj Input object to which the template is applied * \param tmpl Template object * \param tmplVal Template value for regions in the template not in the original object * \param dstErr Error return. * \par Source: * WlzGreyTemplate.c */ WlzObject *WlzGreyTemplate( WlzObject *obj, WlzObject *tmpl, WlzPixelV tmplVal, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzObject *obj1, *obj2; WlzValues values; WlzPixelV bckgrnd; WlzObjectType type; WlzGreyType gtype=WLZ_GREY_UBYTE; WlzIntervalWSpace iwsp1, iwsp2; WlzGreyWSpace gwsp1, gwsp2; int size; WlzErrorNum errNum = WLZ_ERR_NONE; /* check obj */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( WlzGreyTableIsTiled(obj->values.core->type) ){ errNum = WLZ_ERR_VALUES_TYPE; } else { bckgrnd = WlzGetBackground(obj, &errNum); } if(errNum == WLZ_ERR_NONE) { gtype = WlzGreyTableTypeToGreyType(obj->values.core->type, NULL); } break; case WLZ_3D_DOMAINOBJ: return WlzGreyTemplate3d(obj, tmpl, tmplVal, dstErr); case WLZ_TRANS_OBJ: if((values.obj = WlzGreyTemplate(obj->values.obj, tmpl, tmplVal, &errNum)) != NULL){ return WlzMakeMain(WLZ_TRANS_OBJ, obj->domain, values, NULL, NULL, dstErr); } break; case WLZ_EMPTY_OBJ: bckgrnd.type = WLZ_GREY_UBYTE; bckgrnd.v.ubv = 0; break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* check the template */ if( errNum == WLZ_ERR_NONE ){ if( tmpl == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { values.core = NULL; switch( tmpl->type ){ case WLZ_2D_DOMAINOBJ: rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, tmpl->domain, values, NULL, NULL, &errNum); break; case WLZ_TRANS_OBJ: rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, tmpl->values.obj->domain, values, NULL, NULL, &errNum); break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); case WLZ_2D_POLYGON: rtnObj = WlzPolyToObj(tmpl->domain.poly, WLZ_SIMPLE_FILL, &errNum); break; case WLZ_BOUNDLIST: rtnObj = WlzBoundToObj(tmpl->domain.b, WLZ_SIMPLE_FILL, &errNum); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } } /* attach a value table to the template and set to the template value, note the background is set to the input object or zero if empty */ if( errNum == WLZ_ERR_NONE ){ type = WlzGreyTableType(WLZ_GREY_TAB_RAGR, gtype, NULL); if((values.v = WlzNewValueTb(rtnObj, type, bckgrnd, &errNum)) != NULL){ rtnObj->values = WlzAssignValues(values, NULL); errNum = WlzGreySetValue(rtnObj, tmplVal); } } /* copy input obj values within the intersection */ if( errNum == WLZ_ERR_NONE ){ if((obj->type != WLZ_EMPTY_OBJ) ){ if( (obj1 = WlzIntersect2(obj, rtnObj, &errNum)) ){ obj1->values = WlzAssignValues(rtnObj->values, NULL); obj2 = WlzMakeMain(obj1->type, obj1->domain, obj->values, NULL, NULL, NULL); errNum = WlzInitGreyScan(obj1, &iwsp1, &gwsp1); errNum = WlzInitGreyScan(obj2, &iwsp2, &gwsp2); switch( gwsp1.pixeltype ){ case WLZ_GREY_INT: size = sizeof(int); break; case WLZ_GREY_SHORT: size = sizeof(short); break; case WLZ_GREY_UBYTE: size = sizeof(WlzUByte); break; case WLZ_GREY_FLOAT: size = sizeof(float); break; case WLZ_GREY_DOUBLE: size = sizeof(double); break; case WLZ_GREY_RGBA: size = sizeof(WlzUInt); break; default: errNum = WLZ_ERR_GREY_TYPE; break; } while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp1)) == WLZ_ERR_NONE)){ (void) WlzNextGreyInterval(&iwsp2); memcpy((void *) gwsp1.u_grintptr.inp, (const void *) gwsp2.u_grintptr.inp, size * iwsp1.colrmn); } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzFreeObj(obj2); WlzFreeObj(obj1); } else { WlzFreeObj(rtnObj); rtnObj = NULL; } } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \ingroup WlzBinaryOps * \brief Calculate the set union of an array of domain objects. Domians only unless uvt non-zero in which case make an average grey table. Note background values are used in the averaging process. All objects must be domain objects of the same type (2D or 3D) unless WLZ_EMPTY_OBJ, NULL input objects are an error. This function may modify the order of the objects in the array it is passed if the array contains empty objects. * * \return Union of the array of object. * \param n number of input objects * \param objs input object array * \param uvt grey-table copy flag, copy if non-zero. * \param dstErr error return. * \par Source: * WlzUnionN.c */ WlzObject *WlzUnionN( int n, WlzObject **objs, int uvt, WlzErrorNum *dstErr) { WlzObject *obj=NULL; WlzDomain domain; WlzValues values; WlzIntervalDomain *idom; WlzInterval *itvl, *jtvl; WlzIntervalWSpace *iwsp; WlzIntervalWSpace *biwsp, *tiwsp, niwsp; WlzGreyWSpace *gwsp, ngwsp; WlzObjectType type; int i, j, k, l; int inttot, numactive, change, lwas, nints, noverlap; WlzPixelV backg; int line1, lastln; int kol1,lastkl; WlzGreyV gv; WlzGreyP greyptr; int **locbuff; int *locbuffs; int span; WlzErrorNum errNum=WLZ_ERR_NONE; /* preliminary stuff - count of non-NULL objects, note WLZ_EMPTY_OBJs are ignored but NULL objects are an error */ if( n < 1 ){ errNum = WLZ_ERR_PARAM_DATA; } else { for (i=0; i<n ; i++ ){ if ( objs[i] == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; break; } if( objs[i]->type == WLZ_EMPTY_OBJ ){ obj = objs[i]; for ( j=i; j<n-1 ; j++ ){ objs[j] = objs[j+1]; } objs[n-1] = obj; n--; i--; } } } /* n has been checked therefore no objects implies all empty */ if( (errNum == WLZ_ERR_NONE) && (n < 1) ){ return WlzMakeEmpty(dstErr); } /* now check they are all of the same type */ if( errNum == WLZ_ERR_NONE ){ for(i=1; i < n; i++){ if( objs[i]->type != objs[0]->type ){ errNum = WLZ_ERR_OBJECT_TYPE; break; } } } /* now test the type note empty objects have been discarded */ if( errNum == WLZ_ERR_NONE ){ switch( objs[0]->type ){ case WLZ_2D_DOMAINOBJ: break; case WLZ_3D_DOMAINOBJ: return WlzUnion3d(n, objs, uvt, dstErr); case WLZ_TRANS_OBJ: default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* now discard empty objects */ if( errNum == WLZ_ERR_NONE ){ for (i=0; i<n ; i++ ){ if( WlzIsEmpty(objs[i], NULL) ){ obj = objs[i]; for ( j=i; j<n-1 ; j++ ){ objs[j] = objs[j+1]; } objs[n-1] = obj; n--; i--; } } } obj = NULL; /* recheck number of objects */ if( (errNum == WLZ_ERR_NONE) && (n < 1) ){ return WlzMakeEmpty(dstErr); } if( (errNum == WLZ_ERR_NONE) && (n == 1) ){ return WlzMakeMain(objs[0]->type, objs[0]->domain, objs[0]->values, NULL, NULL, dstErr); } /* check if grey-value merge is possible */ if( errNum == WLZ_ERR_NONE ){ for (i=0; i<n ; i++ ){ if( objs[i]->values.core == NULL ){ uvt = 0; break; } } } /* * find the line and column bounds of the union. */ if( errNum == WLZ_ERR_NONE ){ line1 = objs[0]->domain.i->line1; lastln = objs[0]->domain.i->lastln; kol1 = objs[0]->domain.i->kol1; lastkl = objs[0]->domain.i->lastkl; for (i=1; i<n; i++) { idom = objs[i]->domain.i; if (line1 > idom->line1) line1 = idom->line1; if (lastln < idom->lastln) lastln = idom->lastln; if (kol1 > idom->kol1) kol1 = idom->kol1; if (lastkl < idom->lastkl) lastkl = idom->lastkl; } span = lastkl - kol1 +1 ; if( (locbuff = (int **) AlcMalloc((n+1)*sizeof(int *))) == NULL ){ errNum = WLZ_ERR_MEM_ALLOC; } } /* space must be allocated for the largest variety of grey-value */ if( errNum == WLZ_ERR_NONE ){ if( (locbuffs = (int *) AlcMalloc(sizeof(double)*span*(n+1))) == NULL ){ AlcFree((void *) locbuff); errNum = WLZ_ERR_MEM_ALLOC; } else { for(i=0; i <= n; i++){ locbuff[i] = locbuffs + i*span; } } } /* * count the individual intervals so that sufficient space * for the union may be allocated. */ if( errNum == WLZ_ERR_NONE ){ inttot=0; for(i=0; i < n; i++){ inttot += WlzIntervalCount(objs[i]->domain.i, &errNum); } } /* * set up domain, value table structures, and object. */ if( errNum == WLZ_ERR_NONE ){ if( (idom = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, line1,lastln,kol1,lastkl, &errNum)) == NULL ){ AlcFree((void *) locbuffs); AlcFree((void *) locbuff); } else if( (itvl = (WlzInterval *) AlcMalloc(inttot * sizeof(WlzInterval))) == NULL){ AlcFree((void *) locbuffs); AlcFree((void *) locbuff); WlzFreeIntervalDomain(idom); errNum = WLZ_ERR_MEM_ALLOC; } else { idom->freeptr = AlcFreeStackPush(idom->freeptr, (void *)itvl, NULL); lwas = line1; jtvl = itvl; nints = 0; domain.i = idom; values.v = NULL; if( (obj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain, values, NULL, NULL, &errNum)) == NULL ){ WlzFreeIntervalDomain( idom ); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); return(NULL); } } } /* * allocate space for workspaces */ if( errNum == WLZ_ERR_NONE ){ if( (iwsp = (WlzIntervalWSpace *) AlcMalloc (n * sizeof (WlzIntervalWSpace))) == NULL ){ WlzFreeObj( obj ); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); errNum = WLZ_ERR_MEM_ALLOC; obj = NULL; } else { biwsp = iwsp; tiwsp = iwsp + n; } } /* * Construct the union object's table of intervals. * Initialise scanning on each object/workspace combination. * Scan synchronously, setting up the union of adjacent and * overlapping intervals. Needs a clear head !! */ if( errNum == WLZ_ERR_NONE ){ for (i=0; i<n; i++) { WlzInitRasterScan(objs[i], iwsp, WLZ_RASTERDIR_ILIC); WlzNextInterval(iwsp++); } numactive = n; /* * find next line and left hand end of next interval of union */ while (numactive > 0) { /* * find first remaining active object */ iwsp = biwsp; while( iwsp->linrmn < 0 ){ iwsp++; } /* * find minimum line number of remaining active intervals */ l = iwsp->linpos; kol1 = iwsp->lftpos; lastkl = iwsp->rgtpos; for (iwsp++; iwsp<tiwsp; iwsp++) if (iwsp->linrmn >= 0 && iwsp->linpos < l) { l = iwsp->linpos; kol1 = iwsp->lftpos; lastkl = iwsp->rgtpos; } /* * find left-most interval in this line */ for (iwsp=biwsp; iwsp<tiwsp; iwsp++) if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos < kol1) { kol1 = iwsp->lftpos; lastkl = iwsp->rgtpos; } /* * construct maximal interval with current left end-point */ do { change = 0; for (iwsp=biwsp; iwsp<tiwsp; iwsp++) { while( iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= lastkl+1 ){ if (iwsp->rgtpos > lastkl) { lastkl = iwsp->rgtpos; change = 1; } if (WlzNextInterval(iwsp) != WLZ_ERR_NONE) { numactive--; } } } } while (change == 1); itvl->ileft = kol1 - idom->kol1; itvl->iright = lastkl - idom->kol1; if (l == lwas) nints++; else { (void) WlzMakeInterval(lwas,idom,nints,jtvl); for (j = lwas+1; j<l; j++) { (void) WlzMakeInterval(j,idom,0,NULL); } lwas = l; nints = 1; jtvl = itvl; } itvl++; } (void) WlzMakeInterval(lwas,idom,nints,jtvl); for (j = lwas+1; j<=lastln; j++) { (void) WlzMakeInterval(j,idom,0,NULL); } } /* now deal with the grey-values if required */ if( (errNum == WLZ_ERR_NONE) && (uvt != 0) ){ WlzGreyType grey_type; if( (gwsp = (WlzGreyWSpace *) AlcMalloc (n * sizeof (WlzGreyWSpace))) == NULL){ WlzFreeObj( obj ); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); AlcFree((void *) biwsp); errNum = WLZ_ERR_MEM_ALLOC; obj = NULL; } /* construct an empty "ragged-rectangle" greytable with appropriate grey-type */ if( errNum == WLZ_ERR_NONE ){ backg = WlzGetBackground(objs[0], NULL); grey_type = WlzGreyTableTypeToGreyType(objs[0]->values.core->type, NULL); type = WlzGreyTableType(WLZ_GREY_TAB_RAGR, grey_type, NULL); if( (values.v = WlzNewValueTb(obj, type, backg, &errNum)) == NULL ){ WlzFreeObj( obj ); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); AlcFree((void *) biwsp); obj = NULL; } else { obj->values = WlzAssignValues(values, NULL); } } /* fill the grey table. Where more than one input objects overlap, take mean of grey values. */ if( errNum == WLZ_ERR_NONE ){ WlzInitGreyScan(obj, &niwsp, &ngwsp); iwsp = biwsp; for (i=0; i<n; i++) { WlzInitGreyScan(objs[i], iwsp, &gwsp[i]); WlzNextGreyInterval(iwsp++); if( gwsp[i].pixeltype != grey_type ){ AlcFree((void *) gwsp); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); AlcFree((void *) biwsp); WlzFreeObj( obj ); obj = NULL; errNum = WLZ_ERR_GREY_TYPE; } } } if( errNum == WLZ_ERR_NONE ){ while (WlzNextGreyInterval(&niwsp) == WLZ_ERR_NONE) { l = niwsp.linpos; greyptr = ngwsp.u_grintptr; switch( ngwsp.pixeltype ){ case WLZ_GREY_INT: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; gv.inv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while (iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.inv += *(gwsp[i].u_grintptr.inp + k - iwsp->lftpos); } } *greyptr.inp = gv.inv / noverlap; greyptr.inp++; } break; case WLZ_GREY_SHORT: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; gv.shv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while (iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.shv += *(gwsp[i].u_grintptr.shp + k - iwsp->lftpos); } } *greyptr.shp = (short )(gv.shv / noverlap); greyptr.shp++; } break; case WLZ_GREY_UBYTE: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; gv.inv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while (iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.inv += *(gwsp[i].u_grintptr.ubp + k - iwsp->lftpos); } } *greyptr.ubp = (WlzUByte )(gv.inv / noverlap); greyptr.ubp++; } break; case WLZ_GREY_FLOAT: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; gv.flv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while (iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.flv += *(gwsp[i].u_grintptr.flp + k - iwsp->lftpos); } } *greyptr.flp = gv.flv / noverlap; greyptr.flp++; } break; case WLZ_GREY_DOUBLE: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; gv.dbv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while (iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.dbv += *(gwsp[i].u_grintptr.dbp + k - iwsp->lftpos); } } *greyptr.dbp = gv.dbv / noverlap; greyptr.dbp++; } break; case WLZ_GREY_RGBA: /* RGBA to be done - do properly RAB */ for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; gv.rgbv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while (iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.rgbv += *(gwsp[i].u_grintptr.rgbp + k - iwsp->lftpos); } } *greyptr.rgbp = gv.rgbv / noverlap; greyptr.rgbp++; } break; default: break; } } } AlcFree((void *) gwsp); } if( errNum == WLZ_ERR_NONE ){ AlcFree( (void *) biwsp); AlcFree( (void *)locbuff ); AlcFree( (void *)locbuffs ); } if( dstErr ){ *dstErr = errNum; } return( obj ); }
/*! * \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 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 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 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 Compound array. * \ingroup WlzTransform * \brief Computes a compound array of three objects, the objects representing the t11, t12 qnd t22 componemts of a tensor. * \param inobj Given object. * \param basisTensorTr Basis Function tensor transform * \param dstErr Destination error pointer, may be * NULL. */ static WlzCompoundArray *WlzBasisFnTensorTransformObjPrv(WlzObject *inObj, WlzBasisFnTransform *basisTr, WlzErrorNum *dstErr) { WlzObject *objT11 = NULL, *objT12 = NULL, *objT22 = NULL; WlzCompoundArray *cArray = NULL; WlzValues valuesT11, valuesT12, valuesT22; WlzIntervalWSpace iWsp, iWspT11, iWspT12, iWspT22; WlzGreyWSpace gWspT11, gWspT12, gWspT22; WlzDVertex2 sVtx; WlzErrorNum errNum=WLZ_ERR_NONE; WlzObjectType vType; WlzGreyP gPixT11, gPixT12, gPixT22; WlzPixelV backgrnd; WlzFnType basisFnType; double t11Partial, t12APartial, t12BPartial, t22Partial; int k, l; valuesT11.core = NULL; valuesT12.core = NULL; valuesT22.core = NULL; basisFnType = basisTr->basisFn->type; /* Create value tables for the two objects */ vType = WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_FLOAT, NULL); backgrnd.type = WLZ_GREY_FLOAT; backgrnd.v.inv = 0; if((valuesT11.v = WlzNewValueTb(inObj, vType, backgrnd, &errNum)) != NULL) { if((valuesT12.v = WlzNewValueTb(inObj, vType, backgrnd, &errNum)) != NULL) { valuesT22.v = WlzNewValueTb(inObj, vType, backgrnd, &errNum); } else { WlzFreeValueTb(valuesT11.v); WlzFreeValueTb(valuesT12.v); } } else { WlzFreeValueTb(valuesT11.v); } /* create three Wlz objects to hold t11, t22 and t12 tensor components */ if (errNum == WLZ_ERR_NONE) { if ((objT11 = WlzMakeMain(inObj->type, inObj->domain, valuesT11, NULL, NULL, &errNum)) != NULL) { if ((objT12 = WlzMakeMain(inObj->type, inObj->domain, valuesT12, NULL, NULL, &errNum)) != NULL) { if ((objT22 = WlzMakeMain(inObj->type, inObj->domain, valuesT22, NULL, NULL, &errNum)) == NULL) { WlzFreeObj(objT11); objT11 = NULL; WlzFreeObj(objT12); objT12 = NULL; } } else { WlzFreeObj(objT11); objT11 = NULL; } } } /* initialise workspaces */ if (errNum == WLZ_ERR_NONE) { if ((errNum = WlzInitRasterScan(inObj, &iWsp, WLZ_RASTERDIR_ILIC)) == WLZ_ERR_NONE) { if ((errNum = WlzInitGreyScan(objT11, &iWspT11, &gWspT11)) == WLZ_ERR_NONE) { if ((errNum = WlzInitGreyScan(objT12, &iWspT12, &gWspT12)) == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(objT22, &iWspT22, &gWspT22); } } } } /* Calculate tensor components for MQ2 only */ if (errNum == WLZ_ERR_NONE) { switch (basisFnType) { case WLZ_FN_BASIS_2DMQ: while(((errNum = WlzNextInterval(&iWsp)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iWspT11)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iWspT12)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iWspT22)) == WLZ_ERR_NONE)) { gPixT11 = gWspT11.u_grintptr; gPixT12 = gWspT12.u_grintptr; gPixT22 = gWspT22.u_grintptr; l = iWsp.linpos; for (k = iWsp.lftpos; k <= iWsp.rgtpos; k++) { sVtx.vtX = k; sVtx.vtY = l; t11Partial = WlzBasisFnValueMQ2DPrv(basisTr->basisFn, sVtx, 0); *(gPixT11.flp) = (float)t11Partial; ++(gPixT11.flp); t22Partial = WlzBasisFnValueMQ2DPrv(basisTr->basisFn, sVtx, 1); *(gPixT22.flp) = (float)t22Partial; ++(gPixT22.flp); t12APartial = WlzBasisFnValueMQ2DPrv(basisTr->basisFn, sVtx, 2); t12BPartial = WlzBasisFnValueMQ2DPrv(basisTr->basisFn, sVtx, 3); *(gPixT12.flp) = 0.5 * ((float)t12APartial + (float)t12BPartial); ++(gPixT12.flp); } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } break; case WLZ_FN_BASIS_2DTPS: while(((errNum = WlzNextInterval(&iWsp)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iWspT11)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iWspT12)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iWspT22)) == WLZ_ERR_NONE)) { gPixT11 = gWspT11.u_grintptr; gPixT12 = gWspT12.u_grintptr; gPixT22 = gWspT22.u_grintptr; l = iWsp.linpos; for (k = iWsp.lftpos; k <= iWsp.rgtpos; k++) { sVtx.vtX = k; sVtx.vtY = l; t11Partial = WlzBasisFnValueTPS2DPrv(basisTr->basisFn, sVtx, 0); *(gPixT11.flp) = (float)t11Partial; ++(gPixT11.flp); t22Partial = WlzBasisFnValueTPS2DPrv(basisTr->basisFn, sVtx, 1); *(gPixT22.flp) = (float)t22Partial; ++(gPixT22.flp); t12APartial = WlzBasisFnValueTPS2DPrv(basisTr->basisFn, sVtx, 2); t12BPartial = WlzBasisFnValueTPS2DPrv(basisTr->basisFn, sVtx, 3); *(gPixT12.flp) = 0.5 * ((float)t12APartial + (float)t12BPartial); ++(gPixT12.flp); } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } break; default: errNum = WLZ_ERR_TRANSFORM_TYPE; break; } } /* create compound object */ if (errNum == WLZ_ERR_NONE) { cArray = WlzMakeCompoundArray(WLZ_COMPOUND_ARR_1, 1, 3, NULL, objT11->type, &errNum); if (errNum == WLZ_ERR_NONE) { cArray->o[0] = WlzAssignObject(objT11, NULL); cArray->o[1] = WlzAssignObject(objT22, NULL); cArray->o[2] = WlzAssignObject(objT12, NULL); } } if(dstErr) { *dstErr = errNum; } return(cArray); }
/*! * \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); }
/*! * \ingroup WlzValuesUtils * \brief Makes a dithered object from the given grey-level Woolz object. The destination bits are determined by the number of shades in the dithered image (usually 1 bit) and the bit planes to use (typically to match the bit-planes of a display mask). * * \return Object with dithered grey values. * \param o Input object. * \param destBits Destination bit planes for dithered values. * \param dstErr Error return. * \par Source: * WlzGreyDitherObj.c */ WlzObject *WlzGreyDitherObj( WlzObject *o, unsigned int destBits, WlzErrorNum *dstErr) { WlzObject *obj=NULL; WlzIntervalWSpace iwsp1, iwsp2; WlzGreyWSpace gwsp1, gwsp2; int i, j, m, g, G; int n_to; int bit_val[8], permute_val[256]; int factor_from, factor_to, mask_start; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object type - 1 only */ if( o == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( o->type ){ case WLZ_2D_DOMAINOBJ: /* check it has a valuetable */ if( o->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( WlzGreyTableIsTiled(o->values.core->type) ){ errNum = WLZ_ERR_VALUES_TYPE; } break; case WLZ_3D_DOMAINOBJ: case WLZ_TRANS_OBJ: errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_EMPTY_OBJ: obj = WlzMakeEmpty(&errNum); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if( !obj && (errNum == WLZ_ERR_NONE) ){ /* count the bits in the mask */ for(i=1, n_to=0; i <= destBits; i <<= 1 ) { if( i & destBits ) n_to++; } /* check numbers of bits */ if( n_to == 0 ){ errNum = WLZ_ERR_PARAM_DATA; } else { /* make a new object with the same domain */ if((obj = WlzNewGrey(o, &errNum)) != NULL){ if( n_to < 8 ){ /* set up some factors */ factor_from = 255; factor_to = (1<<n_to) - 1; mask_start = (1 << (8-n_to)) - 1; /* set up bit permute lut */ for(i=0, j=1, m=destBits; i < n_to; i++) { while( !(m&1) ) { m = m >> 1; j = j << 1; } m = m >> 1; bit_val[i] = j; } for(i=0; i < (1<<n_to); i++) { permute_val[i] = 0; for(j=0, m=1; j < n_to; j++, m = m<<1 ){ permute_val[i] += (i&m) * bit_val[j]; } } for(;i < 256; i++){ permute_val[i] = 0; } /* now scan the objects */ WlzInitGreyScan(o,&iwsp1,&gwsp1); WlzInitGreyScan(obj,&iwsp2,&gwsp2); while((WlzNextGreyInterval(&iwsp1) == WLZ_ERR_NONE) && (WlzNextGreyInterval(&iwsp2) == WLZ_ERR_NONE ) ) { j = iwsp1.linpos; G = rand() & mask_start; switch( gwsp1.pixeltype ) { case WLZ_GREY_INT: for(i=iwsp1.lftpos; i<=iwsp1.rgtpos; i++, gwsp1.u_grintptr.inp++, gwsp2.u_grintptr.inp++ ) { G += (*gwsp1.u_grintptr.inp) & 255; g = (G * factor_to) / factor_from; (*gwsp2.u_grintptr.inp) = permute_val[g]; G -= (g * factor_from) / factor_to; } break; case WLZ_GREY_SHORT: for(i=iwsp1.lftpos; i<=iwsp1.rgtpos; i++, gwsp1.u_grintptr.shp++, gwsp2.u_grintptr.shp++ ) { G += (*gwsp1.u_grintptr.shp) & 255; g = (G * factor_to) / factor_from; (*gwsp2.u_grintptr.shp) = (short )(permute_val[g]); G -= (g * factor_from) / factor_to; } break; case WLZ_GREY_UBYTE: for(i=iwsp1.lftpos; i<=iwsp1.rgtpos; i++, gwsp1.u_grintptr.ubp++, gwsp2.u_grintptr.ubp++ ) { G += (*gwsp1.u_grintptr.ubp); g = (G * factor_to) / factor_from; (*gwsp2.u_grintptr.ubp) = (WlzUByte )(permute_val[g]); G -= (g * factor_from) / factor_to; } break; case WLZ_GREY_RGBA: /* RGBA to be done RAB */ default: errNum = WLZ_ERR_GREY_TYPE; break; } } } } } }
/*! * \ingroup WlzValuesFilters * \brief Perform 2D seperable transform on a 2D grey-level image. * It is the users responsibility to ensure that the grey-value * types are appropriate. * Now extended to include compound objects. * * \return Pointer to transformed object * \param obj Input object pointer * \param x_fun Convolution function to be applied in the x-direction (along the rows). * \param x_params Parameter pointer to be passed to the x-function. * \param y_fun Convolution function to be applied in the y-direction (down the columns). * \param y_params Parameter pointer to be passed to the y-function. * \param dstErr error return. * \par Source: * WlzSepTrans.c */ WlzObject *WlzSepTrans( WlzObject *obj, WlzIntervalConvFunc x_fun, void *x_params, WlzIntervalConvFunc y_fun, void *y_params, WlzErrorNum *dstErr) { WlzIntervalWSpace iwspace; WlzGreyWSpace gwspace; WlzSepTransWSpace stwspc; WlzValues values; WlzObject *obj1, *obj2; int i, width, height; WlzCompoundArray *cobj1, *cobj2; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object pointers and type */ obj2 = NULL; stwspc.outbuf.p.dbp = NULL; if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( obj->type ){ case WLZ_2D_DOMAINOBJ: /* check 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; } if(WlzGreyTableIsTiled(obj->values.core->type)){ errNum = WLZ_ERR_VALUES_TYPE; break; } break; default: case WLZ_3D_DOMAINOBJ: errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_TRANS_OBJ: if((obj1 = WlzSepTrans(obj->values.obj, x_fun, x_params, y_fun, y_params, &errNum)) != NULL){ values.obj = obj1; return WlzMakeMain(obj->type, obj->domain, values, NULL, obj, dstErr); } break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: cobj1 = (WlzCompoundArray *) obj; if((cobj2 = WlzMakeCompoundArray(cobj1->type, 1, cobj1->n, NULL, cobj1->otype, &errNum)) != NULL){ /* transform each object, ignore type errors */ for(i=0; i < cobj1->n; i++){ cobj2->o[i] = WlzAssignObject(WlzSepTrans(cobj1->o[i], x_fun, x_params, y_fun, y_params, &errNum), NULL); } return (WlzObject *) cobj2; } break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); } } /* make space for a calculation buffer - assume worst case of doubles */ if( errNum == WLZ_ERR_NONE ){ width = obj->domain.i->lastkl - obj->domain.i->kol1 + 1; height = obj->domain.i->lastln - obj->domain.i->line1 + 1; stwspc.inbuf.type = WlzGreyTableTypeToGreyType(obj->values.core->type, NULL); stwspc.bckgrnd = WlzGetBackground(obj, NULL); switch( stwspc.inbuf.type ){ case WLZ_GREY_INT: case WLZ_GREY_SHORT: case WLZ_GREY_UBYTE: stwspc.outbuf.type = WLZ_GREY_INT; break; default: stwspc.outbuf.type = stwspc.inbuf.type; break; } if( (stwspc.outbuf.p.dbp = (double *) AlcMalloc(sizeof(double)*(width>height?width:height))) == NULL){ errNum = WLZ_ERR_MEM_ALLOC; } } /* tranpose the object - interchange x & y coordinates */ if( errNum == WLZ_ERR_NONE ){ obj1 = WlzTransposeObj(obj, &errNum); } /* perform the y convolution */ if((errNum == WLZ_ERR_NONE) && ((errNum = WlzInitGreyScan(obj1, &iwspace, &gwspace)) == WLZ_ERR_NONE)) { while( (errNum = WlzNextGreyInterval(&iwspace)) == WLZ_ERR_NONE ){ stwspc.inbuf.p.inp = gwspace.u_grintptr.inp; stwspc.len = iwspace.rgtpos - iwspace.lftpos + 1; if((errNum = (*y_fun)(&stwspc, y_params)) == WLZ_ERR_NONE){ switch( stwspc.inbuf.type ){ case WLZ_GREY_INT: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.inp++) *stwspc.inbuf.p.inp = stwspc.outbuf.p.inp[i]; break; case WLZ_GREY_SHORT: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.shp++) *stwspc.inbuf.p.shp = (short )(stwspc.outbuf.p.inp[i]); break; case WLZ_GREY_UBYTE: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.ubp++) *stwspc.inbuf.p.ubp = (WlzUByte )(stwspc.outbuf.p.inp[i]); break; case WLZ_GREY_FLOAT: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.flp++) *stwspc.inbuf.p.flp = stwspc.outbuf.p.flp[i]; break; case WLZ_GREY_DOUBLE: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.dbp++) *stwspc.inbuf.p.dbp = stwspc.outbuf.p.dbp[i]; break; case WLZ_GREY_RGBA: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.rgbp++) *stwspc.inbuf.p.rgbp = stwspc.outbuf.p.rgbp[i]; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } else { break; /* break from the while loop */ } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } } /* rotate back and free temporary object */ if( errNum == WLZ_ERR_NONE ){ obj2 = WlzTransposeObj(obj1, &errNum); WlzFreeObj(obj1); } /* perform x convolution */ if((errNum == WLZ_ERR_NONE) && ((errNum = WlzInitGreyScan(obj2, &iwspace, &gwspace)) == WLZ_ERR_NONE)) { while((errNum = WlzNextGreyInterval(&iwspace)) == WLZ_ERR_NONE){ stwspc.inbuf.p.inp = gwspace.u_grintptr.inp; stwspc.len = iwspace.rgtpos - iwspace.lftpos + 1; if( (errNum = (*x_fun)(&stwspc, x_params)) == WLZ_ERR_NONE ){ switch( gwspace.pixeltype ){ case WLZ_GREY_INT: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.inp++) *stwspc.inbuf.p.inp = stwspc.outbuf.p.inp[i]; break; case WLZ_GREY_SHORT: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.shp++) *stwspc.inbuf.p.shp = (short )(stwspc.outbuf.p.inp[i]); break; case WLZ_GREY_UBYTE: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.ubp++) *stwspc.inbuf.p.ubp = (WlzUByte )(stwspc.outbuf.p.inp[i]); break; case WLZ_GREY_FLOAT: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.flp++) *stwspc.inbuf.p.flp = stwspc.outbuf.p.flp[i]; break; case WLZ_GREY_DOUBLE: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.dbp++) *stwspc.inbuf.p.dbp = stwspc.outbuf.p.dbp[i]; break; case WLZ_GREY_RGBA: for(i=0; i < stwspc.len; i++, stwspc.inbuf.p.rgbp++) *stwspc.inbuf.p.rgbp = stwspc.outbuf.p.rgbp[i]; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } else { break; /* break from the while loop */ } } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } /* free the buffer and return transformed object */ if( stwspc.outbuf.p.dbp ){ AlcFree((void *) stwspc.outbuf.p.dbp); } if( dstErr ){ *dstErr = errNum; } return obj2; }
/*! * \return Transformed object. * \ingroup WlzTransform * \brief Transform an object using the given view-transform. * Typically this is for mapping section data back into * the 3D space of the reference image/reconstruction. * \param srcObj Given source object. * \param viewStr Given view transform. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *Wlz3DViewTransformObj( WlzObject *srcObj, WlzThreeDViewStruct *viewStr, WlzErrorNum *dstErr) { WlzErrorNum errNum=WLZ_ERR_NONE; AlcErrno alcErr = ALC_ER_NONE; WlzObject *dstObj=NULL; int area; int i, k, p, xp, yp, line; int plane1, lastpl, line1, lastln, kol1, lastkl; WlzIVertex3 *vertices; int numVtxs, vtxIdx; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzDomain domain, tmpDomain; WlzValues values; int numInts, itvlFlg; WlzInterval *itvl; /* check the object */ if( srcObj == NULL ) { errNum = WLZ_ERR_OBJECT_NULL; } else { switch( srcObj->type ) { case WLZ_2D_DOMAINOBJ: if( srcObj->domain.core == NULL ) { errNum = WLZ_ERR_DOMAIN_NULL; } area = WlzArea(srcObj, &errNum); if( area == 0 ) { dstObj = WlzMakeEmpty(&errNum); } break; case WLZ_2D_POLYGON: /* to be done at some time to 3D polyline */ case WLZ_BOUNDLIST: /* convert to 3D polylines */ case WLZ_TRANS_OBJ: errNum = WLZ_ERR_OBJECT_TYPE; break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* create the voxel list */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { numVtxs = sizeof(WlzIVertex3) * (area+4); vertices = AlcMalloc(sizeof(WlzIVertex3) * (area+4)); numVtxs = 0; if( vertices ) { errNum = WlzInitRasterScan(srcObj, &iwsp, WLZ_RASTERDIR_ILIC); } else { errNum = WLZ_ERR_MEM_ALLOC; } if( errNum == WLZ_ERR_NONE ) { while( (errNum = WlzNextInterval(&iwsp)) == WLZ_ERR_NONE ) { float x, y, z; if((iwsp.linpos < (int) viewStr->minvals.vtY) || (iwsp.linpos > (int) viewStr->maxvals.vtY)) { continue; } yp = iwsp.linpos - (int) viewStr->minvals.vtY; for(k=iwsp.lftpos; k <= iwsp.rgtpos; k++) { if((k < (int) viewStr->minvals.vtX) || (k > (int) viewStr->maxvals.vtX)) { continue; } xp = k - (int) viewStr->minvals.vtX; x = (float )(viewStr->xp_to_x[xp] + viewStr->yp_to_x[yp]); y = (float )(viewStr->xp_to_y[xp] + viewStr->yp_to_y[yp]); z = (float )(viewStr->xp_to_z[xp] + viewStr->yp_to_z[yp]); vertices[numVtxs].vtX = WLZ_NINT(x); vertices[numVtxs].vtY = WLZ_NINT(y); vertices[numVtxs].vtZ = WLZ_NINT(z); numVtxs++; } } if(errNum == WLZ_ERR_EOO) /* Reset error from end of object */ { errNum = WLZ_ERR_NONE; } } } /* sort wrt planes, lines, kols */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { qsort((void *) vertices, (size_t) numVtxs, sizeof(WlzIVertex3), compareVtxVal); /* create planedomain */ plane1 = vertices[0].vtZ; lastpl = vertices[numVtxs - 1].vtZ; line1 = vertices[0].vtY; lastln = line1; kol1 = vertices[0].vtX; lastkl = kol1; for(i=1; i < numVtxs; i++) { if( kol1 > vertices[i].vtX ) { kol1 = vertices[i].vtX; } if( lastkl < vertices[i].vtX ) { lastkl = vertices[i].vtX; } if( line1 > vertices[i].vtY ) { line1 = vertices[i].vtY; } if( lastln < vertices[i].vtY ) { lastln = vertices[i].vtY; } } if( (domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, plane1, lastpl, line1, lastln, kol1, lastkl, &errNum)) == NULL ) { AlcFree((void *) vertices); } } /* for each plane count intervals and make domain */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { vtxIdx = 0; for(p=plane1; p <= lastpl; p++) { /* increment vertex index to current plane */ while( vertices[vtxIdx].vtZ < p ) { vtxIdx++; } /* check for empty domain */ if( vertices[vtxIdx].vtZ > p ) { domain.p->domains[p - plane1].i = NULL; continue; } /* estimate intervals - foreach pixel add one, foreach adjacent pixel on the same line subtract one */ numInts = 1; kol1 = vertices[vtxIdx].vtX; lastkl = kol1; for(i=vtxIdx+1; i < numVtxs; i++) { if( vertices[i].vtZ > p ) { break; } numInts++; if((vertices[i].vtY == vertices[i-1].vtY) && ((vertices[i].vtX == (vertices[i-1].vtX)) || (vertices[i].vtX == (vertices[i-1].vtX + 1)) )) { numInts--; } if(kol1 > vertices[i].vtX) { kol1 = vertices[i].vtX; } if(lastkl < vertices[i].vtX) { lastkl = vertices[i].vtX; } } line1 = vertices[vtxIdx].vtY; lastln = vertices[i-1].vtY; /* make the domain and add the intervals pointer */ tmpDomain.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, line1, lastln, kol1, lastkl, &errNum); itvl = (WlzInterval *) AlcMalloc(sizeof(WlzInterval)*numInts); tmpDomain.i->freeptr = AlcFreeStackPush(tmpDomain.i->freeptr, (void *) itvl, &alcErr); if(alcErr != ALC_ER_NONE) { errNum = WLZ_ERR_MEM_ALLOC; } /* one more loop to add the intervals */ itvl->ileft = vertices[vtxIdx].vtX - kol1; line = vertices[vtxIdx].vtY; itvlFlg = 1; /* interval started */ numInts = 1; for(i=vtxIdx+1; i < numVtxs; i++) { /* new plane -> interval finished if started */ if( vertices[i].vtZ > p ) { if( itvlFlg ) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; WlzMakeInterval(line, tmpDomain.i, numInts, itvl); itvl += numInts; itvlFlg = 0; /* interval finished */ numInts = 0; } break; } /* check if new interval */ if( !itvlFlg ) { itvl->ileft = vertices[i].vtX - kol1; line = vertices[i].vtY; itvlFlg = 1; numInts = 1; continue; /* no further tests */ } /* check for gap - increment interval count */ if((vertices[i].vtY == line) && ((vertices[i].vtX - vertices[i-1].vtX) > 1)) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; numInts++; itvl[numInts-1].ileft = vertices[i].vtX - kol1; itvlFlg = 1; } /* check for new-line */ if( line < vertices[i].vtY ) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; WlzMakeInterval(line, tmpDomain.i, numInts, itvl); itvl += numInts; itvl->ileft = vertices[i].vtX - kol1; line = vertices[i].vtY; itvlFlg = 1; numInts = 1; } } /* complete the last interval */ if( itvlFlg ) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; WlzMakeInterval(line, tmpDomain.i, numInts, itvl); itvl += numInts; } /* add the domain to the planedomain */ domain.p->domains[p - plane1] = WlzAssignDomain(tmpDomain, &errNum); (void) WlzIntervalCount(tmpDomain.i, 0); } } /* create the new object */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { values.core = NULL; dstObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } /* check for grey-level data */ if((errNum == WLZ_ERR_NONE) && dstObj && (dstObj->type != WLZ_EMPTY_OBJ) && srcObj->values.core ) { WlzPixelV bckgrnd; WlzObject *tmpObj; WlzValues tmpValues; WlzDVertex3 vtx; WlzGreyValueWSpace *gVWSp = NULL; WlzObjectType valueTbType; /* explicit intialisation to satisfy strict ANSI on SGI */ bckgrnd = WlzGetBackground(srcObj, &errNum); valueTbType = WlzGreyTableType(WLZ_GREY_TAB_RAGR, bckgrnd.type, NULL); /* make a voxel table */ values.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, plane1, lastpl, bckgrnd, NULL, &errNum); dstObj->values = WlzAssignValues(values, &errNum); /* set up grey-value random access to original and loop through planes setting values */ gVWSp = WlzGreyValueMakeWSp(srcObj, NULL); for(p=plane1; p <= lastpl; p++) { /* check for empty domain */ if( domain.p->domains[p-plane1].core == NULL ) { continue; } /* make a value table */ tmpObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain.p->domains[p-plane1], values.vox->values[p-plane1], NULL, NULL, &errNum); tmpValues.v = WlzNewValueTb(tmpObj, valueTbType, bckgrnd, &errNum); values.vox->values[p-plane1] = WlzAssignValues(tmpValues, &errNum); tmpObj->values = WlzAssignValues(tmpValues, &errNum); /* transfer values */ errNum = WlzInitGreyScan(tmpObj, &iwsp, &gwsp); while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE)) { for(i=0; i<iwsp.colrmn; i++) { vtx.vtX = iwsp.colpos + i; vtx.vtY = iwsp.linpos; vtx.vtZ = p; Wlz3DSectionTransformVtx(&vtx, viewStr); WlzGreyValueGet(gVWSp, 0.0, WLZ_NINT(vtx.vtY), WLZ_NINT(vtx.vtX)); switch( gwsp.pixeltype ) { case WLZ_GREY_LONG: *(gwsp.u_grintptr.lnp+i) = gVWSp->gVal[0].lnv; break; case WLZ_GREY_INT: *(gwsp.u_grintptr.inp+i) = gVWSp->gVal[0].inv; break; case WLZ_GREY_SHORT: *(gwsp.u_grintptr.shp+i) = gVWSp->gVal[0].shv; break; case WLZ_GREY_UBYTE: *(gwsp.u_grintptr.ubp+i) = gVWSp->gVal[0].ubv; break; case WLZ_GREY_FLOAT: *(gwsp.u_grintptr.flp+i) = gVWSp->gVal[0].flv; break; case WLZ_GREY_DOUBLE: *(gwsp.u_grintptr.dbp+i) = gVWSp->gVal[0].dbv; break; case WLZ_GREY_RGBA: *(gwsp.u_grintptr.rgbp+i) = gVWSp->gVal[0].rgbv; break; case WLZ_GREY_BIT: /* not sure what to do with these */ default: break; } } } if(errNum == WLZ_ERR_EOO) /* Reset error from end of object */ { errNum = WLZ_ERR_NONE; } WlzFreeObj(tmpObj); } WlzGreyValueFreeWSp(gVWSp); } /* clean temp allocation */ if( vertices ) { AlcFree((void *) vertices); } if( dstErr ) { *dstErr = errNum; } return dstObj; }
/*! * \return Woolz error code. * \ingroup WlzValuesUtils * \brief Computes the range of values in a RGBA type image. * Currently implemented is modulus range. * Use WlzGreyRange to get the individual colour ranges. * \param obj Given object with RGBA values. * \param min Destination pointer for minimum value. * \param max Destination pointer for maximum value. */ WlzErrorNum WlzRGBAModulusRange( WlzObject *obj, double *min, double *max) { WlzErrorNum errNum=WLZ_ERR_NONE; double val, lmin, lmax; int i, nplanes, initFlg; WlzGreyP g; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzObject tempobj; WlzPlaneDomain *planedm; WlzValues *values; WlzDomain *domains; /* object checks */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if( obj->values.core == NULL){ errNum = WLZ_ERR_VALUES_NULL; } else if( (min == NULL) || (max == NULL) ){ errNum = WLZ_ERR_PARAM_NULL; } /* object type checks */ if( errNum == WLZ_ERR_NONE ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: WlzInitGreyScan(obj, &iwsp, &gwsp); while( (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE ){ g = gwsp.u_grintptr; for(i=0; i<iwsp.colrmn; i++, g.rgbp++){ val = WLZ_RGBA_MODULUS(*g.rgbp); if( !initFlg ){ lmin = val; lmax = val; initFlg = 1; } else { if( val < lmin ){ lmin = val; } if( val > lmax ){ lmax = val; } } } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } *min = lmin; *max = lmax; break; case WLZ_3D_DOMAINOBJ: planedm = obj->domain.p; switch( planedm->type ){ case WLZ_PLANEDOMAIN_DOMAIN: nplanes = planedm->lastpl - planedm->plane1 + 1; domains = planedm->domains; if( obj->values.vox->type != WLZ_VOXELVALUETABLE_GREY ){ return( WLZ_ERR_VOXELVALUES_TYPE ); } values = obj->values.vox->values; tempobj.type = WLZ_2D_DOMAINOBJ; tempobj.plist = NULL; tempobj.assoc = NULL; for(i=0; i < nplanes; i++, domains++, values++){ if( (*domains).core == NULL || (*values).core == NULL ){ continue; } tempobj.domain = *domains; tempobj.values = *values; errNum = WlzRGBAModulusRange(&tempobj, min, max); if( errNum != WLZ_ERR_NONE ){ return( errNum ); } if( !initFlg ){ lmin = *min; lmax = *max; initFlg = 1; continue; } else { if( *min < lmin ){ lmin = *min; } if( *max > lmax ){ lmax = *max; } } } break; default: errNum = WLZ_ERR_PLANEDOMAIN_TYPE; break; } *min = lmin; *max = lmax; break; case WLZ_TRANS_OBJ: return( WlzRGBAModulusRange(obj->values.obj, min, max) ); case WLZ_EMPTY_OBJ: *min = 0.0; *max = 0.0; break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } return errNum; }
/*! * \ingroup WlzValuesUtils * \brief Calculate the modulus of the rgb values and return in an image of grey type WLZ_GREY_SHORT * * \return Grey-level object of modulus values * \param obj Input rgba object * \param dstErr error return * \par Source: * WlzRGBAConvert.c */ WlzObject *WlzRGBAToModulus( WlzObject *obj, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object type, and value type */ if( obj ){ 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( WlzGreyTypeFromObj(obj, &errNum) != WLZ_GREY_RGBA ){ errNum = WLZ_ERR_VALUES_TYPE; } break; case WLZ_3D_DOMAINOBJ: if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if( obj->domain.p->type != WLZ_PLANEDOMAIN_DOMAIN ){ errNum = WLZ_ERR_DOMAIN_TYPE; } else if ( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( obj->values.vox->type != WLZ_VOXELVALUETABLE_GREY ){ errNum = WLZ_ERR_VALUES_TYPE; } else if( WlzGreyTypeFromObj(obj, &errNum) != WLZ_GREY_RGBA ){ errNum = WLZ_ERR_VALUES_TYPE; } return WlzRGBAToModulus3D(obj, dstErr); case WLZ_TRANS_OBJ: /* not difficult, do it later */ errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: /* bit recursive this ! */ errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; } } else { errNum = WLZ_ERR_OBJECT_NULL; } /* create object return */ if( errNum == WLZ_ERR_NONE ){ WlzValues values; WlzObjectType type; WlzPixelV oldBck, newBck; type = WlzGreyTableType( WlzGreyTableTypeToTableType(obj->values.core->type, &errNum), WLZ_GREY_SHORT, &errNum); oldBck = WlzGetBackground(obj, &errNum); newBck.type = WLZ_GREY_SHORT; newBck.v.shv = (short )WLZ_RGBA_MODULUS(oldBck.v.rgbv); /* make values table and return object */ values.v = WlzNewValueTb(obj, type, newBck, &errNum); rtnObj = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); } /* iterate through objects setting values */ if( errNum == WLZ_ERR_NONE ){ WlzIntervalWSpace iwsp0, iwsp1; WlzGreyWSpace gwsp0, gwsp1; int j, k; errNum = WlzInitGreyScan(obj, &iwsp0, &gwsp0); errNum = WlzInitGreyScan(rtnObj, &iwsp1, &gwsp1); while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp0)) == WLZ_ERR_NONE)){ errNum = WlzNextGreyInterval(&iwsp1); for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++, gwsp0.u_grintptr.rgbp++){ *(gwsp1.u_grintptr.shp++) = (short ) WLZ_RGBA_MODULUS(*(gwsp0.u_grintptr.rgbp)); } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \return New 3D domain object with corresponding WLZ_GREY_RGBA values. * \ingroup WlzValuesUtils * \brief Creates a WLZ_GREY_RGBA valued object from the given compound * array. This is a static function which will always be called * with valid parameters so they aren't checked. * \param cObj Compound array object. * \param cSpc The colour space. * \param dstErr Destination error pointer may be NULL. */ static WlzObject *WlzCompoundToRGBA2D(WlzCompoundArray *cObj, WlzRGBAColorSpace cSpc, WlzErrorNum *dstErr) { int i, j; WlzObject *rtnObj=NULL; WlzPixelV bckgrnd; WlzObject *objs[4]; WlzObjectType vType; WlzUInt b[4]; WlzErrorNum errNum=WLZ_ERR_NONE; /* Make a copy of the object pointers because WlzUnionN() modifies the * array if it contains empty objects. */ for(i = 0; i < 3; ++i) { objs[i] = cObj->o[i]; } rtnObj = WlzUnionN(3, objs, 0, &errNum); if(errNum == WLZ_ERR_NONE) { /* Add an RGBA valuetable, extract background for each channel */ vType = WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_RGBA, &errNum); for(i=0; (errNum == WLZ_ERR_NONE) && (i < 3); i++) { bckgrnd = WlzGetBackground(cObj->o[i], &errNum); if(errNum == WLZ_ERR_NONE) { errNum = WlzValueConvertPixel(&bckgrnd, bckgrnd, WLZ_GREY_UBYTE); b[i] = bckgrnd.v.ubv; } } } if(errNum == WLZ_ERR_NONE) { WlzValues values; bckgrnd.type = WLZ_GREY_RGBA; WLZ_RGBA_RGBA_SET(bckgrnd.v.rgbv, b[0], b[1], b[2], 255); values.v = WlzNewValueTb(rtnObj, vType, bckgrnd, &errNum); if(values.v != NULL) { rtnObj->values = WlzAssignValues(values, &errNum); } else { (void )WlzFreeObj(rtnObj); rtnObj = NULL; } } /* Transfer values */ if( errNum == WLZ_ERR_NONE) { WlzGreyValueWSpace *gValWSpc[4]; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyV gval; /* do it dumb fashion for now, rgb only */ gValWSpc[0] = gValWSpc[1] = gValWSpc[2] = gValWSpc[3] = NULL; for(i=0; i < 3; i++) { if((cObj->o[i] != NULL) && (cObj->o[i]->type != WLZ_EMPTY_OBJ)) { gValWSpc[i] = WlzGreyValueMakeWSp(cObj->o[i], &errNum); if(errNum != WLZ_ERR_NONE) { break; } } } if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(rtnObj, &iwsp, &gwsp); } while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE)) { WlzPixelV pix; for(j = iwsp.lftpos; j <= iwsp.rgtpos; j++) { for(i = 0; i < 3; i++) { if(gValWSpc[i] == NULL) { pix.v.ubv = (i < 2)? 0: 255; } else { WlzGreyValueGet(gValWSpc[i], 0, iwsp.linpos, j); pix.type = gValWSpc[i]->gType; pix.v = gValWSpc[i]->gVal[0]; WlzValueConvertPixel(&pix, pix, WLZ_GREY_UBYTE); } b[i] = pix.v.ubv; } WLZ_RGBA_RGBA_SET(gval.rgbv, b[0], b[1], b[2], b[3]); *gwsp.u_grintptr.rgbp = gval.rgbv; gwsp.u_grintptr.rgbp++; } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } for(i=0; i < 3; i++) { WlzGreyValueFreeWSp(gValWSpc[i]); } } if(dstErr != NULL) { *dstErr = errNum; } return(rtnObj); }
int main( int argc, char **argv) { FILE *inFile=stdin; char optList[] = "p:h"; int option; WlzErrorNum errNum=WLZ_ERR_NONE; /* int type; */ WlzObject *obj, *obj1; int i; double x, y, z, val; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyP gptr; /* read the argument list and check for an input file */ opterr = 0; x = y = z = 0.0; while( (option = getopt(argc, argv, optList)) != EOF ){ switch( option ){ case 'p': if( sscanf(optarg, "%lf,%lf,%lf", &x, &y, &z) != 3 ){ fprintf(stderr, "%s: not enough values for vertex\n", argv[0]); usage(argv[0]); return 1; } break; case 't': /* type = atoi(optarg); */ break; case 'h': default: usage(argv[0]); return 1; } } /* get objects from stdin */ if((obj = WlzReadObj(inFile, &errNum)) != NULL){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: break; case WLZ_3D_DOMAINOBJ: /* to be done */ default: fprintf(stderr, "%s: invalid object type: %d\n", argv[0], obj->type); usage(argv[0]); return 1; } } else { fprintf(stderr, "%s: can't read object\n", argv[0]); usage(argv[0]); return 1; } /* scan through object setting distance values use integer values */ if((obj1 = WlzConvertPix(obj, WLZ_GREY_FLOAT, &errNum)) != NULL){ WlzInitGreyScan(obj1, &iwsp, &gwsp); while( WlzNextGreyInterval(&iwsp) == 0 ){ gptr = gwsp.u_grintptr; switch (gwsp.pixeltype) { case WLZ_GREY_INT: for (i=0; i<iwsp.colrmn; i++, gptr.inp++){ val = (iwsp.colpos + i - x)*(iwsp.colpos + i - x) \ + (iwsp.linpos - y) * (iwsp.linpos - y); val = sqrt(val); *gptr.flp = WLZ_NINT(val); } break; default: /* something gone badly wrong - quit */ fprintf(stderr, "%s: something wrong, oops\n", argv[0]); return 1; } } WlzWriteObj(stdout, obj1); WlzFreeObj(obj1); } WlzFreeObj(obj); return 0; }
/*! * \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 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); 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; } } } } 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); }
/*! * \ingroup WlzValuesUtils * \brief Convert a grey-level woolz object to RGBA via a colourmap look-up table. Values are clamped to [0,255] and the LUT is assumed to be unsigned byte 3x256 * * \return Woolz object * \param obj Input object to be converted * \param colormap Colourmap array * \param dstErr Error return * \par Source: * WlzRGBAConvert.c */ WlzObject *WlzIndexToRGBA( WlzObject *obj, unsigned char colormap[3][256], WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzGreyType oldpixtype; WlzGreyP go, gn; WlzIntervalWSpace oldiwsp, newiwsp; WlzGreyWSpace oldgwsp, newgwsp; WlzObjectType newvtbltype; WlzPixelV bg; WlzValues values; int k, greyVal, redVal, greenVal, blueVal; unsigned int rgbaVal; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object - must be domain object with a values table */ if( obj ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.core ){ if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else { oldpixtype = WlzGreyTableTypeToGreyType(obj->values.core->type, NULL); if( oldpixtype == WLZ_GREY_RGBA ){ return WlzMakeMain(obj->type, obj->domain, obj->values, NULL, NULL, dstErr); } } } else { errNum = WLZ_ERR_DOMAIN_NULL; } break; case WLZ_3D_DOMAINOBJ: return WlzIndexToRGBA3D(obj, colormap, dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } else { errNum = WLZ_ERR_OBJECT_NULL; } /* * Set type of new value table so as to preserve * rectangular/single interval/multiple interval * type. */ if( errNum == WLZ_ERR_NONE ){ newvtbltype = WlzGreyTableTypeToTableType(obj->values.core->type, &errNum); } if( errNum == WLZ_ERR_NONE ){ newvtbltype = WlzGreyTableType(newvtbltype, WLZ_GREY_RGBA, &errNum); } /* get the background - note background now carries its own type */ if( errNum == WLZ_ERR_NONE ){ bg = WlzGetBackground(obj, &errNum); switch( bg.type ){ case WLZ_GREY_INT: greyVal = WLZ_CLAMP(bg.v.inv, 0, 255); break; case WLZ_GREY_SHORT: greyVal = WLZ_CLAMP(bg.v.shv, 0, 255); break; case WLZ_GREY_UBYTE: greyVal = bg.v.ubv; break; case WLZ_GREY_FLOAT: greyVal = WLZ_CLAMP(bg.v.flv, 0, 255); break; case WLZ_GREY_DOUBLE: greyVal = (int )WLZ_CLAMP(bg.v.dbv, 0, 255); break; default: errNum = WLZ_ERR_GREY_TYPE; break; } bg.type = WLZ_GREY_RGBA; WLZ_RGBA_RGBA_SET(bg.v.rgbv, colormap[0][greyVal], colormap[1][greyVal], colormap[2][greyVal], 255); } /* * Make the new object with new value table type and value table * allocated (but blank). Share original idom. */ if( errNum == WLZ_ERR_NONE ){ values.v = WlzNewValueTb(obj, newvtbltype, bg, &errNum); } if( errNum == WLZ_ERR_NONE ){ rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, obj->domain, values, obj->plist, obj->assoc, &errNum); } if( errNum == WLZ_ERR_NONE ){ errNum = WlzInitGreyScan(obj, &oldiwsp, &oldgwsp); } if( errNum == WLZ_ERR_NONE ){ errNum = WlzInitGreyScan(rtnObj, &newiwsp, &newgwsp); } while( ((errNum = WlzNextGreyInterval(&oldiwsp)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&newiwsp)) == WLZ_ERR_NONE) ){ go = oldgwsp.u_grintptr; gn = newgwsp.u_grintptr; for(k=0; k <= oldiwsp.colrmn; k++){ switch( oldgwsp.pixeltype ){ case WLZ_GREY_INT: greyVal = WLZ_CLAMP(*(go.inp), 0, 255); go.inp++; break; case WLZ_GREY_SHORT: greyVal = WLZ_CLAMP(*(go.shp), 0, 255); go.shp++; break; case WLZ_GREY_UBYTE: greyVal = *(go.ubp); go.ubp++; break; case WLZ_GREY_FLOAT: greyVal = WLZ_CLAMP(*(go.flp), 0, 255); go.flp++; break; case WLZ_GREY_DOUBLE: greyVal = (int )WLZ_CLAMP(*(go.dbp), 0, 255); go.dbp++; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } redVal = colormap[0][greyVal]; greenVal = colormap[1][greyVal]; blueVal = colormap[2][greyVal]; WLZ_RGBA_RGBA_SET(rgbaVal, redVal, greenVal, blueVal, 0xff); *(gn.rgbp) = rgbaVal; gn.rgbp++; } } /* while */ if(errNum == WLZ_ERR_EOO) /* Reset error from end of intervals */ { errNum = WLZ_ERR_NONE; } if( dstErr ){ *dstErr = errNum; } return rtnObj; }