Ticket #1384 (closed enhancement: wontfix)
Opened 2012-08-10T18:35:13-05:00
Last modified 2013-12-06T17:45:59-06:00
Create ImageStatistics class
| Reported by: | aivar | Owned by: | aivar |
|---|---|---|---|
| Priority: | minor | Milestone: | imagej2-b8-analysis |
| Component: | ImgLib2 | Version: | |
| Severity: | minor | Keywords: | |
| Cc: | Blocked By: | ||
| Blocking: | #794 |
Description (last modified by aivar)
Need to get statistics on an image with the minimal number of passes through the image.
For example it might include methods:
request certain things ahead of time
doMinMax();
doHistogram(int bins);
[or doHistogram(int bins, double min, double max);]
doMean();
do minimal number of passes through the image
process();
get accumulated results
double[] getMinMax();
long[] getHistogram();
double getMean;
Here if you don't specify a min/max for doHistogram the code has to take an initial pass to get min/max then another to build the histogram using that min/max.
Change History
comment:6 Changed 2012-09-07T13:06:01-05:00 by aivar
- Blocking 1128 added; 1386 removed
- Milestone changed from imagej-2.0.0-beta4 to imagej-2.0.0-beta5
comment:8 Changed 2012-10-12T12:34:34-05:00 by bdezonia
I think using the MeasurmentService all this can be accomplished. We should discuss actual examples so we can try.
(Later edit: I may have misspoke. The MeasurementService is pretty simple. Users need to provide aggregating classes to reuse computations.)
comment:9 Changed 2012-10-12T13:28:18-05:00 by aivar
Here's some simplistic pseudo-code for the sort of approach I had in mind:
class MeanFunction extends AbstractBaseFunction {
double sum;
int count;
double mean;
@Override
preprocess() { // called before any pixel processing
sum = 0.0;
count = 0;
}
@Override
processPixel(T pixel) { // processes pixels one by one
sum += T.getRealDouble();
++count;
}
@Override
postprocess() { // called after all pixel processing
double mean = sum / count;
}
getMean() {
return mean;
}
}
class AbstractBaseFunction implements Function {
Function next;
@Override
chain(Function next) { // builds a chain of functions
this.next = next;
}
@Override
chainedPreprocess() { // preprocess the chain
preprocess();
if (null != next) {
next.chainedPreprocess();
}
@Override
chainedProcessPixel(T pixel) { // process pixel through the chain
processPixel(pixel);
if (null != next) {
next.chainedProcessPixel(pixel);
}
}
@Override
chainedPostprocess() { // postprocess the chain
postprocess();
if (null != next) {
next.postprocess();
}
}
abstract preprocess();
abstract postprocess();
abstract processPixel();
}
// usage
MeanFunction meanFunction = new MeanFunction();
MinMaxFunction minMaxFunction = new MinMaxFunction();
meanFunction.chain(minMaxFunction);
process(iterator, meanFunction);
System.out.println("Mean is " + meanFunction.getMean());
System.out.println("Min is " + minMaxFunction.getMin() + " max is " + minMaxFunction.getMax());
. . .
void process(PointSetIterator iterator, Function function) {
function.chainedPreprocess();
while (iterator.hasNext()) {
point = iterator.next();
function.chainedProcessPixel(point);
}
function.chainedPostprocess();
}
comment:10 Changed 2012-10-12T13:42:36-05:00 by aivar
This doesn't handle re-use of computations. Perhaps the chain could be a doubly-linked list, then in the preprocess( ) method you could look back up the chain for the Function you need results from (using a common helper method). Then in processPixel( ) you can call that Function's getters.
comment:11 Changed 2012-10-17T16:29:06-05:00 by curtis
I think this chaining approach is unnecessarily complex. If you have a computation (we'll call it a "module") that could benefit from the outputs of another module, there are a couple of ways of dealing with that to manage efficiency:
1) Create two modules, one that takes e.g. a Dataset and a Histogram, and computes results based on those.
2) Create one module that takes a required Dataset and an optional Histogram, and uses the Histogram results if present (or if not, just computes what is needed on the fly from the Dataset itself).
comment:12 Changed 2012-10-23T14:34:36-05:00 by bdezonia
I've implemented some ideas in the measure-engine branch of Imlib2.
Related fiji email available at: ( https://groups.google.com/forum/?fromgroups=#!topic/fiji-devel/AnYq_caJA1M)
Note that after posting my email dscho chimed in that the KNIME developers have a good start on a measurement engine that they will release to Imglib.
comment:13 Changed 2013-03-05T12:28:37-06:00 by bdezonia
- Blocking 1128 removed
(In #1128) I have been doing some work on this for our most recent beta on imglib's histogram-stuff branch. Soon I'll share with others and solicit feedback.
comment:14 Changed 2013-06-07T16:07:52-05:00 by bdezonia
- Milestone changed from imagej2-b7-ndim-data to imagej2-b8-analysis
comment:15 Changed 2013-12-06T17:45:59-06:00 by aivar
- Status changed from new to closed
- Resolution set to wontfix
My original motivation for the 'minimal number of passes' was based on the case of a huge image that is possibly paged in/out. Other situations might require other optimizations.