利用python進行驗證碼識別(預處理部分)
本代碼只是簡單規範的驗證碼驗證,給初學者們一些小小的啟迪。
一共這幾個部分來進行:
1 二值化圖片
2 去噪
3 去邊框
4 切割文字圖片
5 將切割的文字分別以該文字命名歸類到相同名字的文件夾中用於機器學習
第5步也可以選作用tesseract-ocr直接識別或利用百度AI識別圖片文字(如果驗證碼簡單的話)
直接上代碼:
# -*- coding: utf-8 -*-"""Created on Thu Feb 1 15:52:05 2018@author: Administrator"""from PIL import Imageimport osimport time #命名時用import string #字元串模塊import shutil #文件複製粘貼等操作模塊path=rC:UsersAdministratorDesktoppython之圖像識別2.驗證嗎識別相關pic(字母加數字加邊框)path_save=rC:UsersAdministratorDesktoppython之圖像識別2.驗證嗎識別相關歸類\path_save2=rC:UsersAdministratorDesktoppython之圖像識別2.驗證嗎識別相關cut\path_makedir=rC:UsersAdministratorDesktoppython之圖像識別2.驗證嗎識別相關分類_識別\path_copy_from=rC:UsersAdministratorDesktoppython之圖像識別2.驗證嗎識別相關歸類#import pytesseract #利用著名hp的軟體tesseract來進行簡單的規則的文字識別##上面都是導包,只需要下面這一行就能實現圖片文字識別#text=pytesseract.image_to_string(Image.open(rC:UsersAdministratorDesktoppython之圖像識別pic123.jpg),lang=eng)#print(type(text))################以下為自定義閾值的二值化函數##############def get_bin_table(threshold): #threshold為閾值 """ 獲取灰度轉二值的映射table :param threshold: :return: """ table = [] for i in range(256): if i < threshold: table.append(0) else: table.append(1) return table##########################################################################以下為去噪函數(簡單的刪除點)::9鄰域框,以當前點為中心的田字框,黑點個數##############def sum_9_region(img, x, y): #為輸入圖片,xy分別為像素坐標,故使用其時需要用循環函數來厲遍圖片里所有點 """ 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################以下為去去邊框函數############### 去除邊框def clear_border(img): w = img.width h = img.height for y_b in range(0, h): for x_b in range(0, w): if y_b < 5 or y_b > h - 5: img.putpixel((x_b,y_b),1) if x_b < 5 or x_b > w -5: img.putpixel((x_b,y_b),1) return img###################以下的函數功能為切割一個完整驗證碼的數字,並以原文件名分割的字元來命名,形式為!!!函數里套用函數!!!!!def get_whole_cut_pic(img): #ww_w=img.width #這個暫時不需要了,因為下面直接用width定義了 hh_h=img.height #為了以下避免麻煩,先定義 ################以下為智能切割圖片函數(分別從左、右、上、下(左 右 頂 底)這四個極值坐標來定義,分別是四個函數)############## def cut_get_coord_list(img_in): co_list=[] ww=img_in.width hh=img_in.height trigger1=False #用這樣的觸發事件來終止外循環,不然這哥們會一直循環下去 trigger2=False trigger3=False trigger4=False for x_c in range(ww): ##得到最左面的x值 if trigger1==False: for y_c in range(hh): if img_in.getpixel((x_c,y_c))==0: x_first=x_c co_list.append(x_first) # 左# print(x_1st is:+str(x_first)) trigger1=True break else: break for y_cf in range(hh): ##得到最上面的y值 if trigger3==False: for x_cf in range(ww): if img_in.getpixel((x_cf,y_cf))==0: y_first=y_cf co_list.append(y_first) # 頂# print(y_1st is:+str(y_first)) trigger3=True break else: break for x_cl in range(x_first,ww): #獲得最右端的x值,方法: 判斷每一行的像素值,從最左端的x開始一直到有一整列為白點(像素值為1)為止,該列的所有像素值加起來應該等於該列的長度X1(height X 1即height值) if trigger2==False: x_hang_count=0 #初始x行開始是的像素值,讓後循環相加,直至一列結束,再次重置循環 for y_cl in range(hh): x_hang_count=x_hang_count+img_in.getpixel((x_cl,y_cl)) if y_cl==hh-1 and x_hang_count==hh: x_last=x_cl co_list.append(x_last) # 右# print(x_last is:+str(x_last)) trigger2=True break else: break for y_cls in range(y_first,hh): #獲得最下端的y值, if trigger4==False: y_hang_count=0 for x_cls in range(ww): y_hang_count=y_hang_count+img_in.getpixel((x_cls,y_cls)) if x_cls==ww-1 and y_hang_count==ww: y_last=y_cls co_list.append(y_last) # 底# print(y_last is:+str(y_last)) trigger4=True break else: break return co_list ################################################## f_ex_sl=os.path.splitext(filename)#獲取文件與拓展名分離的元祖,例子:(Y4G7, .png) cut1_list=cut_get_coord_list(img) cropedIm_1 = img.crop((cut1_list[0], cut1_list[1], cut1_list[2], cut1_list[3])) #函數的添加順序是左,頂,右,底,與圖片切割的順序一樣,所以可以直接順序取值使用 cropedIm_1.save(path_save+f_ex_sl[0][0]+-+str(time.time())+.png) cropedIm_1_2=img.crop((cut1_list[2], 0,img.width, hh_h)) ##裁剪剩下的圖片,並保存# print(save 1) cropedIm_1_2.save(path_save2+f_ex_sl[0][0]+-+str(time.time())+.png) cut2_list=cut_get_coord_list(cropedIm_1_2) cropedIm_2 = cropedIm_1_2.crop((cut2_list[0], cut2_list[1], cut2_list[2], cut2_list[3])) #函數的添加順序是左,頂,右,底,與圖片切割的順序一樣,所以可以直接順序取值使用 cropedIm_2.save(path_save+f_ex_sl[0][1]+-+str(time.time())+.png) cropedIm_2_3=cropedIm_1_2.crop((cut2_list[2], 0, cropedIm_1_2.width, hh_h)) ##裁剪剩下的圖片,並保存# print(save 2) cropedIm_2_3.save(path_save2+f_ex_sl[0][1]+-+str(time.time())+.png) cut3_list=cut_get_coord_list(cropedIm_2_3) cropedIm_3 = cropedIm_2_3.crop((cut3_list[0], cut3_list[1], cut3_list[2], cut3_list[3])) #函數的添加順序是左,頂,右,底,與圖片切割的順序一樣,所以可以直接順序取值使用 cropedIm_3.save(path_save+f_ex_sl[0][2]+-+str(time.time())+.png) cropedIm_3_4=cropedIm_2_3.crop((cut3_list[2], 0,cropedIm_2_3.width, hh_h))# print(save 3) cropedIm_3_4.save(path_save2+f_ex_sl[0][2]+-+str(time.time())+.png) cut4_list=cut_get_coord_list(cropedIm_3_4) cropedIm_3 = cropedIm_3_4.crop((cut4_list[0], cut4_list[1], cut4_list[2], cut4_list[3])) #函數的添加順序是左,頂,右,底,與圖片切割的順序一樣,所以可以直接順序取值使用 cropedIm_3.save(path_save+f_ex_sl[0][3]+-+str(time.time())+.png)# print(save 4)# cropedIm_4_5=cropedIm_3_4.crop((cut3_list[2], 0, ww_w, hh_h)) #################以下為厲遍所有帶學習的驗證碼圖片,並對其預處理(二值、去噪、切割、重命名等)################# file_list=os.listdir(path)for filename in file_list: # print(j) pic = Image.open(path+\+filename)# print(path+\+filename) pic_gry = pic.convert(L) # 轉化為灰度圖 width,height = pic.size #獲取長寬信息# print(width) #print(height) #pic_gry.show() # 顯示圖像,好像是調用windows的cmd來運行 #pic_2_bit2=pic_gry.convert(1) # PIL內置命令實現二值化,可以直接將rgb轉換成二值 table_2bit = get_bin_table(180) #定義參數為閾值180,這樣橙色也可以顯示出來 pic_2_bit2 = pic_gry.point(table_2bit, 1) #定義以什麼樣的參數來賦值二值化圖片 注意這裡point()函數只支持灰度圖像的二值轉化,只支持灰度 #pic_2_bit2.save(rceshi.png) #保存圖片 for x in range(width): for y in range(height): b_pt_num=sum_9_region(pic_2_bit2, x, y) #利用去噪函數去噪 # print(b_pt_num) if b_pt_num < 2 : pic_2_bit2.putpixel((x,y),1) #賦值給像素坐標為xy 的點,值1為白色,0為黑色(因為hi二值,只有0和1) clear_border(pic_2_bit2) #去邊框函數 #pic_2_bit2.show() #pic_2_bit2.save(rjiangzao5.png) #保存圖片 get_whole_cut_pic(pic_2_bit2) #調用大函數,將所有圖片切割,並厲遍(上級函數功能) ################################################################################################# #####################以下代碼為 建立n個文件夾,分別命名從A到Z,從0到9,並把上一步生成的圖片檢測名稱,複製到對應的文件夾里##################################### sg_file=os.listdir(path_copy_from) #待複製文件夾里的所有文件list形式#print(sg_file)X_name=string.ascii_uppercase+string.digits #要新建的文件夾所有的名稱合集,利用字元串函數功能,自動生成從0到9,從A到Z的字元串,並相加組成一個大的字元串for X in X_name: if os.path.exists(path_makedir+X): #判斷是否存在文件或目錄name print(已經存在!) else: os.makedirs(path_makedir+X) #創建目錄函數,os.makedirs,即使父級目錄不存在也會創建# print(X+done!) for f_i in sg_file: if f_i[0]==X: shutil.copy(path_copy_from+\+f_i,path_makedir+X) #shutil.copy(r"path1+name1",r"path2") #賦值函數,複製path1里的name文件到path2里 ###############################################################################################################################################接下來就是要進行機器學習部分了###################################
推薦閱讀: