Implementing Otsu's Method Using MATLAB/Python
Abstract
The Otsu's method[1] was proposed in 1979, which segmented images by maximizing variance between classes. In other words, the Otsu's method is a nonparametric segmentation method that divides an image into different regions based on the intensity of the pixels. This article will introduce the Otsu's method in two sections. First, we will understand the principles of the Otsu's method by reviewing the mathematical formulas in the literature. Finally, we will implement the details using Matlab/Python.
Formula[2]
Assume that is the pixel intensity levels of an image which has size of :
where indicates the total number of image pixels, is the number of pixels for intensity level , and probability distribution of all intensity levels is represented by .
Assume there is a threshold , in which th is between and , then the image can be divided into two classes according to . The first class, , contains all pixels with pixel intensity levels between ~ , while contains the rest of the pixels.
where and represent the cumulative probability distributions for and , respectively.
where and indicate the mean intensity levels for and , respectively. denotes the mean intensity level from to . represents the mean intensity level for the whole image. Hence, the objective function of the maximizing variance between classes can be expressed as below:
Based on the above formula, we can find a in the range of ~ to maximize to achieve a effective image segmentation.
Code
function fit = otsu(N, level, x, prob)
fit = zeros(1, N);
for j = 1:N
fit(j) = sum(prob(1:x(j, 1) - 1)) * (sum((1:x(j, 1) - 1) .* ...
prob(1:x(j, 1) - 1) / sum(prob(1:x(j, 1) - 1))) - ...
sum((1:255) .* prob(1:255)) ) ^ 2;
for jlevel = 2:level - 1
fit(j) = fit(j) + sum(prob(x(j, jlevel - 1):x(j, jlevel) - 1)) * ...
(sum((x(j, jlevel - 1):x(j, jlevel) - 1) .* ...
prob(x(j, jlevel - 1):x(j, jlevel) - 1) / ...
sum(prob(x(j, jlevel - 1):x(j, jlevel) - 1))) - ...
sum((1:255) .* prob(1:255))) ^ 2;
end
fit(j) = fit(j) + sum(prob(x(j, level - 1):255)) * ...
(sum((x(j, level - 1):255) .* prob(x(j, level - 1):255) / ...
sum(prob(x(j, level - 1):255))) - sum((1:255) .* prob(1:255))) ^ 2;
if isnan(fit(j)) || isinf(fit(j))
fit(j) = eps;
end
end
fit = fit';
end
import numpy as np
from typing import List, Tuple
def otsu(N: int, level: int, x: np.ndarray, prob: np.ndarray) -> np.ndarray:
fit = np.zeros(N)
total_mean = np.sum(np.arange(256) * prob[:256])
for j in range(N):
fit[j] = 0
thresholds = [0] + x[j, :].tolist() + [256]
for i in range(1, len(thresholds)):
start, end = thresholds[i-1], thresholds[i]
local_prob = prob[start:end]
if np.sum(local_prob) == 0:
continue
local_mean = np.sum(np.arange(start, end) * local_prob) / np.sum(local_prob)
fit[j] += np.sum(local_prob) * (local_mean - total_mean) ** 2
if np.isnan(fit[j]) or np.isinf(fit[j]):
fit[j] = np.finfo(float).eps
return fit
References
Otsu, N. A threshold selection method from gray-level histograms. IEEE transactions on systems, 9, 62-66 (1979). ↩︎
Wang, Z., Mo, Y. & Cui, M. An Efficient Multilevel Threshold Image Segmentation Method for COVID-19 Imaging Using Q-Learning Based Golden Jackal Optimization. J Bionic Eng, 20, 2276–2316 (2023). ↩︎