目录

图像读取主要用了两个库,不同的库是不同的对象:

本次图像识别测试需要以下两个条件:

1. 验证码获取

2. 登录网站

3. 图像处理

4. 验证码识别测试

测试说明

测试代码

测试结果

5. 成功示例的再识别测试

测试说明

测试代码

测试结果

测试注意事项

6. 集成融合投票模型,并使用多进程机制运行程序

测试说明

测试代码

测试结果

单进程运行程序的结果

并行运行程序时的效果及结果​

7. 失败示例的再识别

8. 其他

图像读取主要用了两个库,不同的库是不同的对象:

# plt.imread和PIL.Image.open读入的都是RGB顺序
from PIL import Image
img = Image.open('xxxx.png')  # 读取Image对象
img.save('xxx.png')
'''
print(img.mode)  # 有'1', 'L', 'P', 'RGB', 'RGBA'等
'1': 表示黑白模式照片
'L': 表示灰度模式照片
'RGB': 表示RGB通道模式的彩色照片
'RGBA': 表示RGB通道及Alpha通道的照片
'''
img.show() # 显示图片
img.convert('L')  # 转换为'L'模式
img.crop((20,30,300,200))  # 裁剪
# Image.eval(img, function)  # 对每个像素/通道进行函数处理import cv2
# opencv中cv2.imread读入的是BGR通道顺序
# flags=0是灰度模式,flags=1是默认的彩色模式
# im = cv2.imread('xxxx.png', flags=0) # 读取图像array对象、
im = cv2.imread("imgCode_grey200.jpg", flags=cv2.IMREAD_GRAYSCALE)
cv2.imwrite('imgCode_grey200.jpg', im)
plt.imshow(im) # 显示图片
# plt.show()
# plt.close()
# cv2.imshow('im', im)  # 显示图片## PIL.Image.open和cv2.imread的比较与相互转换的方法
# 当图片是png格式,读取结果是一致的;
# 当图片是jpg格式时,读取结果是不一致的。
# 这可能是因为Image.open 与 cv2.imread 在解码jpg时运算有差异。 # 简单转换
# im = np.array(img, np.uint8)  # copy=True
# im = np.asarray(img, np.uint8)  # copy=False# 不设置dtype为数值的话,得到的可能是布尔值的数组,比如二值化后的图片
im = np.asarray(img)
# img = Image.fromarray(np.uint8(im))
img = Image.fromarray(im)# 标准转换
def PILImageToCV(imagePath):# PIL Image转换成OpenCV格式img = Image.open(imagePath)plt.imshow(img)img = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)plt.imshow(img)plt.show()def CVImageToPIL(imagePath):# OpenCV图片转换为PIL imageimg = cv2.imread(imagePath)plt.imshow(img)img2 = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))plt.imshow(img2)plt.show()

本次图像识别测试需要以下两个条件:

OCR软件:tesseract.exe,通过命令行调用来识别字符。

OCR软件的Python接口:pytesseract,内核是OCR软件tesseract

OCR:Optical Character Recognition (光学字符识别)

备注:另外的一个接口PyOCR,内核可包括tesseract或其他,但也得提前安装OCR软件。

import pytesseractdef get_result_by_imgCode_recognition(img):# 进行验证码识别result = pytesseract.image_to_string(img)  # 接口默认返回的是字符串# ''.join(result.split())  # 去掉全部空格和\n\t等result = ''.join(list(filter(str.isalnum, result)))  # 只保留字母和数字return resultdef pass_counter(img, img_value):# 辨别是否识别正确rst = get_result_by_imgCode_recognition(img)if rst == img_value:return 1else:return 0def most_frequent(lst):# 获取列表最频繁的元素,可用于集成投票获得识别结果# return max(lst, key=lst.count)return max(set(lst), key=lst.count)

1. 验证码获取

通过浏览器的开发者工具,发现验证码图片为base64编码的文件,通过解码后写入文件。

def fetch_imgCode():# 获取验证码url_imgCode = 'xxxx'html = requests.post(url_imgCode)'''print(f'imgCode rsp: {html.text}')imgCode rsp: {"data": {"image_buf_str": "/9j/4AAQ....KAP/9k=","image_code": "16501881494161"},"error_code": 0, "msg": {"en-us": "Success", "zh-CN": "\u6210\u529f"},"request": "POST /public/verificationCode/imgCode"}'''html = html.json()image_buf_str = html['data']['image_buf_str']image_code = html['data']['image_code']# 保存base64编码的图片为图片文件with open(f'./imgCode_png_raw/imgCode_{image_code}.png', 'wb') as f:f.write(base64.b64decode(image_buf_str))return image_code

2. 登录网站

通过向网站发起post请求,可登录网站,一般情况下:

输入image_code对应的正确的验证码的值image_value,即可登录成功。

反过来,如果登录成功,也意味着我们识别出来的验证码值image_value是正确。


HEADERS_PORTAL = {'User-Agent': 'xxxx',"Content-Type": "application/json",
}
def login(image_code, image_value):login_flag = Falseurl_login = 'xxxx'data_login = {"account": "DEMO_Tong","password": "9xdsaGcy","image_code": image_code,"captcha": image_value,"nickname": "DEMO_Tong", "client_type": 100}html = requests.post(url_login, data=json.dumps(data_login), headers=HEADERS_PORTAL)# print(f'login info: {html.text}')html = html.json()if html.get('data'):if html.get('data').get('token'):login_flag = Truereturn login_flag

3. 图像处理

灰度处理、二值处理、去噪、膨胀及腐蚀、倾斜矫正、字符切割、归一化等

# 灰度处理和二值处理
# lookup_table = [0 if i < 200 else 1 for i in range(256)]
def gray_processing(img, threshold = 127):# 转为灰度模式img = img.convert('L')# 转为二值模式,阈值默认是 127,大于为白色,否则黑色。# 为什么127呢,256/2=128, 2^8=256, 一个字节byte是8个比特bit# image.convert('1')  # 即 threshold = 127 # threshold = 125lookup_table = [0 if i < threshold else 1 for i in range(256)]img = img.point(lookup_table, '1')return img# 膨胀腐蚀法def erode_dilate(im, threshold=2):# im = cv2.imread('xxx.jpg', 0)# cv2.imshow('xxx.jpg', im)# (threshold, threshold) 腐蚀矩阵大小kernel = np.ones((threshold, threshold), np.uint8)# 膨胀erosion = cv2.erode(im, kernel, iterations=1)# cv2.imwrite('imgCode_erosion.jpg', erosion)# Image.open('imgCode_erosion.jpg').show()# # 腐蚀# eroded = cv2.dilate(erosion, kernel, iterations=1)# cv2.imwrite('imgCode_eroded.jpg', eroded)# Image.open('imgCode_eroded.jpg').show()return erosion

4.验证码识别测试

测试说明

根据不同的图像处理方式,进行验证码识别测试,积累成功识别示例的同时,观察不同处理方式的识别效果。测试中获取的验证码具有随机性,有容易识别的,也有不容易识别的,但客观上属于同一难度的验证码。

本次识别测试将分为3组,每次识别10000张,通过模拟登录网站来验证是否识别正确。

第一组直接识别原图片文件,标签为“raw”

第二组识别灰度处理和阈值为200的二值处理后的图片对象,标签为“gray”

第三组识别经灰度、二值和膨胀处理后的图片对象,标签为“erosion”

识别的结果根据图像处理方式和识别正确与否,放在不同文件夹,识别结果也追加到文件名:

imgCode_png_raw:存放从网站保存下来的原始图片

imgCode_png_raw_pass:存放raw测试识别正确的原始图片

imgCode_png_raw_fail:存放raw测试识别失败的原始图片

imgCode_png_raw_gray_pass:存放gray测试识别正确的原始图片

imgCode_png_raw_gray_fail:存放gray测试识别失败的已处理后的图片

imgCode_png_raw_gray_erosion_pass:存放erosion测试识别正确的原始图片

imgCode_png_raw_gray_erosion_fail:存放erosion测试识别失败的已处理后的图片

注意:通过浏览器的开发工具可以发现,验证码使用的字体应该是 element-icons.535877f5.woff

测试代码

from tqdm import tqdm, trange
from tqdm.contrib import tzip # tqdm是进度条模块,为了便于观察处理进度
TEST_TOTAL = 10000  # 测试数量1万张def test_raw():print('raw: ')pass_count = 0# for _ in range(TEST_TOTAL):for _ in trange(TEST_TOTAL):try:image_code = fetch_imgCode()img = Image.open(f'./imgCode_png_raw/imgCode_{image_code}.png')result = get_result_by_imgCode_recognition(img)login_flag = login(image_code, result)if login_flag:img.save(f'./imgCode_png_raw_pass/imgCode_{image_code}_{result}.png')pass_count += 1else:img.save(f'./imgCode_png_raw_fail/imgCode_{image_code}_{result}.png')except:info = sys.exc_info()print(info)print(f'pass_rate: {pass_count/TEST_TOTAL*100}')def test_gray():print('gray: ')pass_count = 0for _ in trange(TEST_TOTAL):try:image_code = fetch_imgCode()img = Image.open(f'./imgCode_png_raw/imgCode_{image_code}.png')img_gray = gray_processing(img, threshold=200)result = get_result_by_imgCode_recognition(img_gray)login_flag = login(image_code, result)if login_flag:img.save(f'./imgCode_png_raw_gray_pass/imgCode_{image_code}_{result}.png')pass_count += 1else:img_gray.save(f'./imgCode_png_raw_gray_fail/imgCode_{image_code}_{result}.png')except:info = sys.exc_info()print(info)print(f'pass_rate: {pass_count/TEST_TOTAL*100}')def test_erosion():print('erosion: ')pass_count = 0for _ in trange(TEST_TOTAL):try:image_code = fetch_imgCode()img = Image.open(f'./imgCode_png_raw/imgCode_{image_code}.png')img_gray = gray_processing(img, threshold=200)im = np.asarray(img_gray, np.uint8)  # gray之后变成array,值变为0和1,有效去噪点erosion = erode_dilate(im, threshold=2)img1 = Image.fromarray(erosion*255)  # 值为0到1,整个图片都是黑色的。result = get_result_by_imgCode_recognition(img1) # 这里用array也可以login_flag = login(image_code, result)if login_flag:img.save(f'./imgCode_png_raw_gray_erosion_pass/imgCode_{image_code}_{result}.png')pass_count += 1else:img1.save(f'./imgCode_png_raw_gray_erosion_fail/imgCode_{image_code}_{result}.png')except:info = sys.exc_info()print(info)print(f'pass_rate: {pass_count/TEST_TOTAL*100}')

测试结果

5. 成功示例的再识别测试

测试说明

将通过raw、gray、erosion识别测试正确的示例按照1:1:1的样本比例拷贝到imgCode_pass文件夹,此时的验证码样本都是有正确识别结果的,且数量一定和样本比例均衡,可以用三种处理方式进行再识别,比较三种处理方式的识别效果。

此次再识别测试的样本比例1:1:1,各8844张,共26532张。

测试代码


def test_pass_raw():pass_list = os.listdir('./imgCode_pass')pass_value_list = [img_file[-8:-4] for img_file in pass_list]pass_cnt1 = 0pass_amt = len(pass_list)print(f'pass_amt: {pass_amt}')# for img_file, img_value in zip(pass_list, pass_value_list):for img_file, img_value in tzip(pass_list, pass_value_list):# rawimg = Image.open(f'./imgCode_pass/{img_file}')pass_cnt1 += pass_counter(img, img_value)print(f'raw: \npass_rate:{pass_cnt1 / pass_amt * 100}')def test_pass_gray():pass_list = os.listdir('./imgCode_pass')pass_value_list = [img_file[-8:-4] for img_file in pass_list]pass_cnt2 = 0pass_amt = len(pass_list)print(f'pass_amt: {pass_amt}')# for img_file, img_value in zip(pass_list, pass_value_list):for img_file, img_value in tzip(pass_list, pass_value_list):# rawimg = Image.open(f'./imgCode_pass/{img_file}')# raw + grey200img = gray_processing(img, threshold=200)pass_cnt2 += pass_counter(img, img_value)print(f'raw + grey200: \npass_rate:{pass_cnt2/pass_amt*100}')def test_pass_erosion():pass_list = os.listdir('./imgCode_pass')pass_value_list = [img_file[-8:-4] for img_file in pass_list]pass_cnt3 = 0pass_amt = len(pass_list)print(f'pass_amt: {pass_amt}')# for img_file, img_value in zip(pass_list, pass_value_list):for img_file, img_value in tzip(pass_list, pass_value_list):# rawimg = Image.open(f'./imgCode_pass/{img_file}')# raw + grey200img = gray_processing(img, threshold=200)# raw + grey200 + erosionim = np.asarray(img, np.uint8)  # gray之后变成array,值变为0和1,有效去噪点erosion = erode_dilate(im, threshold=2)img1 = Image.fromarray(erosion*255)  # 值为0到1,整个图片都是黑色的。pass_cnt3 += pass_counter(img1, img_value)print(f'raw + grey200 + erosion(Image): \npass_rate:{pass_cnt3/pass_amt*100}')

测试结果

测试注意事项

此次测试特别需要注意样本比例,如果样本全为通过raw识别测试正确的来进行再识别,使用raw方式将为100%识别正确。下图是使用大部分为raw识别成功的示例来进行再识别的结果,发现不同处理方式的识别模型的识别能力呈下降趋势,越接近raw识别模型的模型精度越好,反正越差。

6. 集成融合投票模型,并使用多进程机制运行程序

测试说明

基于不同的模型的识别效果不一,考虑集成学习的模型融合,使用投票法,通过raw、gray、erosion三种模型进行识别预测投票,将票数多的识别结果作为集成融合投票模型的识别结果,来进行登录验证。

基于集成融合投票模型需要对同一张验证码示例进行3次识别,比较耗时,故使用多进程机制并行地运行程序,减少程序所消耗的时间。

测试代码

def test_ensemble_vote(kwargs):result_list = []image_code = fetch_imgCode()img = Image.open(f'./imgCode_png_raw/imgCode_{image_code}.png')result_list.append(get_result_by_imgCode_recognition(img))img_gray = gray_processing(img, threshold=200)result_list.append(get_result_by_imgCode_recognition(img_gray))im = np.asarray(img_gray, np.uint8)  # gray之后变成array,值变为0和1,有效去噪点erosion = erode_dilate(im, threshold=2)img1 = Image.fromarray(erosion*255)  # 值为0到1,整个图片都是黑色的。result_list.append(get_result_by_imgCode_recognition(img1))result = max(result_list, key=result_list.count)login_flag = login(image_code, result)return login_flagdef test_ensemble_vote_multi():print('test_ensemble_vote_multi: ')from multiprocessing import Poolpool = Pool()pool_result_list = pool.map(test_ensemble_vote, trange(TEST_TOTAL))pool.close()pool.terminate()pool.join()pass_count = pool_result_list.count(True)print(f'pass_rate: {pass_count/TEST_TOTAL*100}')

测试结果

单进程运行程序的结果

 并行运行程序时的效果及结果

7. 失败示例的再识别

使用不同二值化阈值识别的融合投票模型对元模型(raw、gray或erosion)识别失败的例子进行再识别。


def test_fail():## 单独一张图片,不同的二值化阈值,最频繁预测结果# img = Image.open(f'./imgCode_fail/imgCode_16501101286728_359.png')# img.show()# result_list = []# for i in trange(120,200,1):#     img_gray = gray_processing(img, threshold=i)#     img_gray.show()#     result = get_result_by_imgCode_recognition(img_gray)#     result_list.append(result)# print(f'most_frequent(lst): {most_frequent(result_list)}')## 多张图片,不同灰度阈值,最频繁预测结果,目的是寻找最佳阈值fail_list = os.listdir('./imgCode_fail')result_list_1 = []for img_file in fail_list:img = Image.open(f'./imgCode_fail/{img_file}')result_list_2 = []for i in trange(120,200,10):img_gray = gray_processing(img, threshold=i)result = get_result_by_imgCode_recognition(img_gray)result_list_2.append(result)result_list_1.append(result_list_2)for img_file, lst in zip(fail_list, result_list_1):print(f'{img_file}, most_frequent(lst): {most_frequent(lst)}')

8.其他

Python使用pytesseract进行验证码图像识别相关推荐

  1. Python使用百度OCR接口进行验证码图像识别

    上次从pytesseract软件及其python库入门了OCR的图像识别, 包括图像的读取.格式转换和图像处理,也进行了验证码的识别实验,包括验证码获取.登录验证以及不同图像处理的识别效果测试,具体内 ...

  2. Python - WebDriver 识别登录验证码

    Python - WebDriver 识别登录验证码 没什么可说的直接上代码! #-*-coding:utf-8-*- # Time:2017/9/29 7:16 # Author:YangYangJ ...

  3. 【Python爬虫7】验证码处理

    文章目录 1.获得验证码图片 2.光学字符识别验证码 3.用API处理复杂验证码 3.1 9kw打码平台 3.1.1 提交验证码 3.1.2 请求已提交验证码结果 3.1.2与注册功能集成 验证码(C ...

  4. 用Python爬虫破解滑动验证码

    我们可以借用opencv来解决这个问题,主要步骤: opencv 是什么? OpenCV(Open Source Computer Vision Library)是开放源代码计算机视觉库,主要算法涉及 ...

  5. Python OpenCV 图片滑块验证码 滑块图片验证码 快速自动识别方案 代码简单 模板匹配识别 识别成功率达90%+

    前言 通过上一篇的文章大家已经对图片滑块验证码已经有了初步的了解,图片滑块验证码的核心关键在于图片识别接下来接入讲解.因为初版滑块图片识别虽然能识别验证码,通过一些策略调整也相对提高了一些图片识别率, ...

  6. python发送短信验证码登录_python发送短信验证码

    原标题:python发送短信验证码 业务: 手机端点击发送验证码,请求发送到python端,由python调用榛子云短信http://smsow.zhenzikj.com的短信接口,生成验证码并发送. ...

  7. 通过Python的pytesseract库识别图片中的文字

    文章目录 前言 一.pytesseract 1.pytesseract是什么? 2.安装pytesseract 3.查看pytesseract版本 4.安装PIL 5.查看PIL版本 二.Tesser ...

  8. 实战 | 手把手教你用Python+OpenCV实现滑块验证码->自动拖动验证

    导读 本文主要介绍如何使用Python+OpenCV实现滑块验证码->自动拖动验证. 背景介绍 前几天在某网站下载代码时,跳转到滑块验证码界面,需要验证OK后才能下载,貌似这种验证方式现在很流行 ...

  9. python 训练识别验证码_用Python机器学习搞定验证码

    原标题:用Python机器学习搞定验证码 写爬虫有一个绕不过去的问题就是验证码,现在验证码分类大概有4种: 图像类 滑动类 点击类 语音类 今天先来看看图像类,这类验证码大多是数字.字母的组合,国内也 ...

  10. pytesseract识别验证码

    pytesseract识别验证码 0.下载 https://tesseract-ocr.github.io/tessdoc/Installation.html ` 1.安装 选择添加Math 和Chi ...

最新文章

  1. vs发生生成错误_S7报告系统错误:
  2. django-vue-admin脚手架快速开发CRUD教程
  3. CRM客户主数据UI上有哪些字段可以触发partner determination
  4. Spring boot入门(三):集成AdminLTE(Freemarker),结合generate代码生成器,利用DataTable和PageHelper分页...
  5. va_start和va_end的使用及原理
  6. BZOJ 1492 货币兑换Cash
  7. 集群间动态扩展和删除hdfs的datanode和hbase的regionserver
  8. 2016年linux认证,2016年Linux认证考试要点
  9. 线性规划问题的求解——Excel和python编程
  10. linux 使用秘钥认证,linux 密钥验证登录
  11. linux 鼠标光标由箭头变成十字形恢复方法
  12. WinDynamicDesktop下载慢解决方法
  13. Python3 插入排序
  14. 带有神经网络的梯度消失(Vanishing gradients with RNNs)
  15. 建站过程中,网站优化的雷区
  16. java 操作 hbase_Java操作Hbase的基本操作
  17. 说一下“==“和equals方法究竟有什么区别?
  18. 数学建模 matlab 数据建模基础
  19. Android 之路51---百度地图实现
  20. 华为手机word插件加载失败_华为手机里用其他应用打开Word文档打不开怎么办?...

热门文章

  1. 什么叫做:离线下载?-by:nixs
  2. 为什么 iPhone 的原装充电线容易坏?
  3. 苹果测试网速软件,Mac 网速测试工具 SpeedTest by Ookla
  4. YUI Compressor 进行js/css文件混淆压缩
  5. 手机兼容性测试(云测试)
  6. windows系统迁移,C盘搬家
  7. UNIX环境高级编程——第十章信号
  8. DevExpress控件之主题
  9. 计算机打字速录,速录员打字口诀有哪些
  10. 微信小程序全国城市搜索(可进行城市中文拼音首字母搜索)