Otsu's method

From Wikipedia, the free encyclopedia
Jump to navigation Jump to search
An example image thresholded using Otsu's algorithm
Original image

In computer vision and image processing, Otsu's method, named after Nobuyuki Otsu (大津展之, Ōtsu Nobuyuki), is used to perform automatic image thresholding.[1] In the simplest form, the algorithm returns a single intensity threshold that separate pixels into two classes – foreground and background. This threshold is determined by minimizing intra-class intensity variance, or equivalently, by maximizing inter-class variance.[2]

Otsu's method is a one-dimensional discrete analogue of Fisher's discriminant analysis, is related to Jenks optimization method, and is equivalent to a globally optimal k-means[3] performed on the intensity histogram. The extension to multi-level thresholding was described in the original paper,[2] and computationally efficient implementations have since been proposed.[4][5]

Otsu's method

[edit | edit source]
Otsu's method visualization

Let, H be the normalised histogram of the pixels in an image (s.t. it becomes the probability distribution of pixel intensities) with L bins. There are two classes of this histogram: C0 for background pixels, and C1 for foreground pixels. The primary disciminator of pixels (to assort them into classes) is the threshold t. C0 includes pixels from 0 to (t1), and C1 includes from t to (L1).

The algorithm is then global search for an optimal threshold t* such that intra-class variance (variance of pixels intensities in C0 or C1) is minimised.

Let, ω0 denote the cumulative probability of C0, and ω1denote of C1.ω0(t)=i=0t1P(i),ω1(t)=i=tL1P(i).For a classes C0 and C1, the conditional probability of selecting the i-th pixel in those classes is P(i|C0) and P(i|C1) respectively.

Now, let μ0(t) and μ1(t) be the mean (pixel intensity) of C0 and C1 respectively.

μ0(t)=i=0t1iP(i|C0)=i=0t1iP(i)ω0(t)=i=0t1iP(i)ω0(t).

Similarly,

μ1(t)=i=tL1iP(i)ω1(t).

Now, let σ02(t) and σ12(t) be the (pixel intensity) variance of C0 and C1 respectively.

σ02(t)=i=0t1(iμ0)2P(i|C0)=i=0t1(iμ0)2P(i)ω0=i=0t1(iμ0)2P(i)ω0(t).

Similarly,

σ12(t)=i=tL1(iμ1)2P(i)ω1(t).

Let, σb2(t) be the inter-class (pixel intensity) variance, which is defined as the weighted sum of variances of aforementioned two classes.

σb2(t)=σT2[ω0(t)σ02(t)+ω1(t)σ12(t)]=ω0(μ0μT)2+w1(μ1μT)2=ω0ω1(μ0μ1)2.

Where, σT2(t) variance of the total histogram.

Proof

Considering ω0+ω1=1 and ω0μ0+ω1μ1=μT, we can prove the following.

σb2(t)=ω0(μ0μT)2+w1(μ1μT)2=ω0μ02+ω1μ122μT(ω0μ0+ω1μ1)+μT2(ω0+ω1)=ω0μ02+ω1μ122μT2+μT2=ω0μ02+ω1μ12μT2=ω0μ02+ω1μ12(ω0μ0+ω1μ1)2=ω0μ02ω02μ02+ω1μ12ω12μ122ω0μ0ω1μ1=ω0μ02(1ω0)+ω1μ12(1ω1)2ω0μ0ω1μ1=ω0μ02(1ω0)ω0μ0ω1μ1+ω1μ12(1ω1)ω0μ0ω1μ1=ω0ω1μ02ω0ω1μ0μ1+ω0ω1μ12ω0ω1μ0μ1=ω0ω1(μ02μ0μ1)+ω0ω1(μ12μ0μ1)=ω0ω1(μ022μ0μ1+μ12)=ω0ω1(μ0μ1)2.

The algorithm is now to maximise σb2(t), i.e. inter-class variance. This standpoint is motivated by a conjecture that well-thresholded classes would be separated in pixel intensities, and conversely a threshold t* giving the best separation of classes in pixel intensities would be the best threshold.

Formally, this problem is summarised as the following.

σb2(t*)=max0<t<Lσb2(t)

Algorithm

[edit | edit source]
  1. Compute histogram and probabilities of each intensity level.
  2. Set up initial ω0(0), μ0(0) and ω1(0) and μ1(0).
  3. Step through all possible thresholds from t=1 to maximum intensity.
    1. Update ω0(0), μ0(0) and ω1(0) and μ1(0).
    2. Compute σb2(t).
  4. Desired threshold t* corresponds to the maximum σb2(t).

MATLAB implementation

[edit | edit source]

histogramCounts is a 256-element histogram of a grayscale image different gray-levels (typical for 8-bit images). level is the threshold for the image (double).

function level = otsu(histogramCounts)
total = sum(histogramCounts); % total number of pixels in the image 
%% OTSU automatic thresholding
top = 256;
sumB = 0;
wB = 0;
maximum = 0.0;
sum1 = dot(0:top-1, histogramCounts);
for ii = 1:top
    wF = total - wB;
    if wB > 0 && wF > 0
        mF = (sum1 - sumB) / wF;
        val = wB * wF * ((sumB / wB) - mF) * ((sumB / wB) - mF);
        if ( val >= maximum )
            level = ii;
            maximum = val;
        end
    end
    wB = wB + histogramCounts(ii);
    sumB = sumB + (ii-1) * histogramCounts(ii);
end
end

Matlab has built-in functions graythresh() and multithresh() in the Image Processing Toolbox, which are implemented with Otsu's method and multi-Otsu's method respectively.

Python implementation

[edit | edit source]

This implementation requires the NumPy library.

import numpy as np


def otsu_intraclass_variance(image, threshold):
    """
    Otsu's intra-class variance.
    If all pixels are above or below the threshold, this will throw a warning that can safely be ignored.
    """
    return np.nansum(
        [
            np.mean(cls) * np.var(image, where=cls)
            #   weight   ·  intra-class variance
            for cls in [image >= threshold, image < threshold]
        ]
    )
    # NaNs only arise if the class is empty, in which case the contribution should be zero, which `nansum` accomplishes.


# Random image for demonstration:
image = np.random.randint(2, 253, size=(50, 50))

otsu_threshold = min(
    range(np.min(image) + 1, np.max(image)),
    key=lambda th: otsu_intraclass_variance(image, th),
)

Python libraries dedicated to image processing such as OpenCV and Scikit-image provide built-in implementations of the algorithm.

Limitations and variations

[edit | edit source]

Otsu's method performs well when the histogram has a bimodal distribution with a deep and sharp valley between the two peaks.[6]

Like all other global thresholding methods, Otsu's method performs badly in case of heavy noise, small objects size, inhomogeneous lighting and larger intra-class than inter-class variance.[7] In those cases, local adaptations of the Otsu method have been developed.[8]

Moreover, the mathematical grounding of Otsu's method models the histogram of the image as a mixture of two normal distributions with equal variance and equal size.[9] However, Otsu's thresholding may yield satisfying results even when these assumptions are not met, in the same way statistical tests (to which Otsu's method is heavily connected[10]) can perform correctly even when the working assumptions are not fully satisfied.

Several variations of Otsu's methods have been proposed to account for more severe deviations from these assumptions,[9] such as the Kittler–Illingworth method.[11]

A variation for noisy images

[edit | edit source]

A popular local adaptation is the two-dimensional Otsu's method, which performs better for the object segmentation task in noisy images. Here, the intensity value of a given pixel is compared with the average intensity of its immediate neighborhood to improve segmentation results.[8]

At each pixel, the average gray-level value of the neighborhood is calculated. Let the gray level of the given pixel be divided into L discrete values, and the average gray level is also divided into the same L values. Then a pair is formed: the pixel gray level and the average of the neighborhood (i,j). Each pair belongs to one of the L×L possible 2-dimensional bins. The total number of occurrences (frequency) fij of a pair (i,j), divided by the total number of pixels in the image N, defines the joint probability mass function in a 2-dimensional histogram: Pij=fijN,i=0L1j=0L1Pij=1.

And the 2-dimensional Otsu's method is developed based on the 2-dimensional histogram as follows.

The probabilities of two classes can be denoted as ω0=i=0s1j=0t1Pij,ω1=i=sL1j=tL1Pij.

The intensity mean-value vectors of two classes and total mean vector can be expressed as follows: μ0=[μ0i,μ0j]T=[i=0s1j=0t1iPijω0,i=0s1j=0t1jPijω0]T,μ1=[μ1i,μ1j]T=[i=sL1j=tL1iPijω1,i=sL1j=tL1jPijω1]T,μT=[μTi,μTj]T=[i=0L1j=0L1iPij,i=0L1j=0L1jPij]T.

In most cases the probability off-diagonal will be negligible, so it is easy to verify ω0+ω11, ω0μ0+ω1μ1μT.

The inter-class discrete matrix is defined as Sb=k=01ωk[(μkμT)(μkμT)T].

The trace of the discrete matrix can be expressed as tr(Sb)=ω0[(μ0iμTi)2+(μ0jμTj)2]+ω1[(μ1iμTi)2+(μ1jμTj)2]=(μTiω0μi)2+(μTjω0μj)2ω0(1ω0), where μi=i=0s1j=0t1iPij, μj=i=0s1j=0t1jPij.

Similar to one-dimensional Otsu's method, the optimal threshold (s,t) is obtained by maximizing tr(Sb).

Algorithm

[edit | edit source]

The s and t is obtained iteratively, which is similar with one-dimensional Otsu's method. The values of s and t are changed till we obtain the maximum of tr(Sb), that is

max, s, t = 0;

for ss: 0 to L - 1 do
    for tt: 0 to L - 1 do
        evaluate tr(S_b);
        if tr(S_b) > max
            max = tr(S, b);
            s = ss;
            t = tt;
        end if
    end for
end for

return s, t;

Notice that for evaluating tr(Sb), we can use a fast recursive dynamic programming algorithm to improve time performance.[12] However, even with the dynamic programming approach, 2D Otsu's method still has large time complexity. Therefore, much research has been done to reduce the computation cost.[13]

If summed area tables are used to build the 3 tables – sum over Pij, sum over iPij, and sum over jPij – then the runtime complexity is max(O(Npixels),O(Nbins2)). Note that if only coarse resolution is needed in terms of threshold, Nbins can be reduced.

MATLAB implementation

[edit | edit source]

Function inputs and output:

hists is a 256×256 2D histogram of grayscale value and neighborhood average grayscale value pair.
total is the number of pairs in the given image, determined by the number of the bins of 2D histogram at each direction.
threshold is the threshold obtained.
function threshold = otsu_2D(hists, total)
maximum = 0.0;
threshold = 0;
helperVec = 0:255;
mu_t0 = sum(sum(repmat(helperVec',1,256).*hists));
mu_t1 = sum(sum(repmat(helperVec,256,1).*hists));
p_0 = zeros(256);
mu_i = p_0;
mu_j = p_0;
for ii = 1:256
    for jj = 1:256
        if jj == 1
            if ii == 1
                p_0(1,1) = hists(1,1);
            else
                p_0(ii,1) = p_0(ii-1,1) + hists(ii,1);
                mu_i(ii,1) = mu_i(ii-1,1)+(ii-1)*hists(ii,1);
                mu_j(ii,1) = mu_j(ii-1,1);
            end
        else
            p_0(ii,jj) = p_0(ii,jj-1)+p_0(ii-1,jj)-p_0(ii-1,jj-1)+hists(ii,jj); % THERE IS A BUG HERE. INDICES IN MATLAB MUST BE HIGHER THAN 0. ii-1 is not valid
            mu_i(ii,jj) = mu_i(ii,jj-1)+mu_i(ii-1,jj)-mu_i(ii-1,jj-1)+(ii-1)*hists(ii,jj);
            mu_j(ii,jj) = mu_j(ii,jj-1)+mu_j(ii-1,jj)-mu_j(ii-1,jj-1)+(jj-1)*hists(ii,jj);
        end

        if (p_0(ii,jj) == 0)
            continue;
        end
        if (p_0(ii,jj) == total)
            break;
        end
        tr = ((mu_i(ii,jj)-p_0(ii,jj)*mu_t0)^2 + (mu_j(ii,jj)-p_0(ii,jj)*mu_t1)^2)/(p_0(ii,jj)*(1-p_0(ii,jj)));

        if ( tr >= maximum )
            threshold = ii;
            maximum = tr;
        end
    end
end
end

A variation for unbalanced images

[edit | edit source]

When the levels of gray of the classes of the image can be considered as normal distributions but with unequal size and/or unequal variances, assumptions for the Otsu algorithm are not met. The Kittler–Illingworth algorithm (also known as "minimum-error thresholding")[11] is a variation of Otsu's method to handle such cases. There are several ways to mathematically describe this algorithm. One of them is to consider that for each threshold being tested, the parameters of the normal distributions in the resulting binary image are estimated by maximum likelihood estimation given the data.[9]

While this algorithm could seem superior to Otsu's method, it introduces nuisance parameters to be estimated, and this can result in the algorithm being over-parametrized and thus unstable. In many cases where the assumptions from Otsu's method seem at least partially valid, it may be preferable to favor Otsu's method over the Kittler–Illingworth algorithm, following Occam's razor.[9]

Triclass thresholding tentatively divides histogram of an image into three classes, with the TBD class to be processed at next iterations.

Iterative triclass thresholding based on the Otsu's method

[edit | edit source]

One limitation of the Otsu’s method is that it cannot segment weak objects, as the method searches for a single threshold to separate an image into two classes, namely, foreground and background, in one shot. Because the Otsu’s method looks to segment an image with one threshold, it tends to bias toward the class with the large variance.[14] Iterative triclass thresholding algorithm is a variation of the Otsu’s method to circumvent this limitation.[15] Given an image, at the first iteration, the triclass thresholding algorithm calculates a threshold η1 using the Otsu’s method. Based on threshold η1, the algorithm calculates mean μupper[1] of pixels above η1 and mean μlower[1] of pixels below η1. Then the algorithm tentatively separates the image into three classes (hence the name triclass), with the pixels above the upper mean μupper[1] designated as the temporary foreground F class and pixels below the lower mean μlower[1] designated as the temporary background B class. Pixels fall between [μlower[1],μupper[1]] are denoted as a to-be-determined (TBD) region. This completes the first iteration of the algorithm. For the second iteration, the Otsu’s method is applied to the TBD region only to obtain a new threshold η2. The algorithm then calculates the mean μupper[2] of pixels in the TBD region that are above η2 and the mean μlower[2] of pixels in the TBD region that are below η2. Pixels in the TBD region that are greater than the upper mean μupper[2] are added to the temporary foreground F. And pixels in the TBD region that are less than the lower mean μlower[2] are added to the temporary background B. Similarly, a new TBD region is obtained, which contains all the pixels falling between [μlower[2],μupper[2]]. This completes the second iteration. The algorithm then proceeds to the next iteration to process the new TBD region until it meets the stopping criterion. The criterion is that, when the difference between Otsu’s thresholds computed from two consecutive iterations is less than a small number, the iteration shall stop. For the last iteration, pixels above ηn are assigned to the foreground class, and pixels below the threshold are assigned to the background class. At the end, all the temporary foreground pixels are combined to constitute the final foreground. All the temporary background pixels are combined to become the final background. In implementation, the algorithm involves no parameter except for the stopping criterion in terminating the iterations. By iteratively applying the Otsu’s method and gradually shrinking the TBD region for segmentation, the algorithm can obtain a result that preserves weak objects better than the standard Otsu’s method does.

References

[edit | edit source]
  1. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  2. ^ a b Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  3. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  4. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  5. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  6. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  7. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  8. ^ a b Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  9. ^ a b c d Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  10. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  11. ^ a b Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  12. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  13. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  14. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  15. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
[edit | edit source]