When the number of thresholds is set to 1 for the
OtsuMultipleThresholdsCalculator, the computed threshold should be the
same as the computed threshold of OtsuThresholdCalculator. However,
there were a number of discrepancies between the implementations of
the two algorithms leading to different computed thresholds. The
equations used for the two filters are different because the Otsu uses
a simplified mathematical representation that only holds when there is
one threshold, but I have derived the equations and confirmed that
they lead to the same mathematical representation. The discrepancies
have now been corrected (details below), and the algorithms now report
the same threshold.
Because the computed threshold values are slightly different from
before, I updated the regression images to reflect the new changes.
Also, I added a new test that compares the thresholds computed by the
two algorithms for a range of histogram bins.
The OtsuMultipleThresholdsCalculator and HistogramAlgorithmBase have
been corrected to change the GenerateData() method to Compute() and to
make the Update() method simply return Compute(). These classes do
not inherit from ProcessObject, so they are not part of the pipeline
and should therefore not have an Update() method. The Update() method
is now marked as deprecated and surrounded by an
ITK_FUTURE_LEGACY_REMOVE preprocessor directive.
More details on the Otsu computation changes are below:
For all of the tests, I used the 8-bit image
ExternalData/Testing/Data/Input/cthead1.png. For each code line
below, the original line is shown with a "-" first, and the new line
is shown with a "+" first. All of the comments are about the Otsu
because the MultipleOtsu is implemented more accurately.
In Otsu, the global mean was being computed incorrectly. The original
and corrected code are as follows:
- totalMean += ( j + 1 ) * relativeFrequency[j];
+ totalMean += j * relativeFrequency[j];
The initial left mean was being computed incorrectly. By mathematical
definition, when the leftMean is computed from only the first bin of
the histogram, it is equal to the bin value itself.
- double meanLeft = 1.0;
+ double meanLeft = 0.0;
The left mean was computed incorrectly in the loop.
- + ( j + 1 ) * relativeFrequency[j] ) / freqLeft;
+ + j * relativeFrequency[j] ) / freqLeft;
The offset of 1 was incorrect in the GetMeasurement call.
- this->GetOutput()->Set( static_cast<OutputType>(
histogram->GetMeasurement( maxBinNumber + 1, 0 ) ) );
+ this->GetOutput()->Set( static_cast<OutputType>(
histogram->GetMeasurement( maxBinNumber, 0 ) ) );
Finally, there is a discrepancy in that Otsu uses GetMeasurement (as
shown above), but OtsuMultiple uses GetBinMax to get the final
threshold. The difference is that GetMeasurement is the average of
GetBinMax and GetBinMin. When the number of bins is large, this makes
almost no difference because the GetBinMin and GetBinMax are almost
the same. But for small numbers of bins, the GetMeasurement is more
stable. Here are some example results:
Bins: 4,8,16,32,64,128,256,512,1024
GetBinMin: 63.91, 63.83, 63.79, 79.71, 79.70, 81.69, 83.68,
83.67, 83.92
GetBinMax: 127.82, 95.74, 79.74, 87.68, 83.68, 83.68, 84.67,
84.17, 84.17
GetMeasurement: 95.86, 79.79, 71.76, 83.70, 81.69, 82.68, 84.17,
83.92, 84.05
The threshold results are as follows for different number of bins:
Bins: 4,8,16,32,64,128,256,512,1024
Old Otsu threshold: 159.77, 111.70, 87.71, 91.67, 85.68, 84.67, 85.17,
84.42, 84.30
New threshold: 95.86, 79.79, 71.76, 83.70, 81.69, 82.68, 84.17,
83.92, 84.05
The ImageJ Otsu plugin
(http://rsbweb.nih.gov/ij/plugins/otsu-thresholding.html) outputs a
threshold of 79.
The ImageJ MultipleOtsu plugin
(http://rsbweb.nih.gov/ij/plugins/multi-otsu-threshold.html) with 1
threshold outputs a threshold of 87.
Using Matlab, I get 84.
So they are not consistent, but they are all close.
Change-Id: Ic144200390e6c983c113e0655aea56713d3c17bd

changed **18 files**
with **176 additions**
and **40 deletions**.