使用OpenCV对图像进行预处理以供Tesseract OCR使用

36

我正在开发一个应用程序,它使用Tesseract从手机相机拍摄的文档中识别文本。我正在使用OpenCV对图像进行预处理以获得更好的识别结果,应用高斯模糊和二值化阈值方法进行二值化,但是结果非常差。

这里是我用于测试的图像: 输入图像描述

而且,这里是预处理后的图像: 输入图像描述

我可以使用哪些其他过滤器使图像对Tesseract更加易读?

6个回答

70
我在这里描述了一些为Tesseract准备图像的技巧:使用Tesseract识别车牌 在你的示例中,有几件事情需要处理...
你需要让文本变成黑色,而图像的其余部分为白色(不是相反)。这就是字符识别的调优所在。灰度可以,只要背景大部分是全白的,文本大部分是全黑的;文本的边缘可能是灰色(抗锯齿),这可能有助于识别(但并不一定-你需要进行实验)。
您看到的问题之一是图像某些部分的文本非常“细”(阈值化后字母间的间隙会出现),而在其他部分则非常“粗”(字母开始合并)。Tesseract 对此不太友好 :) 这是因为输入图像的光照不均匀,因此单个阈值无法在所有位置上起作用。解决方案是进行“局部自适应阈值处理”,其中针对图像的每个邻域计算不同的阈值。有很多方法可以做到这一点,但可以尝试以下方法:
- OpenCV 中的自适应高斯阈值处理,使用 cv2.adaptiveThreshold(...,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,...) - 局部 Otsu 方法 - 局部自适应直方图均衡化 另一个问题是,这些行不是直的。在我的经验中,Tesseract可以处理非常有限程度的非直线(一些透视畸变、倾斜或扭曲),但它无法处理波浪形的线条。如果可能的话,请确保源图像具有直线:)不幸的是,对于这个问题,没有简单的现成答案;您需要研究文献并自己实现最先进的算法之一(如果可能的话,开源 - 这方面真的需要一个开源解决方案)。例如,使用Google Scholar搜索“曲线线OCR提取”即可开始查找: 最后:我认为与使用C++的OpenCV相比,您最好使用Python生态系统(ndimage,skimage)进行工作。 OpenCV Python包装器对于简单的东西来说还可以,但对于您要尝试的内容,它们无法胜任,您需要获取许多不在OpenCV中的组件(当然,您可以混合和匹配)。 在C ++中实现诸如曲线线检测之类的东西将需要比Python长一个数量级的时间(*即使您不知道Python也是如此)。
祝你好运!

谢谢你的回答。我尝试了直线图片和自适应阈值,得到了不完美但相当不错的结果。我将研究曲线问题,并在解决方案时开源。最后,我会采纳你的建议,至少在这个任务中使用Python。 - Mauricio
很不幸,您的链接已经失效了。我也非常感兴趣。 - linuscl
3
更新的链接: OpenCV 中的自适应高斯阈值处理局部Otsu方法局部自适应直方图均衡化。一个简单的谷歌inurl搜索可以修复很多损坏的链接。 - John Bridge
2
你能更新一下你回答中的外部链接吗?谢谢! - ilke444
1
你知道Tesseract引擎在图像上执行哪些预处理步骤吗?就像这个例子一样,Tesseract能够从彩色图像中检测文本,因此它必须在识别之前执行一些步骤。 - zindarod

27
  1. 以300 dpi(每英寸点数)的分辨率扫描不是正式的OCR(光学字符识别)标准,但被认为是黄金标准。

  2. 将图像转换为灰度有助于提高一般文本阅读精度。

我编写了一个模块,可以读取图片中的文本,并对图像进行处理以获得最佳的OCR结果,Image Text Reader

import tempfile

import cv2
import numpy as np
from PIL import Image

IMAGE_SIZE = 1800
BINARY_THREHOLD = 180

def process_image_for_ocr(file_path):
    # TODO : Implement using opencv
    temp_filename = set_image_dpi(file_path)
    im_new = remove_noise_and_smooth(temp_filename)
    return im_new

def set_image_dpi(file_path):
    im = Image.open(file_path)
    length_x, width_y = im.size
    factor = max(1, int(IMAGE_SIZE / length_x))
    size = factor * length_x, factor * width_y
    # size = (1800, 1800)
    im_resized = im.resize(size, Image.ANTIALIAS)
    temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.jpg')
    temp_filename = temp_file.name
    im_resized.save(temp_filename, dpi=(300, 300))
    return temp_filename

def image_smoothening(img):
    ret1, th1 = cv2.threshold(img, BINARY_THREHOLD, 255, cv2.THRESH_BINARY)
    ret2, th2 = cv2.threshold(th1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    blur = cv2.GaussianBlur(th2, (1, 1), 0)
    ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    return th3

def remove_noise_and_smooth(file_name):
    img = cv2.imread(file_name, 0)
    filtered = cv2.adaptiveThreshold(img.astype(np.uint8), 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 41,
                                     3)
    kernel = np.ones((1, 1), np.uint8)
    opening = cv2.morphologyEx(filtered, cv2.MORPH_OPEN, kernel)
    closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel)
    img = image_smoothening(img)
    or_image = cv2.bitwise_or(img, closing)
    return or_image

尽管经过这么多的优化,Tesseract仍然无法在图像上检测到我的文本。你有什么进一步的想法吗? - Fr_nkenstien
请问您能否在这里查看一个与Tesseract和OpenCV相关的问题:https://dev59.com/ZGAKtIcB2Jgan1zneSex? - Istiaque Ahmed
@yardstick17,它在大多数图像上运行良好,但对于某些图像,结果相当糟糕。例如,对于白色文本的图像,即黑色背景上的白色文本图像,结果并不好。 - Gary Chen

9
注意:这应该是对Alex的评论,但太长了,所以我把它作为答案。
来源于“Tesseract OCR引擎概述,作者Ray Smith,来自Google Inc。”https://github.com/tesseract-ocr/docs/blob/master/tesseracticdar2007.pdf
处理遵循传统的逐步管道,但其中一些阶段在当时是不寻常的,可能现在仍然如此。第一步是连接分量分析,其中存储组件的轮廓。这是当时一个计算上昂贵的设计决策,但有一个重要的优点:通过检查轮廓的嵌套方式以及子轮廓和孙子轮廓的数量,可以简单地检测反向文本并像处理黑白文本一样进行识别。Tesseract可能是第一个能够轻松处理白色背景上的黑色文本的OCR引擎。
因此,似乎不需要在黑色背景上使用黑色文本,反过来也应该可以。

这是旧文档 - 不适用于Tesseract 4.x。 - user898678
@user898678,你能给我展示一个在tesseract 4.x上运行良好的例子吗? - Gary Chen
请将以下与编程有关的内容从英语翻译成中文。只需提供已经二值化图像的黑白文字作为输入即可。 - user898678

2
您可以通过更改 --psm 和 --oem 值来调整 OCR 的配置,在您的情况下,我建议使用
--psm 3 --oem 2
您还可以查看以下链接以获取更多详细信息: 这里

1

-1

我猜你使用了通用的二值化方法,这就是整个图像不能均匀地进行二值化的原因。您可以使用自适应阈值技术进行二值化。您还可以进行一些倾斜校正、透视校正和噪声去除来获得更好的结果。

参考这篇中文 文章 ,了解上述技术以及代码示例。


欢迎来到SO。在回答问题之前,请参考https://stackoverflow.com/help/how-to-answer。在这种情况下,不要发布可能会消失的链接。相反,尝试将所有必要的信息放入您的答案中。 - Unbranded Manchester

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接