two-dimensional Otsu's method
3 views (last 30 days)
Show older comments
I am trying to implement 2D Otsu segmentation method, but i am facing problem in my code. in 2D otsu the gray-level value of each pixel as well as the average value of its immediate neighborhood is studied so that the binarization results are greatly improved. I am attaching code,but it is not working and also hyperlink http://en.wikipedia.org/wiki/Otsu%27s_method
function inputs and output:
%hists is a 256\times 256 2D-histogram of grayscale value and neighborhood average grayscale value pair.
%total is the number of pairs in the given image.
%threshold is the threshold obtained.
function threshold = 2D_otsu(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);
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_t0)^2)/(p_0(ii,jj)*(1-p_0(ii,jj)));
if ( tr >= maximum )
threshold = ii;
maximum = tr;
end
end
end
3 Comments
Prabhu Bevinamarad
on 13 Nov 2020
Hi,
I am new to Matlab. I wanted to apply two-dimensional Otsu's method for thresholding. I am not getting how to find hists i.e. 2D-histogram of grayscale value and neighborhood average grayscale value pair and total is the number of pairs in the given image which are passed as a parameters for otsu_2D function.Can anybody suggest which functions are used.
Thank you
Accepted Answer
Geoff Hayes
on 29 Jan 2016
pramod - the error message is telling you that the code is trying to access an element within your matrix using an index that is zero. I realize that you are considering the neighbourhood surrounding each cell within your 256x256 matrix, but your code will have to account for the edge cases when subtracting one from the index leads to a zero which "falls" outside of your matrix. You will have to guard against this code as follows
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
% here is the new code ***** guard against ii==1
if ii==1
p_0(ii,jj) = p_0(ii,jj-1)+hists(ii,jj);
mu_i(ii,jj) = mu_i(ii,jj-1)+(ii-1)*hists(ii,jj);
mu_j(ii,jj) = mu_j(ii,jj-1)+(jj-1)*hists(ii,jj);
else
p_0(ii,jj) = p_0(ii,jj-1)+p_0(ii-1,jj)-p_0(ii-1,jj-1)+hists(ii,jj);
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
end
I don't know for sure if the above is correct but it will guard against the case where jj is greater than one and ii is equal to one (the pattern is similar to what is already there for the case where jj is one and ii is one). A note should be added to the Wikipedia article indicating that there is a bug with the code.
ImageAnalyst would have a better idea as to whether the above makes sense or not.
And, rather than posting a binary zip file which some of us may be reluctant to open, just attach each file individually (since there are just three).
10 Comments
Image Analyst
on 13 Nov 2020
No idea what this means exactly but as far as I can tell, it's this:
% Read in input image f(x,y) with L = 256 gray levels:
fxy = imread('cameraman.tif');
% No idea what "The local average gray level is also divided into the same L values" means,
% but to get an image where each pixel is the average in a square window around the pixel, do thi
windowWidth = 3; % Whatever you want.
kernel = ones(windowWidth, windowWidth) / windowWidth^2;
gxy = imfilter(fxy, kernel);
% Now get the total number of pixels in fxy and gxy:
total = numel(fxy)
Note that images are indexed fxy(y, x), which is fxy(row, column), and NOT as fxy(x, y).
But gxy is simply a blurred input image -- the local average. It is not a 2-D histogram. I'm wondering if he wants 256 histograms, one for the neighbors of each pixel (not including the pixel itself), like
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 18;
fprintf('Beginning to run %s.m ...\n', mfilename);
echo off;
%===============================================================================
% Get the name of the demo image the user wants to use.
% Let's let the user select from a list of all the demo images that ship with the Image Processing Toolbox.
folder = fileparts(which('cameraman.tif')); % Determine where demo folder is (works with all versions).
% Demo images have extensions of TIF, PNG, and JPG. Get a list of all of them.
imageFiles = [dir(fullfile(folder,'*.TIF')); dir(fullfile(folder,'*.PNG')); dir(fullfile(folder,'*.jpg'))];
for k = 1 : length(imageFiles)
% fprintf('%d: %s\n', k, files(k).name);
[~, baseFileName, extension] = fileparts(imageFiles(k).name);
ca{k} = [baseFileName, extension];
end
% Sort the base file names alphabetically.
[ca, sortOrder] = sort(ca);
imageFiles = imageFiles(sortOrder);
button = menu('Use which gray scale demo image?', ca); % Display all image file names in a popup menu.
% Get the base filename.
baseFileName = imageFiles(button).name; % Assign the one on the button that they clicked on.
% Get the full filename, with path prepended.
fullFileName = fullfile(folder, baseFileName);
grayImage = imread(fullFileName);
[rows, columns, numberOfColorChannels] = size(grayImage);
if numberOfColorChannels == 3
grayImage = rgb2gray(grayImage);
end
subplot(2, 1, 1);
imshow(grayImage);
caption = sprintf('Original gray scale image : %s', baseFileName);
title('Original gray scale image');
drawnow;
% Intantiate 2-D histogram
hist2d = zeros(256, 256);
for col = 2 : columns-1
fprintf('Processing column %d of original image...\n', col);
for row = 2 : rows-1
% Get 3x3 subimage, except for center pixel, so that's 8 pixels.
subImage = [grayImage(row-1, col-1);...
grayImage(row-1, col);...
grayImage(row-1, col+1);...
grayImage(row, col-1);...
grayImage(row, col+1);...
grayImage(row+1, col+1);...
grayImage(row+1, col+1);...
grayImage(row+1, col+1)];
% Get the gray levle of the center pixel
centerGL = grayImage(row, col) + 1; % Add 1 so we don't get 0 because matrices can't have a zeroeth row or column.
for k = 1 : length(subImage)
% Get this gray level
thisGL = subImage(k) + 1; % Add 1 so we don't get 0 because matrices can't have a zeroeth row or column.
% Increment the histogram at the column for the center pixel's gray level
hist2d(centerGL, thisGL) = hist2d(centerGL, thisGL) + 1;
end
end
end
% Display the 2-D histogram
subplot(2, 1, 2);
imshow(hist2d, [], 'Colormap', jet(256));
title('2D histogram');
colorbar

More Answers (1)
Harsha
on 4 Dec 2016
5 Comments
Image Analyst
on 23 Feb 2018
Madhava, I don't understand what you said.
MAS
on 5 Apr 2018
It works absolutely fine for two clusters. Any suggestions to update it for handling multi-level thresholding!?
See Also
Categories
Find more on Computer Vision with Simulink in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!