8

I'm in search for best Adaptive Threshold method for image binarization. But I have any problems with dark and blurry image.
Input image:
Let the Image load...

and when I use Adaptive threshold method I receive this
Output Image:
Let the Image load...

This is not good for me!
So, could someone help me fix this problem?


another image : enter image description here

and : enter image description here

the first seem very bad with @Hammer'solution (i must chose c channel) , the second i can use adaptive threshold normal .
so i want to find the best solution for all cases .

thank Again !

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
minhthuan
  • 201
  • 1
  • 4
  • 8

4 Answers4

8

It seems like color is a much better indicator for segmentation in your image than intensity. Try converting it to HSV and then running OTSU on the H channel.

in python

hsv = cv2.cvtColor(image, cv2.cv.CV_BGR2HSV)
cv2.imshow('hsv', hsv[:,:,0])
(thresh, im_bw) = cv2.threshold(hsv[:,:,0], 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
cv2.imshow('OTSU', im_bw)

gives (hsv)

enter image description here

and then (OTSU)

enter image description here

A little eroding and dilating and you should be good to go

Hammer
  • 10,109
  • 1
  • 36
  • 52
  • 1
    yes, Hammer thank for your question . that seem is good for this case and bad for any . so how can i chose the best solution ? thank ! – minhthuan Sep 05 '13 at 06:40
  • @minhthuan What's the difference result among this good one and other bad ones? Show some images that don't fit Hammer's solution. – WangYudong Sep 05 '13 at 08:23
  • Nice answer. What about choosing thresholds, to get multiple levels ? There is already some OpenCv magic ? – CapelliC Sep 05 '13 at 10:07
6

You might be interested in these adaptive thresholds used by openCV.

I used the adaptive mean threshold. You may have to play with the parameters a bit, but if your images are similar (same size etc), hopefully there won't be too much tweaking required.

# Smooth image
filtered = cv2.adaptiveThreshold(input_image.astype(np.uint8), 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 41, 3)

# Some morphology to clean up image
kernel = np.ones((5,5), np.uint8)
opening = cv2.morphologyEx(filtered, cv2.MORPH_OPEN, kernel)
closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel)

Results:

enter image description here

enter image description here

enter image description here

Pokey McPokerson
  • 752
  • 6
  • 17
3

The following code ...

im=cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,111,3)
cv2.imshow('mkm',im)`

... gives a good result:

adaptive image

UndeadBob
  • 1,110
  • 1
  • 15
  • 34
Mayank Kumar
  • 523
  • 6
  • 9
1

If a single threshold is not enough to separate all images, you could try the Watershed algorithm with two thresholds.

Use a high threshold to get an image with segments that are definitely part of a digit, and a high inverse threshold to get an image with segments that are definitely not part of a digit.

Erode both images a bit to increase the certainty.

Then use the 2 images as seeds for Watershed.

Here is an answer where this is done

Community
  • 1
  • 1
HugoRune
  • 13,157
  • 7
  • 69
  • 144