Пример #1
0
  // returns value of mean intensity+3*SD based on
  // fitting of image histogram to gaussian function
  int getThreshold(ImageProcessor thImage) {
    ImageStatistics imgstat;
    double[][] dHistogram;
    double[] dHistCum;
    double[][] dNoiseFit;
    int nHistSize;
    int nCount, nMaxCount;
    int nDownCount, nUpCount;
    int i, nPeakPos;
    double dRightWidth, dLeftWidth, dWidth;
    double dMean, dSD;
    double[] dFitErrors;
    double dErrCoeff;
    double dSum = 0.0;
    double dSumFit = 0.0;
    LMA fitlma;

    // mean, sd, min, max
    // imgstat = ImageStatistics.getStatistics(thImage, 38, null);
    imgstat =
        ImageStatistics.getStatistics(
            thImage, Measurements.MEAN + Measurements.STD_DEV + Measurements.MIN_MAX, null);
    dMean = imgstat.mean;
    nPeakPos = 0;

    nHistSize = imgstat.histogram.length;
    dHistogram = new double[2][nHistSize];
    nMaxCount = 0;

    // determine position and height of maximum count in histogram (mode)
    // and height at maximum
    for (i = 0; i < nHistSize; i++) {

      nCount = imgstat.histogram[i];
      dHistogram[0][i] = imgstat.min + i * imgstat.binSize;
      dHistogram[1][i] = (double) nCount;
      dSum += (double) nCount;
      if (nMaxCount < nCount) {
        nMaxCount = nCount;
        dMean = imgstat.min + i * imgstat.binSize;
        nPeakPos = i;
      }
    }
    // estimating width of a peak
    // going to the left
    i = nPeakPos;
    while (i > 0 && imgstat.histogram[i] > 0.5 * nMaxCount) {
      i--;
    }
    if (i < 0) i = 0;
    dLeftWidth = i;
    // going to the right
    i = nPeakPos;
    while (i < nHistSize && imgstat.histogram[i] > 0.5 * nMaxCount) {
      i++;
    }
    if (i == nHistSize) i = nHistSize - 1;
    dRightWidth = i;
    // FWHM in bins
    dWidth = (dRightWidth - dLeftWidth);
    dSD = dWidth * imgstat.binSize / 2.35;
    // fitting range +/- 3*SD
    dLeftWidth = nPeakPos - 3 * dWidth / 2.35;
    if (dLeftWidth < 0) dLeftWidth = 0;
    dRightWidth = nPeakPos + 3 * dWidth / 2.35;
    if (dRightWidth > nHistSize) dRightWidth = nHistSize;
    nUpCount = (int) dRightWidth;
    nDownCount = (int) dLeftWidth;
    // preparing histogram range for fitting
    dNoiseFit = new double[2][nUpCount - nDownCount + 1];
    for (i = nDownCount; i <= nUpCount; i++) {
      dNoiseFit[0][i - nDownCount] = dHistogram[0][i];
      dNoiseFit[1][i - nDownCount] = dHistogram[1][i];
      dSumFit += dHistogram[1][i];
    }
    // fitting range is too small, less than 80%
    if ((dSumFit / dSum) < 0.8) {
      // build cumulative distribution
      dHistCum = new double[nHistSize];
      dSumFit = 0;
      for (i = 0; i < nHistSize; i++) {
        dSumFit += dHistogram[1][i];
        dHistCum[i] = dSumFit / dSum;
      }
      nUpCount = 0;
      nDownCount = 0;
      for (i = 0; i < nHistSize; i++) {
        // 10% quantile
        if (dHistCum[i] < 0.11) nDownCount = i;
        // 90% quantile
        if (dHistCum[i] < 0.91) nUpCount = i;
      }
      // preparing histogram range for fitting
      dNoiseFit = new double[2][nUpCount - nDownCount + 1];
      for (i = nDownCount; i <= nUpCount; i++) {
        dNoiseFit[0][i - nDownCount] = dHistogram[0][i];
        dNoiseFit[1][i - nDownCount] = dHistogram[1][i];
      }
    }

    fitlma =
        new LMA(new SMLOneDGaussian(), new double[] {(double) nMaxCount, dMean, dSD}, dNoiseFit);
    fitlma.fit();

    dMean = fitlma.parameters[1];
    dSD = fitlma.parameters[2];

    dFitErrors = fitlma.getStandardErrorsOfParameters();
    // scaling coefficient for parameters errors estimation
    // (Standard deviation of residuals)
    dErrCoeff = Math.sqrt(fitlma.chi2 / (nUpCount - nDownCount + 1 - 3));
    for (i = 0; i < 3; i++) dFitErrors[i] *= dErrCoeff;
    for (i = 0; i < 3; i++) dFitErrors[i] *= 100 / fitlma.parameters[i];

    if (dFitErrors[1] > 20
        || dMean < imgstat.min
        || dMean > imgstat.max
        || dSD < imgstat.min
        || dSD > imgstat.max)
      // fit somehow failed
      return (int) (imgstat.mean + 3.0 * imgstat.stdDev);
    else return (int) (dMean + 3.0 * dSD);
  }