【问题标题】:Recognize a number from an image从图像中识别数字
【发布时间】:2015-06-27 01:11:38
【问题描述】:

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

如何识别图片中的书写数字?

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

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

还有

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

【问题讨论】:

  • 包含两个数字的矩形是否总是在彼此下方?
  • 您正在寻找的是 OCR。您是否在 Google 上搜索过现有的 OCR 工具?事实证明,谷歌有一个叫做 tesseract 的 JNI 实现叫做 tessjeract。看看吧。
  • @npinti 纸张右侧的矩形距离会有所不同,因为两者之间存在问题。 bt 将在一条直线上。
  • @bot 我在它刚刚给我'S878'的那个图像上尝试了tesseract,我试图在java中做
  • @ChetanKinger 显然tessjeract 项目现在已经从网络上消失了:(

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


【解决方案1】:

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

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

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

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

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

作为额外说明,为了减少误报的数量,您可能需要执行以下操作:

  1. 如果您确定某些坐标永远不会包含您想要的数据,请裁剪图像。这应该给你一个更小的图片来处理。

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

编辑:根据您的评论,给出如下内容:

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

您将裁剪图像,以便通过裁剪图像删除没有相关数据的区域(左侧部分),您会得到如下结果:

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

我们的想法是运行 Hough 变换,这样您就可以获得包含如下矩形的页面片段:

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

然后您将再次应用霍夫变换并最终得到两个片段,然后您取左边的片段。

一旦你有了左段,你就可以应用 OCR。

您可以尝试事先应用 OCR,但充其量,OCR 将识别两个数字值,无论是写入的还是输入的,据我所知,这不是您所追求的.

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

【讨论】:

  • 它会是一张纸,所以它是黑白的,是的,盒子会在右边,上面不会有任何文字。只有距离会变化的框,所以先裁剪它然后运行 ​​ocr 并分离值是明智的吗?
  • @Hash:我试图扩充我的答案。如果您有任何疑问,请告诉我。简而言之,在您完成尽可能多的预处理(这就是霍夫变换位就是)之后,您应该将 OCR 部分留到最后。
  • 我记得opencv支持它,但对霍夫变换不熟悉,有什么推荐的教程或示例链接吗?
  • @Hash: This 似乎很有帮助。
  • @pinti:我试过这个:vase.essex.ac.uk/software/HoughTransform 我什么也没得到。你发给我的那个不能让它工作
【解决方案2】:

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

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

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

它内部有一组权重因子,用于计算输出。这些权重因素在训练过程中得到完善。感知器的美妙之处在于,(通过适当的训练)它可以处理以前从未见过的数据。

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

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

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

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

这两个组件都非常受欢迎,并且可以在MATLAB 等教育软件包中使用。

更新:2018 年 6 月 1 日 - 张量流

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

【讨论】:

  • 神经网络非常适合分类。对于多个感知器,您将采用什么方法将结果组合在一起?表决?此外,如果您仍然需要进行培训,为什么不培训 OCR 引擎呢?我认为 OCR 引擎可以利用它是一个字符的知识,而不是仅仅基于像素。否则为什么不是所有的 OCR 引擎都使用直接神经网络。
  • @Noremac 我并不真正将这些字符图视为文本。在我看来,它们更像是图画。另一方面,OCR 非常适合解析通常使用一种特定字体来编写整本书的印刷文本。如果字体始终相同,则不需要神经网络。但对于绘图和图片,我希望神经网络能得到更好的结果。我听说有时 OCR 使用基于矢量的识别而不是字形,这就是您所指的 OCR 类型吗?
  • OCR 引擎可以在此处使用单个作者的“手写字体”进行训练。我很想看看它可以允许多少变化。我认为它可以在有限的词汇量(只有数字)和经过培训的情况下做得很好。感知器可以更好地处理变化,所以我认为这取决于作者的一致性,以及 OCR 引擎知道它是书面字符后有什么优势(如果有的话)。为了跟进我的另一个问题,您建议如何将感知器结果重新组合在一起以获得最终分类?
  • @Noremac 您可以简单地将每个网络结果生成单个输出节点,浮点值 [0.0 - 1.0](即 0.0 = 绝对不匹配,1.0 = 完全匹配。)然后就检查 10 个网络中哪个网络得分最高。
【解决方案3】:

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

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

您可以使用不同的手写数字图像来训练神经网络。训练完成后,如果通过手写数字的图像进行识别,它会返回最相似的数字。

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

【讨论】:

  • 我同意像素矩阵足以将其传递给神经网络(例如感知器网络)。但是,如果矩阵大小是可变的(我猜它不在这里),或者如果您想限制感知器的输入数量,那么最好使用 SOM(如我的回答中所述)。
【解决方案4】:

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

  1. 数字周围的方框是一致的。
  2. 右侧的数字始终为 8(或提前知道)
  3. 左边的数字始终是数字
  4. 左边的数字始终是同一个人的笔迹和书写

然后我们可以使用这些假设来简化问题:

  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/)

不过,要点是使用任何可以将问题简化为更小、更简单的子问题的假设。然后看看有哪些工具可以单独解决这些子问题。

如果您必须开始担心现实世界,也很难做出假设,例如如果这些将被扫描,您将需要考虑“模板”或数字的倾斜或旋转。

【讨论】:

  • 8 会改变。假设我将行和 8 隔离开来,我留下左边的数字(手写文本),那么如果我训练 ocr 会起作用吗?是同一个人写的标记
  • 它的效果如何取决于作者的一致性。我认为这是您最好的镜头,尽管作者始终如一。手写识别是一个完全独立于 OCR 的领域,以解释可能的变化。 OCR 更加严格,不允许有太多变化。
  • 那么推荐什么来识别这些数字?
  • 你问的是手写数字吗?如果是这样,则没有那么多专门用于此的:stackoverflow.com/questions/10249501/…
  • 你训练识别数字可能
【解决方案5】:

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

【讨论】:

  • @amit 人类总是比计算机做 OCR 更好。如果人类无法阅读一段文字,就没有文字。
  • 没有。几年前有一篇文章,他们在其中取了数字,并在图片中添加了随机噪声。在某个噪音点 - 人类无法再正确读取数字,但计算机可以正确识别原始数字。
  • @RobAu 我很久以前读过它,我什至不记得作者是谁或它是在哪里出版的。会试一试,但不要屏住呼吸。 :|
  • @tobltobs 如果你是正确的,那么你的邮件是如何到达你家的?如今,邮局的邮件分拣几乎完全由计算机完成。
【解决方案6】:

这是一个简单的方法:

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

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

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

  4. 执行 OCR。 应用轻微的 Gaussian blur,然后使用 Pytesseract 进行 OCR。


这是每个步骤的可视化:

输入图像->二值图像->水平蒙版->垂直蒙版

组合蒙版-> 结果-> 应用轻微模糊

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()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-18
    • 2013-02-16
    • 2020-11-10
    • 2016-12-26
    • 2011-05-20
    相关资源
    最近更新 更多