您可以尝试构建一个背景模型,然后按该模型对每个输入像素进行加权。 输出增益在大部分图像中应该是相对恒定的。以下是此方法的步骤:
- 应用软中值模糊滤镜以去除小噪点
- 通过局部最大值获取背景模型。应用一个非常强的
close 操作,使用一个大的structuring element(我正在使用大小为15 的矩形内核)
- 通过在每个局部最大像素之间划分
255 来执行增益调整。使用每个输入图像像素加权此值。
- 你应该得到一个很好的图像,其中背景照明几乎标准化,
threshold这个图像得到文本的二进制掩码
这是代码:
import numpy as np
import cv2
# image path
path = "C:/opencvImages/sheet01.jpg"
# Read an image in default mode:
inputImage = cv2.imread(path)
# Remove small noise via median:
filterSize = 5
imageMedian = cv2.medianBlur(inputImage, filterSize)
# Get local maximum:
kernelSize = 15
maxKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernelSize, kernelSize))
localMax = cv2.morphologyEx(imageMedian, cv2.MORPH_CLOSE, maxKernel, None, None, 1, cv2.BORDER_REFLECT101)
# Adjust image gain:
height, width, depth = localMax.shape
# Create output Mat:
outputImage = np.zeros(shape=[height, width, depth], dtype=np.uint8)
for i in range(0, height):
for j in range(0, width):
# Get current BGR pixels:
v1 = inputImage[i, j]
v2 = localMax[i, j]
# Gain adjust:
tempArray = []
for c in range(0, 3):
currentPixel = v2[c]
if currentPixel != 0:
gain = 255 / v2[c]
gain = v1[c] * gain
else:
gain = 0
# Gain set and clamp:
tempArray.append(np.clip(gain, 0, 255))
# Set pixel vec to out image:
outputImage[i, j] = tempArray
# Convert RGB to grayscale:
grayscaleImage = cv2.cvtColor(outputImage, cv2.COLOR_BGR2GRAY)
# Threshold:
threshValue = 110
_, binaryImage = cv2.threshold(grayscaleImage, threshValue, 255, cv2.THRESH_BINARY)
# Write image:
imageFilename = "C:/opencvImages/binaryMask2.png"
cv2.imwrite(imageFilename, binaryImage)
我得到以下测试完整图像的结果:
还有裁剪后的文字:
请注意,增益调整操作未矢量化。脚本很慢,主要是因为我从Python 开始,不知道正确的Numpy 语法来加速这个操作。我已经使用C++ 很长时间了,请随时进一步改进代码。
编辑:
请注意,您的结果只能与您输入的质量一样好。查看您的输入并问自己“对于自动化流程来说,这是一个好的输入吗?”(自动化流程通常不是很聪明)。您发布的第二张图片质量非常低。不仅模糊,而且分辨率低,并且有压缩伪影。所有这些因素都会阻碍自动化处理。
话虽如此,您可以在原始版本中加入以下改进:
在灰度输出上尝试normalizebrightness-contrast:
grayscaleImage = np.uint8(cv2.normalize(grayscaleImage, grayscaleImage, 0, 255, cv2.NORM_MINMAX))
您的灰度图像来自:
致:
稍微暗一点,对比度有所提高。让我们尝试通过Otsu thresholding自动计算最优阈值:
threshValue, binaryImage = cv2.threshold(grayscaleImage, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
它让你得到这个:
但是,如果我们将bias 添加到 Otsu 的阈值,我们可以调整结果,如下所示:
threshValue, binaryImage = cv2.threshold(grayscaleImage, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
bias = 0.9
threshValue = bias * threshValue
_, binaryImage = cv2.threshold(grayscaleImage, threshValue, 255, cv2.THRESH_BINARY)
这是使用此方法可以获得的最佳图像质量。
如果您觉得这些建议和技巧有用,请至少给我的答案投票。