// 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); }