qitong 2019-06-27
在上一篇博客Python图像处理之图片文字识别(OCR)中我们介绍了在Python中如何利用Tesseract软件来识别图片中的英文与中文,本文将具体介绍如何在Python中利用Tesseract软件来识别验证码(数字加字母)。
我们在网上浏览网页或注册账号时,会经常遇到验证码(CAPTCHA),如下图:
本文将具体介绍如何利用Python的图像处理模块pillow和OCR模块pytesseract来识别上述验证码(数字加字母)。
我们识别上述验证码的算法过程如下:
我们的图片如下(共66张图片):
完整的Python代码如下:
import os import pytesseract from PIL import Image from collections import defaultdict # tesseract.exe所在的文件路径 pytesseract.pytesseract.tesseract_cmd = 'C://Program Files (x86)/Tesseract-OCR/tesseract.exe' # 获取图片中像素点数量最多的像素 def get_threshold(image): pixel_dict = defaultdict(int) # 像素及该像素出现次数的字典 rows, cols = image.size for i in range(rows): for j in range(cols): pixel = image.getpixel((i, j)) pixel_dict[pixel] += 1 count_max = max(pixel_dict.values()) # 获取像素出现出多的次数 pixel_dict_reverse = {v:k for k,v in pixel_dict.items()} threshold = pixel_dict_reverse[count_max] # 获取出现次数最多的像素点 return threshold # 按照阈值进行二值化处理 # threshold: 像素阈值 def get_bin_table(threshold): # 获取灰度转二值的映射table table = [] for i in range(256): rate = 0.1 # 在threshold的适当范围内进行处理 if threshold*(1-rate)<= i <= threshold*(1+rate): table.append(1) else: table.append(0) return table # 去掉二值化处理后的图片中的噪声点 def cut_noise(image): rows, cols = image.size # 图片的宽度和高度 change_pos = [] # 记录噪声点位置 # 遍历图片中的每个点,除掉边缘 for i in range(1, rows-1): for j in range(1, cols-1): # pixel_set用来记录该店附近的黑色像素的数量 pixel_set = [] # 取该点的邻域为以该点为中心的九宫格 for m in range(i-1, i+2): for n in range(j-1, j+2): if image.getpixel((m, n)) != 1: # 1为白色,0位黑色 pixel_set.append(image.getpixel((m, n))) # 如果该位置的九宫内的黑色数量小于等于4,则判断为噪声 if len(pixel_set) <= 4: change_pos.append((i,j)) # 对相应位置进行像素修改,将噪声处的像素置为1(白色) for pos in change_pos: image.putpixel(pos, 1) return image # 返回修改后的图片 # 识别图片中的数字加字母 # 传入参数为图片路径,返回结果为:识别结果 def OCR_lmj(img_path): image = Image.open(img_path) # 打开图片文件 imgry = image.convert('L') # 转化为灰度图 # 获取图片中的出现次数最多的像素,即为该图片的背景 max_pixel = get_threshold(imgry) # 将图片进行二值化处理 table = get_bin_table(threshold=max_pixel) out = imgry.point(table, '1') # 去掉图片中的噪声(孤立点) out = cut_noise(out) #保存图片 # out.save('E://figures/img_gray.jpg') # 仅识别图片中的数字 #text = pytesseract.image_to_string(out, config='digits') # 识别图片中的数字和字母 text = pytesseract.image_to_string(out) # 去掉识别结果中的特殊字符 exclude_char_list = ' .:\\|\'\"?![],()~@#$%^&*_+-={};<>/¥' text = ''.join([x for x in text if x not in exclude_char_list]) #print(text) return text def main(): # 识别指定文件目录下的图片 # 图片存放目录figures dir = 'E://figures' correct_count = 0 # 图片总数 total_count = 0 # 识别正确的图片数量 # 遍历figures下的png,jpg文件 for file in os.listdir(dir): if file.endswith('.png') or file.endswith('.jpg'): # print(file) image_path = '%s/%s'%(dir,file) # 图片路径 answer = file.split('.')[0] # 图片名称,即图片中的正确文字 recognizition = OCR_lmj(image_path) # 图片识别的文字结果 print((answer, recognizition)) if recognizition == answer: # 如果识别结果正确,则total_count加1 correct_count += 1 total_count += 1 print('Total count: %d, correct: %d.'%(total_count, correct_count)) ''' # 单张图片识别 image_path = 'E://figures/code (1).jpg' OCR_lmj(image_path) ''' main()
运行结果如下:
('101659', '101659') ('111073', '111073') ('114510', '114510') ('118235', '118235') ('124677', '124677') ('147291', '147291') ('169147', '169147') ('185302', '185302') ('23YB', '23YB') ('262051', '262051') ('2HED', '2MED') ('315386', '315386') ('3D7K', '3D7K') ('3DYH', '3DYH') ('3QG8', '30G8') ('3XNR', 'EXNR') ('44G5', '44G5') ('470259', '470259') ('515413', '515413') ('522351', '522351') ('539824', '539824') ('5CVL', 'SCVL') ('642689', '642689') ('671991', '671991') ('672838', '672838') ('6F5Y', '6F5Y') ('6USB', 'GUSB') ('703167', '703167') ('765120', '765120') ('779931', '779931') ('8UEF', '8SUEF') ('905857', '905857') ('9H4H', '9H4H') ('9SK1', 'OSK1') ('BDP4', 'BDP4') ('DXV3', 'DXV3') ('E78Y', 'E78Y') ('EAHR', 'EAHR') ('F585', 'Fss§') ('FBV8', 'FBV8') ('FJKK', 'FJKK') ('GXKQ', 'GXKQ') ('H7Y9', 'H7Y9') ('J4LJ', 'J4LJ') ('J8YH', 'J8YH') ('JCDL', 'JCDL') ('JTX2', 'JTX2') ('JYLH', 'JYLH') ('KFYA', 'KFYA') ('L3VZ', 'L3VZ') ('LCGV', 'LCGV') ('LKEK', 'LKEK') ('N3FJ', 'N3FJ') ('PJZN', 'PJZN') ('PNDQ', 'PNDQ') ('Q7HP', 'Q7HP') ('QSHU', 'QSHU') ('R1RN', 'RLRN') ('RPNX', 'RPNX') ('TUKG', 'TUKG') ('U9G3', 'U9G3') ('UZAH', 'UZAH') ('V6P9', 'very') ('Y18D', '18D') ('Y237', 'Y237') ('ZZT5', '2215') Total count: 66, correct: 54.
我们可以看到图片识别的正确率为80%以上,其中数字类图片的识别正确率为100%.
我们可以在图片识别方面的算法再加改进,以提高图片识别的正确率。当然,以上算法并不是对所有验证码都适用,不同的验证码需要用不同的图片处理算法。
注意:本人现已开通两个微信公众号: 因为Python(微信号为:python_math)以及轻松学会Python爬虫(微信号为:easy_web_scrape), 欢迎大家关注哦~~