camscanner 应用程序可能正在使用一些复杂的算法来处理各种闪电情况等。但我将尝试介绍解决此类问题的基本方法,这里的基本思想是给定输入的 二值化图像,或者更准确地说,我们可以说 限制 给定图像,如果您查看 OpenCV 文档,有很多关于对给定图像进行阈值处理的参考,所以让我们从 documentation 开始。
-
全局阈值:在这种方法中,我们假设前景的强度值始终低于某个值,在印刷纸张的上下文中,我们假设墨水颜色始终为黑色和纸张颜色是均匀的,强度大于墨水颜色的强度,所以我们安全地假设一些阈值(比如 40),(最大值为 255)并将输入图像的阈值设置为:
ret, thresh1 = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)
ret, thresh1 = cv2.threshold(img, 130, 255, cv2.THRESH_BINARY)
There are many disadvantages to this method, First of all it is **NOT** independent of intensity variance, So there is a very less chance that you can accurately estimate a threshold value which segments text from the given image, It has very limited applications, can be only applied in case where the background paper is exactly white with minimum variation in intensity, so this process cannot be used for **Real world** images.
-
自适应阈值:该方法涵盖了给定图像中的强度变化问题,这里对相邻像素的值进行阈值处理,因此成功捕获了从低强度到高强度的过渡,反之亦然用这种方法:
thresh = cv2.adaptiveThreshold(original_img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
*Further Work*: You may work on various techniques of denoising the binary image, to remove the dots, Or have a look at removing the salt and pepper noise from the image.
-
Otu 的二值化:这是另一种很好的方法,它可以智能地计算最大值之间的阈值,在某些情况下它可能工作得很好,但在你的情况下它似乎失败了。
ret2,thresh = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
它基本上做了相同的全局阈值处理但是现在阈值是自动计算的,使得阈值位于两个峰值之间,从而将墨水从纸张中分割出来。
推荐方法:
我想最好的方法是自适应阈值,您可以尝试其他一些预处理技术,例如sharpening image、Histogram Equalisation 等,并分析它如何创建更真实的输出,您可以也尝试做一些后期处理比如denoising the image,Morphological operations
我尝试了图像的去噪,发现它比其他方法更有效,
denoised = cv2.fastNlMeansDenoising(thresh, 11, 31, 9) # you may experiment with the constants here
但我欢迎您尝试上述方法的各种组合,看看哪一种适用于所有情况。
注意:上述技术可能适用于色彩较少的图像。不过这里还有一个excellent answer,可以解决彩色图片的情况。