日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

用OpenCV和OCR识别图片中的表格数据

發布時間:2024/1/1 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用OpenCV和OCR识别图片中的表格数据 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

作者:?jclian,喜歡算法,熱愛分享,希望能結交更多志同道合的朋友一起在學習Python的道路上走得更遠!

??在很多時候,我們的數據來源形式是多種多樣的,有時候數據(或表格)也會呈現在圖片中。那么,我們如何來獲取圖片中的有用數據呢?當一張圖片中含有表格數據的時候,我們可以用OpenCV識別表格中的直線,然后再用OCR技術識別其中的文字。
??本文僅作為如何識別圖片中的表格的一個例子,希望能給讀者一些啟示。筆者用到的工具如下:

  • opencv

  • pyteressact

  • numpy

我們用opencv來識別表格中的直線,用pyteressact來識別單元格文字,用numpy做數值處理。我們要識別的示例圖片(AI.png)如下:

示例圖片 AI.png

我們分以下幾步進行識別:

  • 識別表格中的橫線,即分割記錄(每一行)的橫線;

  • 識別表格中的豎線,即每個列的分割線;

  • 找到數據所在的單元格;

  • 利用pyteressact識別單元格的文字。

  • 識別表格中的橫線

    ??識別橫線之前,我們先創建一個圖片表格識別類(ImageTableOCR),如下:

    #?-*-?coding:?utf-8?-*-
    import?cv2
    import?pytesseract
    import?numpy?as?np

    class?ImageTableOCR(object):

    ????#?初始化
    ????def?__init__(self,?ImagePath):
    ????????#?讀取圖片
    ????????self.image?=?cv2.imread(ImagePath,?1)
    ????????#?把圖片轉換為灰度模式
    ????????self.gray?=?cv2.cvtColor(self.image,?cv2.COLOR_BGR2GRAY)

    其中self.image為RGB模塊的圖片,self.gray為灰度模式的圖片。
    ??接下來,我們識別圖片中的分割兩條記錄的橫線。注意到,相鄰兩條記錄之間的顏色是不一致的,因此,我們利用圖片灰度化后,每一行像素的平均值的差的絕對值來作為相鄰兩條記錄的分割線,這樣就能檢測出分割兩條記錄的橫線了。具體的識別橫線的函數的Python代碼如下:(接以上代碼)

    ????#?橫向直線檢測
    ????def?HorizontalLineDetect(self):

    ????????#?圖像二值化
    ????????ret,?thresh1?=?cv2.threshold(self.gray,?240,?255,?cv2.THRESH_BINARY)
    ????????#?進行兩次中值濾波
    ????????blur?=?cv2.medianBlur(thresh1,?3)??#?模板大小3*3
    ????????blur?=?cv2.medianBlur(blur,?3)??#?模板大小3*3

    ????????h,?w?=?self.gray.shape

    ????????#?橫向直線列表
    ????????horizontal_lines?=?[]
    ????????for?i?in?range(h?-?1):
    ????????????#?找到兩條記錄的分隔線段,以相鄰兩行的平均像素差大于120為標準
    ????????????if?abs(np.mean(blur[i,?:])?-?np.mean(blur[i?+?1,?:]))?>?120:
    ????????????????#?在圖像上繪制線段
    ????????????????horizontal_lines.append([0,?i,?w,?i])
    ????????????????cv2.line(self.image,?(0,?i),?(w,?i),?(0,?255,?0),?2)

    ????????horizontal_lines?=?horizontal_lines[1:]
    ????????#?print(horizontal_lines)
    ????????return?horizontal_lines

    首先對圖片進行二值化處理,再進行兩次中值濾波,這樣是為了使相鄰兩條記錄之間的像素區別盡可能大。然后對該圖片中的每一行的像素進行檢測, 以相鄰兩行的平均像素差大于120為標準, 識別出分割兩條記錄的橫線。識別后的橫線如下:(圖片中的綠色線段)

    識別橫線后的圖片

    識別表格中的豎線

    ??在這一步中,我們利用opencv中的Hough直線檢測方法來檢測圖片中的豎線。完整的Python代碼如下:(接以上代碼)

    ????#??縱向直線檢測
    ????def?VerticalLineDetect(self):
    ????????#?Canny邊緣檢測
    ????????edges?=?cv2.Canny(self.gray,?30,?240)

    ????????#?Hough直線檢測
    ????????minLineLength?=?500
    ????????maxLineGap?=?30
    ????????lines?=?cv2.HoughLinesP(edges,?1,?np.pi/180,?100,?minLineLength,?maxLineGap).tolist()
    ????????lines.append([[13,?937,?13,?102]])
    ????????lines.append([[756,?937,?756,?102]])
    ????????sorted_lines?=?sorted(lines,?key=lambda?x:?x[0])

    ????????#?縱向直線列表
    ????????vertical_lines?=?[]
    ????????for?line?in?sorted_lines:
    ????????????for?x1,?y1,?x2,?y2?in?line:
    ????????????????#?在圖片上繪制縱向直線
    ????????????????if?x1?==?x2:
    ????????????????????print(line)
    ????????????????????vertical_lines.append((x1,?y1,?x2,?y2))
    ????????????????????cv2.line(self.image,?(x1,?y1),?(x2,?y2),?(0,?0,?255),?2)

    ????????return?vertical_lines

    首先我們對灰度圖片進行Canny邊緣檢測,在此基礎上再利用Hough直線檢測方法識別圖片中的直線,要求識別的最大間距為30,線段長度最小為500,并且為豎直直線(x1 == x2),當然,也有一些人為的因素,那就是筆者自己添加了兩條豎直直線([[13, 937, 13, 102]],[[756, 937, 756, 102]])。運行上述方法,輸出的結果如下:

    [[13, 937, 13, 102]]
    [[75, 937, 75, 102]]
    [[77, 937, 77, 102]]
    [[270, 937, 270, 104]]
    [[272, 937, 272, 102]]
    [[756, 937, 756, 102]]

    識別豎直直線后的圖片如下:(圖片中的紅色線段)

    識別豎線后的圖片

    可以看到,圖片六條豎直的線段都已經完整標記出來了。

    識別圖片中的單元格

    ??在識別圖片中的單元格之前,我們先來識別每個單元格所在的頂點,也就是上述識別后的橫線與豎線的交點。完整的Python代碼如下:(接以上代碼)

    ????#?頂點檢測
    ????def?VertexDetect(self):
    ????????vertical_lines?=?self.VerticalLineDetect()
    ????????horizontal_lines?=?self.HorizontalLineDetect()

    ????????#?頂點列表
    ????????vertex?=?[]
    ????????for?v_line?in?vertical_lines:
    ????????????for?h_line?in?horizontal_lines:
    ????????????????vertex.append((v_line[0],?h_line[1]))

    ????????#print(vertex)

    ????????#?繪制頂點
    ????????for?point?in?vertex:
    ????????????cv2.circle(self.image,?point,?1,?(255,?0,?0),?2)

    ????????return?vertex

    頂點檢測后的圖片如下:(圖片中的藍色點即為每個單元格的頂點)

    頂點檢測后的圖片

    由此可見,我們識別出來的單元格的頂點是正確的。接著,我們把這些單元格取出來,代碼如下:(接以上代碼)

    #?尋找單元格區域
    ????def?CellDetect(self):
    ????????vertical_lines?=?self.VerticalLineDetect()
    ????????horizontal_lines?=?self.HorizontalLineDetect()

    ????????#?頂點列表
    ????????rects?=?[]
    ????????for?i?in?range(0,?len(vertical_lines)?-?1,?2):
    ????????????for?j?in?range(len(horizontal_lines)?-?1):
    ????????????????rects.append((vertical_lines[i][0],?horizontal_lines[j][1],?
    ??????????????????????????????vertical_lines[i?+?1][0],?horizontal_lines[j?+?1][1]))

    ????????#?print(rects)
    ????????return?rects

    以第一個單元格為例,其圖像如下:

    第一個單元格的圖片

    識別單元格的文字

    ??在識別出圖片中表格的單元格后,我們可以對該單元格圖片進行文字識別,我們使用的OCR工具為Teressact, 其Python的接口為pyteressact 。具體的Python代碼如下:(接以上代碼)

    #?識別單元格中的文字
    ????def?OCR(self):
    ????????rects?=?self.CellDetect()
    ????????thresh?=?self.gray

    ????????#?特殊字符列表
    ????????special_char_list?=?'?`~!@#$%^&*()-_=+[]{}|\;:‘’,。《》/?ˇ'
    ????????for?i?in?range(20):
    ????????????rect1?=?rects[i]
    ????????????DetectImage1?=?thresh[rect1[1]:rect1[3],?rect1[0]:rect1[2]]

    ????????????#?Tesseract所在的路徑
    ????????????pytesseract.pytesseract.tesseract_cmd?=?'C://Program?Files?(x86)/Tesseract-OCR/tesseract.exe'
    ????????????#?識別數字(每行第一列)
    ????????????text1?=?pytesseract.image_to_string(DetectImage1,?config="--psm?10")
    ????????????print(text1,?end='-->')

    ????????????#?識別漢字(每行第二列)
    ????????????rect2?=?rects[i+20]
    ????????????DetectImage2?=?thresh[rect2[1]:rect2[3],?rect2[0]:rect2[2]]
    ????????????text2?=?pytesseract.image_to_string(DetectImage2,?config='--psm?7',?lang='chi_sim')
    ????????????text2?=?''.join([char?for?char?in?text2?if?char?not?in?special_char_list])
    ????????????print(text2,?end='-->')

    ????????????#?識別漢字(每行第三列)
    ????????????rect3?=?rects[i+40]
    ????????????DetectImage3?=?thresh[rect3[1]:rect3[3],?rect3[0]:rect3[2]]
    ????????????text3?=?pytesseract.image_to_string(DetectImage3,?config='--psm?7',?lang='chi_sim')
    ????????????text3?=?''.join([char?for?char?in?text3?if?char?not?in?special_char_list])
    ????????????print(text3)

    識別后的結果如下:

    I-->度一-->開放的人一智能服務平臺
    2-->肌訊-->互聯網綜合服務
    3-->標為-->人一智能自動化業務、智能屹片
    4-->阿里巴巴-->互聯網綜合服務
    5-->平安集口-->人T智能金融研發平仄
    6-->華大基因-->精準檢測、醫療數據運營服務
    d-->搜狗-->綜合人T智能解決方案平臺
    8-->一科大訊飛-->智能語音技術
    9-->一中利創湯-->智能終端平臺技術
    10-->珍山集團-->SaaS級智能營銷云平臺
    i-->商湯科技-->人工智能視覺深度學習平臺
    12-->神州泰岳-->綜合類軟件產品及服務
    13-->寒武紅科技-->深度學對專用的智能盂片
    14-->漢王科技-->文字識別技術與智能交工
    15-->全志刑技-->智能芯片設計
    16-->face曠視科技-->人T智能產品和行業解夷方案
    17-->創略科技-->智能客戶數據平臺
    18-->海云數據-->企業級大數據整體運營與分析服務
    19-->影渭科技-->視覺技術、智能影像生產企業
    20-->智蹈智能-->智能機器人技術提供和平臺運蕭

    下面,我們來統計一下識別的準確率。在原來的表格中,一共是20個數字加上280個漢字(包括標點)加上10個英語字母(包括標點),對于識別的結果,其中數字類識別正確17個,漢字正確256個,英語字母8個,因此,總的識別的準確率為90.6% ,識別的結果還是可以的。

    總結

    ??本文僅作為如何識別圖片中的表格的一個例子,希望能給讀者一些啟示。對于不同的圖片表格,需要具體問題具體分析。
    ??雖然筆者盡可能把整個過程寫得簡單明了,但其中的探索過程卻是很復雜的。而且值得注意的是,在本文中的檢測橫線的方法僅適用于相鄰兩條記錄有顏色差別的表格圖片。
    ??完整的Python代碼如下,希望能給大家一些思考。

    #?-*-?coding:?utf-8?-*-
    import?cv2
    import?pytesseract
    import?numpy?as?np

    class?ImageTableOCR(object):

    ????#?初始化
    ????def?__init__(self,?ImagePath):
    ????????#?讀取圖片
    ????????self.image?=?cv2.imread(ImagePath,?1)
    ????????#?把圖片轉換為灰度模式
    ????????self.gray?=?cv2.cvtColor(self.image,?cv2.COLOR_BGR2GRAY)

    ????#?橫向直線檢測
    ????def?HorizontalLineDetect(self):

    ????????#?圖像二值化
    ????????ret,?thresh1?=?cv2.threshold(self.gray,?240,?255,?cv2.THRESH_BINARY)
    ????????#?進行兩次中值濾波
    ????????blur?=?cv2.medianBlur(thresh1,?3)??#?模板大小3*3
    ????????blur?=?cv2.medianBlur(blur,?3)??#?模板大小3*3

    ????????h,?w?=?self.gray.shape

    ????????#?橫向直線列表
    ????????horizontal_lines?=?[]
    ????????for?i?in?range(h?-?1):
    ????????????#?找到兩條記錄的分隔線段,以相鄰兩行的平均像素差大于120為標準
    ????????????if?abs(np.mean(blur[i,?:])?-?np.mean(blur[i?+?1,?:]))?>?120:
    ????????????????#?在圖像上繪制線段
    ????????????????horizontal_lines.append([0,?i,?w,?i])
    ????????????????#?cv2.line(self.image,?(0,?i),?(w,?i),?(0,?255,?0),?2)

    ????????horizontal_lines?=?horizontal_lines[1:]
    ????????#?print(horizontal_lines)
    ????????return?horizontal_lines

    ????#??縱向直線檢測
    ????def?VerticalLineDetect(self):
    ????????#?Canny邊緣檢測
    ????????edges?=?cv2.Canny(self.gray,?30,?240)

    ????????#?Hough直線檢測
    ????????minLineLength?=?500
    ????????maxLineGap?=?30
    ????????lines?=?cv2.HoughLinesP(edges,?1,?np.pi/180,?100,?minLineLength,?maxLineGap).tolist()
    ????????lines.append([[13,?937,?13,?102]])
    ????????lines.append([[756,?937,?756,?102]])
    ????????sorted_lines?=?sorted(lines,?key=lambda?x:?x[0])

    ????????#?縱向直線列表
    ????????vertical_lines?=?[]
    ????????for?line?in?sorted_lines:
    ????????????for?x1,?y1,?x2,?y2?in?line:
    ????????????????#?在圖片上繪制縱向直線
    ????????????????if?x1?==?x2:
    ????????????????????#?print(line)
    ????????????????????vertical_lines.append((x1,?y1,?x2,?y2))
    ????????????????????#?cv2.line(self.image,?(x1,?y1),?(x2,?y2),?(0,?0,?255),?2)

    ????????return?vertical_lines

    ????#?頂點檢測
    ????def?VertexDetect(self):
    ????????vertical_lines?=?self.VerticalLineDetect()
    ????????horizontal_lines?=?self.HorizontalLineDetect()

    ????????#?頂點列表
    ????????vertex?=?[]
    ????????for?v_line?in?vertical_lines:
    ????????????for?h_line?in?horizontal_lines:
    ????????????????vertex.append((v_line[0],?h_line[1]))

    ????????#print(vertex)

    ????????#?繪制頂點
    ????????for?point?in?vertex:
    ????????????cv2.circle(self.image,?point,?1,?(255,?0,?0),?2)

    ????????return?vertex

    ????#?尋找單元格區域
    ????def?CellDetect(self):
    ????????vertical_lines?=?self.VerticalLineDetect()
    ????????horizontal_lines?=?self.HorizontalLineDetect()

    ????????#?頂點列表
    ????????rects?=?[]
    ????????for?i?in?range(0,?len(vertical_lines)?-?1,?2):
    ????????????for?j?in?range(len(horizontal_lines)?-?1):
    ????????????????rects.append((vertical_lines[i][0],?horizontal_lines[j][1],?
    ??????????????????????????????vertical_lines[i?+?1][0],?horizontal_lines[j?+?1][1]))

    ????????#?print(rects)
    ????????return?rects

    ????#?識別單元格中的文字
    ????def?OCR(self):
    ????????rects?=?self.CellDetect()
    ????????thresh?=?self.gray

    ????????#?特殊字符列表
    ????????special_char_list?=?'?`~!@#$%^&*()-_=+[]{}|\;:‘’,。《》/?ˇ'
    ????????for?i?in?range(20):
    ????????????rect1?=?rects[i]
    ????????????DetectImage1?=?thresh[rect1[1]:rect1[3],?rect1[0]:rect1[2]]

    ????????????#?Tesseract所在的路徑
    ????????????pytesseract.pytesseract.tesseract_cmd?=?'C://Program?Files?(x86)/Tesseract-OCR/tesseract.exe'
    ????????????#?識別數字(每行第一列)
    ????????????text1?=?pytesseract.image_to_string(DetectImage1,?config="--psm?10")
    ????????????print(text1,?end='-->')

    ????????????#?識別漢字(每行第二列)
    ????????????rect2?=?rects[i+20]
    ????????????DetectImage2?=?thresh[rect2[1]:rect2[3],?rect2[0]:rect2[2]]
    ????????????text2?=?pytesseract.image_to_string(DetectImage2,?config='--psm?7',?lang='chi_sim')
    ????????????text2?=?''.join([char?for?char?in?text2?if?char?not?in?special_char_list])
    ????????????print(text2,?end='-->')

    ????????????#?識別漢字(每行第三列)
    ????????????rect3?=?rects[i+40]
    ????????????DetectImage3?=?thresh[rect3[1]:rect3[3],?rect3[0]:rect3[2]]
    ????????????text3?=?pytesseract.image_to_string(DetectImage3,?config='--psm?7',?lang='chi_sim')
    ????????????text3?=?''.join([char?for?char?in?text3?if?char?not?in?special_char_list])
    ????????????print(text3)

    ????#?顯示圖像
    ????def?ShowImage(self):
    ????????cv2.imshow('AI',?self.image)
    ????????cv2.waitKey(0)
    ????????#?cv2.imwrite('E://Horizontal.png',?self.image)

    ImagePath?=?'E://AI.png'
    imageOCR?=?ImageTableOCR(ImagePath)
    imageOCR.OCR()

    熱 門 推 薦
    為你的Python程序加密
    用Python開發計時器程序
    硬核 | 用Python給女朋友送一顆彩蛋

    用Pandas庫實現MySQL數據庫的讀寫
    推薦Python中文社區旗下的幾個服務類公眾號

    ▼ 長按掃碼上方二維碼或點擊下方閱讀原文

    免費成為社區注冊會員,會員可以享受更多權益

    總結

    以上是生活随笔為你收集整理的用OpenCV和OCR识别图片中的表格数据的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。