2

Given an image (Like the one given below) I need to convert it into a binary image (black and white pixels only). This sounds easy enough, and I have tried with two thresholding functions. The problem is I cant get the perfect edges using either of these functions. Any help would be greatly appreciated.

The filters I have tried are, the Euclidean distance in the RGB and HSV spaces.

Sample image:

enter image description here

Here it is after running an RGB threshold filter. (40% it more artefects after this)

enter image description here

Here it is after running an HSV threshold filter. (at 30% the paths become barely visible but clearly unusable because of the noise)

enter image description here

The code I am using is pretty straightforward. Change the input image to appropriate color spaces and check the Euclidean distance with the the black color.

sqrt(R*R + G*G + B*B)

since I am comparing with black (0, 0, 0)

Faroq AL-Tam
  • 495
  • 5
  • 10
Ahmed Aeon Axan
  • 2,139
  • 1
  • 17
  • 30
  • Have you tried hough function and noise filters? I'm sure you can make good use of matlab's imnoise(..) – Iancovici Jun 13 '13 at 14:26
  • not really, because as I increase the threshold alot of the image gets completely blackened out because of the shadows I guess. And i figured a noise filter could'nt eliminate those.. I could be wrong. – Ahmed Aeon Axan Jun 13 '13 at 14:28
  • Try finding the lines either using edge detection or by using something like the hough transform. – Zaphod Jun 13 '13 at 14:42
  • I am writing this on the android platform. So if you guys could recommend a good library to use.. I dont want to write all these algorithms by hand obviously – Ahmed Aeon Axan Jun 13 '13 at 14:43
  • 1
    See this question: http://stackoverflow.com/questions/4632174/what-processing-steps-should-i-use-to-clean-photos-of-line-drawings – Mark Ransom Jun 13 '13 at 16:45

5 Answers5

3

Your problem appears to be the variation in lighting over the scanned image which suggests that a locally adaptive thresholding method would give you better results.

The Sauvola method calculates the value of a binarized pixel based on the mean and standard deviation of pixels in a window of the original image. This means that if an area of the image is generally darker (or lighter) the threshold will be adjusted for that area and (likely) give you fewer dark splotches or washed-out lines in the binarized image.

http://www.mediateam.oulu.fi/publications/pdf/24.p

I also found a method by Shafait et al. that implements the Sauvola method with greater time efficiency. The drawback is that you have to compute two integral images of the original, one at 8 bits per pixel and the other potentially at 64 bits per pixel, which might present a problem with memory constraints.

http://www.dfki.uni-kl.de/~shafait/papers/Shafait-efficient-binarization-SPIE08.pdf

I haven't tried either of these methods, but they do look promising. I found Java implementations of both with a cursory Google search.

beaker
  • 16,331
  • 3
  • 32
  • 49
1

Running an adaptive threshold over the V channel in the HSV color space should produce brilliant results. Best results would come with higher than 11x11 size window, don't forget to choose a negative value for the threshold.

Adaptive thresholding basically is:

if (Pixel value + constant > Average pixel value in the window around the pixel )
    Pixel_Binary = 1;
else
    Pixel_Binary = 0;
Boyko Perfanov
  • 3,007
  • 18
  • 34
  • 1
    No need to convert to HSV when you're starting with a mostly gray image already - just pick the channel from R,G,B that has the least noise, usually green. – Mark Ransom Jun 13 '13 at 16:22
1

Due to the noise and the illumination variation you may need an adaptive local thresholding, thanks to Beaker for his answer too.

Therefore, I tried the following steps:

  • Convert it to grayscale.

  • Do the mean or the median local thresholding, I used 10 for the window size and 10 for the intercept constant and got this image (smaller values might also work): image

    Please refer to : http://homepages.inf.ed.ac.uk/rbf/HIPR2/adpthrsh.htm if you need more information on this techniques.

  • To make sure the thresholding was working fine, I skeletonized it to see if there is a line break. This skeleton may be the one needed for further processing.

image

  • To get ride of the remaining noise you can just find the longest connected component in the skeletonized image.

Thank you.

Faroq AL-Tam
  • 495
  • 5
  • 10
0

You probably want to do this as a three-step operation.

  1. use leveling, not just thresholding: Take the input and scale the intensities (gamma correct) with parameters that simply dull the mid tones, without removing the darks or the lights (your rgb threshold is too strong, for instance. you lost some of your lines).

  2. edge-detect the resulting image using a small kernel convolution (5x5 for binary images should be more than enough). Use a simple [1 2 3 2 1 ; 2 3 4 3 2 ; 3 4 5 4 3 ; 2 3 4 3 2 ; 1 2 3 2 1] kernel (normalised)

  3. threshold the resulting image. You should now have a much better binary image.

Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
  • I am writing this on the Android platform, so Could you point me to a good library which would handle these operations for me? – Ahmed Aeon Axan Jun 13 '13 at 14:43
  • The kernel you specify will blur the image, not detect edges. – Zaphod Jun 13 '13 at 14:44
  • oops, sorry, @Zaphod is quite right: that was a smoothing kernel; There are simple 5x5 kernels, but https://en.wikipedia.org/wiki/Edge_detection has a good rundown on why this works, and some common kernels. Also: I'm not sure whether Android has any built in, but as a Java based language writing convolution is pretty simple if you have access to an image's pixels. Create an array the same size as the image pixel array, convolute the image, putting the result in the new array, and then do your thresholding based on the new array. – Mike 'Pomax' Kamermans Jun 13 '13 at 14:49
0

You could try a black top-hat transform. This involves substracting the Image from the closing of the Image. I used a structural element window size of 11 and a constant threshold of 0.1 (25.5 on for a 255 scale)

You should get something like:

enter image description here

Which you can then easily threshold:

enter image description here

Best of luck.

Omar Wagih
  • 8,504
  • 7
  • 59
  • 75