Histogram Thresholding

Histogram thresholding is a classical image segmentation algorithm. The idea is pretty straightforward. We set an intensity threshold in between the background and intersted tissues (foreground) to segement tissues from the image.

  • Decide a threshold (based on the histogram). Then for all pixels in the image, label as class 1 or class 0 if greater or less than the threshold

Ostu Thresholding

Basic global histogram thresholding algorithm. Ostu assumes that distribution characteristics for foreground and background are approximately equal, except for their means.

Assumptions:

  • Histogram(andtheimage)are bimodal.

  • No use of spatial coherence.

  • Assumes uniform illumination, so the bimodal brightness behavior arises from object appearance differences only.

Find the threshold that minimizes the weighted within-class variance == maximizes the between-class variance

The within-class variance is calculated as follows: σW2=Wbσb2+Wfσf2\sigma_W^2=W_b\sigma_b^2+W_f\sigma_f^2,

WbW_b is the weight, μb\mu_b is the mean, σb2\sigma_b^2 is the variance for background;

WfW_f is the weight, μf\mu_f is the mean, σf2\sigma_f^2 is the variance for foreground.

Ostu visualization (adapted from Wikipedia)

Given a histogram with nn bins, for 1in1\leq i \leq n, we select the left ii bins as background (it doesn't matter we call it background or foreground, the idea is we select these a group), and the remaining nin-i bins as foreground, then to calculate within-class variance.

% img is the input image, inten_hist is the intensity histogram of img
function [img]=OstuThresholding(img, inten_hist)
number=inten_hist.NumBins;
temp_var=Inf;
temp_T=-1;
for i=1:number-1
    % calculate the weight
    weight_one=sum(inten_hist.Values(1:i),"all");
    weight_two=sum(inten_hist.Values(i+1:number),"all");
    % calculate the mean
    mean_one=sum(inten_hist.Values(1:i).*linspace(1,i,i)./weight_one,"all");
    mean_two=sum(inten_hist.Values(i+1:number).*linspace(i+1,number,number-i)./weight_two,"all");
    % calculate the variance
    variance_one=sum((linspace(1,i,i)-mean_one).^2.*inten_hist.Values(1:i)./weight_one,"all");
    variance_two=sum((linspace(i+1,number,number-i)-mean_two).^2.*inten_hist.Values(i+1:number)./weight_two,"all");
    w_one=mean(inten_hist.Values(1:i));
    w_two=mean(inten_hist.Values(i+1:number));
    % calculate the within-class variance
    withinclass_var=w_one*variance_one+w_two*variance_two;
    if withinclass_var<temp_var
        temp_var=withinclass_var;
        temp_T=i;
    end
end
% set the threshold
ostu_bar=inten_hist.BinEdges(temp_T+1);
% segment the image based on ostu threshold
img(img<ostu_bar)=0;
img(img>=ostu_bar)=1;
Input Image

In this demo, Ostu thresholding performs well and segment the tissue from the background successfully.

However, Ostu thresholding has several disadvantages such as only consider the intensity and does not consider any relationships between pixels, choose one fix threshold for the whole image, etc. Therefore, there are serveral variation thresholding techniques trying to resolve some of these problems: Adaptive thresholding, HSV Segmentation.

Last updated