识别图像中的数字

时间:2015-04-20 10:45:19

标签: java image-processing ocr tesseract hough-transform

我正在尝试编写一个应用程序来查找图像中的数字并添加它们。

如何识别图像中的书写号码?

enter image description here

我需要在图像中有许多方框来获取左侧的数字并将它们相加以得出总数。我怎样才能做到这一点?

编辑:我在图像上做了一个java tesseract ocr,但我没有得到任何正确的结果。我怎么训练呢?

我做了边缘检测我得到了这个:

enter image description here

6 个答案:

答案 0 :(得分:20)

您很可能需要执行以下操作:

  1. 在整个页面上应用Hough Transform算法,这应该会产生一系列页面部分。

  2. 对于您获得的每个部分,请再次应用它。如果当前部分产生了2个元素,那么你应该处理一个类似于上面的矩形。

  3. 完成后,您可以使用OCR提取数值。

  4. 在这种情况下,我建议您查看JavaCV(OpenCV Java Wrapper),它应该允许您处理Hough变换部分。然后你需要一些类似于Tess4j(Tesseract Java Wrapper)的东西,它可以让你提取你所追求的数字。

    另外请注意,为了减少误报的数量,您可能需要执行以下操作:

    1. 如果您确定某些坐标永远不会包含您所追踪的数据,请裁剪图像。这样可以为您提供更小的图片。

    2. 将图像更改为灰度可能是明智的(假设您正在使用彩色图像)。颜色会对OCR解析图像的能力产生负面影响。

    3. 编辑:根据你的评论,给出类似的东西:

      +------------------------------+
      |                   +---+---+  |
      |                   |   |   |  |
      |                   +---+---+  |
      |                   +---+---+  |
      |                   |   |   |  |
      |                   +---+---+  |
      |                   +---+---+  |
      |                   |   |   |  |
      |                   +---+---+  |
      |                   +---+---+  |
      |                   |   |   |  |
      |                   +---+---+  |
      +------------------------------+
      

      你会裁剪图像,以便通过裁剪图像来移除没有相关数据的区域(左边的部分),你会得到类似的东西:

      +-------------+
      |+---+---+    |
      ||   |   |    | 
      |+---+---+    |
      |+---+---+    |
      ||   |   |    |
      |+---+---+    |
      |+---+---+    |
      ||   |   |    |
      |+---+---+    |
      |+---+---+    |
      ||   |   |    |
      |+---+---+    |
      +-------------+
      

      这个想法是运行Hough变换,这样你就可以得到包含矩形的页面片段,如下所示:

      +---+---+    
      |   |   |     
      +---+---+ 
      

      然后您将再次应用Hough变换并最终得到两个分段,然后选择左分段。

      一旦你有左段,你就可以申请OCR了。

      可以尝试先手动应用OCR,但最好的情况是,OCR会同时识别两个数字值,无论是写入的还是两种类型的,这些都是我得到的,不是你想要的

      此外,描绘矩形的额外线条可能会使OCR偏离轨道,并使其产生不良结果。

答案 1 :(得分:10)

我建议结合2个基本的神经网络组件:

  • 感知
  • 自组织地图(SOM)

perceptron 是一个非常简单的神经网络组件。它需要多个输入并产生1个输出。您需要通过输入和输出来训练它。这是一个自学习的组成部分。

在内部,它有一系列权重因子,用于计算输出。这些体重因素在训练期间是完善的。关于感知器的美妙之处在于,(经过适当的培训)它可以处理以前从未见过的数据。

您可以通过在多层网络中安排来使感知器更强大,这意味着一个感知器的输出充当另一个感知器的输入。

在您的情况下,您应该使用10个感知器网络,每个数值一个(0-9)。

但是为了使用感知器,你需要一组数字输入。首先,您需要将视觉图像转换为数值。 A Self Organized Map(SOM)使用互连点网格。这些点应该被吸引到图像的像素上(见下文)

Self Organized Map

这两个组件很好地协同工作。 SOM具有固定数量的网格节点,您的感知器需要固定数量的输入。

这两个组件都非常受欢迎,可以在教育软件包中使用,例如MATLAB

更新时间:06/01/2018 - Tensor Flow

This video tutorial演示了如何使用Google的TensorFlow框架在python中完成它。 (点击here获取书面教程)。

答案 2 :(得分:8)

神经网络是解决此类问题的典型方法。

在这种情况下,您可以将每个手写数字视为像素矩阵。如果您使用与要识别的图像大小相同的图像训练神经网络,则可能会获得更好的结果。

您可以使用不同的手写数字图像训练神经网络。一旦经过培训,如果您传递手写号码的图像进行识别,它将返回最相似的号码。

当然,训练图像的质量是获得良好效果的关键因素。

答案 3 :(得分:5)

在大多数图像处理问题中,您希望尽可能多地利用信息。鉴于图像,我们可以做出假设(可能还有更多):

  1. 数字周围的方框是一致的。
  2. 右侧的数字始终为8(或提前知道)
  3. 左侧的数字始终为数字
  4. 左边的数字总是手写并由同一个人写的
  5. 然后我们可以使用这些假设来简化问题:

    1. 您可以使用更简单的方法查找数字(模板匹配)。当你有匹配的坐标时,你可以创建一个子图像并减去模板,只留下你想要给OCR引擎的数字。 http://docs.opencv.org/doc/tutorials/imgproc/histograms/template_matching/template_matching.html
    2. 如果您知道期望的数字,那么您可以从其他来源获取这些数字而不会冒OCR错误的风险。您甚至可以将8作为模板的一部分。
    3. 基于此,您可以大大减少词汇量(可能的OCR结果),提高OCR引擎的准确性。 TesseractOCR有一个白名单设置(请参阅https://code.google.com/p/tesseract-ocr/wiki/FAQ#How_do_I_recognize_only_digits?)。
    4. OCR引擎难以识别手写(它们用于打印字体)。但是,您可以训练OCR引擎识别作者的“字体”。 (见http://michaeljaylissner.com/posts/2012/02/11/adding-new-fonts-to-tesseract-3-ocr-engine/
    5. 但要点是使用任何可以将问题简化为更小,更简单的子问题的假设。然后看看有哪些工具可以单独解决每个子问题。

      如果您不得不开始担心现实世界,也很难做出假设,例如,如果扫描它们,您需要考虑“模板”或数字的倾斜或旋转。

答案 4 :(得分:1)

放弃。真。作为一个人,我不能确定第三个字母是'1'还是'7'。人类在解密方面更胜一筹,因此计算机将失败。 '1'和'7'只是一个有问题的情况,'8'和'6','3'和'9'也难以解密/区分。您的错误报价将> 10%。 如果所有的笔迹都来自同一个人,你可以尝试为此训练OCR,但即使在这种情况下,你仍然会有大约3%的错误。可能是您的用例很特殊,但这些错误通常会禁止任何类型的自动处理。 如果我真的需要自动化,我会调查Mechanical Turk。

答案 5 :(得分:1)

这是一种简单的方法:

  1. 获得二进制图像。加载图像,转换为灰度,然后使用Otsu的阈值获得像素范围为[0...255]的1通道二进制图像。

  2. 检测水平和垂直线。创建水平和垂直structuring elements,然后通过执行morphological operations在蒙版上绘制线。

  3. 删除水平和垂直线。使用bitwise_or操作合并水平和垂直蒙版,然后使用bitwise_and操作删除线条。

    < / li>
  4. 执行OCR。先应用Gaussian blur,然后再使用Pytesseract进行OCR。


以下是每个步骤的可视化结果:

输入图像->二进制图像->水平掩模->垂直掩模

enter image description here enter image description here enter image description here enter image description here

联合遮罩->结果->出现了轻微的模糊感

enter image description here enter image description here enter image description here

OCR的结果

38
18
78

我用Python实现了它,但是您可以使用Java改编类似的方法

import cv2
import pytesseract

pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"

# Load image, grayscale, 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]

# Detect horizontal lines
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25,1))
horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=1)

# Detect vertical lines
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,25))
vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=1)

# Remove horizontal and vertical lines
lines = cv2.bitwise_or(horizontal, vertical)
result = cv2.bitwise_not(image, image, mask=lines)

# Perform OCR with Pytesseract
result = cv2.GaussianBlur(result, (3,3), 0)
data = pytesseract.image_to_string(result, lang='eng', config='--psm 6')
print(data)

# Display
cv2.imshow('thresh', thresh)
cv2.imshow('horizontal', horizontal)
cv2.imshow('vertical', vertical)
cv2.imshow('lines', lines)
cv2.imshow('result', result)
cv2.waitKey()