本文目錄一覽:
- 1、python抓取網頁時是如何處理驗證碼的
- 2、如何利用Python 做驗證碼識別
- 3、python如何識別驗證碼
- 4、python怎麼生成隨機圖形驗證碼
- 5、python爬驗證碼
- 6、如何利用Python做簡單的驗證碼識別
python抓取網頁時是如何處理驗證碼的
python抓取網頁時是如何處理驗證碼的?下面給大家介紹幾種方法:
1、輸入式驗證碼
這種驗證碼主要是通過用戶輸入圖片中的字母、數字、漢字等進行驗證。如下圖:
解決思路:這種是最簡單的一種,只要識別出裡面的內容,然後填入到輸入框中即可。這種識別技術叫OCR,這裡我們推薦使用Python的第三方庫,tesserocr。對於沒有什麼背影影響的驗證碼如圖2,直接通過這個庫來識別就可以。但是對於有嘈雜的背景的驗證碼這種,直接識別識別率會很低,遇到這種我們就得需要先處理一下圖片,先對圖片進行灰度化,然後再進行二值化,再去識別,這樣識別率會大大提高。
相關推薦:《Python入門教程》
2、滑動式驗證碼
這種是將備選碎片直線滑動到正確的位置,如下圖:
解決思路:對於這種驗證碼就比較複雜一點,但也是有相應的辦法。我們直接想到的就是模擬人去拖動驗證碼的行為,點擊按鈕,然後看到了缺口的位置,最後把拼圖拖到缺口位置處完成驗證。
第一步:點擊按鈕。然後我們發現,在你沒有點擊按鈕的時候那個缺口和拼圖是沒有出現的,點擊後才出現,這為我們找到缺口的位置提供了靈感。
第二步:拖到缺口位置。
我們知道拼圖應該拖到缺口處,但是這個距離如果用數值來表示?
通過我們第一步觀察到的現象,我們可以找到缺口的位置。這裡我們可以比較兩張圖的像素,設置一個基準值,如果某個位置的差值超過了基準值,那我們就找到了這兩張圖片不一樣的位置,當然我們是從那塊拼圖的右側開始並且從左到右,找到第一個不一樣的位置時就結束,這是的位置應該是缺口的left,所以我們使用selenium拖到這個位置即可。
這裡還有個疑問就是如何能自動的保存這兩張圖?
這裡我們可以先找到這個標籤,然後獲取它的location和size,然後 top,bottom,left,right = location[‘y’] ,location[‘y’]+size[‘height’]+ location[‘x’] + size[‘width’] ,然後截圖,最後摳圖填入這四個位置就行。
具體的使用可以查看selenium文檔,點擊按鈕前摳張圖,點擊後再摳張圖。最後拖動的時候要需要模擬人的行為,先加速然後減速。因為這種驗證碼有行為特徵檢測,人是不可能做到一直勻速的,否則它就判定為是機器在拖動,這樣就無法通過驗證了。
3、點擊式的圖文驗證和圖標選擇
圖文驗證:通過文字提醒用戶點擊圖中相同字的位置進行驗證。
圖標選擇: 給出一組圖片,按要求點擊其中一張或者多張。借用萬物識別的難度阻擋機器。
這兩種原理相似,只不過是一個是給出文字,點擊圖片中的文字,一個是給出圖片,點出內容相同的圖片。
這兩種沒有特別好的方法,只能藉助第三方識別接口來識別出相同的內容,推薦一個超級鷹,把驗證碼發過去,會返回相應的點擊坐標。
然後再使用selenium模擬點擊即可。具體怎麼獲取圖片和上面方法一樣。
4、宮格驗證碼
這種就很棘手,每一次出現的都不一樣,但是也會出現一樣的。而且拖動順序都不一樣。
但是我們發現不一樣的驗證碼個數是有限的,這裡採用模版匹配的方法。我覺得就好像暴力枚舉,把所有出現的驗證碼保存下來,然後挑出不一樣的驗證碼,按照拖動順序命名,我們從左到右上下到下,設為1,2,3,4。上圖的滑動順序為4,3,2,1,所以我們命名4_3_2_1.png,這裡得手動搞。當驗證碼出現的時候,用我們保存的圖片一一枚舉,與出現這種比較像素,方法見上面。如果匹配上了,拖動順序就為4,3,2,1。然後使用selenium模擬即可。
如何利用Python 做驗證碼識別
#!/usr/bin/python3.4
# -*- coding: utf-8 -*-
# 1、pip3 install pyocr
# 2、pip3 install pillow or easy_install Pillow
# 3、安裝tesseract-ocr:,安裝在C:\Program Files\下
# 4、要求python默認安裝在C盤
#
# 代碼:
# !/usr/bin/python3.4
# -*- coding: utf-8 -*-
import pytesseract
from PIL import Image
image = Image.open(‘../jpg/code.png’)
code = pytesseract.image_to_string(image)
print(code)
python如何識別驗證碼
我們首先識別最簡單的一種驗證碼,即圖形驗證碼。這種驗證碼最早出現,現在也很常見,一般由4位字母或者數字組成。例如,中國知網的註冊頁面有類似的驗證碼,頁面如下所示:
表單中最後一項就是圖形驗證碼,我們必須完全正確輸入圖中的字符才可以完成註冊。
更多有關驗證碼的知識,可以參考這些文章:
Python3爬蟲進階:識別圖形驗證碼
Python3爬蟲進階:識別極驗滑動驗證碼
Python3爬蟲進階:識別點觸點選驗證碼
Python3爬蟲進階:識別微博宮格驗證碼
·本節目標以知網的驗證碼為例,講解利用OCR技術識別圖形驗證碼的方法。
·準備工作識別圖形驗證碼需要庫tesserocr,以mac安裝為例:在mac下,我們首先使用Homebrew安裝ImageMagick和tesseract庫: brew install imagemagickbrew install tesseract 接下來再安裝tesserocr即可:pip3 install tesserocr pillow這樣我們就完成了 tesserocr的安裝。
·獲取驗證碼為了便於實驗,我們先將驗證碼的圖片保存到本地。打開開發者工具,找到驗證碼元素。驗證碼元素是一張圖片,它的ser屬 性是CheckCode.aspk。所以我們直接打開如下鏈接就可以看到一個驗證碼,右鍵保存即可,將其命名為code.jpg:
這樣我們就得到一張驗證碼圖片,以供測試識別使用。
相關推薦:《Python教程》
識別測試
接下來新建一個項目,將驗證碼圖片放到項目根目錄下,用tesserocr庫識別該驗證碼,代碼如下所示:
這裡我們新建了一個Image對戲那個,調用了tesserocr的image_to_text( )方法。傳入該Image對象即可完成識別,實現過程非常簡單,結果如下:
我們可以看到,識別的結果和實際結果有偏差,這是因為驗證碼內的多餘線條幹擾了圖片的識別。
另外,tesserocr還有一個更加簡單的方法,這個方法可以直接將圖片文件轉為字符串,代碼如下:
不過這種方法的識別效果不如上一種的好。
驗證碼處理
對於上面的圖片,我們可以看到其實並沒有完全識別正確,所以我們需要對圖像作進一步的處理,如灰度轉換、二值化等操作。
我們可以利用Image對象的convert( )方法參數傳入L,即可將圖片轉化為灰度圖像,代碼如下:
傳入1即可將圖片進行二值化處理,如下所示:
我們還可以指定二值化的閾值。上面的方法採用的是默認閾值127。不過我們不能直接轉化原圖,要將原圖先轉化為灰度圖像,然後再指定二值化閾值,代碼如下:
在這裡,變量threshold代表二值化閾值,閾值設置為160,之後我們來看看我們的結果:
我們可以看到現在的二維碼就比較方便我們進行識別了;那麼對於一些有干擾的圖片,我們做一些灰度和二值化處理,這會提高圖片識別的正確率。
python怎麼生成隨機圖形驗證碼
1.安裝pillow模塊
pip install pillow
2.pillow模塊的基本使用
1.創建圖片
from PIL import Image
#定義使用Image類實例化一個長為400px,寬為400px,基於RGB的(255,255,255)顏色的圖片
img1=Image.new(mode=”RGB”,size=(400,400),color=(255,255,255))
#把生成的圖片保存為”pic.png”格式
with open(“pic.png”,”wb”) as f:
img1.save(f,format=”png”)
#顯示圖片
img1.show()
運行程序,程序會在py文件的同級下生成一個名為”pic.png”的小圖片,圖片長為400px,寬為400px,顏色為白色.
2.創建畫筆
#創建畫筆,用於在圖片上生成內容
draw1=ImageDraw.Draw(img1,mode=”RGB”)
3.在圖片上生成點
#在(100,100)坐標上生成一個紅點,指定的坐標不能超過圖片的尺寸
draw1.point([100,100],pill=”red”)
#在(80,80)坐標上生成一個黑點,指定的坐標不能超過圖片的尺寸
draw1.point([80,80],fill=(0,0,0))
4.在圖片上畫線
#第一個括號裡面的參數是坐標,前兩個數為開始坐標,後兩個數為結束坐標
#括號里的第二個參數指定顏色,可以直接指定,也可以用RGB來表示顏色
draw1.line((100,100,100,300),fill=”red”)
draw1.line((100,200,200,100),fill=”blue”)
運行程序,畫筆會在(100,100)到(100,300)坐標之間畫一條紅色的豎線,在(100,200)到(200,100)坐標之間畫一根藍色的斜線
5.在圖片在畫圓
#括號里的第一個參數是坐標,前兩個數為起始坐標,後兩個為結束坐標
#用這兩個坐標之間的正方形區域生成一個圓,大括號里的第二個參數為圓的開始角度
#第三個參數為圓的結束角度,0到360表示所畫的是一個完整的圓形,
#也可以指定的數字來生成一段為圓弧,最後一個參數表示顏色,也可以用RGB來表示想要的顏色
draw1.arc((100,100,300,300),0,360,fill=”red”)
draw1.arc((0,0,300,300),0,90,fill=”blue”)
6.在圖片在寫文本
#使用畫筆的text方法在圖片上生成文本
#第一個參數為坐標,第二個參數為所有生成的文本的內容
#第三個參數為文本的顏色
draw1.text([0,0],”python”,”blue”)
7.在圖片在生成指定字體的文本
#先實例化一個字體對象,第一個參數表示字體的路徑,第二個參數表示字體大小
font1=ImageFont.truetype(“One Chance.ttf”,28)
#在圖片上生成字體
#第一個括號里的參數表示坐標,第二個參數表示寫入的內容
#第三個參數表示顏色,第四個參數表示使用的字體對象
draw1.text([200,200],”linux”,”red”,font=font1)
圖片驗證碼的實例
#導入random模塊
import random
#導入Image,ImageDraw,ImageFont模塊
from PIL import Image,ImageDraw,ImageFont
#定義使用Image類實例化一個長為120px,寬為30px,基於RGB的(255,255,255)顏色的圖片
img1=Image.new(mode=”RGB”,size=(120,30),color=(255,255,255))
#實例化一支畫筆
draw1=ImageDraw.Draw(img1,mode=”RGB”)
#定義要使用的字體
font1=ImageFont.truetype(“One Chance.ttf”,28)
for i in range(5):
#每循環一次,從a到z中隨機生成一個字母或數字
#65到90為字母的ASCII碼,使用chr把生成的ASCII碼轉換成字符
#str把生成的數字轉換成字符串
char1=random.choice([chr(random.randint(65,90)),str(random.randint(0,9))])
#每循環一次重新生成隨機顏色
color1=(random.randint(0,255),random.randint(0,255),random.randint(0,255))
#把生成的字母或數字添加到圖片上
#圖片長度為120px,要生成5個數字或字母則每添加一個,其位置就要向後移動24px
draw1.text([i*24,0],char1,color1,font=font1)
#把生成的圖片保存為”pic.png”格式
with open(“pic.png”,”wb”) as f:
img1.save(f,format=”png”)
python爬驗證碼
1.找地址
首先,我們要找到這個網站生成驗證碼的地址,這個地址我們可以通過查看他的源代碼來實現。
1.找地址
首先,我們要找到這個網站生成驗證碼的地址,這個地址我們可以通過查看他的源代碼來實現。
就以某大學教務網為例,這個教務網的模板很多學校都在採用:
我就截取表單的驗證碼部分即可。
td align=”center” rowspan=”3″
img id=”imgCode” src=”../sys/ValidateCode.aspx”
onclick=”changeValidateCode(this)” alt=”單擊可更換圖片!”
style=”CURSOR: pointer;”
br看不清,則單擊圖片!
/td123456123456
這裡就可以知道,地址就是../sys/ValidateCode.aspx
組合一下地址就是
也就是我們等一下要用到的地址了。
我們可以查看一下那個網頁。
2.處理圖片
去查看了一下那個地址
果不其然,都是亂碼,因為驗證碼分為兩種。
1)直接處理成JPG/GIF/PNG或者其他格式,然後直接讀取到一個圖片地址。
2)接收用戶觸發,然後生成,再直接處理成圖像,不讀取到一個圖片地址。
我們這裡是第二種,我們要自己來讀取他,到本地,再手動輸入驗證碼。
# -*- coding: utf-8 -*-
import urllib2
#驗證碼的處理#
#驗證碼生成頁面的地址#
im_url = ”
#讀取驗證碼圖片#
im_data = urllib2.urlopen(im_url).read()
#打開一個Code.PNG文件在D盤,沒有的話自動生成#
f=open(‘d:\\Code.png’,’wb’)
#寫入圖片內容#
f.write(im_data)
#關閉文件#
f.close()1234567891011121312345678910111213
這裡包括兩個部分:
1)打開那個生成驗證碼圖片的頁面,讀取
2)將讀取到的內容,保存成圖片,下載到本地
我們這裡的地址是可以隨便寫的,保存在你想保存的地方。
到這裡我們就完成了驗證碼的一小部分。
by–LoDog
希望能幫到你!
如何利用Python做簡單的驗證碼識別
1 摘要
驗證碼是目前互聯網上非常常見也是非常重要的一個事物,充當著很多系統的 防火牆 功能,但是隨時OCR技術的發展,驗證碼暴露出來的安全問題也越來越嚴峻。本文介紹了一套字符驗證碼識別的完整流程,對於驗證碼安全和OCR識別技術都有一定的借鑒意義。
然後經過了一年的時間,筆者又研究和get到了一種更強大的基於CNN卷積神經網絡的直接端到端的驗證識別技術(文章不是我的,然後我把源碼整理了下,介紹和源碼在這裡面):
基於python語言的tensorflow的‘端到端’的字符型驗證碼識別源碼整理(github源碼分享)
2 關鍵詞
關鍵詞:安全,字符圖片,驗證碼識別,OCR,Python,SVM,PIL
3 免責聲明
本文研究所用素材來自於某舊Web框架的網站 完全對外公開 的公共圖片資源。
本文只做了該網站對外公開的公共圖片資源進行了爬取, 並未越權 做任何多餘操作。
本文在書寫相關報告的時候已經 隱去 漏洞網站的身份信息。
本文作者 已經通知 網站相關人員此系統漏洞,並積極向新系統轉移。
本報告的主要目的也僅是用於 OCR交流學習 和引起大家對 驗證安全的警覺 。
4 引言
關於驗證碼的非技術部分的介紹,可以參考以前寫的一篇科普類的文章:
互聯網安全防火牆(1)–網絡驗證碼的科普
裡面對驗證碼的種類,使用場景,作用,主要的識別技術等等進行了講解,然而並沒有涉及到任何技術內容。本章內容則作為它的 技術補充 來給出相應的識別的解決方案,讓讀者對驗證碼的功能及安全性問題有更深刻的認識。
5 基本工具
要達到本文的目的,只需要簡單的編程知識即可,因為現在的機器學習領域的蓬勃發展,已經有很多封裝好的開源解決方案來進行機器學習。普通程序員已經不需要了解複雜的數學原理,即可以實現對這些工具的應用了。
主要開發環境:
python3.5
python SDK版本
PIL
圖片處理庫
libsvm
開源的svm機器學習庫
關於環境的安裝,不是本文的重點,故略去。
6 基本流程
一般情況下,對於字符型驗證碼的識別流程如下:
準備原始圖片素材
圖片預處理
圖片字符切割
圖片尺寸歸一化
圖片字符標記
字符圖片特徵提取
生成特徵和標記對應的訓練數據集
訓練特徵標記數據生成識別模型
使用識別模型預測新的未知圖片集
達到根據“圖片”就能返回識別正確的字符集的目標
7 素材準備
7.1 素材選擇
由於本文是以初級的學習研究目的為主,要求 “有代表性,但又不會太難” ,所以就直接在網上找個比較有代表性的簡單的字符型驗證碼(感覺像在找漏洞一樣)。
最後在一個比較舊的網站(估計是幾十年前的網站框架)找到了這個驗證碼圖片。
原始圖:
放大清晰圖:
此圖片能滿足要求,仔細觀察其具有如下特點。
有利識別的特點 :
由純阿拉伯數字組成
字數為4位
字符排列有規律
字體是用的統一字體
以上就是本文所說的此驗證碼簡單的重要原因,後續代碼實現中會用到
不利識別的特點 :
圖片背景有干擾噪點
這雖然是不利特點,但是這個干擾門檻太低,只需要簡單的方法就可以除去
7.2 素材獲取
由於在做訓練的時候,需要大量的素材,所以不可能用手工的方式一張張在瀏覽器中保存,故建議寫個自動化下載的程序。
主要步驟如下:
通過瀏覽器的抓包功能獲取隨機圖片驗證碼生成接口
批量請求接口以獲取圖片
將圖片保存到本地磁盤目錄中
這些都是一些IT基本技能,本文就不再詳細展開了。
關於網絡請求和文件保存的代碼,如下:
def downloads_pic(**kwargs):
pic_name = kwargs.get(‘pic_name’, None)
url = ‘httand_code_captcha/’
res = requests.get(url, stream=True)
with open(pic_path + pic_name+’.bmp’, ‘wb’) as f: for chunk in res.iter_content(chunk_size=1024): if chunk: # filter out keep-alive new chunks f.write(chunk)
f.flush()
f.close()
循環執行N次,即可保存N張驗證素材了。
下面是收集的幾十張素材庫保存到本地文件的效果圖:
8 圖片預處理
雖然目前的機器學習算法已經相當先進了,但是為了減少後面訓練時的複雜度,同時增加識別率,很有必要對圖片進行預處理,使其對機器識別更友好。
針對以上原始素材的處理步驟如下:
讀取原始圖片素材
將彩色圖片二值化為黑白圖片
去除背景噪點
8.1 二值化圖片
主要步驟如下:
將RGB彩圖轉為灰度圖
將灰度圖按照設定閾值轉化為二值圖
image = Image.open(img_path)
imgry = image.convert(‘L’) # 轉化為灰度圖table = get_bin_table()
out = imgry.point(table, ‘1’)
上面引用到的二值函數的定義如下:
1234567891011121314 def get_bin_table(threshold=140): “”” 獲取灰度轉二值的映射table :param threshold: :return: “”” table = [] for i in range(256): if i threshold: table.append(0) else: table.append(1) return table
由PIL轉化後變成二值圖片:0表示黑色,1表示白色。二值化後帶噪點的 6937 的像素點輸出後如下圖:
1111000111111000111111100001111100000011
1110111011110111011111011110111100110111
1001110011110111101011011010101101110111
1101111111110110101111110101111111101111
1101000111110111001111110011111111101111
1100111011111000001111111001011111011111
1101110001111111101011010110111111011111
1101111011111111101111011110111111011111
1101111011110111001111011110111111011100
1110000111111000011101100001110111011111
如果你是近視眼,然後離屏幕遠一點,可以隱約看到 6937 的骨架了。
8.2 去除噪點
在轉化為二值圖片後,就需要清除噪點。本文選擇的素材比較簡單,大部分噪點也是最簡單的那種 孤立點,所以可以通過檢測這些孤立點就能移除大量的噪點。
關於如何去除更複雜的噪點甚至干擾線和色塊,有比較成熟的算法: 洪水填充法 Flood Fill ,後面有興趣的時間可以繼續研究一下。
本文為了問題簡單化,乾脆就用一種簡單的自己想的 簡單辦法 來解決掉這個問題:
對某個 黑點 周邊的九宮格裡面的黑色點計數
如果黑色點少於2個則證明此點為孤立點,然後得到所有的孤立點
對所有孤立點一次批量移除。
下面將詳細介紹關於具體的算法原理。
將所有的像素點如下圖分成三大類
頂點A
非頂點的邊界點B
內部點C
種類點示意圖如下:
其中:
A類點計算周邊相鄰的3個點(如上圖紅框所示)
B類點計算周邊相鄰的5個點(如上圖紅框所示)
C類點計算周邊相鄰的8個點(如上圖紅框所示)
當然,由於基準點在計算區域的方向不同,A類點和B類點還會有細分:
A類點繼續細分為:左上,左下,右上,右下
B類點繼續細分為:上,下,左,右
C類點不用細分
然後這些細分點將成為後續坐標獲取的準則。
主要算法的python實現如下:
def sum_9_region(img, x, y): “””
9鄰域框,以當前點為中心的田字框,黑點個數
:param x:
:param y:
:return: “””
# todo 判斷圖片的長寬度下限
cur_pixel = img.getpixel((x, y)) # 當前像素點的值
width = img.width
height = img.height if cur_pixel == 1: # 如果當前點為白色區域,則不統計鄰域值
return 0 if y == 0: # 第一行
if x == 0: # 左上頂點,4鄰域
# 中心點旁邊3個點
sum = cur_pixel \ + img.getpixel((x, y + 1)) \ + img.getpixel((x + 1, y)) \ + img.getpixel((x + 1, y + 1)) return 4 – sum elif x == width – 1: # 右上頂點
sum = cur_pixel \ + img.getpixel((x, y + 1)) \ + img.getpixel((x – 1, y)) \ + img.getpixel((x – 1, y + 1)) return 4 – sum else: # 最上非頂點,6鄰域
sum = img.getpixel((x – 1, y)) \ + img.getpixel((x – 1, y + 1)) \ + cur_pixel \ + img.getpixel((x, y + 1)) \ + img.getpixel((x + 1, y)) \ + img.getpixel((x + 1, y + 1)) return 6 – sum elif y == height – 1: # 最下面一行
if x == 0: # 左下頂點
# 中心點旁邊3個點
sum = cur_pixel \ + img.getpixel((x + 1, y)) \ + img.getpixel((x + 1, y – 1)) \ + img.getpixel((x, y – 1)) return 4 – sum elif x == width – 1: # 右下頂點
sum = cur_pixel \ + img.getpixel((x, y – 1)) \ + img.getpixel((x – 1, y)) \ + img.getpixel((x – 1, y – 1)) return 4 – sum else: # 最下非頂點,6鄰域
sum = cur_pixel \ + img.getpixel((x – 1, y)) \ + img.getpixel((x + 1, y)) \ + img.getpixel((x, y – 1)) \ + img.getpixel((x – 1, y – 1)) \ + img.getpixel((x + 1, y – 1)) return 6 – sum else: # y不在邊界
if x == 0: # 左邊非頂點
sum = img.getpixel((x, y – 1)) \ + cur_pixel \ + img.getpixel((x, y + 1)) \ + img.getpixel((x + 1, y – 1)) \ + img.getpixel((x + 1, y)) \ + img.getpixel((x + 1, y + 1)) return 6 – sum elif x == width – 1: # 右邊非頂點
# print(‘%s,%s’ % (x, y))
sum = img.getpixel((x, y – 1)) \ + cur_pixel \ + img.getpixel((x, y + 1)) \ + img.getpixel((x – 1, y – 1)) \ + img.getpixel((x – 1, y)) \ + img.getpixel((x – 1, y + 1)) return 6 – sum else: # 具備9領域條件的
sum = img.getpixel((x – 1, y – 1)) \ + img.getpixel((x – 1, y)) \ + img.getpixel((x – 1, y + 1)) \ + img.getpixel((x, y – 1)) \ + cur_pixel \ + img.getpixel((x, y + 1)) \ + img.getpixel((x + 1, y – 1)) \ + img.getpixel((x + 1, y)) \ + img.getpixel((x + 1, y + 1)) return 9 – sum
Tips:這個地方是相當考驗人的細心和耐心程度了,這個地方的工作量還是蠻大的,花了半個晚上的時間才完成的。
計算好每個像素點的周邊像素黑點(注意:PIL轉化的圖片黑點的值為0)個數後,只需要篩選出個數為 1或者2 的點的坐標即為 孤立點 。這個判斷方法可能不太準確,但是基本上能夠滿足本文的需求了。
經過預處理後的圖片如下所示:
對比文章開頭的原始圖片,那些 孤立點 都被移除掉,相對比較 乾淨 的驗證碼圖片已經生成。
9 圖片字符切割
由於字符型 驗證碼圖片 本質就可以看着是由一系列的 單個字符圖片 拼接而成,為了簡化研究對象,我們也可以將這些圖片分解到 原子級 ,即: 只包含單個字符的圖片。
於是,我們的研究對象由 “N種字串的組合對象” 變成 “10種阿拉伯數字” 的處理,極大的簡化和減少了處理對象。
9.1 分割算法
現實生活中的字符驗證碼的產生千奇百怪,有各種扭曲和變形。關於字符分割的算法,也沒有很通用的方式。這個算法也是需要開發人員仔細研究所要識別的字符圖片的特點來制定的。
當然,本文所選的研究對象盡量簡化了這個步驟的難度,下文將慢慢進行介紹。
使用圖像編輯軟件(PhoneShop或者其它)打開驗證碼圖片,放大到像素級別,觀察其它一些參數特點:
可以得到如下參數:
整個圖片尺寸是 40*10
單個字符尺寸是 6*10
左右字符和左右邊緣相距2個像素
字符上下緊挨邊緣(即相距0個像素)
這樣就可以很容易就定位到每個字符在整個圖片中佔據的像素區域,然後就可以進行分割了,具體代碼如下:
def get_crop_imgs(img): “””
按照圖片的特點,進行切割,這個要根據具體的驗證碼來進行工作. # 見原理圖
:param img:
:return: “””
child_img_list = [] for i in range(4):
x = 2 + i * (6 + 4) # 見原理圖
y = 0
child_img = img.crop((x, y, x + 6, y + 10))
child_img_list.append(child_img) return child_img_list
然後就能得到被切割的 原子級 的圖片元素了:
9.2 內容小結
基於本部分的內容的討論,相信大家已經了解到了,如果驗證碼的干擾(扭曲,噪點,干擾色塊,干擾線……)做得不夠強的話,可以得到如下兩個結論:
4位字符和40000位字符的驗證碼區別不大
純字母
不區分大小寫。分類數為26
區分大小寫。分類數為52
純數字。分類數為10
數字和區分大小寫的字母組合。分類數為62
純數字 和 數字及字母組合 的驗證碼區別不大
在沒有形成 指數級或者幾何級 的難度增加,而只是 線性有限級 增加計算量時,意義不太大。
10 尺寸歸一
本文所選擇的研究對象本身尺寸就是統一狀態:6*10的規格,所以此部分不需要額外處理。但是一些進行了扭曲和縮放的驗證碼,則此部分也會是一個圖像處理的難點。
11 模型訓練步驟
在前面的環節,已經完成了對單個圖片的處理和分割了。後面就開始進行 識別模型 的訓練了。
整個訓練過程如下:
大量完成預處理並切割到原子級的圖片素材準備
對素材圖片進行人為分類,即:打標籤
定義單張圖片的識別特徵
使用SVM訓練模型對打了標籤的特徵文件進行訓練,得到模型文件
12 素材準備
本文在訓練階段重新下載了同一模式的4數字的驗證圖片總計:3000張。然後對這3000張圖片進行處理和切割,得到12000張原子級圖片。
在這12000張圖片中刪除一些會影響訓練和識別的強幹擾的干擾素材,切割後的效果圖如下:
13 素材標記
由於本文使用的這種識別方法中,機器在最開始是不具備任何 數字的觀念的。所以需要人為的對素材進行標識,告訴 機器什麼樣的圖片的內容是 1……。
這個過程叫做 “標記”。
具體打標籤的方法是:
為0~9每個數字建立一個目錄,目錄名稱為相應數字(相當於標籤)
人為判定 圖片內容,並將圖片拖到指定數字目錄中
每個目錄中存放100張左右的素材
一般情況下,標記的素材越多,那麼訓練出的模型的分辨能力和預測能力越強。例如本文中,標記素材為十多張的時候,對新的測試圖片識別率基本為零,但是到達100張時,則可以達到近乎100%的識別率
14 特徵選擇
對於切割後的單個字符圖片,像素級放大圖如下:
從宏觀上看,不同的數字圖片的本質就是將黑色按照一定規則填充在相應的像素點上,所以這些特徵都是最後圍繞像素點進行。
字符圖片 寬6個像素,高10個像素 ,理論上可以最簡單粗暴地可以定義出60個特徵:60個像素點上面的像素值。但是顯然這樣高維度必然會造成過大的計算量,可以適當的降維。
通過查閱相應的文獻 [2],給出另外一種簡單粗暴的特徵定義:
每行上黑色像素的個數,可以得到10個特徵
每列上黑色像素的個數,可以得到6個特徵
最後得到16維的一組特徵,實現代碼如下:
def get_feature(img): “””
獲取指定圖片的特徵值,
1. 按照每排的像素點,高度為10,則有10個維度,然後為6列,總共16個維度
:param img_path:
:return:一個維度為10(高度)的列表 “””
width, height = img.size
pixel_cnt_list = []
height = 10 for y in range(height):
pix_cnt_x = 0 for x in range(width): if img.getpixel((x, y)) == 0: # 黑色點
pix_cnt_x += 1
pixel_cnt_list.append(pix_cnt_x) for x in range(width):
pix_cnt_y = 0 for y in range(height): if img.getpixel((x, y)) == 0: # 黑色點
pix_cnt_y += 1
pixel_cnt_list.append(pix_cnt_y) return pixel_cnt_list
然後就將圖片素材特徵化,按照 libSVM 指定的格式生成一組帶特徵值和標記值的向量文
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/257846.html