34
$\begingroup$

I'm trying to implement various binarization algorithms to the image shown: enter image description here

Here's the code:

clc;
clear;
x=imread('n2.jpg');     %load original image

% Now we resize the images so that computational work becomes easier later onwards for us.

size(x);
x=imresize(x,[500 800]);
figure;
imshow(x);
title('original image');

z=rgb2hsv(x);       %extract the value part of hsv plane
v=z(:,:,3);
v=imadjust(v);

%now we find the mean and standard deviation required for niblack and %sauvola algorithms

m = mean(v(:))
s=std(v(:))
k=-.4;
value=m+ k*s;
temp=v;

% implementing niblack thresholding algorithm:

for p=1:1:500
    for q=1:1:800
        pixel=temp(p,q);
        if(pixel>value)
            temp(p,q)=1;
        else
            temp(p,q)=0;
        end
    end
end
figure;
imshow(temp);
title('result by niblack');
k=kittlerMet(g);
figure;
imshow(k);
title('result by kittlerMet');

% implementing sauvola thresholding algorithm:

val2=m*(1+.1*((s/128)-1));
t2=v;
for p=1:1:500
for q=1:1:800
    pixel=t2(p,q);
    if(pixel>value)
        t2(p,q)=1;
    else
        t2(p,q)=0;
    end
end

end

figure;
imshow(t2);
title('result by sauvola');

The results I obtained are as shown: enter image description here enter image description here enter image description here

As you can see the resultant images are degraded at the darker spots.Could someone please suggest how to optimize my result??

$\endgroup$
2
  • 1
    $\begingroup$ Can you use color information to throw away the background instead of brightness only? $\endgroup$
    – endolith
    Commented Apr 5, 2012 at 16:02
  • $\begingroup$ Respected Sir/madam. I am doing project on image processing.i am interesting binarization concept..please check and correct the coding... I take the coding and run the program.But some error occur this coding... Undefined function or variable 'g'. and another one is Error in msp (line 31) k=kittlerMet(g);.. How to solve it... Please correct the coding... $\endgroup$
    – muthu
    Commented Mar 20, 2015 at 9:31

5 Answers 5

52
$\begingroup$

Your image doesn't have uniform brightness,so you shouldn't work with a uniform threshold. You need an adaptive threshold. This can be implemented by preprocessing the image to make the brightness more uniform across the image (code written in Mathematica, you'll have to implement the Matlab version for yourself):

A simple way to make the brightness uniform is to remove the actual text from the image using a closing filter:

white = Closing[src, DiskMatrix[5]]

enter image description here

The filter size should be chosen larger than the font stroke width and smaller than the size of the stains you're trying to remove.

EDIT: I was asked in the comments to explain what a closing operation does. It's a morphological dilation followed by a morphological erosion. The dilation essentially moves the structuring element at every position in the image, and picks the brightest pixel under the mask, thus :

  • removing dark structures smaller than the structuring element
  • shrinking larger dark structures by the size of the structuring element
  • enlarging bright structures

The erosion operation does the opposite (it picks the darkest pixel under inside the structuring element), so if you apply it on the dilated image:

  • the dark structures that were removed because they're smaller than the structuring element are still gone
  • the darker structures that were shrunk are enlarged again to their original size (though their shape will be smoother)
  • the bright structures are reduced to their original size

So the closing operation removes small dark objects with only minor changes to larger dark objects and bright objects.

Here's an example with different structuring element sizes:

enter image description here

As the size of the structuring element increases, more and more of the characters is removed. At radius=5, all of the characters are removed. If the radius is increased further, the smaller stains are removed, too:

enter image description here

Now you just divide the original image by this "white image" to get an image of (nearly) uniform brightness:

whiteAdjusted = Image[ImageData[src]/ImageData[white]*0.85]

enter image description here

This image can now be binarized with a constant threshold:

Binarize[whiteAdjusted , 0.6]

enter image description here

$\endgroup$
14
  • 5
    $\begingroup$ Wow! This is really cool! Huge +1! $\endgroup$
    – Phonon
    Commented Apr 4, 2012 at 14:03
  • $\begingroup$ @nikie +1 Very nice - what do you mean exactly by closing filter must be "chosen larger than the font stroke"? Width or length of any letter? Furthermore, what is a closing filter 'really' doing? Thanks! $\endgroup$
    – Spacey
    Commented Apr 4, 2012 at 16:02
  • 1
    $\begingroup$ @Mohammad: I've added a little explanation to my answer. And yes, these are non-linear operations. The common heading is morphological image processing. $\endgroup$ Commented Apr 4, 2012 at 20:15
  • 1
    $\begingroup$ @nikie Never mind, the white is the max, not the black. :-) $\endgroup$
    – Spacey
    Commented Apr 4, 2012 at 20:33
  • 1
    $\begingroup$ @gdelfino: I usually try to avoid it by using a large enough mask, and use Clip[ImageData[white],{eps,Infinity}] where eps is a small number, to be safe. $\endgroup$ Commented Nov 22, 2012 at 19:53
7
$\begingroup$

Nikie's answer seems best and also seems to be working and producing results. So it's a clear winner.

However, just to documentation i adding one more reference, that could just be very fast.

This technique is called Adaptive thresholding which doesn't require to learn the background explicitly.

Essentially, instead of finding the most suitable global threshold - we can partition the image in a local window (say about 7x7 or appropriate) and find thresholds that changes as the window traverses.

The reference below details the exact method. http://homepages.inf.ed.ac.uk/rbf/HIPR2/adpthrsh.htm

This method would be relatively computationally faster.

$\endgroup$
3
  • $\begingroup$ Aren't those two things essentially the same? Namely estimating the local mean of the signal prior to thresholding? $\endgroup$
    – Maurits
    Commented Apr 9, 2012 at 11:12
  • 1
    $\begingroup$ @Maurits It looks like the main differences are the ordering and the statistics used. For example, in the opening/closing operators, (which are made up of dilation and erosion but in a different order), a window is raster scanned and max is taken. (Among other things). However in the adaptive threshold the mean/median can be taken instead of the max. $\endgroup$
    – Spacey
    Commented Apr 9, 2012 at 23:17
  • $\begingroup$ OP asked it on SO as well, which I answered. But in principle, I don't think there is any difference between the answers, one is always estimating local statistics. If you do adapative thresholding, you also learn the background in the process. $\endgroup$
    – Maurits
    Commented Apr 10, 2012 at 7:54
7
$\begingroup$

Another way using a bandpass filter (in MATLAB). Playing around with the difference of Gaussian parameters may give better results. The process is basically bandpass filter the image to remove the low frequency background blobs, normalise to [0,1] required for 'graythresh' command, threshold image.

Load image and convert to grayscale double:

I = imread('hw.jpg');
I = rgb2gray(I);
I = double(I);

enter image description here

Filter using difference of Gaussian kernel and normalise:

J = imgaussian(I,1.5) - imgaussian(I,0.5);
J = J - min(J(:));
J = J / max(J(:));

enter image description here

Calculate threshold and make 010101:

T = J > graythresh(J);

enter image description here

$\endgroup$
5
$\begingroup$

This is a good Matlab code for adaptive thresholding: http://www.mathworks.com/matlabcentral/fileexchange/8647-local-adaptive-thresholding

$\endgroup$
2
  • $\begingroup$ Argh! Requires the image processing toolbox though. :-/ $\endgroup$
    – Spacey
    Commented Apr 9, 2012 at 23:00
  • $\begingroup$ Indeed. Sorry if you do not have it. But DIPImage is a free Image Tolbox for Matlab. diplib.org/documentation It has a few methods for thresholding (check segmentation section) and you can also do all the morphological operations like closing. The developer also has a blog cb.uu.se/~cris/blog/index.php/archives/tag/matlab $\endgroup$
    – MyCarta
    Commented Apr 10, 2012 at 14:15
1
$\begingroup$

I Will try this coding.But i don't have a correct answer...

clc;
clear;
x=imread('base2.jpg');
size(x);
x=imresize(x,[500 800]);
figure;
imshow(x);
title('original image');
z=rgb2hsv(x);       %extract the value part of hsv plane
v=z(:,:,3);
v=imadjust(v);
m = mean(v(:))
s=std(v(:))
k=-2;
value=m+ k*s;
temp=v;
for p=1:1:500
    for q=1:1:800
        pixel=temp(p,q);
        if(pixel>value)
            temp(p,q)=1;
        else
            temp(p,q)=0;
        end
    end
end
figure;
imshow(temp);
title('result by niblack');
% k=kittlerMet(g);
% figure;
% imshow(k);
% title('result by kittlerMet');

val2=m*(1+.1*((s/128)-1));
t2=v;
for p=1:1:500
for q=1:1:800
    pixel=t2(p,q);
    if(pixel>value)
        t2(p,q)=1;
    else
        t2(p,q)=0;
    end
end

end
figure;
imshow(t2);
title('result by sauvola');

enter image description here

enter image description here

$\endgroup$
1
  • 2
    $\begingroup$ If this is meant to answer the question, please explain what you're doing and why. $\endgroup$
    – Matt L.
    Commented Mar 20, 2015 at 11:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.