您好,登錄后才能下訂單哦!
這篇文章主要介紹Python如何使用KNN進行驗證碼識別,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
我們學校的驗證碼是這樣的:,其實就是簡單地把字符進行旋轉然后加上一些微弱的噪點形成的。我們要識別,就得逆行之,具體思路就是,首先二值化去掉噪點,然后把單個字符分割出來,最后旋轉至標準方向,然后從這些處理好的圖片中選出模板,最后每次新來一張驗證碼就按相同方式處理,然后和這些模板進行比較,選擇判別距離最近的一個模板作為其判斷結果(亦即KNN的思想,本文取K=1)。接下來按步驟進行說明。
首先得有大量的驗證碼,我們通過爬蟲來實現,代碼如下
#-*- coding:UTF-8 -*- import urllib,urllib2,cookielib,string,Image def getchk(number): #創建cookie對象 cookie = cookielib.LWPCookieJar() cookieSupport= urllib2.HTTPCookieProcessor(cookie) opener = urllib2.build_opener(cookieSupport, urllib2.HTTPHandler) urllib2.install_opener(opener) #首次與教務系統鏈接獲得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豐富的圖像處理函數能給我們省下很多時間,,我們遍歷source文件夾,對每一張驗證碼圖片進行二值化處理,把處理過的圖片存入bw目錄下。代碼如下
mydir='./source/'; bw = './bw/'; if mydir(end)~='\' mydir=[mydir,'\']; end DIRS=dir([mydir,'*.jpg']); %擴展名 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
處理結果如圖:
mydir='./bw/'; letter = './letter/'; if mydir(end)~='\' mydir=[mydir,'\']; end DIRS=dir([mydir,'*.jpg']); %擴展名 n=length(DIRS); for i=1:n if ~DIRS(i).isdir img = imread(strcat(mydir,DIRS(i).name )); img = im2bw(img);%二值化 img = 1-img;%顏色反轉讓字符成為聯通域,方便去除噪點 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
處理結果如圖:
接下來進行旋轉,哪找一個什么標準呢?據觀察,這些字符旋轉不超過60度,那么在正負60度之間,統一旋轉至字符寬度最小就行了。代碼如下
if mydir(end)~='\' mydir=[mydir,'\']; end DIRS=dir([mydir,'*.jpg']); %擴展名 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<minwidth minwidth = width; imgrr = imgr; end end name = strcat(rotate,DIRS(i).name) imwrite(imgrr,name); end end
處理結果如圖,一共2000個字符的圖片存在rotate文件夾中
現在從rotate文件夾中選取一套模板,涵蓋每一個字符,一個字符可以選取多個圖片,因為即使有前面的諸多處理也不能保證一個字符的最終呈現形式只有一種,多選幾個才能保證覆蓋率。把選出來的模板圖片存入samples文件夾下,這個過程很耗時耗力。可以找同學幫忙~,如圖
測試代碼如下:首先對測試驗證碼進行上述操作,然后和選出來的模板進行比較,采用差分值最小的模板作為測試樣本的字符選擇,代碼如下
% 具有差分最小值的圖作為答案
mydir='./test/'; samples = './samples/'; if mydir(end)~='\' mydir=[mydir,'\']; end if samples(end)~='\' samples=[samples,'\']; end DIRS=dir([mydir,'*.jpg']); %擴展? DIRS1=dir([samples,'*.jpg']); %擴展名 n=length(DIRS);%驗證碼總圖數 singleerror = 0;%單個錯誤 uniterror = 0;%一張驗證碼錯誤個數 for i=1:n if ~DIRS(i).isdir realcodes = DIRS(i).name(1:4); fprintf('驗證碼實際字符:%s\n',realcodes); img = imread(strcat(mydir,DIRS(i).name )); img = rgb2gray(img); img = im2bw(img); img = 1-img;%顏色反轉讓字符成為聯通域 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 width<minwidth minwidth = width; imgrr = imgr; end end mindiffv = 1000000; for jj = 1:length(DIRS1) imgsample = imread(strcat(samples,DIRS1(jj).name )); imgsample = im2bw(imgsample); diffv = abs(imgsample-imgrr); alldiffv = sum(sum(diffv)); if alldiffv<mindiffv mindiffv = alldiffv; code = DIRS1(jj).name; code = code(1); end end codes = [codes,code]; end fprintf('驗證碼測試字符:%s\n',codes); num = codes-realcodes; num = length(find(num~=0)); singleerror = singleerror + num; if num>0 uniterror = uniterror +1; end fprintf('錯誤個數:%d\n',num); end end fprintf('\n-----結果統計如下-----\n\n'); fprintf('測試驗證碼的字符數量:%d\n',n*4); fprintf('測試驗證碼的字符錯誤數量:%d\n',singleerror); fprintf('單個字符識別正確率:%.2f%%\n',(1-singleerror/(n*4))*100); fprintf('測試驗證碼圖的數量:%d\n',n); fprintf('測試驗證碼圖的錯誤數量:%d\n',uniterror); fprintf('填對驗證碼的概率:%.2f%%\n',(1-uniterror/n)*100);
結果:
驗證碼實際字符:2B4E
驗證碼測試字符:2B4F
錯誤個數:1
驗證碼實際字符:4572
驗證碼測試字符:4572
錯誤個數:0
驗證碼實際字符:52CY
驗證碼測試字符:52LY
錯誤個數:1
驗證碼實際字符:83QG
驗證碼測試字符:85QG
錯誤個數:1
驗證碼實際字符:9992
驗證碼測試字符:9992
錯誤個數:0
驗證碼實際字符:A7Y7
驗證碼測試字符:A7Y7
錯誤個數:0
驗證碼實際字符:D993
驗證碼測試字符:D995
錯誤個數:1
驗證碼實際字符:F549
驗證碼測試字符:F5A9
錯誤個數:1
驗證碼實際字符:FMC6
驗證碼測試字符:FMLF
錯誤個數:2
驗證碼實際字符:R4N4
驗證碼測試字符:R4N4
錯誤個數:0
-----結果統計如下-----
測試驗證碼的字符數量:40
測試驗證碼的字符錯誤數量:7
單個字符識別正確率:82.50%
測試驗證碼圖的數量:10
測試驗證碼圖的錯誤數量:6
填對驗證碼的概率:40.00%
可見單個字符準確率是比較高的的了,但是綜合準確率還是不行,觀察結果至,錯誤的字符就是那些易混淆字符,比如E和F,C和L,5和3,4和A等,所以我們能做的事就是增加模板中的樣本數量,以期盡量減少混淆。
增加了幾十個樣本過后再次試驗,結果:
驗證碼實際字符:2B4E
驗證碼測試字符:2B4F
錯誤個數:1
驗證碼實際字符:4572
驗證碼測試字符:4572
錯誤個數:0
驗證碼實際字符:52CY
驗證碼測試字符:52LY
錯誤個數:1
驗證碼實際字符:83QG
驗證碼測試字符:83QG
錯誤個數:0
驗證碼實際字符:9992
驗證碼測試字符:9992
錯誤個數:0
驗證碼實際字符:A7Y7
驗證碼測試字符:A7Y7
錯誤個數:0
驗證碼實際字符:D993
驗證碼測試字符:D993
錯誤個數:0
驗證碼實際字符:F549
驗證碼測試字符:F5A9
錯誤個數:1
驗證碼實際字符:FMC6
驗證碼測試字符:FMLF
錯誤個數:2
驗證碼實際字符:R4N4
驗證碼測試字符:R4N4
錯誤個數:0
-----結果統計如下-----
測試驗證碼的字符數量:40
測試驗證碼的字符錯誤數量:5
單個字符識別正確率:87.50%
測試驗證碼圖的數量:10
測試驗證碼圖的錯誤數量:4
填對驗證碼的概率:60.00%
可見無論是單個字符識別正確率還是整個驗證碼正確的概率都有了提升。能夠預見:隨著模板數量的增多,正確率會不斷地提高。
以上是“Python如何使用KNN進行驗證碼識別”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。