[Python爬蟲] 九、機器視覺與機器圖像識別之Tesseract


往期內容提要:

另:感謝大家一直以來對我的關注和支持,我已於今日(2020年2月17日)認證爲博客專家,距19年3月14日第一次發文,已經11個月了,感謝CSDN官方對我博文的認可,博客專家是對我的莫大的激勵,自己會繼續努力寫出更多更有質量的博文,在研究領域不斷探索和進步。
在這裏插入圖片描述


一、機器視覺

從 Google 的無人駕駛汽車到可以識別假鈔的自動售賣機,機器視覺一直都是一個應用廣 泛且具有深遠的影響和雄偉的願景的領域。

我們將重點介紹機器視覺的一個分支:文字識別,介紹如何用一些 Python庫來識別和使用在線圖片中的文字。

我們可以很輕鬆的閱讀圖片裏的文字,但是機器閱讀這些圖片就會非常困難,利用這種人類用戶可以正常讀取但是大多數機器人都沒法讀取的圖片,驗證碼 (CAPTCHA)就出現了。驗證碼讀取的難易程度也大不相同,有些驗證碼比其他的更加難讀。

將圖像翻譯成文字一般被稱爲光學文字識別(Optical Character Recognition, OCR)。可以實現OCR的底層庫並不多,目前很多庫都是使用共同的幾個底層 OCR 庫,或者是在上面 進行定製。在讀取和處理圖像、圖像相關的機器學習以及創建圖像等任務中,Python 一直都是非常出色的語言。雖然有很多庫可以進行圖像處理,但在這裏我們只重點介紹:Tesseract


二、Tesseract 安裝

Tesseract 是一個 OCR 庫,目前由 Google 贊助(Google 也是一家以 OCR 和機器學習技術聞名於世的公司)。Tesseract 是目前公認最優秀、最精確的開源 OCR 系統,除了極高的精確度,Tesseract 也具有很高的靈活性。它可以通過訓練識別出任何字體,也可以識別出任何 Unicode 字符。

(1) 安裝Tesseract

  • Windows系統:下載可執行安裝文件https://code.google.com/p/tesseract-ocr/downloads/list安裝。
  • Linux 系統:可以通過 apt-get 安裝: $sudo apt-get tesseract-ocr
  • Mac OS X系統:用Homebrew(http://brew.sh/)等第三方庫可以很方便地安裝

(2) 安裝pytesseract

Tesseract 是一個 Python 的命令行工具,不是通過 import 語句導入的庫。安裝之後,要用 tesseract 命令在 Python 的外面運行,但我們可以通過 pip 安裝支持Python 版本的 Tesseract庫:

pip install pytesseract

三、處理格式規範文字

處理的大多數文字最好都是比較乾淨、格式規範的。格式規範的文字通常可以滿足一些需求,通常格式規範的文字具有以下特點:

  • 使用一個標準字體(不包含手寫體、草書,或者十分“花哨的”字體)
  • 即使被複印或拍照,字體還是很清晰,沒有多餘的痕跡或污點
  • 排列整齊,沒有歪歪斜斜的字
  • 沒有超出圖片範圍,也沒有殘缺不全,或緊緊貼在圖片的邊緣

文字的一些格式問題在圖片預處理時可以進行解決。例如,可以把圖片轉換成灰度圖,調整亮度和對比度,還可以根據需要進行裁剪和旋轉(詳情需要了解圖像與信號處理)等。

(1) 格式規範文字的理想示例

在這裏插入圖片描述

通過下面的命令運行 Tesseract,讀取文件並把結果寫到一個文本文件中: tesseract test.jpg text

在這裏插入圖片描述

cat text.txt 即可顯示結果。

識別結果很準確,不過符號^和*分別被表示成了雙引號和單引號。大體上可以讓你很舒服地閱讀。

(2) 通過Python代碼實現

import pytesseract
from PIL import Image

image = Image.open('test.jpg')
text = pytesseract.image_to_string(image)
print text

運行結果:

This is some text, written in Arial, that will be read by
Tesseract. Here are some symbols: !@#$%"&*()

(3) 對圖片進行閾值過濾和降噪處理

很多時候我們在網上會看到這樣的圖片:

在這裏插入圖片描述

Tesseract 不能完整處理這個圖片,主要是因爲圖片背景色是漸變的,最終結果是這樣:

在這裏插入圖片描述

隨着背景色從左到右不斷加深,文字變得越來越難以識別,Tesseract 識別出的 每一行的最後幾個字符都是錯的。遇到這類問題,可以先用 Python 腳本對圖片進行清理。利用 PIL 庫,我們可以創建一個閾值過濾器來去掉漸變的背景色,只把文字留下來,從而讓圖片更加清晰,便於 Tesseract 讀取:

from PIL import Image
import subprocess

def cleanFile(filePath, newFilePath):
    image = Image.open(filePath)

    # 對圖片進行閾值過濾(低於143的置爲黑色,否則爲白色)
    image = image.point(lambda x: 0 if x < 143 else 255)
    # 重新保存圖片
    image.save(newFilePath)

    # 調用系統的tesseract命令對圖片進行OCR識別     
    subprocess.call(["tesseract", newFilePath, "output"])

    # 打開文件讀取結果
    with open("output.txt", 'r') as f:
        print(f.read())

if __name__ == "__main__":
    cleanFile("text2.png", "text2clean.png")

通過一個閾值對前面的“模糊”圖片進行過濾的結果:

在這裏插入圖片描述

除了一些標點符號不太清晰或丟失了,大部分文字都被讀出來了。Tesseract 給出了最好的 結果:

在這裏插入圖片描述

(4) 從網站圖片中抓取文字

用 Tesseract 讀取硬盤裏圖片上的文字,可能不怎麼令人興奮,但當我們把它和網絡爬蟲組合使用時,就能成爲一個強大的工具。

網站上的圖片可能並不是故意把文字做得很花哨 (就像餐館菜單的 JPG 圖片上的藝術字),但它們上面的文字對網絡爬蟲來說就是隱藏起來 了,舉個例子:

  • 雖然亞馬遜的 robots.txt 文件允許抓取網站的產品頁面,但是圖書的預覽頁通常不讓網絡機 器人採集。

  • 圖書的預覽頁是通過用戶觸發 Ajax 腳本進行加載的,預覽圖片隱藏在 div 節點 下面;其實,普通的訪問者會覺得它們看起來更像是一個 Flash 動畫,而不是一個圖片文 件。當然,即使我們能獲得圖片,要把它們讀成文字也沒那麼簡單。

  • 下面的程序就解決了這個問題:首先導航到托爾斯泰的《戰爭與和平》的大字號印刷版 1, 打開閱讀器,收集圖片的 URL 鏈接,然後下載圖片,識別圖片,最後打印每個圖片的文 字。因爲這個程序很複雜,利用了前面幾章的多個程序片段,所以我增加了一些註釋以讓 每段代碼的目的更加清晰:

import time
from urllib.request import urlretrieve
import subprocess
from selenium import webdriver
#創建新的Selenium driver
driver = webdriver.PhantomJS()

# 用Selenium試試Firefox瀏覽器:
# driver = webdriver.Firefox()

driver.get("http://www.amazon.com/War-Peace-Leo-Nikolayevich-Tolstoy/dp/1427030200")
# 單擊圖書預覽按鈕 driver.find_element_by_id("sitbLogoImg").click() imageList = set()
# 等待頁面加載完成
time.sleep(5)
# 當向右箭頭可以點擊時,開始翻頁
while "pointer" in driver.find_element_by_id("sitbReaderRightPageTurner").get_attribute("style"):
    driver.find_element_by_id("sitbReaderRightPageTurner").click()
    time.sleep(2)
    # 獲取已加載的新頁面(一次可以加載多個頁面,但是重複的頁面不能加載到集合中)
    pages = driver.find_elements_by_xpath("//div[@class='pageImage']/div/img")
    for page in pages:
        image = page.get_attribute("src")
        imageList.add(image)
driver.quit()

# 用Tesseract處理我們收集的圖片URL鏈接
for image in sorted(imageList):
    # 保存圖片
    urlretrieve(image, "page.jpg")
    p = subprocess.Popen(["tesseract", "page.jpg", "page"], stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    f = open("page.txt", "r")
    p.wait() print(f.read())

和我們前面使用 Tesseract 讀取的效果一樣,這個程序也會完美地打印書中很多長長的段落,第六頁的預覽如下所示:

6
     "A word of friendly advice, mon
     cher. Be off as soon as you can,
     that's all I have to tell you. Happy
     he who has ears to hear. Good-by,
     my dear fellow. Oh, by the by!" he
     shouted through the doorway after
     Pierre, "is it true that the countess
     has fallen into the clutches of the
     holy fathers of the Society of je-
     sus?"
     Pierre did not answer and left Ros-
     topchin's room more sullen and an-
     gry than he had ever before shown
     himself.

但是當文字出現在彩色封面上時,結果就不那麼完美了:

   WEI' nrrd Peace
   Len Nlkelayevldu Iolfluy
   Readmg shmdd be ax
   wlnvame asnossxble Wenfler
   an mm m our cram: Llhvary
   - Leo Tmsloy was a Russian rwovelwst
   I and moval phflmopher med lur
   A ms Ideas 01 nonviolenx reswslance m 5 We range     0, "and"

如果想把文字加工成普通人可以看懂的效果,還需要花很多時間去處理。

比如,通過給 Tesseract 提供大量已知的文字與圖片映射集,經過訓練 Tesseract 就可以“學會”識別同一種字體,而且可以達到極高的精確率和準確率,甚至可以忽略圖片中文字的背景色和相對位置等問題。


四、處理驗證碼

(1) 嘗試對知乎網驗證碼進行處理:

當前許多流行的內容管理系統加了驗證碼模塊,那麼我們如何識別驗證碼呢?

大多數網站生成的驗證碼圖片都具有以下屬性。

  • 它們是服務器端的程序動態生成的圖片。驗證碼圖片的 src 屬性可能和普通圖片不太一 樣,比如 <img src="WebForm.aspx?id=8AP85CQKE9TJ">,但是可以和其他圖片一樣進行 下載和處理。
  • 圖片的答案存儲在服務器端的數據庫裏。
  • 很多驗證碼都有時間限制,如果你太長時間沒解決就會失效。
  • 常用的處理方法就是,首先把驗證碼圖片下載到硬盤裏,清理乾淨,然後用 Tesseract 處理 圖片,最後返回符合網站要求的識別結果。
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import requests
import time
import pytesseract
from PIL import Image
from bs4 import BeautifulSoup

	def captcha(data):
	    with open('captcha.jpg','wb') as fp:
	        fp.write(data)
	    time.sleep(1)
	    image = Image.open("captcha.jpg")
	    text = pytesseract.image_to_string(image)
	    print "機器識別後的驗證碼爲:" + text
	    command = raw_input("請輸入Y表示同意使用,按其他鍵自行重新輸入:")
	    if (command == "Y" or command == "y"):
	        return text
	    else:
	        return raw_input('輸入驗證碼:')
	
	def zhihuLogin(username,password):
	
	    # 構建一個保存Cookie值的session對象
	    sessiona = requests.Session()
	    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0'}
	
	    # 先獲取頁面信息,找到需要POST的數據(並且已記錄當前頁面的Cookie)
	    html = sessiona.get('https://www.zhihu.com/#signin', headers=headers).content
	
	    # 找到 name 屬性值爲 _xsrf 的input標籤,取出value裏的值
	    _xsrf = BeautifulSoup(html ,'lxml').find('input', attrs={'name':'_xsrf'}).get('value')
	
	    # 取出驗證碼,r後面的值是Unix時間戳,time.time()
	    captcha_url = 'https://www.zhihu.com/captcha.gif?r=%d&type=login' % (time.time() * 1000)
	    response = sessiona.get(captcha_url, headers = headers)
	
	
	    data = {
	        "_xsrf":_xsrf,
	        "email":username,
	        "password":password,
	        "remember_me":True,
	        "captcha": captcha(response.content)
	    }
	
	    response = sessiona.post('https://www.zhihu.com/login/email', data = data, headers=headers)
	    print response.text
	
	    response = sessiona.get('https://www.zhihu.com/people/maozhaojun/activities', headers=headers)
	    print response.text


if __name__ == "__main__":
    zhihuLogin('[email protected]','ALAxxxxIME')

(2) 嘗試處理中文字符

如果手頭上有中文的訓練數據,也可以嘗試對中文進行識別。

命令:tesseract --list-langs可以查看當前支持的語言,chi_sim表示支持簡體中文。

在這裏插入圖片描述

那麼在使用時候,可以指定某個語言來進行識別,如:

tesseract -l chi_sim paixu.png paixu

在這裏插入圖片描述

表現在程序裏,則可以這麼寫:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from PIL import Image
import subprocess

def cleanFile(filePath)
    image = Image.open(filePath)

    # 調用系統的tesseract命令, 對圖片進行OCR中文識別
    subprocess.call(["tesseract", "-l", "chi_sim", filePath, "paixu"])

    # 打開文件讀取結果
    with open("paixu.txt", 'r') as f:
        print(f.read())

if __name__ == "__main__":
    cleanFile("paixu.png")

結果如下:

在這裏插入圖片描述


五、訓練Tesseract

要使用 Tesseract 的功能,比如後面的示例中訓練程序識別字母,要先在系統中設置一 個新的環境變量 $TESSDATA_PREFIX,讓 Tesseract 知道訓練的數據文件存儲在哪裏,然後搞一份 tessdata 數據文件,放到Tesseract目錄下。

  • 在大多數 Linux 系統和 Mac OS X 系統上,你可以這麼設置: $export TESSDATA_PREFIX=/usr/local/share/Tesseract

  • 在 Windows 系統上也類似,你可以通過下面這行命令設置環境變量: #setx TESSDATA_PREFIX C:\Program Files\Tesseract OCR\Tesseract

用下面的代碼運行 Tesseract 識別圖片:

tesseract captchaExample.png output

大多數其他的驗證碼都是比較簡單的。例如,流行的 PHP 內容管理系統 Drupal 有一個著名的驗證碼模塊 https://www.drupal.org/project/captcha,可以生成不同難度的驗證碼。

影響驗證碼識別難度因素 影響原因
大小 過小字體需要進行額外的訓練才能識別
字體種類 種類越多越難以識別
傾斜程度 隨機的傾斜程度迷惑 OCR 軟件識別
字母和數字是否混用 增加待搜索字符的數量
疊加,交叉 在每一個字母外面畫一個方框時,如重疊在一起識別難度加大
背景色、線條 產生對 OCR 程序產生干擾的噪點
背景與字體顏色對比度 對比度越小越難識別

創建樣本庫訓練Tesseract

要訓練 Tesseract 識別一種文字,無論是晦澀難懂的字體還是驗證碼,你都需要向 Tesseract 提供每個字符不同形式的樣本。

首先要收集大量的驗證碼樣本,樣本的數量和複雜程度,會決定訓練的效果。第二步是準確地告訴 Tesseract 一張圖片中的每個字符是什麼,以及每個字符的具體位置。

這裏需要創建一些矩形定位文件(box file),一個驗證碼圖片生成一個矩形定位文件,也可以通過jTessBoxEditor軟件來修改矩形的定位。

一個圖片的矩形定位文件如下所示:

      4  15 26 33 55 0
      M  38 13 67 45 0
      m  79 15 101 26 0
      C  111 33 136 60 0
      3  147 17 176 45 0

第一列符號是圖片中的每個字符,後面的 4 個數字分別是包圍這個字符的最小矩形的座標 (圖片左下角是原點 (0,0),4 個數字分別對應每個字符的左下角 x 座標、左下角 y 座標、右上角 x 座標和右上角 y 座標),最後一個數字“0”表示圖片樣本的編號。

矩形定位文件必須保存在一個 .box 後綴的文本文件中,(例如 4MmC3.box)。

博客園的一篇不錯的訓練教程:http://www.cnblogs.com/mjorcen/p/3800739.html?utm_source=tuicool&utm_medium=referral

前面的內容只是對 Tesseract 庫的字體訓練和識別能力的一個簡略概述。如果你對 Tesseract 的其他訓練方法感興趣,甚至打算建立自己的驗證碼訓練文件庫,推薦閱讀 Tesseract 官方文檔:https://github.com/tesseract-ocr/tesseract/wiki,加油!


後期內容提要:

  • [Python爬蟲] 十、Scrapy 框架

如果您有任何疑問或者好的建議,期待你的留言與評論!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章