Opencv,Python - 如何删除日期文本周围的灰色像素

问题描述

我正在尝试使用 Python/OpenCV 去除日期周围的灰色“噪音”,以帮助 OCR(光学字符识别)识别日期。

enter image description here

原始图像如下所示:https://static.mothership.sg/1/2017/03/10-Feb-MC-1.jpg

我尝试的 python 脚本如下所示。但是,我还有其他类似的图像,其中对比度或照明条件各不相同。

import cv2
import numpy as np

img = cv2.imread("mc.jpeg")
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

alpha = 3.5
beta = -2

new = alpha * img + beta
new = np.clip(new,255).astype(np.uint8)

cv2.imwrite("cleaned.png",new)

我也尝试过 Thresholding 和/或 adaptiveThresholding,有一段时间,我能够将日期与灰色背景分开。有时这是非常具有挑战性的。我想知道有没有自动确定阈值的方法

以下是我希望实现的目标。

enter image description here

enter image description here

模糊图像:

enter image description here

解决方法

Otsu 的二值化会根据图像直方图自动计算阈值。

# Otsu's thresholding after Gaussian filtering
blur = cv2.GaussianBlur(img,(5,5),0)
ret,Otsu = cv2.threshold(blur,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

cv2.imwrite("Otsu's_thresholding",Otsu)

看到这个link

,

您可以尝试构建背景模型,然后通过该模型对每个输入像素进行加权。 输出增益在图像的大部分时间应该是相对恒定的。这些是此方法的步骤:

  1. 应用柔和的中值模糊滤镜以去除小噪点
  2. 通过局部最大值获取背景模型。应用一个非常强大的 close 操作,带有一个大 structuring element(我使用的是大小为 15 的矩形核)
  3. 通过在每个局部最大像素之间划分 255 来执行增益调整。用每个输入图像像素加权这个值。
  4. 你应该得到一个很好的图像,其中背景照明几乎标准化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,1,cv2.BORDER_REFLECT101)

# Adjust image gain:
height,width,depth = localMax.shape

# Create output Mat:
outputImage = np.zeros(shape=[height,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,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,cv2.THRESH_BINARY)

# Write image:
imageFilename = "C:/opencvImages/binaryMask2.png"
cv2.imwrite(imageFilename,binaryImage)

我得到以下测试完整图像的结果:

以及裁剪后的文本:

请注意,增益调整操作未矢量化。脚本很慢,主要是因为我从 Python 开始,并且不知道正确的 Numpy 语法来加速此操作。我已经使用 C++ 很长时间了,所以请随时进一步改进代码。

编辑:

请注意,您的结果只能与输入的质量一样好。查看您的输入并问自己“这对自动化流程来说是一个好的输入吗?”(自动化流程通常不是很聪明)。您发布的第二张图片非常质量很差。不仅模糊而且分辨率低并且有压缩伪影。所有这些因素都会阻碍自动化处理。

话虽如此,您可以在原版中加入以下改进: 尝试 normalize 灰度输出的亮度对比度:

grayscaleImage = np.uint8(cv2.normalize(grayscaleImage,grayscaleImage,cv2.NORM_MINMAX))

您的灰度图像来自:

为此:

有点暗,对比度有所提高。让我们尝试通过 Otsu thresholding 自动计算最佳阈值:

threshValue,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

它让你知道:

但是,如果我们将 bias 添加到 Otsu 的阈值,我们可以调整结果,如下所示:

threshValue,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
bias = 0.9
threshValue = bias * threshValue
_,cv2.THRESH_BINARY)

这是使用这种方法可以获得的最佳图像质量。 如果您觉得这些建议和技巧有用,请至少为我的回答点赞。