从直方图密度自动查找最佳图像阈值

时间:2017-09-08 15:09:08

标签: python opencv image-processing histogram

我希望在显示器上执行光学字符识别(OCR),并希望程序在不同的光照条件下工作。为此,我需要处理和阈值图像,使每个数字周围没有噪声,允许我检测数字的轮廓并从那里执行OCR。我需要使用的阈值适应这些不同的光照条件。我已经尝试过自适应阈值处理,但我还没有能够让它工作。

我的图像处理很简单:加载图像(i),灰度i(g),将直方图均衡应用于g(h),并将二进制阈值应用于阈值= t的h。我已经使用了几个不同的数据集,并发现使OCR工作的最佳阈值在(h)的直方图中最高密度的范围内(没有间隙的图的唯一部分) )。 A histogram of (h). The values t=[190,220] are optimal for OCR

(h)的直方图。值t = [190,220]对于OCR是最佳的。可以在此处找到描述我的问题的更完整的图像集:http://imgur.com/a/wRgi7

我当前的解决方案,但有点笨拙和缓慢,检查:

    1. There must be 3 digits
    2. The first digit must be reasonably small in size
    3. There must be at least one contour recognized as a digit
    4. The digit must be recognized in the digit dictionary

除非所有案件都被接受,否则阈值会增加10(从较低值开始)并再次尝试。

我可以识别(h)直方图上的最佳阈值这一事实可能只是确认偏差,但我想知道是否有一种方法可以提取该值。这与我之前使用直方图的方式不同,后者更多的是找到峰值/谷值。

我使用cv2进行图像处理,使用matplotlib.pyplot进行直方图。

4 个答案:

答案 0 :(得分:2)

起初,我想"好吧,只需制作数据出现的索引的直方图"这完全有用,但我认为这不会真正解决你想要做的基础工作。

我认为你错误地解释了直方图均衡。直方图均衡所做的是在高度集中的区域中缩小直方图,这样如果您使用直方图采用不同的区域大小,您将在区域内获得或多或少相等的数量。这些值密集的唯一原因是,特别是因为它们在图像中看起来较少。直方图均衡化使其他更流行的值显得更少。正如您在原始灰度直方图中看到的那样,范围很好的原因是,190到220之间的值非常接近图像再次变亮的位置;即,明亮的价值观明确的地方。

通过绘制具有不同箱尺寸的直方图,您可以直接看到equalizeHist的工作方式。例如,这里循环使用3到20的bin大小:

Multiple hist values

编辑:所以为了清楚起见,你想要的是原始直方图中较低凹凸和较高凹凸之间的这个标记区域。您不需要为此使用均衡直方图。实际上,这就是Otsu阈值处理(跟Otsu's method}实际上的作用:你假设数据遵循双峰分布,并找到明确标记两个分布之间点的点。

答案 1 :(得分:2)

检查一下:link它真的不依赖于密度,它可以工作,因为你分离了2个最大值。局部最大值是主要类别前景 - 左侧局部最大值(文本像素)和背景右侧局部最大值(白皮书)。最佳阈值应该最佳地分离这些最大值。并且最佳阈值位于两个局部最大值之间的局部最小区域。

答案 2 :(得分:1)

基本上,你要问的是找到256 x 1数组中最长的非零元素序列的索引。

根据这个answer,你应该得到你想要的东西:

import cv2
import numpy as np

# load in grayscale

img = cv2.imread("image.png",0)
hist = cv2.calcHist([img],[0],None,[256],[0,256])

non_zero_sequences = np.where(np.diff(np.hstack(([False],hist!=0,[False]))))[0].reshape(-1,2)
longest_sequence_id = np.diff(non_zero_sequences,axis=1).argmax()
longest_sequence_start = non_zero_sequences[longest_sequence_id,0]
longest_sequence_stop = non_zero_sequences[longest_sequence_id,1]

请注意,它未经测试。

答案 3 :(得分:1)

我还建议使用自动阈值处理方法,如Otsu的方法(here对方法的一个很好的解释)。

在Python OpenCV中,你有tutorial解释了如何进行Otsu的二值化。

如果您想尝试其他自动阈值处理方法,可以查看ImageJ / Fiji软件。例如,这个page总结了所有实现的方法。

灰度图片

Grayscale

<强>结果:

Results

如果要重新实现这些方法,可以查看Auto_Threshold插件的源代码。我使用Fiji进行了此演示。