摘要:接下來按步驟進(jìn)行說明。總結(jié)這種方法的可擴(kuò)展性很弱,而且只適用于簡單的驗證碼,那種根本就別提了。
前言
之前做了一個校園交友的APP,其中一個邏輯是通過用戶的教務(wù)系統(tǒng)來確認(rèn)用戶是一名在校大學(xué)生,基本的想法是通過用戶的賬號和密碼,用爬蟲的方法來確認(rèn)信息,但是許多教務(wù)系統(tǒng)都有驗證碼,當(dāng)時是通過本地服務(wù)器去下載驗證碼,然后分發(fā)給客戶端,然后讓用戶自己填寫驗證碼,與賬號密碼一并提交給服務(wù)器,然后服務(wù)器再去模擬登錄教務(wù)系統(tǒng)以確認(rèn)用戶能否登錄該教務(wù)系統(tǒng)。驗證碼無疑讓我們想使得用戶快速認(rèn)證的想法破滅了,但是當(dāng)時也沒辦法,最近看了一些機(jī)器學(xué)習(xí)的內(nèi)容,覺得對于大多數(shù)學(xué)校的那些極簡單的驗證碼應(yīng)該是可以用KNN這種方法來破解的,于是整理了一下思緒,擼起袖子做起來!
分析我們學(xué)校的驗證碼是這樣的:,其實就是簡單地把字符進(jìn)行旋轉(zhuǎn)然后加上一些微弱的噪點形成的。我們要識別,就得逆行之,具體思路就是,首先二值化去掉噪點,然后把單個字符分割出來,最后旋轉(zhuǎn)至標(biāo)準(zhǔn)方向,然后從這些處理好的圖片中選出模板,最后每次新來一張驗證碼就按相同方式處理,然后和這些模板進(jìn)行比較,選擇判別距離最近的一個模板作為其判斷結(jié)果(亦即KNN的思想,本文取K=1)。接下來按步驟進(jìn)行說明。
獲得驗證碼首先得有大量的驗證碼,我們通過爬蟲來實現(xiàn),代碼如下
#-*- coding:UTF-8 -*- import urllib,urllib2,cookielib,string,Image def getchk(number): #創(chuàng)建cookie對象 cookie = cookielib.LWPCookieJar() cookieSupport= urllib2.HTTPCookieProcessor(cookie) opener = urllib2.build_opener(cookieSupport, urllib2.HTTPHandler) urllib2.install_opener(opener) #首次與教務(wù)系統(tǒng)鏈接獲得cookie# #偽裝browser headers = { "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Encoding":"gzip,deflate", "Accept-Language":"zh-CN,zh;q=0.8", "User-Agent":"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36" } req0 = urllib2.Request( url ="http://mis.teach.ustc.edu.cn", headers = headers #請求頭 ) # 捕捉http錯誤 try : result0 = urllib2.urlopen(req0) except urllib2.HTTPError,e: print e.code #提取cookie getcookie = ["",] for item in cookie: getcookie.append(item.name) getcookie.append("=") getcookie.append(item.value) getcookie = "".join(getcookie) #修改headers headers["Origin"] = "http://mis.teach.ustc.edu.cn" headers["Referer"] = "http://mis.teach.ustc.edu.cn/userinit.do" headers["Content-Type"] = "application/x-www-form-urlencoded" headers["Cookie"] = getcookie for i in range(number): req = urllib2.Request( url ="http://mis.teach.ustc.edu.cn/randomImage.do?date="1469451446894"", headers = headers #請求頭 ) response = urllib2.urlopen(req) status = response.getcode() picData = response.read() if status == 200: localPic = open("./source/"+str(i)+".jpg", "wb") localPic.write(picData) localPic.close() else: print "failed to get Check Code " if __name__ == "__main__": getchk(500)
這里下載了500張驗證碼到source目錄下面。如圖:
二值化matlab豐富的圖像處理函數(shù)能給我們省下很多時間,,我們遍歷source文件夾,對每一張驗證碼圖片進(jìn)行二值化處理,把處理過的圖片存入bw目錄下。代碼如下
mydir="./source/"; bw = "./bw/"; if mydir(end)~="" mydir=[mydir,""]; end DIRS=dir([mydir,"*.jpg"]); %擴(kuò)展名 n=length(DIRS); for i=1:n if ~DIRS(i).isdir img = imread(strcat(mydir,DIRS(i).name )); img = rgb2gray(img);%灰度化 img = im2bw(img);%0-1二值化 name = strcat(bw,DIRS(i).name) imwrite(img,name); end end
處理結(jié)果如圖:
分割mydir="./bw/"; letter = "./letter/"; if mydir(end)~="" mydir=[mydir,""]; end DIRS=dir([mydir,"*.jpg"]); %擴(kuò)展名 n=length(DIRS); for i=1:n if ~DIRS(i).isdir img = imread(strcat(mydir,DIRS(i).name )); img = im2bw(img);%二值化 img = 1-img;%顏色反轉(zhuǎn)讓字符成為聯(lián)通域,方便去除噪點 for ii = 0:3 region = [ii*20+1,1,19,20];%把一張驗證碼分成四個20*20大小的字符圖片 subimg = imcrop(img,region); imlabel = bwlabel(subimg); % imshow(imlabel); if max(max(imlabel))>1 % 說明有噪點,要去除 % max(max(imlabel)) % imshow(subimg); stats = regionprops(imlabel,"Area"); area = cat(1,stats.Area); maxindex = find(area == max(area)); area(maxindex) = 0; secondindex = find(area == max(area)); imindex = ismember(imlabel,secondindex); subimg(imindex==1)=0;%去掉第二大連通域,噪點不可能比字符大,所以第二大的就是噪點 end name = strcat(letter,DIRS(i).name(1:length(DIRS(i).name)-4),"_",num2str(ii),".jpg") imwrite(subimg,name); end end end
處理結(jié)果如圖:
旋轉(zhuǎn)接下來進(jìn)行旋轉(zhuǎn),哪找一個什么標(biāo)準(zhǔn)呢?據(jù)觀察,這些字符旋轉(zhuǎn)不超過60度,那么在正負(fù)60度之間,統(tǒng)一旋轉(zhuǎn)至字符寬度最小就行了。代碼如下
if mydir(end)~="" mydir=[mydir,""]; end DIRS=dir([mydir,"*.jpg"]); %擴(kuò)展名 n=length(DIRS); for i=1:n if ~DIRS(i).isdir img = imread(strcat(mydir,DIRS(i).name )); img = im2bw(img); minwidth = 20; for angle = -60:60 imgr=imrotate(img,angle,"bilinear","crop");%crop 避免圖像大小變化 imlabel = bwlabel(imgr); stats = regionprops(imlabel,"Area"); area = cat(1,stats.Area); maxindex = find(area == max(area)); imindex = ismember(imlabel,maxindex);%最大連通域為1 [y,x] = find(imindex==1); width = max(x)-min(x)+1; if width處理結(jié)果如圖,一共2000個字符的圖片存在rotate文件夾中
模板選取現(xiàn)在從rotate文件夾中選取一套模板,涵蓋每一個字符,一個字符可以選取多個圖片,因為即使有前面的諸多處理也不能保證一個字符的最終呈現(xiàn)形式只有一種,多選幾個才能保證覆蓋率。把選出來的模板圖片存入samples文件夾下,這個過程很耗時耗力??梢哉彝瑢W(xué)幫忙~,如圖
測試測試代碼如下
首先對測試驗證碼進(jìn)行上述操作,然后和選出來的模板進(jìn)行比較,采用差分值最小的模板作為測試樣本的字符選擇,代碼如下% 具有差分最小值的圖作為答案 mydir="./test/"; samples = "./samples/"; if mydir(end)~="" mydir=[mydir,""]; end if samples(end)~="" samples=[samples,""]; end DIRS=dir([mydir,"*.jpg"]); %擴(kuò)展? DIRS1=dir([samples,"*.jpg"]); %擴(kuò)展名 n=length(DIRS);%驗證碼總圖數(shù) singleerror = 0;%單個錯誤 uniterror = 0;%一張驗證碼錯誤個數(shù) for i=1:n if ~DIRS(i).isdir realcodes = DIRS(i).name(1:4); fprintf("驗證碼實際字符:%s ",realcodes); img = imread(strcat(mydir,DIRS(i).name )); img = rgb2gray(img); img = im2bw(img); img = 1-img;%顏色反轉(zhuǎn)讓字符成為聯(lián)通域 subimgs = []; for ii = 0:3 region = [ii*20+1,1,19,20];%奇怪,為什么這樣才能均分? subimg = imcrop(img,region); imlabel = bwlabel(subimg); if max(max(imlabel))>1 % 說明有雜點 stats = regionprops(imlabel,"Area"); area = cat(1,stats.Area); maxindex = find(area == max(area)); area(maxindex) = 0; secondindex = find(area == max(area)); imindex = ismember(imlabel,secondindex); subimg(imindex==1)=0;%去掉第二大連通域 end subimgs = [subimgs;subimg]; end codes = []; for ii = 0:3 region = [ii*20+1,1,19,20]; subimg = imcrop(img,region); minwidth = 20; for angle = -60:60 imgr=imrotate(subimg,angle,"bilinear","crop");%crop 避免圖像大小變化 imlabel = bwlabel(imgr); stats = regionprops(imlabel,"Area"); area = cat(1,stats.Area); maxindex = find(area == max(area)); imindex = ismember(imlabel,maxindex);%最大連通域為1 [y,x] = find(imindex==1); width = max(x)-min(x)+1; if width0 uniterror = uniterror +1; end fprintf("錯誤個數(shù):%d ",num); end end fprintf(" -----結(jié)果統(tǒng)計如下----- "); fprintf("測試驗證碼的字符數(shù)量:%d ",n*4); fprintf("測試驗證碼的字符錯誤數(shù)量:%d ",singleerror); fprintf("單個字符識別正確率:%.2f%% ",(1-singleerror/(n*4))*100); fprintf("測試驗證碼圖的數(shù)量:%d ",n); fprintf("測試驗證碼圖的錯誤數(shù)量:%d ",uniterror); fprintf("填對驗證碼的概率:%.2f%% ",(1-uniterror/n)*100); 結(jié)果:
驗證碼實際字符:2B4E 驗證碼測試字符:2B4F 錯誤個數(shù):1 驗證碼實際字符:4572 驗證碼測試字符:4572 錯誤個數(shù):0 驗證碼實際字符:52CY 驗證碼測試字符:52LY 錯誤個數(shù):1 驗證碼實際字符:83QG 驗證碼測試字符:85QG 錯誤個數(shù):1 驗證碼實際字符:9992 驗證碼測試字符:9992 錯誤個數(shù):0 驗證碼實際字符:A7Y7 驗證碼測試字符:A7Y7 錯誤個數(shù):0 驗證碼實際字符:D993 驗證碼測試字符:D995 錯誤個數(shù):1 驗證碼實際字符:F549 驗證碼測試字符:F5A9 錯誤個數(shù):1 驗證碼實際字符:FMC6 驗證碼測試字符:FMLF 錯誤個數(shù):2 驗證碼實際字符:R4N4 驗證碼測試字符:R4N4 錯誤個數(shù):0 -----結(jié)果統(tǒng)計如下----- 測試驗證碼的字符數(shù)量:40 測試驗證碼的字符錯誤數(shù)量:7 單個字符識別正確率:82.50% 測試驗證碼圖的數(shù)量:10 測試驗證碼圖的錯誤數(shù)量:6 填對驗證碼的概率:40.00%可見單個字符準(zhǔn)確率是比較高的的了,但是綜合準(zhǔn)確率還是不行,觀察結(jié)果至,錯誤的字符就是那些易混淆字符,比如E和F,C和L,5和3,4和A等,所以我們能做的事就是增加模板中的樣本數(shù)量,以期盡量減少混淆。
增加了幾十個樣本過后再次試驗,結(jié)果:驗證碼實際字符:2B4E 驗證碼測試字符:2B4F 錯誤個數(shù):1 驗證碼實際字符:4572 驗證碼測試字符:4572 錯誤個數(shù):0 驗證碼實際字符:52CY 驗證碼測試字符:52LY 錯誤個數(shù):1 驗證碼實際字符:83QG 驗證碼測試字符:83QG 錯誤個數(shù):0 驗證碼實際字符:9992 驗證碼測試字符:9992 錯誤個數(shù):0 驗證碼實際字符:A7Y7 驗證碼測試字符:A7Y7 錯誤個數(shù):0 驗證碼實際字符:D993 驗證碼測試字符:D993 錯誤個數(shù):0 驗證碼實際字符:F549 驗證碼測試字符:F5A9 錯誤個數(shù):1 驗證碼實際字符:FMC6 驗證碼測試字符:FMLF 錯誤個數(shù):2 驗證碼實際字符:R4N4 驗證碼測試字符:R4N4 錯誤個數(shù):0 -----結(jié)果統(tǒng)計如下----- 測試驗證碼的字符數(shù)量:40 測試驗證碼的字符錯誤數(shù)量:5 單個字符識別正確率:87.50% 測試驗證碼圖的數(shù)量:10 測試驗證碼圖的錯誤數(shù)量:4 填對驗證碼的概率:60.00%可見無論是單個字符識別正確率還是整個驗證碼正確的概率都有了提升。能夠預(yù)見:隨著模板數(shù)量的增多,正確率會不斷地提高。
總結(jié)這種方法的可擴(kuò)展性很弱,而且只適用于簡單的驗證碼,12306那種根本就別提了。
更新7.28
總之就是學(xué)習(xí)的道路還很長,我會慢慢的改善這種方法的。再增加了幾十個模板后結(jié)果如下:
驗證碼實際字符:2B4E 驗證碼測試字符:2B4E 錯誤個數(shù):0 驗證碼實際字符:4572 驗證碼測試字符:4572 錯誤個數(shù):0 驗證碼實際字符:52CY 驗證碼測試字符:52LY 錯誤個數(shù):1 驗證碼實際字符:83QG 驗證碼測試字符:83QG 錯誤個數(shù):0 驗證碼實際字符:9992 驗證碼測試字符:9992 錯誤個數(shù):0 驗證碼實際字符:A7Y7 驗證碼測試字符:A7Y7 錯誤個數(shù):0 驗證碼實際字符:D993 驗證碼測試字符:D993 錯誤個數(shù):0 驗證碼實際字符:F549 驗證碼測試字符:F549 錯誤個數(shù):0 驗證碼實際字符:FMC6 驗證碼測試字符:FMLF 錯誤個數(shù):2 驗證碼實際字符:R4N4 驗證碼測試字符:R4N4 錯誤個數(shù):0 -----結(jié)果統(tǒng)計如下----- 測試驗證碼的字符數(shù)量:40 測試驗證碼的字符錯誤數(shù)量:3 單個字符識別正確率:92.50% 測試驗證碼圖的數(shù)量:10 測試驗證碼圖的錯誤數(shù)量:2 填對驗證碼的概率:80.00%增加測試集至20個,結(jié)果如下:
驗證碼實際字符:2B4E 驗證碼測試字符:2B4E 錯誤個數(shù):0 驗證碼實際字符:4572 驗證碼測試字符:4572 錯誤個數(shù):0 驗證碼實際字符:4Q33 驗證碼測試字符:4Q33 錯誤個數(shù):0 驗證碼實際字符:52CY 驗證碼測試字符:52LY 錯誤個數(shù):1 驗證碼實際字符:6S3C 驗證碼測試字符:6S3C 錯誤個數(shù):0 驗證碼實際字符:7456 驗證碼測試字符:74F5 錯誤個數(shù):2 驗證碼實際字符:775D 驗證碼測試字符:775D 錯誤個數(shù):0 驗證碼實際字符:792Z 驗證碼測試字符:7PZZ 錯誤個數(shù):2 驗證碼實際字符:83QG 驗證碼測試字符:83QG 錯誤個數(shù):0 驗證碼實際字符:8JXB 驗證碼測試字符:BJXB 錯誤個數(shù):1 驗證碼實際字符:9992 驗證碼測試字符:9992 錯誤個數(shù):0 驗證碼實際字符:9LW7 驗證碼測試字符:9LW7 錯誤個數(shù):0 驗證碼實際字符:A7Y7 驗證碼測試字符:A7Y7 錯誤個數(shù):0 驗證碼實際字符:D993 驗證碼測試字符:D993 錯誤個數(shù):0 驗證碼實際字符:F549 驗證碼測試字符:F549 錯誤個數(shù):0 驗證碼實際字符:FMC6 驗證碼測試字符:FMLF 錯誤個數(shù):2 驗證碼實際字符:KXCV 驗證碼測試字符:KXCV 錯誤個數(shù):0 驗證碼實際字符:L9AC 驗證碼測試字符:E9AC 錯誤個數(shù):1 驗證碼實際字符:R4N4 驗證碼測試字符:R4N4 錯誤個數(shù):0 驗證碼實際字符:Z89V 驗證碼測試字符:Z89V 錯誤個數(shù):0 -----結(jié)果統(tǒng)計如下----- 測試驗證碼的字符數(shù)量:80 測試驗證碼的字符錯誤數(shù)量:9 單個字符識別正確率:88.75% 測試驗證碼圖的數(shù)量:20 測試驗證碼圖的錯誤數(shù)量:6 填對驗證碼的概率:70.00%結(jié)果還算是比較穩(wěn)定的,再次增加模板數(shù)量:
驗證碼實際字符:2B4E 驗證碼測試字符:2B4E 錯誤個數(shù):0 驗證碼實際字符:4572 驗證碼測試字符:4572 錯誤個數(shù):0 驗證碼實際字符:4Q33 驗證碼測試字符:4Q33 錯誤個數(shù):0 驗證碼實際字符:52CY 驗證碼測試字符:52LY 錯誤個數(shù):1 驗證碼實際字符:6S3C 驗證碼測試字符:6S3C 錯誤個數(shù):0 驗證碼實際字符:7456 驗證碼測試字符:74F5 錯誤個數(shù):2 驗證碼實際字符:775D 驗證碼測試字符:775D 錯誤個數(shù):0 驗證碼實際字符:792Z 驗證碼測試字符:792Z 錯誤個數(shù):0 驗證碼實際字符:83QG 驗證碼測試字符:83QG 錯誤個數(shù):0 驗證碼實際字符:8JXB 驗證碼測試字符:8JXB 錯誤個數(shù):0 驗證碼實際字符:9992 驗證碼測試字符:9992 錯誤個數(shù):0 驗證碼實際字符:9LW7 驗證碼測試字符:9LW7 錯誤個數(shù):0 驗證碼實際字符:A7Y7 驗證碼測試字符:A7Y7 錯誤個數(shù):0 驗證碼實際字符:D993 驗證碼測試字符:D993 錯誤個數(shù):0 驗證碼實際字符:F549 驗證碼測試字符:F549 錯誤個數(shù):0 驗證碼實際字符:FMC6 驗證碼測試字符:FMLF 錯誤個數(shù):2 驗證碼實際字符:KXCV 驗證碼測試字符:KXCV 錯誤個數(shù):0 驗證碼實際字符:L9AC 驗證碼測試字符:E9AC 錯誤個數(shù):1 驗證碼實際字符:R4N4 驗證碼測試字符:R4N4 錯誤個數(shù):0 驗證碼實際字符:Z89V 驗證碼測試字符:Z89V 錯誤個數(shù):0 -----結(jié)果統(tǒng)計如下----- 測試驗證碼的字符數(shù)量:80 測試驗證碼的字符錯誤數(shù)量:6 單個字符識別正確率:92.50% 測試驗證碼圖的數(shù)量:20 測試驗證碼圖的錯誤數(shù)量:4 填對驗證碼的概率:80.00%正確率有提升,但是也不是很明顯。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/38066.html
摘要:在本次課程中,著重講解的是傳統(tǒng)的機(jī)器學(xué)習(xí)技術(shù)及各種算法。回歸對連續(xù)型數(shù)據(jù)進(jìn)行預(yù)測趨勢預(yù)測等除了分類之外,數(shù)據(jù)挖掘技術(shù)和機(jī)器學(xué)習(xí)技術(shù)還有一個非常經(jīng)典的場景回歸。 摘要: 什么是數(shù)據(jù)挖掘?什么是機(jī)器學(xué)習(xí)?又如何進(jìn)行Python數(shù)據(jù)預(yù)處理?本文將帶領(lǐng)大家一同了解數(shù)據(jù)挖掘和機(jī)器學(xué)習(xí)技術(shù),通過淘寶商品案例進(jìn)行數(shù)據(jù)預(yù)處理實戰(zhàn),通過鳶尾花案例介紹各種分類算法。 課程主講簡介:韋瑋,企業(yè)家,資深I(lǐng)T領(lǐng)...
閱讀 2272·2021-10-09 09:41
閱讀 3430·2021-09-13 10:34
閱讀 1937·2019-08-30 12:59
閱讀 572·2019-08-29 17:27
閱讀 1073·2019-08-29 16:07
閱讀 2966·2019-08-29 13:15
閱讀 1321·2019-08-29 13:14
閱讀 1573·2019-08-26 12:18