【问题标题】:My own OCR-program in Python我自己的 Python OCR 程序
【发布时间】:2010-12-31 16:35:42
【问题描述】:

我还是个初学者,但我想写一个字符识别程序。这个程序还没有准备好。而且我编辑了很多,因此 cmets 可能不完全匹配。我将使用 8-connectivity 进行连接组件标记。

from PIL import Image
import numpy as np

im = Image.open("D:\\Python26\\PYTHON-PROGRAMME\\bild_schrift.jpg")

w,h = im.size
w = int(w)
h = int(h)

#2D-Array for area
area = []
for x in range(w):
    area.append([])
    for y in range(h):
        area[x].append(2) #number 0 is white, number 1 is black

#2D-Array for letter
letter = []
for x in range(50):
    letter.append([])
    for y in range(50):
        letter[x].append(0)

#2D-Array for label
label = []
for x in range(50):
    label.append([])
    for y in range(50):
        label[x].append(0)

#image to number conversion
pix = im.load()
threshold = 200
for x in range(w):
    for y in range(h):
        aaa = pix[x, y]
        bbb = aaa[0] + aaa[1] + aaa[2] #total value
        if bbb<=threshold:
            area[x][y] = 1
        if bbb>threshold:
            area[x][y] = 0
np.set_printoptions(threshold='nan', linewidth=10)

#matrix transponation
ccc = np.array(area) 
area = ccc.T #better solution?

#find all black pixel and set temporary label numbers
i=1
for x in range(40): # width (later)
    for y in range(40): # heigth (later)
        if area[x][y]==1:
            letter[x][y]=1
            label[x][y]=i
            i += 1

#connected components labeling
for x in range(40): # width (later)
    for y in range(40): # heigth (later)
        if area[x][y]==1:
            label[x][y]=i
            #if pixel has neighbour:
            if area[x][y+1]==1:
                #pixel and neighbour get the lowest label             
                pass # tomorrows work
            if area[x+1][y]==1:
                #pixel and neighbour get the lowest label             
                pass # tomorrows work            
            #should i also compare pixel and left neighbour?

#find width of the letter
#find height of the letter
#find the middle of the letter
#middle = [width/2][height/2] #?
#divide letter into 30 parts --> 5 x 6 array

#model letter
#letter A-Z, a-z, 0-9 (maybe more)

#compare each of the 30 parts of the letter with all model letters
#make a weighting

#print(letter)

im.save("D:\\Python26\\PYTHON-PROGRAMME\\bild2.jpg")
print('done')

【问题讨论】:

  • 嗯...魔鬼在细节中。为了使其正常工作,我认为您需要加载许多不同的字体。我的预感是 OCR 程序会循环使用各种字体,直到找到他们喜欢的字体。显然,有很多关于这个主题的论文发表。为什么要将其作为您的第一个 Python 任务之一来实现?
  • 更多说明:如果您的代码是黑白的,一切都很好。但是,如果某些字母/单词是灰色的怎么办?您需要类似 Gimp 的“按颜色给定阈值选择区域”操作。我个人会从计算暗度分布开始 - 平均暗度 + 图像的标准。然后我会从一个“白色”点开始,继续选择白色,直到我识别出非白色的岛屿——那些是潜在的字母。顺便说一句,您不需要随机性 - 广度优先搜索也可以帮助您定位所有黑色像素......诀窍在于定位岛屿。
  • 我的幼稚方法是:a)找到一个 iland,b)包围它,c)记住它在测试中的原始位置,d)从图像中删除它(将剩余区域涂成白色)和将其附加到要处理的迷你图像列表中……这是一种开始。我个人会阅读现有方法,因为线性代数和统计等可能会为你打包一些非常强大的东西。
  • 对……您刚刚描述了广度优先搜索。查一下。我建议通过 DFS,因为你可以在 N 个像素后停下来吃一个球而不是意大利面(不是那么重要)——因为这对于一个字母来说太大了。
  • 没错,理论上 DFS 和 BFS 应该计算相同的东西。在这种情况下,我更喜欢 BFS,因为它还可以为您计算级别 - 可以帮助您“剥洋葱”。

标签: python arrays artificial-intelligence ocr


【解决方案1】:

OCR 确实不是一件容易的事。这就是文本验证码仍然有效的原因:)

仅谈论字母提取而不是模式识别,您用来分离字母的技术称为Connected Component Labeling。由于您正在寻求一种更有效的方法来执行此操作,因此请尝试实现本文中描述的两遍算法。另一种描述可以在文章Blob extraction中找到。

编辑:这是我建议的算法的实现:

import sys
from PIL import Image, ImageDraw

class Region():
    def __init__(self, x, y):
        self._pixels = [(x, y)]
        self._min_x = x
        self._max_x = x
        self._min_y = y
        self._max_y = y

    def add(self, x, y):
        self._pixels.append((x, y))
        self._min_x = min(self._min_x, x)
        self._max_x = max(self._max_x, x)
        self._min_y = min(self._min_y, y)
        self._max_y = max(self._max_y, y)

    def box(self):
        return [(self._min_x, self._min_y), (self._max_x, self._max_y)]

def find_regions(im):
    width, height  = im.size
    regions = {}
    pixel_region = [[0 for y in range(height)] for x in range(width)]
    equivalences = {}
    n_regions = 0
    #first pass. find regions.
    for x in xrange(width):
        for y in xrange(height):
            #look for a black pixel
            if im.getpixel((x, y)) == (0, 0, 0, 255): #BLACK
                # get the region number from north or west
                # or create new region
                region_n = pixel_region[x-1][y] if x > 0 else 0
                region_w = pixel_region[x][y-1] if y > 0 else 0

                max_region = max(region_n, region_w)

                if max_region > 0:
                    #a neighbour already has a region
                    #new region is the smallest > 0
                    new_region = min(filter(lambda i: i > 0, (region_n, region_w)))
                    #update equivalences
                    if max_region > new_region:
                        if max_region in equivalences:
                            equivalences[max_region].add(new_region)
                        else:
                            equivalences[max_region] = set((new_region, ))
                else:
                    n_regions += 1
                    new_region = n_regions

                pixel_region[x][y] = new_region

    #Scan image again, assigning all equivalent regions the same region value.
    for x in xrange(width):
        for y in xrange(height):
                r = pixel_region[x][y]
                if r > 0:
                    while r in equivalences:
                        r = min(equivalences[r])

                    if not r in regions:
                        regions[r] = Region(x, y)
                    else:
                        regions[r].add(x, y)

    return list(regions.itervalues())

def main():
    im = Image.open(r"c:\users\personal\py\ocr\test.png")
    regions = find_regions(im)
    draw = ImageDraw.Draw(im)
    for r in regions:
        draw.rectangle(r.box(), outline=(255, 0, 0))
    del draw 
    #im.show()
    output = file("output.png", "wb")
    im.save(output)
    output.close()

if __name__ == "__main__":
    main()

这不是 100% 完美的,但由于您这样做只是为了学习,所以这可能是一个很好的起点。通过每个字符的边界框,您现在可以使用其他人在此处建议的神经网络。

【讨论】:

  • 你好 jbochi。在你写信给我之前,我就有了 Connected Component Labeling 的想法。我将在我的新版本中使用它。
  • 我犯了一个错误。我一行一行地看着。我应该先看完整封信,然后再看下一封信。就像你之前描述的那样。 :)
  • 但是为什么是北和西像素(考虑 4 连接时)而不是南和西像素?我从左上角开始,从左到右。
  • @kame,您应该始终测试您之前已经测试过的像素。假设您在 (x=5, y=5) 处发现了一个黑色像素。如果 (4, 5) 或 (5, 4) 也是黑色的,您应该给 (5, 5) 相同的区域/字母编号。如果它们都是白色的,请创建一个新的字母编号。如果您需要任何帮助来实现这一点,请告诉我。
  • 我要准备考试了,但我很快会继续
【解决方案2】:

OCR 非常非常难。即使使用计算机生成的字符,如果您事先不知道字体和字体大小,这也是相当具有挑战性的。即使您完全匹配字符,我也不会将其称为“开始”编程项目。这很微妙。

如果您想识别扫描的或手写的字符,那就更难了 - 您需要使用高级数学、算法和机器学习。关于这个主题的书籍和文章都不少,因此您无需重新发明轮子。

我很佩服你的努力,但我认为你还没有达到任何实际困难的程度。到目前为止,您只是随机探索像素并将它们从一个阵列复制到另一个阵列。您实际上还没有进行任何比较,我不确定您“随机行走”的目的。

  • 为什么是随机的?编写正确的随机算法非常困难。我建议先从确定性算法开始。
  • 为什么要从一个阵列复制到另一个阵列?为什么不直接比较?

当您进行比较时,您将不得不处理图像与“原型”不完全相同的事实,目前尚不清楚您将如何处理。

不过,根据您目前编写的代码,我有一个想法给您:尝试编写一个程序,通过图像中的“迷宫”找到自己的路。输入将是图像,加上起始像素和目标像素。输出是一条从起点到终点的迷宫路径。这是一个比 OCR 容易得多的问题 - 解决迷宫是计算机非常擅长的事情 - 但它仍然很有趣且具有挑战性。

【讨论】:

  • 你好 dmazzoni。在较新的版本中,我不使用随机性。现在我将使用 DFS 或 BFS。 / 从一个数组复制到另一个?因为我想将字母与模型字母进行比较。 / 我没有说我想如何进行比较,但我有一个计划;)迷宫的东西也很有趣,但尽管有警告,我还是会用 OCR 来做。 :)
【解决方案3】:

如今,大多数 OCR 算法都基于神经网络算法。 Hopfield networks 是一个很好的起点。基于可用的 Hopfield 模型here in C,我在 python 中构建了一个非常基本的图像识别算法,类似于您所描述的。我已经发布了完整的源代码here。这是一个玩具项目,不适合真正的 OCR,但可以让您朝着正确的方向开始。

Hopfield 模型用作自动关联存储器,以存储和调用一组位图图像。通过计算相应的权重矩阵来存储图像。此后,从任意配置开始,内存将准确定位到存储的图像,该图像在汉明距离方面最接近起始配置。 因此,如果存储图像的版本不完整或损坏,网络能够调用相应的原始图像。

可以在here 找到一个带有示例的 Java 小程序;网络使用数字 0-9 的示例输入进行训练。画在右边的方框里,点击测试,看看网络上的结果。

不要让数学符号吓到您,一旦您获得源代码,算法就很简单。

【讨论】:

  • 比起数学符号,我更害怕链接到的凌乱的 Python 代码。如果您打算将其作为答案的一部分,我可以建议您对其进行清理。
【解决方案4】:

OCR 非常非常困难!尝试 OCR 的方法将取决于您要完成的任务(手写识别、计算机生成的文本阅读等)

不过,为了让您入门,请阅读神经网络和 OCR。以下是一些关于该主题的即兴文章:

http://www.codeproject.com/KB/cs/neural_network_ocr.aspx

http://www.codeproject.com/KB/dotnet/simple_ocr.aspx

使用您最喜欢的搜索引擎查找信息。

玩得开心!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-23
    • 1970-01-01
    • 2018-04-01
    • 1970-01-01
    相关资源
    最近更新 更多