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