package ij.process; import ij.measure.Calibration; /** 16-bit image statistics, including histogram. */ public class ShortStatistics extends ImageStatistics { /** Construct an ImageStatistics object from a ShortProcessor using the standard measurement options (area, mean, mode, min and max). */ public ShortStatistics(ImageProcessor ip) { this(ip, AREA+MEAN+MODE+MIN_MAX, null); } /** Constructs a ShortStatistics object from a ShortProcessor using the specified measurement options. The 'cal' argument, which can be null, is currently ignored. */ public ShortStatistics(ImageProcessor ip, int mOptions, Calibration cal) { this.width = ip.getWidth(); this.height = ip.getHeight(); setup(ip, cal); nBins = 256; double minT = ip.getMinThreshold(); int minThreshold,maxThreshold; if ((mOptions&LIMIT)==0 || minT==ImageProcessor.NO_THRESHOLD) {minThreshold=0; maxThreshold=65535;} else {minThreshold=(int)minT; maxThreshold=(int)ip.getMaxThreshold();} int[] hist = ip.getHistogram(); // 65536 bin histogram histogram16 =hist; float[] cTable = cal!=null?cal.getCTable():null; getRawMinAndMax(hist, minThreshold, maxThreshold); histMin = min; histMax = max; getStatistics(ip, hist, (int)min, (int)max, cTable); if ((mOptions&MODE)!=0) getMode(); if ((mOptions&ELLIPSE)!=0 || (mOptions&SHAPE_DESCRIPTORS)!=0) fitEllipse(ip, mOptions); else if ((mOptions&CENTROID)!=0) getCentroid(ip, minThreshold, maxThreshold); if ((mOptions&(CENTER_OF_MASS|SKEWNESS|KURTOSIS))!=0) calculateMoments(ip, minThreshold, maxThreshold, cTable); if ((mOptions&MIN_MAX)!=0 && cTable!=null) getCalibratedMinAndMax(hist, (int)min, (int)max, cTable); if ((mOptions&MEDIAN)!=0) calculateMedian(hist, minThreshold, maxThreshold, cal); if ((mOptions&AREA_FRACTION)!=0) calculateAreaFraction(ip, hist); } void getRawMinAndMax(int[] hist, int minThreshold, int maxThreshold) { int min = minThreshold; while ((hist[min]==0) && (min<65535)) min++; this.min = min; int max = maxThreshold; while ((hist[max]==0) && (max>0)) max--; this.max = max; } void getStatistics(ImageProcessor ip, int[] hist, int min, int max, float[] cTable) { int count; double value; double sum = 0.0; double sum2 = 0.0; nBins = ip.getHistogramSize(); histMin = ip.getHistogramMin(); histMax = ip.getHistogramMax(); if (histMin==0.0 && histMax==0.0) { histMin = min; histMax = max; } else { if (min<histMin) min = (int)histMin; if (max>histMax) max = (int)histMax; } binSize = (histMax-histMin)/nBins; double scale = 1.0/binSize; int hMin = (int)histMin; histogram = new int[nBins]; // 256 bin histogram int index; int maxCount = 0; for (int i=min; i<=max; i++) { count = hist[i]; if (count>maxCount) { maxCount = count; dmode = i; } pixelCount += count; value = cTable==null?i:cTable[i]; sum += value*count; sum2 += (value*value)*count; index = (int)(scale*(i-hMin)); if (index>=nBins) index = nBins-1; histogram[index] += count; } area = pixelCount*pw*ph; mean = sum/pixelCount; umean = mean; calculateStdDev(pixelCount, sum, sum2); if (cTable!=null) dmode = cTable[(int)dmode]; } void getMode() { int count; maxCount = 0; for (int i=0; i<nBins; i++) { count = histogram[i]; if (count > maxCount) { maxCount = count; mode = i; } } //ij.IJ.write("mode2: "+mode+" "+dmode+" "+maxCount); } void getCentroid(ImageProcessor ip, int minThreshold, int maxThreshold) { short[] pixels = (short[])ip.getPixels(); byte[] mask = ip.getMaskArray(); boolean limit = minThreshold>0 || maxThreshold<65535; int count=0, i, mi, v; double xsum=0.0, ysum=0.0; for (int y=ry,my=0; y<(ry+rh); y++,my++) { i = y*width + rx; mi = my*rw; for (int x=rx; x<(rx+rw); x++) { if (mask==null||mask[mi++]!=0) { if (limit) { v = pixels[i]&0xffff; if (v>=minThreshold&&v<=maxThreshold) { count++; xsum+=x; ysum+=y; } } else { count++; xsum+=x; ysum+=y; } } i++; } } xCentroid = xsum/count+0.5; yCentroid = ysum/count+0.5; if (cal!=null) { xCentroid = cal.getX(xCentroid); yCentroid = cal.getY(yCentroid, height); } } void calculateMoments(ImageProcessor ip, int minThreshold, int maxThreshold, float[] cTable) { short[] pixels = (short[])ip.getPixels(); byte[] mask = ip.getMaskArray(); int i, mi, iv; double v, v2, sum1=0.0, sum2=0.0, sum3=0.0, sum4=0.0, xsum=0.0, ysum=0.0; for (int y=ry,my=0; y<(ry+rh); y++,my++) { i = y*width + rx; mi = my*rw; for (int x=rx; x<(rx+rw); x++) { if (mask==null || mask[mi++]!=0) { iv = pixels[i]&0xffff; if (iv>=minThreshold&&iv<=maxThreshold) { v = cTable!=null?cTable[iv]:iv; v2 = v*v; sum1 += v; sum2 += v2; sum3 += v*v2; sum4 += v2*v2; xsum += x*v; ysum += y*v; } } i++; } } double mean2 = mean*mean; double variance = sum2/pixelCount - mean2; double sDeviation = Math.sqrt(variance); skewness = ((sum3 - 3.0*mean*sum2)/pixelCount + 2.0*mean*mean2)/(variance*sDeviation); kurtosis = (((sum4 - 4.0*mean*sum3 + 6.0*mean2*sum2)/pixelCount - 3.0*mean2*mean2)/(variance*variance)-3.0); xCenterOfMass = xsum/sum1+0.5; yCenterOfMass = ysum/sum1+0.5; if (cal!=null) { xCenterOfMass = cal.getX(xCenterOfMass); yCenterOfMass = cal.getY(yCenterOfMass, height); } } void getCalibratedMinAndMax(int[] hist, int minValue, int maxValue, float[] cTable) { min = Double.MAX_VALUE; max = -Double.MAX_VALUE; double v = 0.0; for (int i=minValue; i<=maxValue; i++) { if (hist[i]>0) { v = cTable[i]; if (v<min) min = v; if (v>max) max = v; } } } }