<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          基于OpenCV的表格文本內(nèi)容提取

          共 8353字,需瀏覽 17分鐘

           ·

          2020-09-06 06:48


          點擊上方小白學(xué)視覺”,選擇加"星標(biāo)"或“置頂

          重磅干貨,第一時間送達

          小伙伴們可能會覺得從圖像中提取文本是一件很麻煩的事情,尤其是需要提取大量文本時。PyTesseract是一種光學(xué)字符識別(OCR),該庫提了供文本圖像。

          PyTesseract確實有一定的效果,用PyTesseract來檢測短文本時,結(jié)果相當(dāng)不錯。但是,當(dāng)我們用它來檢測表格中的文本時,算法執(zhí)行失敗。

          圖1.直接使用PyTesseract檢測表中的文本

          圖1描繪了文本檢測結(jié)果,綠色框包圍了檢測到的單詞。可以看出算法對于大部分文本都無法檢測,尤其是數(shù)字。而這些數(shù)字卻是展示了每日COVID-19病例的相關(guān)信息。那么,如何提取這些信息?

          簡介

          在編寫算法時,我們通常應(yīng)該以我們?nèi)祟惱斫鈫栴}的方式來編寫算法。這樣,我們可以輕松地將想法轉(zhuǎn)化為算法。

          當(dāng)我們閱讀表格時,首先注意到的就是單元格。一個單元格使用邊框(線)與另一個單元格分開,邊框可以是垂直的也可以是水平的。識別單元格后,我們繼續(xù)閱讀其中的信息。將其轉(zhuǎn)換為算法,您可以將過程分為三個過程,即單元格檢測區(qū)域(ROI)選擇文本提取

          在執(zhí)行每個任務(wù)之前,讓我們先導(dǎo)入必要內(nèi)容

          import cv2 as cvimport numpy as npfilename = 'filename.png'img = cv.imread(cv.samples.findFile(filename))cImage = np.copy(img) #image to draw linescv.imshow("image", img) #name the window as "image"cv.waitKey(0)cv.destroyWindow("image") #close the window

          單元格檢測

          查找表格中的水平線和垂直線可能是最容易開始的。有多種檢測線的方法,這里我們采用OpenCV庫中的Hough Line Transform。

          在應(yīng)用霍夫線變換之前,需要進行一些預(yù)處理。第一是將存在的RGB圖像轉(zhuǎn)換為灰度圖像。因為灰度圖像對于Canny邊緣檢測而言非常重要。

          gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)cv.imshow("gray", gray)cv.waitKey(0)cv.destroyWindow("gray")canny = cv.Canny(gray, 50, 150)cv.imshow("canny", canny)cv.waitKey(0)cv.destroyWindow("canny")

          下面的兩幅圖分別顯示了灰度圖像和Canny圖像。

          圖2.灰度和Canny圖像

          霍夫線變換

          在OpenCV中,此算法有兩種類型,即標(biāo)準(zhǔn)霍夫線變換和概率霍夫線變換。標(biāo)準(zhǔn)變換為我們提供直線方程,因此我們無法得知直線的起點和終點。概率變換將為我們提供線列表,即直線起點與終點的坐標(biāo)值列表。我們優(yōu)先選用的是概率變化。

          圖3.霍夫線變換結(jié)果示例(來源:OpenCV)

          對于HoughLinesP函數(shù),有如下幾個輸入?yún)?shù):

          • image?-8位單通道二進制源圖像。該圖像可以通過該功能進行修改。

          • rho?—累加器的距離分辨率,以像素為單位。

          • theta?—弧度的累加器角度分辨率。

          • threshold-累加器閾值參數(shù)。僅返回那些獲得足夠投票的行

          • line?—?線的輸出向量。這里設(shè)置為無,該值保存到linesP

          • minLineLength?—最小行長。短于此的線段將被拒絕。

          • maxLineGap?—同一線上的點之間允許鏈接的最大間隙。

          # cv.HoughLinesP(image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]]) → linesrho = 1theta = np.pi/180threshold = 50minLinLength = 350maxLineGap = 6linesP = cv.HoughLinesP(canny, rho , theta, threshold, None, minLinLength, maxLineGap)

          為了區(qū)分水平線和垂直線,我們定義了一個函數(shù)并根據(jù)該函數(shù)的返回值添加列表。

          def is_vertical(line):    return line[0]==line[2]def is_horizontal(line):    return line[1]==line[3]horizontal_lines = []vertical_lines = []
          if linesP is not None: for i in range(0, len(linesP)): l = linesP[i][0] if (is_vertical(l)): vertical_lines.append(l)
          elif (is_horizontal(l)): horizontal_lines.append(l)for i, line in enumerate(horizontal_lines): cv.line(cImage, (line[0], line[1]), (line[2], line[3]), (0,255,0), 3, cv.LINE_AA)
          for i, line in enumerate(vertical_lines): cv.line(cImage, (line[0], line[1]), (line[2], line[3]), (0,0,255), 3, cv.LINE_AA)
          cv.imshow("with_line", cImage)cv.waitKey(0)cv.destroyWindow("with_line") #close the window


          圖4.霍夫線變換結(jié)果—沒有重疊濾波器

          重疊濾波器

          檢測到的線如上圖所示。但是,霍夫線變換結(jié)果中有一些重疊的線。較粗的線由多個相同位置,長度不同的線組成。為了消除此重疊線,我們定義了一個重疊過濾器。

          最初,基于分類索引對線進行分類,水平線的y?和垂直線的x?。如果下一行的間隔小于一定距離,則將其視為與上一行相同的行。

          def overlapping_filter(lines, sorting_index):    filtered_lines = []
          lines = sorted(lines, key=lambda lines: lines[sorting_index]) separation = 5 for i in range(len(lines)): l_curr = lines[i] if(i>0): l_prev = lines[i-1] if ( (l_curr[sorting_index] - l_prev[sorting_index]) > separation): filtered_lines.append(l_curr) else: filtered_lines.append(l_curr)
          return filtered_lines

          實現(xiàn)重疊濾鏡并在圖像上添加文本,現(xiàn)在代碼應(yīng)如下所示:

          horizontal_lines = []vertical_lines = []
          if linesP is not None: for i in range(0, len(linesP)): l = linesP[i][0] if (is_vertical(l)): vertical_lines.append(l)
          elif (is_horizontal(l)): horizontal_lines.append(l) horizontal_lines = overlapping_filter(horizontal_lines, 1) vertical_lines = overlapping_filter(vertical_lines, 0)for i, line in enumerate(horizontal_lines): cv.line(cImage, (line[0], line[1]), (line[2], line[3]), (0,255,0), 3, cv.LINE_AA) cv.putText(cImage, str(i) + "h", (line[0] + 5, line[1]), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv.LINE_AA) for i, line in enumerate(vertical_lines): cv.line(cImage, (line[0], line[1]), (line[2], line[3]), (0,0,255), 3, cv.LINE_AA) cv.putText(cImage, str(i) + "v", (line[0], line[1] + 5), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv.LINE_AA)
          cv.imshow("with_line", cImage)cv.waitKey(0)cv.destroyWindow("with_line") #close the window


          圖5.霍夫線變換結(jié)果—帶重疊濾波器

          有了這個代碼,就不會提取出重疊的行了。此外,我們還將在圖像中寫入水平和垂直線的索引,這將有利于ROI的選擇。

          ROI選擇

          首先,我們需要定義列數(shù)和行數(shù)。這里我們只對第二行第十四行以及所有列中的數(shù)據(jù)感興趣。對于列,我們定義了一個名為關(guān)鍵字的列表,將其用于字典關(guān)鍵字。

          ## set keywordskeywords = ['no', 'kabupaten', 'kb_otg', 'kl_otg', 'sm_otg', 'ks_otg', 'not_cvd_otg',            'kb_odp', 'kl_odp', 'sm_odp', 'ks_odp', 'not_cvd_odp', 'death_odp',            'kb_pdp', 'kl_pdp', 'sm_pdp', 'ks_pdp', 'not_cvd_pdp', 'death_pdp',            'positif', 'sembuh', 'meninggal']
          dict_kabupaten = {} for keyword in keywords: dict_kabupaten[keyword] = []
          ## set counter for image indexingcounter = 0
          ## set line indexfirst_line_index = 1last_line_index = 14

          然后,要選擇ROI,我們定義了一個函數(shù),該函數(shù)將圖像(水平線和垂直線都作為輸入)以及線索引作為邊框。此函數(shù)返回裁剪的圖像及其在圖像全局坐標(biāo)中的位置和大小

          def get_cropped_image(image, x, y, w, h):    cropped_image = image[ y:y+h , x:x+w ]    return cropped_imagedef get_ROI(image, horizontal, vertical, left_line_index, right_line_index, top_line_index, bottom_line_index, offset=4):    x1 = vertical[left_line_index][2] + offset    y1 = horizontal[top_line_index][3] + offset    x2 = vertical[right_line_index][2] - offset    y2 = horizontal[bottom_line_index][3] - offset
          w = x2 - x1 h = y2 - y1
          cropped_image = get_cropped_image(image, x1, y1, w, h)
          return cropped_image, (x1, y1, w, h)

          裁剪的圖像將用于下一個任務(wù),即文本提取。返回的第二個參數(shù)將用于繪制ROI的邊界框

          文字提取

          現(xiàn)在,我們定義了ROI功能。我們可以繼續(xù)提取結(jié)果。我們可以通過遍歷單元格來讀取列中的所有數(shù)據(jù)。列數(shù)由關(guān)鍵字的長度指定,而行數(shù)則由定義。

          首先,讓我們定義一個函數(shù)來繪制文本和周圍的框,并定義另一個函數(shù)來提取文本。

          import pytesseractpytesseract.pytesseract.tesseract_cmd = r'C:\Program Files (x86)\Tesseract-OCR\tesseract.exe'def draw_text(src, x, y, w, h, text):    cFrame = np.copy(src)    cv.rectangle(cFrame, (x, y), (x+w, y+h), (255, 0, 0), 2)    cv.putText(cFrame, "text: " + text, (50, 50), cv.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 0), 5, cv.LINE_AA)
          return cFramedef detect(cropped_frame, is_number = False): if (is_number): text = pytesseract.image_to_string(cropped_frame, config ='-c tessedit_char_whitelist=0123456789 --psm 10 --oem 2') else: text = pytesseract.image_to_string(cropped_frame, config='--psm 10')
          return text

          將圖像轉(zhuǎn)換為黑白以獲得更好的效果,讓我們開始迭代!

          counter = 0print("Start detecting text...")(thresh, bw) = cv.threshold(gray, 100, 255, cv.THRESH_BINARY)for i in range(first_line_index, last_line_index):    for j, keyword in enumerate(keywords):        counter += 1
          left_line_index = j right_line_index = j+1 top_line_index = i bottom_line_index = i+1
          cropped_image, (x,y,w,h) = get_ROI(bw, horizontal, vertical, left_line_index, right_line_index, top_line_index, bottom_line_index)
          if (keywords[j]=='kabupaten'): text = detect(cropped_image) dict_kabupaten[keyword].append(text)
          else: text = detect(cropped_image, is_number=True) dict_kabupaten[keyword].append(text) image_with_text = draw_text(img, x, y, w, h, text)

          問題解決

          這是文本提取的結(jié)果!我們只選擇了最后三列,因為它對某些文本給出了奇怪的結(jié)果,其余的很好,所以我不顯示它。

          圖6.檢測到的文本—版本1

          一些數(shù)字被檢測為隨機文本,即39個數(shù)據(jù)中的5個。這是由于最后三列與其余列不同。文本為白色時背景為黑色,會以某種方式影響文本提取的性能。

          圖7.二進制圖像

          為了解決這個問題,讓我們倒數(shù)最后三列。

          def invert_area(image, x, y, w, h, display=False):    ones = np.copy(image)    ones = 1
          image[ y:y+h , x:x+w ] = ones*255 - image[ y:y+h , x:x+w ]
          if (display): cv.imshow("inverted", image) cv.waitKey(0) cv.destroyAllWindows() return imageleft_line_index = 17right_line_index = 20top_line_index = 0bottom_line_index = -1
          cropped_image, (x, y, w, h) = get_ROI(img, horizontal, vertical, left_line_index, right_line_index, top_line_index, bottom_line_index)gray = get_grayscale(img)bw = get_binary(gray)bw = invert_area(bw, x, y, w, h, display=True)

          結(jié)果如下所示。

          圖8.處理后的二進制圖像

          結(jié)果

          反轉(zhuǎn)圖像后,重新執(zhí)行步驟,這是最終結(jié)果!

          算法成功檢測到文本后,現(xiàn)在可以將其保存到Python對象(例如Dictionary或List)中。由于Tesseract訓(xùn)練數(shù)據(jù)中未包含某些地區(qū)名稱(“ Kabupaten / Kota”中的名稱),因此無法準(zhǔn)確檢測到。但是,由于可以精確檢測到地區(qū)的索引,因此這不會成為問題。文本提取可能無法檢測到其他字體的文本,具體取決于所使用的字體,如果出現(xiàn)誤解,例如將“ 5”檢測為“ 8”,則可以進行諸如腐蝕膨脹之類的圖像處理。

          源代碼:https://github.com/fazlurnu/Text-Extraction-Table-Image


          流群


          歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器自動駕駛、計算攝影、檢測、分割、識別、醫(yī)學(xué)影像、GAN算法競賽等微信群(以后會逐漸細(xì)分),請掃描下面微信號加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三?+?上海交大?+?視覺SLAM“。請按照格式備注,否則不予通過。添加成功后會根據(jù)研究方向邀請進入相關(guān)微信群。請勿在群內(nèi)發(fā)送廣告,否則會請出群,謝謝理解~



          瀏覽 52
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  影音先锋AV成人资源网 | 淫色激情网| 国产黄视频在线免费看 | 久久美国发布站 | 中文字幕在线成人 |