Using the threshold functions in open CV on an image to get a binary image, with Otsu's thresholding I get a image that has white spots due to different lighting conditions in parts of the image
or with adaptive threshold to fix the lighting conditions, it fails to accurately represent the pencil-filled bubbles that Otsu actually can represent.
How can I get both the filled bubbles represented and a fixed lighting conditions without patches?
Here's the original image

Here is my code
#binary image conversion
thresh2 = cv2.adaptiveThreshold(papergray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 21, 13)
thresh = cv2.threshold(papergray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cv2.imshow("Binary", thresh) #Otsu's
cv2.imshow("Adpative",thresh2)




Problems with your approach:
The methods you have tried out:
What you can try:
OpenCV's
ximgprocmodule has specialized binary image generation methods. One such method is the popular Niblack threshold technique.This is a local threshold technique that depends on statistical measures. It divides the image into blocks (sub-images) of size predefined by the user. A threshold is set based on the mean minus k times standard deviation of pixel values for each block. The
kis decided by the user.Code:
Result:
Links:
To know more about
cv2.ximgproc.niBlackThresholdThere are other binarization techniques available that you may want to explore. It also contains links to research papers that explain each of these techniques on detail.
Edit: Adaptive threshold actually works if you know what you are working with. You can decide the kernel size beforehand.
See Prashant's answer.