python驗證碼識別教程之灰度處理、二值化、降噪與tesserocr識別


python驗證碼識別教程之灰度處理、二值化、降噪與tesserocr識別

 更新時間:2018年06月04日 11:04:53   作者:Hi!Roy!   我要評論
 
這篇文章主要給大家介紹了關於python驗證碼識別教程之灰度處理、二值化、降噪與tesserocr識別的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨着小編來一起學習學習吧
 

前言

寫爬蟲有一個繞不過去的問題就是驗證碼,現在驗證碼分類大概有4種:

  1. 圖像類
  2. 滑動類
  3. 點擊類
  4. 語音類

今天先來看看圖像類,這類驗證碼大多是數字、字母的組合,國內也有使用漢字的。在這個基礎上增加噪點、干擾線、變形、重疊、不同字體顏色等方法來增加識別難度。

相應的,驗證碼識別大體可以分為下面幾個步驟:

  1. 灰度處理
  2. 增加對比度(可選)
  3. 二值化
  4. 降噪
  5. 傾斜校正分割字符
  6. 建立訓練庫
  7. 識別

由於是實驗性質的,文中用到的驗證碼均為程序生成而不是批量下載真實的網站驗證碼,這樣做的好處就是可以有大量的知道明確結果的數據集。

當需要真實環境下需要獲取數據時,可以使用結合各個大碼平台來建立數據集進行訓練。

生成驗證碼這里我使用Claptcha (本地下載)這個庫,當然Captcha本地下載)這個庫也是個不錯的選擇。

為了生成最簡單的純數字、無干擾的驗證碼,首先需要將claptcha.py的285行_drawLine做一些修改,我直接讓這個函數返回None,然后開始生成驗證碼:

?
1
2
3
4
from claptcha import Claptcha
 
c = Claptcha( "8069" , "/usr/share/fonts/truetype/freefont/FreeMono.ttf" )
t,_ = c.write( '1.png' )

這里需要注意ubuntu的字體路徑,也可以在網上下載其他字體使用。生成驗證碼如下:


可以看出,驗證碼有形變。對於這類最簡單的驗證碼,可以直接使用谷歌開源的tesserocr來識別。

首先安裝:

?
1
2
apt-get install tesseract-ocr libtesseract-dev libleptonica-dev
pip install tesserocr

然后開始識別:

?
1
2
3
4
5
6
7
from PIL import Image
import tesserocr
 
p1 = Image. open ( '1.png' )
tesserocr.image_to_text(p1)
 
'8069\n\n'

可以看出,對於這種簡單的驗證碼,基本什么都不做識別率就已經很高了。有興趣的小伙伴可以用更多的數據來測試,這里我就不展開了。

接下來,在驗證碼背景添加噪點來看看:

?
1
2
c = Claptcha( "8069" , "/usr/share/fonts/truetype/freefont/FreeMono.ttf" ,noise = 0.4 )
t,_ = c.write( '2.png' )

生成驗證碼如下:


識別:

?
1
2
3
p2 = Image. open ( '2.png' )
tesserocr.image_to_text(p2)
'8069\n\n'

效果還可以。接下來生成一個字母數字組合的:

?
1
2
c2 = Claptcha( "A4oO0zZ2" , "/usr/share/fonts/truetype/freefont/FreeMono.ttf" )
t,_ = c2.write( '3.png' )

生成驗證碼如下:

第3個為小寫字母o,第4個為大寫字母O,第5個為數字0,第6個為小寫字母z,第7個為大寫字母Z,最后一個是數字2。人眼已經跪了有木有!但現在一般驗證碼對大小寫是不做嚴格區分的,看自動識別什么樣吧:

?
1
2
3
p3 = Image. open ( '3.png' )
tesserocr.image_to_text(p3)
'AMOOZW\n\n'

人眼都跪的計算機當然也廢了。但是,對於一些干擾小、形變不嚴重的,使用tesserocr還是十分簡單方便的。然后將修改的claptcha.py的285行_drawLine還原,看添加干擾線的情況。

?
1
2
3
p4 = Image. open ( '4.png' )
tesserocr.image_to_text(p4)
''

加了條干擾線就完全識別不出來了,那么有沒有什么辦法去除干擾線呢?

雖然圖片看上去是黑白的,但還需要進行灰度處理,否則使用load()函數得到的是某個像素點的RGB元組而不是單一值了。處理如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
def binarizing(img,threshold):
  """傳入image對象進行灰度、二值處理"""
  img = img.convert( "L" ) # 轉灰度
  pixdata = img.load()
  w, h = img.size
  # 遍歷所有像素,大於閾值的為黑色
  for y in range (h):
   for x in range (w):
    if pixdata[x, y] < threshold:
     pixdata[x, y] = 0
    else :
     pixdata[x, y] = 255
  return img

處理后的圖片如下:

可以看出處理后圖片銳化了很多,接下來嘗試去除干擾線,常見的4鄰域、8鄰域算法。所謂的X鄰域算法,可以參考手機九宮格輸入法,按鍵5為要判斷的像素點,4鄰域就是判斷上下左右,8鄰域就是判斷周圍8個像素點。如果這4或8個點中255的個數大於某個閾值則判斷這個點為噪音,閾值可以根據實際情況修改。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def depoint(img):
  """傳入二值化后的圖片進行降噪"""
  pixdata = img.load()
  w,h = img.size
  for y in range ( 1 ,h - 1 ):
   for x in range ( 1 ,w - 1 ):
    count = 0
    if pixdata[x,y - 1 ] > 245 : #上
     count = count + 1
    if pixdata[x,y + 1 ] > 245 : #下
     count = count + 1
    if pixdata[x - 1 ,y] > 245 : #左
     count = count + 1
    if pixdata[x + 1 ,y] > 245 : #右
     count = count + 1
    if pixdata[x - 1 ,y - 1 ] > 245 : #左上
     count = count + 1
    if pixdata[x - 1 ,y + 1 ] > 245 : #左下
     count = count + 1
    if pixdata[x + 1 ,y - 1 ] > 245 : #右上
     count = count + 1
    if pixdata[x + 1 ,y + 1 ] > 245 : #右下
     count = count + 1
    if count > 4 :
     pixdata[x,y] = 255
  return img

處理后的圖片如下:


好像……根本沒卵用啊?!確實是這樣的,因為示例中的圖片干擾線的寬度和數字是一樣的。對於干擾線和數據像素不同的,比如Captcha生成的驗證碼:

從左到右依次是原圖、二值化、去除干擾線的情況,總體降噪的效果還是比較明顯的。另外降噪可以多次執行,比如我對上面的降噪后結果再進行依次降噪,可以得到下面的效果:


再進行識別得到了結果:

?
1
2
3
p7 = Image. open ( '7.png' )
tesserocr.image_to_text(p7)
'8069 ,,\n\n'

另外,從圖片來看,實際數據顏色明顯和噪點干擾線不同,根據這一點可以直接把噪點全部去除,這里就不展開說了。
第一篇文章,先記錄如何將圖片進行灰度處理、二值化、降噪,並結合tesserocr來識別簡單的驗證碼,剩下的部分在下一篇文章中和大家一起分享。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM