前言
CAPTCHA全稱Completely Automated Public Turing Test to Tell Computers and Humans Apart,即全自動區分人機的圖靈測試。這也是驗證碼誕生的主要任務。但是隨著近年來大數據運算和機器視覺的發展,用機器視覺識別圖像已經變得非常容易,過去用于區分人機的驗證碼也開始變得不再安全。
接下來就讓我們從零開始,深入圖像處理和算法構建,來看看使用機器視覺來識別過時的驗證碼( 如下所示 )究竟可以有多簡單。
![[機器視覺]使用python自動識別驗證碼詳解](https://cache.yisu.com/upload/information/20200622/113/35199.jpg)
載入需要的程序包 & 設置全局變量
import requests import time from io import BytesIO from PIL import Image import os import numpy as np # 獲取驗證碼的網址 CAPT_URL = "http://xxxxxxxxxxxx.cn/servlet/ImageServlet" # 驗證碼的保存路徑 CAPT_PATH = "capt/" if not os.path.exists(CAPT_PATH): os.mkdir(CAPT_PATH) # 將驗證碼轉為灰度圖時用到的"lookup table" THRESHOLD = 165 LUT = [0]*THRESHOLD + [1]*(256 - THRESHOLD)
從網站獲取驗證碼
capt_fetch()方法非常簡單,我們直接從網站獲取驗證碼,將其轉換為Image對象,等待被訓練和測試等環節調用。
def capt_fetch(): """ 從網站獲取驗證碼,將驗證碼轉為Image對象 :require requests: import requests :require time: import time :require BytesIO: from io import BytesIO :require Image: from PIL import Image :param: :return capt: 一個Image對象 """ # 從網站獲取驗證碼 capt_raw = requests.get(CAPT_URL) # 將二進制的驗證碼圖片寫入IO流 f = BytesIO(capt_raw.content) # 將驗證碼轉換為Image對象 capt = Image.open(f) return capt
保存驗證碼到本地
def capt_download():
"""
將Image類型的驗證碼對象保存到本地
:require Image: from PIL import Image
:require os: import os
:require capt_fetch(): 從nbsc網站獲取驗證碼
:require CAPT_PATH: 驗證碼保存路徑
:param:
:return:
"""
capt = capt_fetch()
capt.show()
text = raw_input("請輸入驗證碼中的字符:")
suffix = str(int(time.time() * 1e3))
capt.save(CAPT_PATH + text + "_" + suffix + ".jpg")
圖像預處理
def capt_process(capt):
"""
圖像預處理:將驗證碼圖片轉為二值型圖片,按字符切割
:require Image: from PIL import Image
:require LUT: A lookup table, 包含256個值
:param capt: 驗證碼Image對象
:return capt_per_char_list: 一個數組包含四個元素,每個元素是一張包含單個字符的二值型圖片
"""
capt_gray = capt.convert("L")
capt_bw = capt_gray.point(LUT, "1")
capt_per_char_list = []
for i in range(4):
x = 5 + i * 15
y = 2
capt_per_char = capt_bw.crop((x, y, x + 15, y + 18))
capt_per_char_list.append(capt_per_char)
return capt_per_char_list
圖像預處理的效果如下:
![[機器視覺]使用python自動識別驗證碼詳解](https://cache.yisu.com/upload/information/20200622/113/35200.jpg)
原始圖像
![[機器視覺]使用python自動識別驗證碼詳解](https://cache.yisu.com/upload/information/20200622/113/35201.jpg)
灰度圖
![[機器視覺]使用python自動識別驗證碼詳解](https://cache.yisu.com/upload/information/20200622/113/35202.jpg)
黑白圖
![[機器視覺]使用python自動識別驗證碼詳解](https://cache.yisu.com/upload/information/20200622/113/35203.jpg)
按字符切分后的黑白圖像
由于字符寬窄有差異,這里我們按字符切分后,有些字符會多出來一部分,有些字符會丟失一部分。比如7多了一筆看起來像個三角形,M少了一豎看起來像N。但只要符號之間有區分度,依然能夠準確分類。
提取圖像中的特征值
def capt_inference(capt_per_char): """ 提取圖像特征 :require numpy: import numpy as np :param capt_per_char: 由單個字符組成的二值型圖片 :return char_features:一個數組,包含 capt_per_char中字符的特征 """ char_array = np.array(capt_per_char) total_pixels = np.sum(char_array) cols_pixels = np.sum(char_array, 0) rows_pixels = np.sum(char_array, 1) char_features = np.append(cols_pixels, rows_pixels) char_features = np.append(total_pixels, char_features) return char_features.tolist()
生成訓練集
這里我們會將預分類的每張驗證碼分別讀入內存,從它們的圖像中提取特征值,從它們的名稱中提取驗證碼所對應的文字(標簽),并將特征值與標簽分別匯總成列表,注意train_labels中的每個元素是與train_table中的每一行相對應的。
def train():
"""
將預分類的驗證碼圖片集轉化為字符特征訓練集
:require Image: from PIL import Image
:require os: import os
:require capt_process(): 圖像預處理
:require capt_inference(): 提取圖像特征
:param:
:return train_table: 驗證碼字符特征訓練集
:return train_labels: 驗證碼字符預分類結果
"""
files = os.listdir(CAPT_PATH)
train_table = []
train_labels = []
for f in files:
train_labels += list(f.split("_")[0])
capt = Image.open(CAPT_PATH + f)
capt_per_char_list = capt_process(capt)
for capt_per_char in capt_per_char_list:
char_features = capt_inference(capt_per_char)
train_table.append(char_features)
return train_table, train_labels
定義分類模型
def nnc(train_table, test_vec, train_labels): """ Nearest Neighbour Classification(近鄰分類法), 根據已知特征矩陣的分類情況,預測未分類的特征向量所屬類別 :require numpy: import numpy as np :param train_table: 預分類的特征矩陣 :param test_vec: 特征向量, 長度必須與矩陣的列數相等 :param labels: 特征矩陣的類別向量 :return : 預測特征向量所屬的類別 """ dist_mat = np.square(np.subtract(train_table, test_vec)) dist_vec = np.sum(dist_mat, axis = 1) pos = np.argmin(dist_vec) return train_labels[pos]
測試模型分類效果
最后,我們需要測試我們的理論是否有效,通過調用test()方法,我們會先從網站獲取驗證碼圖像,對圖像進行處理、特征提取,然后調用nnc()方法對提取到的四組特征值做近鄰分類,分別得到驗證碼中的四個字符。最后將驗證碼圖像和識別到的字符傳出,方便我們比對識別結果。
def test():
"""
測試模型分類效果
:require Image: from PIL import Image
:require capt_fetch(): 從nbsc網站獲取驗證碼
:require capt_process(): 圖像預處理
:require capt_inference(): 提取圖像特征
:train_table, train_labels: train_table, train_labels = train()
:param:
:return capt: 驗證碼圖片
:return test_labels: 驗證碼識別結果
"""
test_labels = []
capt = capt_fetch()
capt_per_char_list = capt_process(capt)
for capt_per_char in capt_per_char_list:
char_features = capt_inference(capt_per_char)
label = nnc(train_table, char_features, train_labels)
test_labels.append(label)
test_labels = "".join(test_labels)
return capt, test_labels
訓練數據,識別驗證碼
# 下載120張圖片到本地 for i in range(120): capt_download() # 模型的訓練與測試 train_table, train_labels = train() test_capt, test_labels = test()
最后我們調用test()方法驗證我們的理論是否成立,識別效果如下:
獲取到的驗證碼
![[機器視覺]使用python自動識別驗證碼詳解](https://cache.yisu.com/upload/information/20200622/113/35204.jpg)
識別結果
![[機器視覺]使用python自動識別驗證碼詳解](https://cache.yisu.com/upload/information/20200622/113/35205.jpg)
結語
至此,我們通過機器視覺識別驗證碼的任務算是完成了。至于正確率,大概每10張驗證碼,40各字符中會預測失誤一個字符。這已經比較接近我們人類的識別準確率了,當然,我們還可以通過建立起更龐大的學習庫,使用knn或更復雜的模型,使用卷積核處理圖片等方式,使識別準確率更高。
當然,我們這里所用的方法,只適用于識別比較簡單的驗證碼。對于更加復雜的驗證碼(如下圖),以上方法是不起作用的,但這并不代表這樣的驗證碼不能通過機器視覺進行識別。
![[機器視覺]使用python自動識別驗證碼詳解](https://cache.yisu.com/upload/information/20200622/113/35206.jpg)
我們已經看到,隨著機器視覺的發展,通過傳統的驗證碼來區分人機已經越來越難了。當然,為了網絡的安全性,我們也可使用更復雜的驗證碼,或者新型的驗證方式,比如拖動滑塊、短信驗證、掃碼登陸等。
以上所述是小編給大家介紹的python自動識別驗證碼詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網站的支持!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。