最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

[機器視覺]使用python自動識別驗證碼詳解

 更新時間:2019年05月16日 10:13:52   作者:無夢之夜  
這篇文章主要介紹了python自動識別驗證碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

CAPTCHA全稱Completely Automated Public Turing Test to Tell Computers and Humans Apart,即全自動區(qū)分人機的圖靈測試。這也是驗證碼誕生的主要任務(wù)。但是隨著近年來大數(shù)據(jù)運算和機器視覺的發(fā)展,用機器視覺識別圖像已經(jīng)變得非常容易,過去用于區(qū)分人機的驗證碼也開始變得不再安全。

接下來就讓我們從零開始,深入圖像處理和算法構(gòu)建,來看看使用機器視覺來識別過時的驗證碼( 如下所示 )究竟可以有多簡單。

載入需要的程序包 & 設(shè)置全局變量

import requests
import time
from io import BytesIO
from PIL import Image
import os
import numpy as np

# 獲取驗證碼的網(wǎng)址
CAPT_URL = "http://xxxxxxxxxxxx.cn/servlet/ImageServlet"

# 驗證碼的保存路徑
CAPT_PATH = "capt/"
if not os.path.exists(CAPT_PATH):
  os.mkdir(CAPT_PATH)

# 將驗證碼轉(zhuǎn)為灰度圖時用到的"lookup table"
THRESHOLD = 165
LUT = [0]*THRESHOLD + [1]*(256 - THRESHOLD)

從網(wǎng)站獲取驗證碼

capt_fetch()方法非常簡單,我們直接從網(wǎng)站獲取驗證碼,將其轉(zhuǎn)換為Image對象,等待被訓(xùn)練和測試等環(huán)節(jié)調(diào)用。

def capt_fetch():
  """
  從網(wǎng)站獲取驗證碼,將驗證碼轉(zhuǎn)為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對象
  """
  # 從網(wǎng)站獲取驗證碼
  capt_raw = requests.get(CAPT_URL)

  # 將二進制的驗證碼圖片寫入IO流
  f = BytesIO(capt_raw.content)

  # 將驗證碼轉(zhuǎn)換為Image對象
  capt = Image.open(f)

  return capt

保存驗證碼到本地

  1. 一個強大的機器學(xué)習(xí)模型,是離不開強大的訓(xùn)練集作支持的。這里我們也必須先有一個預(yù)先打好標簽(預(yù)分類)的驗證碼圖片集,才能開始訓(xùn)練模型。
  2. capt_download()方法就是我們用來建立訓(xùn)練圖像集的方法。它會調(diào)用capt_fetch()方法,將獲得的Image對象展示給用戶,等待用戶輸入驗證碼中的字符,然后將圖片命名為用戶輸入的字符存儲起來。
  3. 當然,為了避免文件名重復(fù)(比如獲取到了兩張字符完全相同的驗證碼),capt_download()方法將系統(tǒng)時間也加入到了文件名中。
def capt_download():
  """
  將Image類型的驗證碼對象保存到本地

  :require Image: from PIL import Image
  :require os: import os

  :require capt_fetch(): 從nbsc網(wǎng)站獲取驗證碼
  :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")

 圖像預(yù)處理

  1. capt_process()方法會先將驗證碼轉(zhuǎn)為灰度圖,然后再根據(jù)全局變量中定義的LUT將灰度圖轉(zhuǎn)化為黑白圖片。并按照驗證碼中四個字符所在的位置進行切割。
  2. 從彩色圖片到灰度圖,再到黑白圖,看似驗證碼中的信息損失了很多,實際上這樣做的目的是為了使字符的特征更加明顯。
  3. 其實我們最終得到的黑白圖像會有一些噪點存在,這主要是由于前景色與背景色不存在嚴格的區(qū)分度,我們可以使用濾波器過濾掉這些噪點,但少量的噪點會被訓(xùn)練模型當作誤差處理,并不影響我們分類。至于過濾噪點的方法,我會專門寫一篇帖子。
def capt_process(capt):
  """
  圖像預(yù)處理:將驗證碼圖片轉(zhuǎn)為二值型圖片,按字符切割

  :require Image: from PIL import Image
  :require LUT: A lookup table, 包含256個值

  :param capt: 驗證碼Image對象
  :return capt_per_char_list: 一個數(shù)組包含四個元素,每個元素是一張包含單個字符的二值型圖片
  """
  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

圖像預(yù)處理的效果如下:

原始圖像

灰度圖

黑白圖

按字符切分后的黑白圖像

由于字符寬窄有差異,這里我們按字符切分后,有些字符會多出來一部分,有些字符會丟失一部分。比如7多了一筆看起來像個三角形,M少了一豎看起來像N。但只要符號之間有區(qū)分度,依然能夠準確分類。

提取圖像中的特征值

  1. 到了這一步,我們得到的圖像都是由單個字符組成的黑白圖片(0為黑色像素點,1為白色像素點)。此時,如果我們把圖片轉(zhuǎn)為數(shù)組,就會得到一個由0,1組成的矩陣,其長寬恰與圖片的大小相同, 每一個數(shù)字代表一個像素點。
  2. 接下來我們需要考慮如何提取能夠區(qū)分不同字符的特征值。我們可以直接用圖像中的每一個像素點作為一個特征值,也可以匯總圖像中共有多少黑色像素點(當然,這樣每張圖片只能提取一個特征值),還可以按區(qū)域匯總圖像中的像素點,比如先將圖片四等分,匯總四張“子圖片”中的像素點,如果覺得特征不夠多,還可以繼續(xù)下分,直至精確到每一個像素點。
  3. 為了使代碼更加簡潔,我們這里直接匯總、分行列匯總了圖像像素點的個數(shù),共提取了1張圖片 + 15列 + 18行 ==> 34個特征值。至于按區(qū)域匯總的方法,還是等我們有空了單獨寫一篇帖子。
def capt_inference(capt_per_char):
  """
  提取圖像特征

  :require numpy: import numpy as np

  :param capt_per_char: 由單個字符組成的二值型圖片
  :return char_features:一個數(shù)組,包含 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()

生成訓(xùn)練集

這里我們會將預(yù)分類的每張驗證碼分別讀入內(nèi)存,從它們的圖像中提取特征值,從它們的名稱中提取驗證碼所對應(yīng)的文字(標簽),并將特征值與標簽分別匯總成列表,注意train_labels中的每個元素是與train_table中的每一行相對應(yīng)的。

def train():
  """
  將預(yù)分類的驗證碼圖片集轉(zhuǎn)化為字符特征訓(xùn)練集

  :require Image: from PIL import Image
  :require os: import os

  :require capt_process(): 圖像預(yù)處理
  :require capt_inference(): 提取圖像特征

  :param:
  :return train_table: 驗證碼字符特征訓(xùn)練集
  :return train_labels: 驗證碼字符預(yù)分類結(jié)果
  """
  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

定義分類模型

  1. 只要我們提取的特征值具有足夠的區(qū)分度(能夠區(qū)分不同字符),理論上我們可以使用任何機器學(xué)習(xí)的模型建立特征值與標簽的相關(guān)。
  2. 我嘗試過使用knn,svm,Decision Tree,ANN等各種主流機器學(xué)習(xí)模型對提取的訓(xùn)練數(shù)據(jù)進行分類,盡管不同模型表現(xiàn)各異,但識別準確率都可以很輕松的達到90%以上。
  3. 這里我們不打算使用復(fù)雜的第三方模型完成學(xué)習(xí)過程,所以我們在這里自己寫了一個分類模型。模型實現(xiàn)的nnc算法是knn的一種,通過比對未知分類的一組特征值測試集與那一組已知分類的特征值訓(xùn)練集最接近,判定測試集的分類情況應(yīng)該和與其最接近的訓(xùn)練集的分類情況訓(xùn)練集標簽相同。
  4. 當然,我們也可以稍加改造直接實現(xiàn)knn算法,找到3組、5組或k組與未知分類的特征向量最接近的訓(xùn)練集中的特征向量,并通過票選與其對應(yīng)的標簽,預(yù)測未知分類的特征向量在大概率上應(yīng)該屬于哪一類。
def nnc(train_table, test_vec, train_labels):
  """
  Nearest Neighbour Classification(近鄰分類法),
  根據(jù)已知特征矩陣的分類情況,預(yù)測未分類的特征向量所屬類別

  :require numpy: import numpy as np

  :param train_table: 預(yù)分類的特征矩陣
  :param test_vec: 特征向量, 長度必須與矩陣的列數(shù)相等
  :param labels: 特征矩陣的類別向量
  :return : 預(yù)測特征向量所屬的類別 
  """

  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]

 測試模型分類效果

最后,我們需要測試我們的理論是否有效,通過調(diào)用test()方法,我們會先從網(wǎng)站獲取驗證碼圖像,對圖像進行處理、特征提取,然后調(diào)用nnc()方法對提取到的四組特征值做近鄰分類,分別得到驗證碼中的四個字符。最后將驗證碼圖像和識別到的字符傳出,方便我們比對識別結(jié)果。

def test():
  """
  測試模型分類效果

  :require Image: from PIL import Image

  :require capt_fetch(): 從nbsc網(wǎng)站獲取驗證碼
  :require capt_process(): 圖像預(yù)處理
  :require capt_inference(): 提取圖像特征
  :train_table, train_labels: train_table, train_labels = train()

  :param:
  :return capt: 驗證碼圖片
  :return test_labels: 驗證碼識別結(jié)果
  """

  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

訓(xùn)練數(shù)據(jù),識別驗證碼

  1. 方法具備,接下來就是我們實踐的環(huán)節(jié)了。
  2. 首先,我們需要建立一個機器學(xué)習(xí)庫,即一個預(yù)分類的驗證碼圖片集。這里我們僅僅獲取了120張驗證碼作為訓(xùn)練集,相比tensorflow動輒成千上萬次的迭代,我們建立模型所需的樣本量非常之少。當然,這也要感謝我們使用的nnc算法并不需要十分龐大的訓(xùn)練集支持,才使得我們能夠節(jié)省很多預(yù)分類時人工識別驗證碼的精力。
  3. 接下來,我們會調(diào)用train()方法生成訓(xùn)練集和訓(xùn)練集標簽,這兩個數(shù)組會被test()方法用到,但我們把這兩個數(shù)組存儲在全局變量里,所以不需要特意傳遞給test()方法。
# 下載120張圖片到本地
for i in range(120):
  capt_download()

# 模型的訓(xùn)練與測試
train_table, train_labels = train()
test_capt, test_labels = test()

最后我們調(diào)用test()方法驗證我們的理論是否成立,識別效果如下:

獲取到的驗證碼

識別結(jié)果

結(jié)語

至此,我們通過機器視覺識別驗證碼的任務(wù)算是完成了。至于正確率,大概每10張驗證碼,40各字符中會預(yù)測失誤一個字符。這已經(jīng)比較接近我們?nèi)祟惖淖R別準確率了,當然,我們還可以通過建立起更龐大的學(xué)習(xí)庫,使用knn或更復(fù)雜的模型,使用卷積核處理圖片等方式,使識別準確率更高。

當然,我們這里所用的方法,只適用于識別比較簡單的驗證碼。對于更加復(fù)雜的驗證碼(如下圖),以上方法是不起作用的,但這并不代表這樣的驗證碼不能通過機器視覺進行識別。

我們已經(jīng)看到,隨著機器視覺的發(fā)展,通過傳統(tǒng)的驗證碼來區(qū)分人機已經(jīng)越來越難了。當然,為了網(wǎng)絡(luò)的安全性,我們也可使用更復(fù)雜的驗證碼,或者新型的驗證方式,比如拖動滑塊、短信驗證、掃碼登陸等。

以上所述是小編給大家介紹的python自動識別驗證碼詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Python的多態(tài)性實例分析

    Python的多態(tài)性實例分析

    這篇文章主要介紹了Python的多態(tài)性,以實例形式深入淺出的分析了Python在面向?qū)ο缶幊讨卸鄳B(tài)性的原理與實現(xiàn)方法,需要的朋友可以參考下
    2015-07-07
  • Pandas在數(shù)據(jù)分析和機器學(xué)習(xí)中的應(yīng)用及優(yōu)勢

    Pandas在數(shù)據(jù)分析和機器學(xué)習(xí)中的應(yīng)用及優(yōu)勢

    Pandas是Python中用于數(shù)據(jù)處理和數(shù)據(jù)分析的庫,它提供了靈活的數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)操作工具,包括Series和DataFrame等。Pandas還支持大量數(shù)據(jù)操作和數(shù)據(jù)分析功能,包括數(shù)據(jù)清洗、轉(zhuǎn)換、篩選、聚合、透視表、時間序列分析等
    2023-04-04
  • 用Python識別人臉,人種等各種信息

    用Python識別人臉,人種等各種信息

    這篇文章主要介紹了用Python識別人臉,人種等各種信息,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-07-07
  • 用Python計算三角函數(shù)之a(chǎn)tan()方法的使用

    用Python計算三角函數(shù)之a(chǎn)tan()方法的使用

    這篇文章主要介紹了用Python計算三角函數(shù)之a(chǎn)tan()方法的使用,是Python入門的基礎(chǔ)知識,需要的朋友可以參考下
    2015-05-05
  • python實現(xiàn)獲取單向鏈表倒數(shù)第k個結(jié)點的值示例

    python實現(xiàn)獲取單向鏈表倒數(shù)第k個結(jié)點的值示例

    這篇文章主要介紹了python實現(xiàn)獲取單向鏈表倒數(shù)第k個結(jié)點的值,結(jié)合實例形式分析了Python針對單向鏈表的定義、遍歷、傳值、判斷等相關(guān)操作技巧,需要的朋友可以參考下
    2019-10-10
  • Python元類編程實現(xiàn)一個簡單的ORM

    Python元類編程實現(xiàn)一個簡單的ORM

    本文主要介紹了Python元類編程實現(xiàn)一個簡單的ORM,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • Python?OpenCV實現(xiàn)姿態(tài)識別的詳細代碼

    Python?OpenCV實現(xiàn)姿態(tài)識別的詳細代碼

    這篇文章主要介紹了Python?OpenCV實現(xiàn)姿態(tài)識別的方法,本文通過截圖實例代碼相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • 深入理解Python單元測試unittest的使用示例

    深入理解Python單元測試unittest的使用示例

    本篇文章主要介紹了深入理解Python單元測試unittest的使用示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • 利用Python開發(fā)實現(xiàn)簡單的記事本

    利用Python開發(fā)實現(xiàn)簡單的記事本

    最近想對python加深學(xué)習(xí)一下,同時也是想試著做一些東西,所以使用python,結(jié)合Tkinter來做一個簡單的跨平臺記事本。最終實現(xiàn)的記事本如下,也算是麻雀雖小,五臟俱全了,之后也是會繼續(xù)完善的。文中通過圖文及示例代碼介紹的很詳細,有需要的朋友們可以參考借鑒。
    2016-11-11
  • python dict亂碼如何解決

    python dict亂碼如何解決

    在本篇文章里小編給大家分享了關(guān)于python dict亂碼解決方法,需要的朋友們可以參考下。
    2020-06-06

最新評論

陆川县| 杨浦区| 呼伦贝尔市| 蒙阴县| 亳州市| 太白县| 布尔津县| 开化县| 肥东县| 蒙城县| 会昌县| 上蔡县| 永泰县| 中西区| 东方市| 招远市| 东乌珠穆沁旗| 巧家县| 沾化县| 邛崃市| 颍上县| 清徐县| 宁明县| 龙川县| 桃源县| 武汉市| 博客| 京山县| 英吉沙县| 清新县| 安新县| 贵阳市| 阳高县| 绥宁县| 波密县| 安图县| 建始县| 泾阳县| 克拉玛依市| 万源市| 方山县|