niblack thresholding
Asked Answered
I

3

3

I am trying to implement the niblack thresholding algorithm which uses the formula:

pixel = ( pixel >  mean + k * standard_deviation ) ? object : background

where k has standard value 0. Could someone please tell me how to implement this in matlab? I cant figure out how to do it

Interplanetary answered 26/3, 2012 at 11:14 Comment(0)
C
5

The power of Matlab is matrix operations, so you can do a lot without a single for-loop. The code below does what you need.

% define parameters
imgname = 'rice.png'; % matlab's image
filt_radius = 25; % filter radius [pixels]
k_threshold = 0.2; % std threshold parameter
%% load the image
X = double(imread(imgname)); 
X = X / max(X(:)); % normalyze to [0, 1] range
%% build filter
fgrid = -filt_radius : filt_radius;
[x, y] = meshgrid(fgrid);
filt = sqrt(x .^ 2 + y .^ 2) <= filt_radius;
filt = filt / sum(filt(:));
%% calculate mean, and std
local_mean = imfilter(X, filt, 'symmetric');
local_std = sqrt(imfilter(X .^ 2, filt, 'symmetric'));
%% calculate binary image
X_bin = X >= (local_mean + k_threshold * local_std);
%% plot
figure; ax = zeros(4,1);
ax(1) = subplot(2,2,1); imshow(X); title('original image');
ax(2) = subplot(2,2,2); imshow(X_bin); title('binary image');
ax(3) = subplot(2,2,3); imshow(local_mean); title('local mean');
ax(4) = subplot(2,2,4); imshow(local_std); title('local std');
linkaxes(ax, 'xy');

enter image description here

Costive answered 27/3, 2012 at 14:34 Comment(1)
Are you sure about the image for local std? I tried testing my own implementation done in Java with the grayscale image you provided and the results are quite different. It looks like our std is the same as the mean?Millhon
P
3

I would like to say upfront it is not Niblack algorithm but rather an implementation that gives better result. I don't know where this implementation will fail but I tried to binarize the above image and the result is as below.

Binarized grains

I divided the image up into 25*25 pixels block and then used a global set mean of 90 and global set mean of 20. And then applied Otsu's binarization on small windows.

set_mean = 90
set_sd = 20
mean_block = np.mean(block)
sd_block = np.std(block)
if sd_block > set_sd:
    ret, block = cv2.threshold(block, 0, 255, cv2.THRESH_OTSU)
elif sd_block < set_sd:
    if mean_block > set_mean:
        block[:] = 255 #white
    else:
        block[:] = 0 #black
return block

If the small window's standard deviation(SD) is greater than the set one, then otsu's thresholding is used, else based on whether the mean is greater or smaller than set mean, the pixels in the window are set to complete black or white.

Potentate answered 27/7, 2014 at 5:57 Comment(2)
It would be quite handy to also include the code that splits the larger image into blocks. Any chance you could add that, please?Carboloy
Here is a link see the img_divide function for dividing the image up. It is not an efficient code, I must add.Potentate
C
0

You can process the whole image: Assuming you have three matrices: img_in, object, background

flag = img_in >  mean + k * standard_deviation;
img_out = flag .* object + (1 - flag) .* background;
Costive answered 26/3, 2012 at 11:46 Comment(2)
It is very unclear from your description what you intend to do. Please specify your input, and desired output.Costive
i take a document image and after converting it to grayscale i try to implement this thresholding algorithm. But I dont know how to implement it to each pixel individually so the final result is a binarized image in which the text gets separated from the background .Could you please tell me how to do that??Interplanetary

© 2022 - 2024 — McMap. All rights reserved.