最近在項目中遇到關于字符識別的需求,所以寫篇文章分享一下^_^
?1.識別流程綜述
??????? 首先,要識別的圖像是只有表格數據區的像并且圖像的位置需要正(這里的正是指圖像要么偏90°要么就是完全擺正的.)
然后對于輸入的圖片按照表格的邊界裁剪,裁剪出來的表格一定是一個單元格,這個單元格只包含數據.像下面這樣的:
最后調用tesseract-ocr對這些小的單元格上的字符進行識別.
2.圖像預處理部分
??????? 我們需要先對輸入的圖像進行灰度處理,如果直接使用
???????????????????? image = cv2.imread(image_path)
函數讀取的圖像是有三個維度的,這個可以使用numpy中的
image.shape
屬性看出來,正常的圖片是三個維度,灰度圖是有兩個維度.(當圖像被讀取出來后就可以看作三維的矩陣)
???????? 灰度處理還不夠,因為cv2.findContour函數輸入的圖像必須是一個二值化的圖像.所以需要調用
adaptive_binary = cv2.adaptiveThreshold(src_gray_image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
和
ret, thresh = cv2.threshold(adaptive_binary, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
將圖像轉化為二值圖,像下面這種
???????? 在二值圖的基礎上調用
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
函數找到圖像上所有閉合的曲線.為了便于觀察,我將所有的曲線都畫在了圖像上
在這些曲線里面只有能正確截取數據單元格的曲線才是我們想要的,所以需要對這寫曲線進行過濾.我采用的第一層過濾就是使用閉合曲線的面積,計算閉合曲線的面積可以使用
for cnt? in contours:
??????? area = cv2.contourArea(cnt)
? ? ? if area < threshold:
????????????? continue
????? else:
? ? ? ?? x, y, w, h = cv2.boundingRect(cnt)??? # x,y表示矩形框的左下角點坐標,w,h表示寬和高
函數, 通過面積過濾后剩下的矩形閉合曲線我畫在下圖:
接下來就可以對給定的圖像進行裁剪了,裁剪使用的方法很簡單,把給定的圖像看成一個二維的矩陣,只需要根據cv2.boundingRect輸出的數據在矩陣里面截取子矩陣.
pice = src_image[(y + yoffset) : (y + w - yoffset), (x + xoffset) : (x + w - xoffset)]
然后使用tesseract-ocr對這些單元格進行識別,采用多進程
def distinguish(self, pice_list):
??????? pool = multiprocessing.Pool(processes = 4)
??????? for pice in pice_list:
????????????? outfile = self.outdir + pice.split("/")[-1][:-4]
???????????? conmand = 'tesseract ' + pice + ' '+ outfile + ' -psm 6 t_config'? # tesseract 圖像位置 輸出文件名稱? 參數
???????????? pool.apply_async(os.system, (conmand,))
?????? pool.close()
?????? pool.join()
最后將輸出文件按照裁剪順序將內容讀取出來拼接一下就能得到想要的結果了.^_^(第一次寫,有錯誤的地方歡迎指出,輕噴~)