/** * Computes an alpha trimmed mean upon the current region of the current function. Note that this * method uses memory to make a copy of the input values. Larger input regions might require a lot * of memory. * * @param alpha A number between 0 and 0.5 specifying the proportion of samples to ignore on each * end. * @return The measured value */ public double alphaTrimmedMean(double alpha) { if ((alpha < 0) || (alpha >= 0.5)) throw new IllegalArgumentException("alpha value must be >= 0 and < 0.5"); T tmp = func.createOutput(); values.clear(); iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); values.add(tmp.getRealDouble()); } values.sortValues(); double tailSize = alpha * values.size(); // can we avoid interpolation? if (tailSize == Math.floor(tailSize)) { // yes, trim count is exactly an integer return calcTrimmedMean(values, (int) tailSize); } // no, trim count is a float value // calc two trimmed means and interpolate to find the value between them double mean1 = calcTrimmedMean(values, (int) Math.floor(tailSize)); double mean2 = calcTrimmedMean(values, (int) Math.ceil(tailSize)); double fraction = tailSize - Math.floor(tailSize); double interpolation = ((1 - fraction) * mean1) + (fraction * mean2); return interpolation; }
/** * Resets the StatCalculator to work with a new function and/or region. The calculator does the * minimum amount of reinitialization. * * @param newFunc The new {@link Function} to use for obtaining sample values * @param newRegion The new {@link PointSet} region over which to gather samples */ public void reset(Function<long[], T> newFunc, PointSet newRegion) { func = newFunc; if (newRegion == region) { iter.reset(); } else { region = newRegion; iter = region.iterator(); } values.clear(); }
/** * Computes the minimum value upon the current region of the current function. * * @return The measured value */ public double min() { T tmp = func.createOutput(); double min = Double.POSITIVE_INFINITY; iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); double value = tmp.getRealDouble(); min = Math.min(min, value); } return min; }
/** * Computes the product of all the values of the current region of the current function. * * @return The measured value */ public double product() { T tmp = func.createOutput(); double prod = 1; iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); double value = tmp.getRealDouble(); prod *= value; } return prod; }
/** * Computes a trimmed mean upon the current region of the current function. Note that this method * uses memory to make a copy of the input values. Larger input regions might require a lot of * memory. * * @param halfTrimSize The number of samples to ignore from each end of the data * @return The measured value */ public double trimmedMean(int halfTrimSize) { T tmp = func.createOutput(); values.clear(); iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); values.add(tmp.getRealDouble()); } values.sortValues(); return calcTrimmedMean(values, halfTrimSize); }
/** * Computes the sum of all the values of the current region of the current function. * * @return The measured value */ public double sum() { T tmp = func.createOutput(); double sum = 0; iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); double value = tmp.getRealDouble(); sum += value; } return sum; }
/** * Computes the maximum value upon the current region of the current function. * * @return The measured value */ public double max() { T tmp = func.createOutput(); double max = Double.NEGATIVE_INFINITY; iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); double value = tmp.getRealDouble(); max = Math.max(max, value); } return max; }
/** * Computes the arithmetic mean (or average) upon the current region of the current function. * * @return The measured value */ public double arithmeticMean() { T tmp = func.createOutput(); double sum = 0; long numElements = 0; iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); sum += tmp.getRealDouble(); numElements++; } return sum / numElements; }
/** * Computes the sum of squared deviations of the values of the current region of the current * function. * * @return The measured value */ public double sumOfSquaredDeviations() { T tmp = func.createOutput(); final double xbar = arithmeticMean(); double sum = 0; iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); double value = tmp.getRealDouble(); double term = value - xbar; sum += (term * term); } return sum; }
/** * Computes the harmonic mean upon the current region of the current function. * * @return The measured value */ public double harmonicMean() { T tmp = func.createOutput(); double sum = 0; long numElements = 0; iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); double value = tmp.getRealDouble(); sum += 1 / value; numElements++; } return numElements / sum; // looks weird but it is correct }
/** * Computes the contraharmonic mean upon the current region of the current function. * * @return The measured value */ public double contraharmonicMean(double order) { T tmp = func.createOutput(); double sum1 = 0; double sum2 = 0; iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); double value = tmp.getRealDouble(); sum1 += Math.pow(value, order + 1); sum2 += Math.pow(value, order); } return sum1 / sum2; }
/** * Computes the centroid point of the current region and returns it as a pair of Doubles. The * first element in the pair is the x component and the second element is the y component. * * @return The measured point stored in a Tuple2 */ public Tuple2<Double, Double> centroidXY() { double sumX = 0; double sumY = 0; long numElements = 0; iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); sumX += pos[0]; sumY += pos[1]; numElements++; } double cx = (sumX / numElements) + 0.5; double cy = (sumY / numElements) + 0.5; return new Tuple2<Double, Double>(cx, cy); }
/** * Computes a weighted sum of the current function values over the current region. The weights are * provided and there must be as many weights as there are points in the current region. * * @return The measured value */ public double weightedSum(double[] weights) { long numElements = region.size(); if (numElements != weights.length) throw new IllegalArgumentException("number of weights does not equal number of samples"); T tmp = func.createOutput(); double sum = 0; int i = 0; iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); double value = tmp.getRealDouble(); sum += weights[i++] * value; } return sum; }
/** * Computes the center of mass point of the current region of the current function. Returns it as * a pair of Doubles. The first element in the pair is the x component and the second element is * the y component. * * @return The measured point stored in a Tuple2 */ public Tuple2<Double, Double> centerOfMassXY() { T tmp = func.createOutput(); double sumV = 0; double sumX = 0; double sumY = 0; iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); double v = tmp.getRealDouble(); sumV += v; sumX += v * pos[0]; sumY += v * pos[1]; } double cx = (sumX / sumV) + 0.5; double cy = (sumY / sumV) + 0.5; return new Tuple2<Double, Double>(cx, cy); }
@Override public void run() { if (!threshSrv.hasThreshold(input)) { cancel("This command requires a thresholded image."); return; } ThresholdOverlay thresh = threshSrv.getThreshold(input); PointSetIterator iter = thresh.getPointsWithin().iterator(); if (!iter.hasNext()) { cancel("No pixels are within the threshold"); return; } Dataset ds = dispSrv.getActiveDataset(input); final int numDims = ds.numDimensions(); final long[] dimensions = new long[numDims]; final long[] min = new long[numDims]; /* * First pass - find minima and maxima so we can use a shrunken image in some cases. */ for (int i = 0; i < numDims; i++) { min[i] = (long) Math.floor(thresh.realMin(i)); dimensions[i] = (long) Math.floor(thresh.realMax(i) - thresh.realMin(i) + 1); } final ArrayImg<BitType, BitArray> arrayMask = new ArrayImgFactory<BitType>().createBitInstance(dimensions, 1); final BitType t = new BitType(arrayMask); arrayMask.setLinkedType(t); final Img<BitType> mask = new ImgTranslationAdapter<BitType, ArrayImg<BitType, BitArray>>(arrayMask, min); final RandomAccess<BitType> raMask = mask.randomAccess(); iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); raMask.setPosition(pos); raMask.get().set(true); } output = new BinaryMaskOverlay(context, new BinaryMaskRegionOfInterest<BitType, Img<BitType>>(mask)); output.setAlpha(alpha); output.setFillColor(color); for (int i = 0; i < numDims; i++) { output.setAxis(ds.getImgPlus().axis(i), i); } }
/** * Computes the (biased) skew value upon the current region of the current function. * * @return The measured value */ public double populationSkew() { T tmp = func.createOutput(); double xbar = arithmeticMean(); double s2 = 0; double s3 = 0; long numElements = 0; iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); double value = tmp.getRealDouble(); numElements++; double v = value - xbar; double v2 = v * v; double v3 = v2 * v; s2 += v2; s3 += v3; } double n = numElements; double m2 = s2 / n; double m3 = s3 / n; return m3 / Math.pow(m2, 1.5); }
/** * Computes the (biased) kurtosis value upon the current region of the current function. * * @return The measured value */ public double populationKurtosis() { T tmp = func.createOutput(); double xbar = arithmeticMean(); double s2 = 0; double s4 = 0; long numElements = 0; iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); double value = tmp.getRealDouble(); numElements++; double v = value - xbar; double v2 = v * v; double v4 = v2 * v2; s2 += v2; s4 += v4; } double n = numElements; double m2 = s2 / n; double m4 = s4 / n; return m4 / (m2 * m2); }
/** * Computes the median upon the current region of the current function. Note that this method uses * memory to make a copy of the input values. Larger input regions might require a lot of memory. * * @return The measured value */ public double median() { T tmp = func.createOutput(); values.clear(); iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); values.add(tmp.getRealDouble()); } final int numElements = values.size(); if (numElements <= 0) throw new IllegalArgumentException("number of samples must be greater than 0"); values.sortValues(); // odd number of elements if ((numElements % 2) == 1) return values.get(numElements / 2); // else an even number of elements double value1 = values.get((numElements / 2) - 1); double value2 = values.get((numElements / 2)); return (value1 + value2) / 2; }