Reputation: 305
I want to be able to find the bounding boxes of digits in images that may or may not have shadows in it.
To do that I convert the image to grayscale, then to black and white and then I find the digits with cv2.findCountours()
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = cv2.bitwise_not(img)
img = cv2.GaussianBlur(img,(3,3),0)
cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU,img)
contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
But in the last example I get this black and white image:
Which doesn't allow the find contours function to work well.
Is there a way to solve this problem?
Upvotes: 0
Views: 346
Reputation: 485
Otsu's threshold is not the right option. It is correct given a histogram with bimodal distribution. Read more here.
Among many alternatives is adaptive threshold.
import cv2
img = cv2.imread("path/to/image")
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = cv2.bitwise_not(img)
img = cv2.GaussianBlur(img, (3, 3), 0)
# _, img = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 401)
contours, _, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
You here have to provide a value of the size of the block size of the adaptive kernel. I think 401 worked fine here, but it might not work on your other images.
For a little simpler solution, here is one using the OpenCV Wrapper library:
import cv2
import opencv_wrapper as cvw
import numpy as np
img = cv2.imread("masterproject/numbers.jpg")
img = cvw.bgr2gray(img)
img = ~img.astype(np.uint8) # Not part of the library, this is numpy. Only works with uint8
img = cvw.blur_gaussian(img, 3)
img = cvw.threshold_adaptive(img, 401)
contours = cvw.find_external_contours(img)
cvw.draw_contours(img, contours, cvw.Color.GREEN)
Upvotes: 1