最近做文檔識別方面的項目,做漢字識別需要建立字庫,在網上找了各種OCR,感覺都不好,這方面的技術應該比較成熟了,OCR的軟件很多,但沒有找到幾篇有含金量量的論文,也沒有看到哪位大牛公開字庫,我用pygame渲染字體來生成字庫,也用PIL對整齊的圖片進行切割得到字庫。
pygame渲染字體來生成字庫
用pygame渲染字體我參考的這篇文章,根據GB2323-8標准,漢語中常用字3500個,覆蓋了99.7%的使用率,加上次常用共6763個,覆蓋99.99%的使用率。先生成一個字體圖片,從網上找來3500個常用漢字,對每一個子按字體進行渲染:
1 def pasteWord(word): 2 '''輸入一個文字,輸出一張包含該文字的圖片''' 3 pygame.init() 4 font = pygame.font.Font(os.path.join("./fonts", "a.ttf"), 22) 5 text = word.decode('utf-8') 6 imgName = "E:/dataset/chinesedb/chinese/"+text+".png" 7 paste(text,font,imgName) 8 9 def paste(text,font,imgName,area = (0, -9)): 10 '''根據字體,將一個文字黏貼到圖片上,並保存''' 11 im = Image.new("RGB", (32, 32), (255, 255, 255)) 12 rtext = font.render(text, True, (0, 0, 0), (255, 255, 255)) 13 sio = StringIO.StringIO() 14 pygame.image.save(rtext, sio) 15 sio.seek(0) 16 line = Image.open(sio) 17 im.paste(line, area) 18 #im.show() 19 im.save(imgName)
渲染圖片次數多總是報錯,對於渲染失敗的文字我又重試,最終得到了一個包含3510字(加上10個數字)的字庫:
字符分割生成字庫
另外一種辦法就是把3500個字放在word排好,然后轉PDF保存成圖片,像下面這樣:
密密麻麻的字,但非常整齊,不需要什么圖片處理算法,只要找到空白的行和列,按行和列就可以進行切割,切割出來也好,只要保存有序切割,切出來的圖片依然可以與字對應,下面是切割的代碼:
1 #!encoding=utf-8 2 import Image 3 import os 4 5 def yStart(grey): 6 m,n = grey.size 7 for j in xrange(n): 8 for i in xrange(m): 9 if grey.getpixel((i,j)) == 0: 10 return j 11 def yEnd(grey): 12 m,n = grey.size 13 for j in xrange(n-1,-1,-1): 14 for i in xrange(m): 15 if grey.getpixel((i,j)) == 0: 16 return j 17 18 def xStart(grey): 19 m,n = grey.size 20 for i in xrange(m): 21 for j in xrange(n): 22 if grey.getpixel((i,j)) == 0: 23 return i 24 def xEnd(grey): 25 m,n = grey.size 26 for i in xrange(m-1,-1,-1): 27 for j in xrange(n): 28 if grey.getpixel((i,j)) == 0: 29 return i 30 def xBlank(grey): 31 m,n = grey.size 32 blanks = [] 33 for i in xrange(m): 34 for j in xrange(n): 35 if grey.getpixel((i,j)) == 0: 36 break 37 if j == n-1: 38 blanks.append(i) 39 return blanks 40 41 def yBlank(grey): 42 m,n = grey.size 43 blanks = [] 44 for j in xrange(n): 45 for i in xrange(m): 46 if grey.getpixel((i,j)) == 0: 47 break 48 if i == m-1: 49 blanks.append(j) 50 return blanks 51 52 def getWordsList(): 53 f = open('3500.txt') 54 line = f.read().strip() 55 wordslist = line.split(' ') 56 f.close() 57 return wordslist 58 59 count = 0 60 wordslist = [] 61 def getWordsByBlank(img,path): 62 '''根據行列的空白取圖片,效果不錯''' 63 global count 64 global wordslist 65 grey = img.split()[0] 66 xblank = xBlank(grey) 67 yblank = yBlank(grey) 68 #連續的空白像素可能不止一個,但我們只保留連續區域的第一個空白像素和最后一個空白像素,作為文字的起點和終點 69 xblank = [xblank[i] for i in xrange(len(xblank)) if i == 0 or i == len(xblank)-1 or not (xblank[i]==xblank[i-1]+1 and xblank[i]==xblank[i+1]-1)] 70 yblank = [yblank[i] for i in xrange(len(yblank)) if i == 0 or i == len(yblank)-1 or not (yblank[i]==yblank[i-1]+1 and yblank[i]==yblank[i+1]-1)] 71 for j in xrange(len(yblank)/2): 72 for i in xrange(len(xblank)/2): 73 area = (xblank[i*2],yblank[j*2],xblank[i*2+1]+32,yblank[j*2]+32)#這里固定字的大小是32個像素 74 #area = (xblank[i*2],yblank[j*2],xblank[i*2+1],yblank[j*2+1]) 75 word = img.crop(area) 76 word.save(path+wordslist[count]+'.png') 77 count += 1 78 if count >= len(wordslist): 79 return 80 81 82 def getWordsFormImg(imgName,path): 83 png = Image.open(imgName,'r') 84 img = png.convert('1') 85 grey = img.split()[0] 86 #先剪出文字區域 87 area = (xStart(grey)-1,yStart(grey)-1,xEnd(grey)+2,yEnd(grey)+2) 88 img = img.crop(area) 89 getWordsByBlank(img,path) 90 91 def getWrods(): 92 global wordslist 93 wordslist = getWordsList() 94 imgs = ["l1.png","l2.png","l3.png"] 95 for img in imgs: 96 getWordsFormImg(img,'words/') 97 98 if __name__ == "__main__": 99 getWrods()
切出來的字的效果也很好的:
自己對這圖像處理本來就不熟悉,用的都是土包子的方法。漢字的識別難度是比較大的,對應整齊的圖片,采樣DTW對字庫求相似項,效果還不錯,但用掃描儀、相機拍下來的文章切割處理后,效果很差。我用了BP神經網絡,但3500個漢字相當於3500個類,這個超多類別的分類問題,BP也很難應付,主要是訓練數據太少,手里只有一份字庫。
如果您有什么好的方法識別圖片漢字的方法,希望給與我分享,謝謝!