-1

I'm trying to threshold an image using Otsu's method in Opencv:

input-image

Although when I threshold it, some parts of the picture are completely surrounded by white and creates and ends up in Opencv not detecting all the contours in the image. This is what I get when I do Otsu's method thresholding usingret,thresh=cv2.threshold(blurred,0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU):

thresholding-the-image

EDIT: Some people have asked for the code I am using so here it is:

gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)

cv2.imshow('Input Image', image)
cv2.waitKey(0)

blurred = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.adaptiveThreshold(blurred,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
                               cv2.THRESH_BINARY_INV,81,2)
#ret, thresh = cv2.threshold(blurred,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
#thresh_value = 70
#ret,thresh= cv2.threshold(blurred,thresh_value,255,cv2.THRESH_BINARY)

Now it makes some checkered noise: WOAH

hypadr1v3
  • 543
  • 4
  • 26
  • 1
    it's because of the brightness loss to the borders of your image. Capture more uniformely iuminated scenes or use different lenses – Micka Aug 13 '18 at 04:30
  • 1
    The problem here is the lightning not contour or threshold. Are you limited to this image? Do you need image processing in this conditions? – Fred Guth Aug 13 '18 at 05:07
  • If I can get image processing in these conditions that would be nice because I can't tell everyone who uses this to go out in the sun – hypadr1v3 Aug 13 '18 at 05:36
  • or get more powerful lights – hypadr1v3 Aug 13 '18 at 05:36
  • 1
    Try blurring/averaging your image say 100x100 (which will remove high frequency information and only leave slowly changing things like the uneven lighting) and subtracting the blurred image from the original to remove the slowly changing things and leave the sharp details of the text... https://stackoverflow.com/a/27893051/2836621 – Mark Setchell Aug 13 '18 at 10:16

2 Answers2

2

You do not need to manually find a sweet spot! Let OpenCV do it for you!

OpenCV has an adaptive thresholding algorithm exactly from problems like this, called adaptiveThreshold

This function divides the image into multiple sub-images, and thresholds each one individually. This means that it will find a nice threshold value for each part of the image and give you a nice and uniformly lit image. See this example.

Try this:

th3 = cv.adaptiveThreshold(blurred,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,\
        cv.THRESH_BINARY,11,2)

Update: Functions like these do not work perfectly out of the box. If it still creates artefacts like salt and pepper noise, you can try:

  • Significantly increasing the blockSize. This can ensure that each block has a letter inside, which will hopefully mean the threshold will be chosen better. (e.g. Dividing the image into 25 blocks instead of 100. A blocksize of 11 pixels is very small.)
  • First apply a blurring filter to ease out the bad spots creating the seasoning noise. (With the image name blurry I imagine that you've done this already.
  • First the simple threshold function to just removes some noise. For example setting all pixels above 5 and below 100 equal to zero. Then after that apply the adaptiveThreshold.
  • Follow @Mark`s advice by subtracting a blurred image from the original image. (See this thread)

I hope this helps!

Hein Wessels
  • 937
  • 5
  • 15
  • 2
    it makes a lot of salt and pepper noise that creates a BIG disruption in opencv and gives numbers like `5698 contours detected`. At least Otsu's threshold gives a good threshold in the part it actually gets – hypadr1v3 Aug 13 '18 at 09:55
  • @Nazar, I updated my answer with a few more suggestions. I hope it helps. – Hein Wessels Aug 13 '18 at 10:05
  • 1
    Still gives the salt and pepper noise and now doesn't even detect the letters anymore :( – hypadr1v3 Aug 13 '18 at 10:13
  • what do you mean by normal threshold? – hypadr1v3 Aug 13 '18 at 10:26
  • The one you used originally (`cv2.threshold`). – Hein Wessels Aug 13 '18 at 10:30
  • and how do you add 2 arguments into one argument? – hypadr1v3 Aug 13 '18 at 10:35
  • and I don't really know how to subtract the blurred image from the original(sorry I'm still pretty new to OpenCV – hypadr1v3 Aug 13 '18 at 10:47
  • 1
    @NazarKhan You can fine tune the window size and weight, to get the desired output with lesser salt and pepper noise. If it is still getting in your way then you can filter the contours on the size to ignore very small contours which lead to salt and pepper noise, You can also try some morphology operations as well. – ZdaR Aug 13 '18 at 10:47
  • morphological operations helped, and I tried fine tuning it but now I got some checkered kind of output – hypadr1v3 Aug 13 '18 at 10:52
  • which stops anything except the edges of the image being detected – hypadr1v3 Aug 13 '18 at 10:59
  • looked more into it and now I got it! Works perfect – hypadr1v3 Aug 15 '18 at 03:51
0

Instead of using Otsu's method try global thresholding method.

thresh_value = 50
ret,thresh= cv2.threshold(blurred,thresh_value,255,cv2.THRESH_BINARY)

change the thresh_value parameter until you get the result you want.

Get to know more about thresholding techniques please refer the documentation.

Ishara Madhawa
  • 3,549
  • 5
  • 24
  • 42