我自己的Python OCR程序

27 投票
4 回答
22746 浏览
提问于 2025-04-15 17:32

我还是个初学者,但我想写一个字符识别程序。这个程序还没有完成。我修改了很多地方,所以评论可能和代码不完全一致。我会使用8连通性来进行连通组件标记。

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

4 个回答

5

现在大多数的光学字符识别(OCR)算法都是基于神经网络的。霍普菲尔德网络是一个很好的入门选择。基于霍普菲尔德模型,我在这里用C语言实现了一个非常基础的图像识别算法,和你描述的类似。我把完整的源代码放在这里。这个项目只是个玩具,不适合真正的OCR,但可以帮助你入门。

霍普菲尔德模型被用作一种自联想记忆,用来存储和回忆一组位图图像。图像通过计算一个对应的权重矩阵来存储。之后,从一个任意的配置开始,记忆会稳定到与起始配置在汉明距离上最接近的那个存储图像。因此,给定一个不完整或损坏的存储图像,网络能够回忆出对应的原始图像。

你可以在这里找到一个Java小程序来玩一个例子;这个网络是用数字0到9的示例输入进行训练的。在右边的框里画图,点击测试,看看网络的结果。

不要被数学符号吓到,一旦你看到源代码,这些算法其实很简单。

7

OCR(光学字符识别)是非常非常难的。即使是计算机生成的字符,如果你事先不知道字体和字号,识别起来也会很有挑战性。即使你能完全匹配字符,我也不认为这算是一个“入门”编程项目,因为这其中的细节非常复杂。

如果你想识别扫描的或手写的字符,那就更难了——你需要用到高级数学、算法和机器学习。关于这个话题,有很多书籍和成千上万的文章,所以你不需要重新发明轮子。

我很欣赏你的努力,但我觉得你还没有遇到真正的困难。到目前为止,你只是随机探索像素,并把它们从一个数组复制到另一个数组。你还没有进行任何比较,我也不太明白你“随机漫步”的目的是什么。

  • 为什么要随机?写出正确的随机算法是相当困难的。我建议你先从一个确定性的算法开始。
  • 你为什么要从一个数组复制到另一个数组?为什么不直接进行比较呢?

当你进行比较时,你会发现图像和“原型”并不完全相同,而你还不清楚该如何处理这种情况。

不过,根据你到目前为止写的代码,我有个建议:试着写一个程序,让它在图像中的“迷宫”里找到出路。输入是图像,还有起始像素和目标像素。输出是从起点到目标的路径。这比OCR简单多了——解决迷宫问题是计算机擅长的事情,但这仍然有趣且具有挑战性。

34

确实,OCR(光学字符识别)并不是一件简单的事情。这也是为什么文字验证码仍然有效的原因 :)

如果只谈字母提取,而不涉及模式识别,你现在用来分离字母的技术叫做 连通组件标记。既然你在寻找更高效的方法,可以试试这篇文章中提到的双通道算法。你也可以在这篇文章中找到另一种描述:Blob提取

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

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

这个实现并不是百分之百完美,但因为你只是为了学习,所以这可能是一个不错的起点。通过每个字符的边框框选,你现在可以像其他人建议的那样使用神经网络。

撰写回答