gpt4 book ai didi

python - 如何使用 Python OpenCV 从 OCR 图像中去除噪声伪影?

转载 作者:太空宇宙 更新时间:2023-11-03 21:28:57 27 4
gpt4 key购买 nike

我有包含数字的图像子集。每个子集都由 Tesseract 读取以进行 OCR。不幸的是,对于某些图像,原始图像的裁剪并不是最佳的。

enter image description here

因此,图像顶部和底部的一些伪影/残留物会阻碍 Tesseract 识别图像上的字符。然后我想摆脱这些工件并得到类似的结果:

enter image description here

首先,我考虑了一个简单的方法:我将第一行像素设置为引用:如果在 x 轴上发现了伪影(即,如果图像已二值化,则为白色像素),我将沿着 y 轴移除它轴直到下一个黑色像素。这种方法的代码如下:

import cv2
inp = cv2.imread("testing_file.tif")
inp = cv2.cvtColor(inp, cv2.COLOR_BGR2GRAY)
_,inp = cv2.threshold(inp, 150, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

ax = inp.shape[1]
ay = inp.shape[0]

out = inp.copy()
for i in range(ax):
j = 0
while j in range(ay):
if out[j,i] == 255:
out[j,i] = 0
else:
break
j+=1

out = cv2.bitwise_not(out)
cv2.imwrite('output.png',out)

但结果一点也不好:

enter image description here

然后我偶然发现了 scipy ( here ) 中的 flood_fill 函数,但发现它太耗时而且效率不高。在 SO here 上提出了类似的问题但没有太大帮助。也许可以考虑使用 k 最近邻方法?我还发现,在某些条件下合并相邻像素的方法称为生长方法,其中单链接是最常见的(here)。

您会推荐什么来去除上下工件?

最佳答案

这里有一个简单的方法:

  • 将图像转换为灰度
  • Otsu 获取二值图像的阈值
  • 创建特殊的水平内核并扩张
  • 检测水平线,对最大轮廓进行排序,然后绘制到蒙版上
  • 按位与

转为灰度后,我们用Otsu的阈值得到二值图像

enter image description here

# Read in image, convert to grayscale, and Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

接下来我们创建一个长的水平内核并膨胀以将数字连接在一起

enter image description here

# Create special horizontal kernel and dilate 
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (70,1))
dilate = cv2.dilate(thresh, horizontal_kernel, iterations=1)

从这里我们检测水平线并对最大轮廓进行排序。这个想法是最大的轮廓将是数字的中间部分,其中数字都是“完整的”。任何较小的轮廓都将是部分或截断的数字,因此我们在这里将它们过滤掉。我们将这个最大的轮廓绘制到蒙版上

enter image description here

# Detect horizontal lines, sort for largest contour, and draw on mask
mask = np.zeros(image.shape, dtype=np.uint8)
detected_lines = cv2.morphologyEx(dilate, cv2.MORPH_OPEN, horizontal_kernel, iterations=1)
cnts = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:
cv2.drawContours(mask, [c], -1, (255,255,255), -1)
break

现在我们有了所需数字的轮廓,我们只需按位并使用我们的原始图像并将背景着色为白色即可得到我们的结果

enter image description here

# Bitwise-and to get result and color background white
mask = cv2.cvtColor(mask,cv2.COLOR_BGR2GRAY)
result = cv2.bitwise_and(image,image,mask=mask)
result[mask==0] = (255,255,255)

完整性的完整代码

import cv2
import numpy as np

# Read in image, convert to grayscale, and Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Create special horizontal kernel and dilate
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (70,1))
dilate = cv2.dilate(thresh, horizontal_kernel, iterations=1)

# Detect horizontal lines, sort for largest contour, and draw on mask
mask = np.zeros(image.shape, dtype=np.uint8)
detected_lines = cv2.morphologyEx(dilate, cv2.MORPH_OPEN, horizontal_kernel, iterations=1)
cnts = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:
cv2.drawContours(mask, [c], -1, (255,255,255), -1)
break

# Bitwise-and to get result and color background white
mask = cv2.cvtColor(mask,cv2.COLOR_BGR2GRAY)
result = cv2.bitwise_and(image,image,mask=mask)
result[mask==0] = (255,255,255)

cv2.imshow('thresh', thresh)
cv2.imshow('dilate', dilate)
cv2.imshow('result', result)
cv2.waitKey()

关于python - 如何使用 Python OpenCV 从 OCR 图像中去除噪声伪影?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58295150/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com