生活随笔
收集整理的這篇文章主要介紹了
机器学习案例:验证码识别(Captcha)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
驗(yàn)證碼(CAPTCHA,全自動(dòng)區(qū)分計(jì)算機(jī)和人類(lèi)的圖靈測(cè)試)的縮寫(xiě),是一種區(qū)分用戶是計(jì)算機(jī)還是人工智能的全自動(dòng)程序。
實(shí)驗(yàn)步驟:
- 1、創(chuàng)建驗(yàn)證碼
- 2、對(duì)驗(yàn)證碼進(jìn)行01值化
- 3、降噪
- 4、對(duì)驗(yàn)證碼進(jìn)行切分
- 5、對(duì)切分后的驗(yàn)證碼進(jìn)行圖片轉(zhuǎn)數(shù)字化
- 6、使用邏輯回歸建模
- 7、對(duì)新輸入的圖片進(jìn)行預(yù)測(cè)
驗(yàn)證碼的創(chuàng)建
1、隨機(jī)生成驗(yàn)證碼的顏色
2、隨機(jī)生成驗(yàn)證碼數(shù)字
3、使用PIL進(jìn)行畫(huà)圖
import os
from PIL
import Image
from PIL
import ImageDraw
from PIL
import ImageFont
import random
import matplotlib
.pyplot
as plt
def getRandomColor():"""獲取一個(gè)隨機(jī)顏色(r,g,b)格式的:return:"""c1
= random
.randint
(0, 255)c2
= random
.randint
(0, 255)c3
= random
.randint
(0, 255)if c1
== 255:c1
= 0if c2
== 255:c2
= 0if c3
== 255:c3
= 0return (c1
, c2
, c3
)
def getRandomStr():"""獲取一個(gè)隨機(jī)數(shù)字,每個(gè)數(shù)字的顏色也是隨機(jī)的:return:"""random_num
= str(random
.randint
(0, 9))return random_num
def generate_captcha():"""使用PIL畫(huà)圖步驟:return: """image
= Image
.new
('RGB', (150, 50), (255, 255, 255))draw
= ImageDraw
.Draw
(image
)font
= ImageFont
.truetype
("arlrdbd.ttf", size
=32) label
= ""
for i
in range(5):random_char
= getRandomStr
()label
+= random_chardraw
.text
((10+i
*30, 0), random_char
, getRandomColor
(), font
=font
)width
= 150height
= 30for i
in range(3):x1
= random
.randint
(0, width
)x2
= random
.randint
(0, width
)y1
= random
.randint
(0, height
)y2
= random
.randint
(0, height
)draw
.line
((x1
, y1
, x2
, y2
), fill
=(0, 0, 0))for i
in range(5):draw
.point
([random
.randint
(0, width
), random
.randint
(0, height
)], fill
=getRandomColor
())x
= random
.randint
(0, width
)y
= random
.randint
(0, height
)draw
.arc
((x
, y
, x
+ 4, y
+ 4), 0, 90, fill
=(0, 0, 0))image
.save
(open(''.join
(['captcha_images/', label
, '.png']), 'wb'), 'png')
執(zhí)行代碼之后,會(huì)在‘captcha_images’下生成實(shí)驗(yàn)所需的圖片,如圖:
圖像處理:對(duì)生成的圖片進(jìn)行處理
(1)對(duì)驗(yàn)證碼圖片二值化,首先把圖像從RGB 三通道轉(zhuǎn)化成Gray單通道,然后把灰度圖(0~255)轉(zhuǎn)化成二值圖(0,1)。
(2)將處理好的二值圖進(jìn)行降噪,去除圖片中的噪點(diǎn)和噪線
from PIL
import Image
import numpy
as np
import matplotlib
.pyplot
as plt
import os
def binarization(path
):"""把一個(gè)rgb的圖轉(zhuǎn)換成一個(gè)二值圖:param path::return:"""img
= Image
.open(path
)img_gray
= img
.convert
("L")img_gray
= np
.array
(img_gray
)w
, h
= img_gray
.shape
for x
in range(w
):for y
in range(h
):gray
= img_gray
[x
, y
]if gray
<= 220:img_gray
[x
, y
] = 0else:img_gray
[x
, y
] = 1plt
.figure
("")plt
.imshow
(img_gray
, cmap
="gray")plt
.axis
("off")plt
.show
()return img_gray
def noiseReduction(img_gray
, label
):"""降噪,也就是處理離群點(diǎn)如果一個(gè)像素點(diǎn)周?chē)挥行∮?個(gè)黑點(diǎn)的時(shí)候,那么這個(gè)點(diǎn)就是離群點(diǎn):param img_gray::param label::return:"""height
, width
= img_gray
.shape
for x
in range(height
):for y
in range(width
):cnt
= 0if img_gray
[x
, y
] == 1:continueelse:try:if img_gray
[x
-1, y
-1] == 0:cnt
+= 1except:passtry:if img_gray
[x
-1, y
] == 0:cnt
+= 1except:passtry:if img_gray
[x
-1, y
+1] == 0:cnt
+= 1except:passtry:if img_gray
[x
, y
-1] == 0:cnt
+= 1except:passtry:if img_gray
[x
, y
+1] == 0:cnt
+= 1except:passtry:if img_gray
[x
+1, y
-1] == 0:cnt
+= 1except:passtry:if img_gray
[x
+1, y
] == 0:cnt
+= 1except:passtry:if img_gray
[x
+1, y
+1] == 0:cnt
+= 1except:passif cnt
< 4: img_gray
[x
, y
] = 1plt
.figure
(" ")plt
.imshow
(img_gray
, cmap
="gray")plt
.axis
("off")plt
.savefig
("".join
(["clean_captcha_img/", label
, ".png"]))def image_2_clean():"""把所有的圖像都轉(zhuǎn)化成二值圖:return:"""captchas
= os
.listdir
("".join
(["captcha_images/"]))for captcha
in captchas
:label
= captcha
.split
(".")[0]image_path
= "".join
(["captcha_images/", captcha
])im
= binarization
(image_path
)noiseReduction
(im
, label
)if __name__
== '__main__':image_2_clean
()
圖像分割:對(duì)降噪后的圖片進(jìn)行分割,并對(duì)分割后的圖片進(jìn)行存儲(chǔ)
import os
from PIL
import Image
from PIL
import ImageDraw
from PIL
import ImageFont
import random
import matplotlib
.pyplot
as plt
def cutImg(label
):"""把圖像的每一個(gè)數(shù)字都切分出來(lái),并且存到新的文件夾下:param label::return:"""labels
= list(label
)img
= Image
.open("".join
(['clean_captcha_img/', label
, '.png']))for i
in range(5):pic
= img
.crop
((100*(1+i
), 170, 100*(1+i
)+100, 280))plt
.imshow
(pic
)seq
= get_save_seq
(label
[i
])pic
.save
("".join
(["cut_number/", str(label
[i
]), "/", str(seq
), '.png']))
def get_save_seq(num
):"""得到需要保存的數(shù)據(jù)的文件名每一個(gè)數(shù)文件下的文件名,都是從0開(kāi)始保存 0.png, 1.png....:param num::return:"""nmlist
= os
.listdir
("".join
(["cut_number/", num
, "/"]))if len(nmlist
) == 0 or nmlist
is None:return 0else:max_file
= 0for file in nmlist
:if int(file.split
(".")[0]) > max_file
:max_file
= int(file.split
(".")[0])return int(max_file
) + 1
def clean_to_cut():"""對(duì)每一個(gè)文件都進(jìn)行切分:return:"""captchas
= os
.listdir
("".join
(["clean_captcha_img"]))for captcha
in captchas
:label
= captcha
.split
(".")[0]cutImg
(label
)
def create_dir():for i
in range(10):os
.mkdir
("".join
(["cut_number/", str(i
)]))if __name__
== '__main__':clean_to_cut
()
圖片轉(zhuǎn)數(shù)字化:對(duì)切分后的圖片灰度化、二值化,使用Image.open()打開(kāi)圖片文件,得到plt圖片對(duì)象,將plt圖片對(duì)象轉(zhuǎn)換為ndarray對(duì)象,將二值化后的圖像轉(zhuǎn)化為1行n列,存入X列表中,并將其對(duì)應(yīng)的數(shù)字存入Y列表中。
模型的生成:將X,Y傳入邏輯回歸模型中,使用交叉驗(yàn)證和網(wǎng)格搜索尋找最優(yōu)的參數(shù)。
import os
from PIL
import Image
import numpy
as np
import matplotlib
.pyplot
as plt
from sklearn
.linear_model
import LogisticRegression
from sklearn
.model_selection
import train_test_split
from sklearn
.model_selection
import GridSearchCV
from sklearn
.externals
import joblib
from sklearn
.metrics
import confusion_matrix
from sklearn
.metrics
import precision_score
from sklearn
.metrics
import recall_score
def load_data():"""把數(shù)據(jù)從cut_number里面導(dǎo)出來(lái)其中X指的是每一個(gè)數(shù)字的01值的排列, Y指的是這個(gè)數(shù)字是什么:return:"""X
, Y
= [], []cut_list
= os
.listdir
("cut_number")for numC
in cut_list
:num_list_dir
= "".join
(["cut_number/", str(numC
), "/"])nums_dir
= os
.listdir
(num_list_dir
)for num_file
in nums_dir
:img
= Image
.open("".join
(["cut_number/", str(numC
), "/", num_file
]))img_gray
= img
.convert
("L")img_array
= np
.array
(img_gray
)w
, h
= img_array
.shape
for x
in range(w
):for y
in range(h
):gray
= img_array
[x
, y
]if gray
<= 220:img_array
[x
, y
] = 0else:img_array
[x
, y
] = 1img_re
= img_array
.reshape
(1, -1)X
.append
(img_re
[0])Y
.append
(int(numC
))return np
.array
(X
), np
.array
(Y
)def generate_model(X
, Y
):"""生成模型:param X::param Y::return:"""X_train
, X_test
, Y_train
, Y_test
= train_test_split
(X
, Y
, test_size
=0.3)log_clf
= LogisticRegression
(multi_class
="ovr", solver
="sag", max_iter
=10000)param_grid
= {"tol": [1e-4, 1e-5, 1e-2], "C": [0.4, 0.6, 0.8]}grid_search
= GridSearchCV
(log_clf
, param_grid
=param_grid
, cv
=3)grid_search
.fit
(X
, Y
)print(grid_search
.best_params_
)print("模型生成成功")joblib
.dump
(log_clf
, "captcha_model/captcha_model.model")print("模型保存成功")if __name__
== '__main__':X
, Y
= load_data
()generate_model
(X
, Y
)
圖片的預(yù)測(cè):
輸入要預(yù)測(cè)的圖片,對(duì)其進(jìn)行灰度化,二值化,并進(jìn)行分割,將分割出來(lái)的五個(gè)圖片輸入進(jìn)模型中。
import os
from PIL
import Image
import numpy
as np
import matplotlib
.pyplot
as plt
from sklearn
.linear_model
import LogisticRegression
from sklearn
.model_selection
import train_test_split
from sklearn
.model_selection
import GridSearchCV
from sklearn
.externals
import joblib
from sklearn
.metrics
import confusion_matrix
from sklearn
.metrics
import precision_score
from sklearn
.metrics
import recall_score
from .captcha_logistic
import *def get_model():model
= joblib
.load
('captcha_model/captcha_model.model')return model
def model_predict():path
= 'captcha_predict/unknown.png'pre_img_gray
= binarization
(path
)noiseReduction
(pre_img_gray
, 'unknown')labels
= ['0', '1', '2', '3', '4']img
= Image
.open(''.join
(['clean_captcha_img/unknown.png']))for i
in range(5):pic
= img
.crop
((100 * (1 + i
), 170, 100 * (1 + i
) + 100, 280))plt
.imshow
(pic
)pic
.save
(''.join
(['captcha_predict/', labels
[i
], '.png']))result
= ''model
= get_model
()for i
in range(5):path
= ''.join
(['captcha_predict/', labels
[i
], '.png'])img
= Image
.open(path
)img_gray
= img
.convert
('L')img_array
= np
.array
(img_gray
)w
, h
= img_array
.shape
for x
in range(w
):for y
in range(h
):gray
= img_array
[x
, y
]if gray
<= 220:img_array
[x
, y
] = 0else:img_array
[x
, y
] = 1img_re
= img_array
.reshape
(1, -1)X
= img_re
[0]y_pre
= model
.predict
([X
])result
= ''.join
([result
, str(y_pre
[0])])return result
if __name__
== '__main__':result
= model_predict
()print(result
)
總結(jié)
以上是生活随笔為你收集整理的机器学习案例:验证码识别(Captcha)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。