/*! * \return Woolz error code. * \ingroup WlzArithmetic * \brief Sets the values of the return object from the input object * using simple linear scaling, see WlzScalarMulAdd(). The * objects are known to be 2D, have the same domain. * \param rObj * \param iObj * \param m * \param a */ static WlzErrorNum WlzScalarMulAddSet2D(WlzObject *rObj, WlzObject *iObj, double m, double a) { int bufLen; WlzGreyWSpace iGWSp, rGWSp; WlzIntervalWSpace iIWSp = {0}, rIWSp = {0}; WlzErrorNum errNum = WLZ_ERR_NONE; bufLen = iObj->domain.i->lastkl - iObj->domain.i->kol1 + 1; if((bufLen != iObj->domain.i->lastkl - iObj->domain.i->kol1 + 1) || (bufLen < 0)) { errNum = WLZ_ERR_DOMAIN_DATA; } else if(bufLen > 0) { if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(iObj, &iIWSp, &iGWSp); } if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(rObj, &rIWSp, &rGWSp); } if(errNum == WLZ_ERR_NONE) { double *buf = NULL; if((buf = AlcMalloc(sizeof(double) * bufLen)) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { while((errNum = WlzNextGreyInterval(&iIWSp)) == WLZ_ERR_NONE) { int t, idN, itvLen; double f; itvLen = iIWSp.colrmn; (void )WlzNextGreyInterval(&rIWSp); switch(iGWSp.pixeltype) { case WLZ_GREY_INT: WlzValueCopyIntToDouble(buf, iGWSp.u_grintptr.inp, itvLen); break; case WLZ_GREY_SHORT: WlzValueCopyShortToDouble(buf, iGWSp.u_grintptr.shp, itvLen); break; case WLZ_GREY_UBYTE: WlzValueCopyUByteToDouble(buf, iGWSp.u_grintptr.ubp, itvLen); break; case WLZ_GREY_FLOAT: WlzValueCopyFloatToDouble(buf, iGWSp.u_grintptr.flp, itvLen); break; case WLZ_GREY_DOUBLE: WlzValueCopyDoubleToDouble(buf, iGWSp.u_grintptr.dbp, itvLen); break; case WLZ_GREY_RGBA: WlzValueCopyRGBAToDouble(buf, iGWSp.u_grintptr.rgbp, itvLen); break; default: break; } switch(rGWSp.pixeltype) { case WLZ_GREY_UBYTE: for(idN = 0; idN < itvLen; ++idN) { f = (buf[idN] * m) + a; f = WLZ_CLAMP(f, 0, 255); rGWSp.u_grintptr.ubp[idN] = WLZ_NINT(f); } break; case WLZ_GREY_SHORT: for(idN = 0; idN < itvLen; ++idN) { f = (buf[idN] * m) + a; f = WLZ_CLAMP(f, SHRT_MIN, SHRT_MAX); rGWSp.u_grintptr.shp[idN] = WLZ_NINT(f); } break; case WLZ_GREY_INT: for(idN = 0; idN < itvLen; ++idN) { f = (buf[idN] * m) + a; f = WLZ_CLAMP(f, INT_MIN, INT_MAX); rGWSp.u_grintptr.inp[idN] = WLZ_NINT(f); } break; case WLZ_GREY_RGBA: for(idN = 0; idN < itvLen; ++idN) { WlzUInt u; f = (buf[idN] * m) + a; f = WLZ_CLAMP(f, 0, 255); t = WLZ_NINT(f); WLZ_RGBA_RGBA_SET(u, t, t, t, 255); rGWSp.u_grintptr.inp[idN] = u; } case WLZ_GREY_FLOAT: for(idN = 0; idN < itvLen; ++idN) { double t; t = (buf[idN] * m) + a; rGWSp.u_grintptr.flp[idN] = WLZ_CLAMP(t, -(FLT_MAX), FLT_MAX); } break; case WLZ_GREY_DOUBLE: for(idN = 0; idN < itvLen; ++idN) { rGWSp.u_grintptr.dbp[idN] = (buf[idN] * m) + a; } break; default: break; } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } } AlcFree(buf); } (void )WlzEndGreyScan(&iIWSp, &iGWSp); (void )WlzEndGreyScan(&rIWSp, &rGWSp); } return(errNum); }
/*! * \return 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); }
int main(int argc, char **argv) { int idB, idD, option, numDbn = 0, synthesize = 0, fitCnt = 0, ok = 1, usage = 0; double tD0, tD1, tD2, pos, mu, sigma, alpha, binCnt, sumArea, pkSigma = 1.0, pkThresh = 1.0, fitTol = 0.1; double *fitMu = NULL, *fitSigma = NULL, *fitAlpha = NULL, *fitArea = NULL, *synBuf = NULL; WlzHistogramDomain *inDom, *outDom; WlzErrorNum errNum = WLZ_ERR_NONE; FILE *fP = NULL; WlzObject *inObj = NULL, *outObj = NULL; char *outDatFileStr, *inObjFileStr; const char *errMsg; static char optList[] = "l:n:o:s:t:hy", outDatFileStrDef[] = "-", inObjFileStrDef[] = "-"; opterr = 0; outDatFileStr = outDatFileStrDef; inObjFileStr = inObjFileStrDef; while(ok && ((option = getopt(argc, argv, optList)) != -1)) { switch(option) { case 'l': if(sscanf(optarg, "%lg", &fitTol) != 1) { usage = 1; ok = 0; } break; case 'n': if(sscanf(optarg, "%d", &numDbn) != 1) { usage = 1; ok = 0; } break; case 'o': outDatFileStr = optarg; break; case 's': if(sscanf(optarg, "%lg", &pkSigma) != 1) { usage = 1; ok = 0; } break; case 't': if(sscanf(optarg, "%lg", &pkThresh) != 1) { usage = 1; ok = 0; } break; case 'y': synthesize = 1; break; case 'h': default: usage = 1; ok = 0; break; } } if((inObjFileStr == NULL) || (*inObjFileStr == '\0') || (outDatFileStr == NULL) || (*outDatFileStr == '\0')) { ok = 0; usage = 1; } if(ok && (optind < argc)) { if((optind + 1) != argc) { usage = 1; ok = 0; } else { inObjFileStr = *(argv + optind); } } if(ok) { errNum = WLZ_ERR_READ_EOF; if((inObjFileStr == NULL) || (*inObjFileStr == '\0') || ((fP = (strcmp(inObjFileStr, "-")? fopen(inObjFileStr, "r"): stdin)) == NULL) || ((inObj= WlzAssignObject(WlzReadObj(fP, &errNum), NULL)) == NULL)) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to read object from file %s (%s).\n", *argv, inObjFileStr, errMsg); } if(fP && strcmp(inObjFileStr, "-")) { fclose(fP); } } if(ok) { if(inObj->type != WLZ_HISTOGRAM) { ok = 0; (void )fprintf(stderr, "%s: input object read from file %s not a histogram\n", *argv, inObjFileStr); } } if(ok) { if(inObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(inObj->type != WLZ_HISTOGRAM) { errNum = WLZ_ERR_OBJECT_TYPE; } else if((inDom = inObj->domain.hist) == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if((inDom->nBins < 0) || (inDom->maxBins < 0) || (inDom->binSize <= DBL_EPSILON)) { errNum = WLZ_ERR_DOMAIN_DATA; } else if((inDom->type != WLZ_HISTOGRAMDOMAIN_INT) && (inDom->type != WLZ_HISTOGRAMDOMAIN_FLOAT)) { errNum = WLZ_ERR_DOMAIN_TYPE; } } if(ok) { errNum = WlzHistogramFitPeaks(inObj, numDbn, pkSigma, pkThresh, fitTol, &fitCnt, &fitMu, &fitCnt, &fitSigma, &fitCnt, &fitAlpha, NULL); if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to fit histogram (%s).\n", *argv, errMsg); } } if(ok && (inDom->nBins > 0) && (fitCnt > 0)) { if(((fitArea = (double *)AlcMalloc(fitCnt * sizeof(double))) == NULL) || ((synBuf = (double *)AlcCalloc(inDom->nBins, sizeof(double))) == NULL)) { errNum = WLZ_ERR_MEM_ALLOC; ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to fit histogram (%s).\n", *argv, errMsg); } } if(ok && (fitCnt > 0)) { binCnt = WlzHistogramBinSum(inDom); for(idD = 0; idD < fitCnt; ++idD) { mu = *(fitMu + idD); sigma = *(fitSigma + idD); alpha = *(fitAlpha + idD); tD0 = alpha / (sqrt(2.0 * WLZ_M_PI) * sigma); for(idB = 0; idB < inDom->nBins; ++idB) { pos = inDom->origin + (idB * inDom->binSize) - mu; tD1 = pos / sigma; tD1 = -0.5 * (tD1 * tD1); tD2 = tD0 * exp(tD1); *(synBuf + idB) += tD2; *(fitArea + idD) += tD2 * inDom->binSize; sumArea += tD2 * inDom->binSize; } } tD0 = binCnt / sumArea; for(idD = 0; idD < fitCnt; ++idD) { *(fitArea + idD) *= tD0; } for(idB = 0; idB < inDom->nBins; ++idB) { *(synBuf + idB) *= tD0; } if((fP = (strcmp(outDatFileStr, "-")? fopen(outDatFileStr, "w"): stdout)) == NULL) { ok = 0; (void )fprintf(stderr, "%s: failed to write output data\n", *argv); } else { if(synthesize) { outObj = WlzMakeHistogram(inDom->type, inDom->nBins, &errNum); if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to synthesize histogram (%s).\n", *argv, errMsg); } else { outDom = outObj->domain.hist; outDom->nBins = inDom->nBins; outDom->origin = inDom->origin; outDom->binSize = inDom->binSize; switch(inDom->type) { case WLZ_HISTOGRAMDOMAIN_INT: WlzValueCopyDoubleToInt(outDom->binValues.inp, synBuf, inDom->nBins); break; case WLZ_HISTOGRAMDOMAIN_FLOAT: WlzValueCopyDoubleToDouble(outDom->binValues.dbp, synBuf, inDom->nBins); break; default: break; } if(WlzWriteObj(fP, outObj) != WLZ_ERR_NONE) { ok = 0; (void )fprintf(stderr, "%s: failed to write output object\n", *argv); } } } else { if(fitCnt > 0) { for(idD = 0; idD < fitCnt; ++idD) { fprintf(fP, "%8g %8g %8g %8g\n", *(fitMu + idD), *(fitSigma + idD), *(fitAlpha + idD), *(fitArea + idD)); } } } if(strcmp(outDatFileStr, "-")) { fclose(fP); } } } if(inObj) { WlzFreeObj(inObj); } if(outObj) { WlzFreeObj(outObj); } if(fitArea) { AlcFree(fitArea); } if(synBuf) { AlcFree(synBuf); } if(fitMu) { AlcFree(fitMu); } if(fitSigma) { AlcFree(fitSigma); } if(fitAlpha) { AlcFree(fitAlpha); } if(usage) { (void )fprintf(stderr, "Usage: %s%sExample: %s%s", *argv, " [-h] [-y] [-o<out file>] [-s#] [-t#] [-l#] [<in object>]\n" "Options:\n" " -l Log-liklihood fitting tolerance.\n" " -n Number of Gaussian distributions.\n" " -o Output data file name.\n" " -s Minimum Gaussian sigma (standard deviation).\n" " -t Threshold value for peak height.\n" " -y Synthesize a new histogram from the mixture of Gaussians, by\n" " default just the statistics are output.\n" " -h Help, prints this usage message.\n" "Fits a mixture of Gaussian distributions to the given Woolz histogram\n" "using a maximum liklihood estimate. If given the number of Gaussian\n" "distributions is zero (default) then Gaussians will be fitted to\n" "peaks found using WlzHistogramFindPeaks.\n" "Either the statistics of the Gaussian mixture are output in the format\n" " <mu (mean)> <sigma (std dev)> <alpha (height)> <area>\n" "one record for each fitted Gaussian, or a synthesized histogram built\n" "using the statistics is output.\n" "Objects/data are read from stdin and written to stdout unless the\n" "filenames are given.\n", *argv, " -s1.0 -t 10.0 myhist.wlz\n" "The input Woolz histogram object is read from myhist.wlz. Histogram\n" "peaks are detected using a Gaussian smoothing filter with a sigma value\n" "of 1.0 and a threshold value of 10.0, the maximum liklihood mixture\n" "of Gaussians is computed and the mixture statistics are written to the\n" "standard output.\n"); } return(!ok); }