当前位置:首页 > 默认分类 > 正文内容

python实现对简单的运算型验证码的识别【不使用OpenCV】

virtualman3年前 (2022-06-09)默认分类3293

最近在写我们学校的教务系统的手机版,在前端用户执行绑定操作后,服务器将执行登录,但在登录过程中,教务系统中有个运算型的验证码,大致是这个样子的: image image

下面我们开始实现这个验证码的识别。

1、图片读取

从网站上下载大量同类型的验证码,人工标记上每个验证码的识别结果

2、图片灰度化、二值化

灰度化,在RGB模型中,如果R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫灰度值,因此,灰度图像每个像素只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为0-255。
通过PIL中的算法即可快速实现灰度化:
img=img.convert("L")
这样我们就得到了R=G=B的代码
接下来我们要进行二值化,二值化的目的就是把文字和背景部分严格区分开。可以通过尝试的方法,找到一个阈值,然后将RGB大于阈值的置为1,否则置为0。

3、降噪

本次实践并没有用到,因为验证码比较简单,并没有用到此步骤

4、分割

我们根据验证码本身,通过分割割除每一块数字、符号的图片

5、获取样本并计算特征值

接下来我们有了各个数字图片的样本。

如何和新来的图片进行匹配?

我们要通过计算黑色像素点/总像素点的值然后对所有图片都如此操作,分别取 分割出来的6份中第一份的平均值,这样的到了能代表0这个图片的6份数值存起来后面用。

6、识别图片

将计算好的 6个值与我们之前给0-9计算的这个值分别进行比较 找出和0-9最相似的数字 这个数字就是我们想要的结果
完整代码:

  • import base64
  • import json
  • import os
  • import random
  • import string
  • from PIL import Image, ImageDraw
  • import requests
  • import ssl
  • def getimg(filename):
  •     url = "【验证码获取网址已删除】"
  •     r = requests.get(url, verify=False)
  •     # print(r.text)
  •     res = json.loads(r.text)
  •     print(res)
  •     # print(res['content'])
  •     f = open(filename, 'wb')
  •     # 获取动漫头像
  •     anime = res['content'].split(',')[1]
  •     # print(anime)
  •     # 对返回的头像进行解码
  •     anime = base64.b64decode(anime)
  •     # 将头像写入文件当中
  •     f.write(anime)
  •     f.close()
  • def get_block_score(img):
  •     sum = 0
  •     black = 0
  •     for i in range(img.size[0]):
  •         for j in range(img.size[1]):
  •             if img.getpixel((i, j)) == 0:
  •                 black += 1
  •             sum += 1
  •     return black, sum
  • #  计算特征值
  • def get_features_vaule_by_img(img):
  •     wide = img.size[0]
  •     one_wide = int(wide / 2)
  •     high = img.size[1]
  •     one_high = int(high / 3)
  •     score_lsit = []
  •     for i in range(3):
  •         for j in range(2):
  •             img_one = img.crop((j * one_wide, i * one_high, (j + 1) * one_wide, (i + 1) * one_high))
  •             black, sum = get_block_score(img_one)
  •             score_lsit.append(black * 1.0 / sum)
  •     return  score_lsit
  • def ez_map(thresold):
  •     res = []
  •     for i in range(256):
  •         if i < thresold:
  •             res.append(0)
  •         else:
  •             res.append(1)
  •     return res
  • def pre_hd_ez(img):
  •     img = img.convert("L")
  •     # 二值
  •     thresold = 140
  •     table = ez_map(thresold)
  •     # img=img.convert("1")
  •     img = img.point(table, '1')
  •     return img
  • def pre_split_img(img):
  •     imgs = []
  •     num1 = (20,6,31,21)
  •     fuhao = (36,6,50,21)
  •     num2 = (51,6,62,21)
  •     img_num1 = img.crop(num1)
  •     img_fuhao = img.crop(fuhao)
  •     img_num2 = img.crop(num2)
  •     imgs.append(img_num1)
  •     imgs.append(img_fuhao)
  •     imgs.append(img_num2)
  •     return imgs
  • filename =""
  • def Base64ToImage(_base64):
  •     str = random.sample(string.ascii_letters + string.digits, 16)
  •     global filename
  •     filename = ''.join(str) +'.jpg'
  •     f = open(filename, 'wb')
  •     # 获取动漫头像
  •     anime = _base64.split(',')[1]
  •     # 对返回的头像进行解码
  •     anime = base64.b64decode(anime)
  •     # 将头像写入文件当中
  •     f.write(anime)
  •     f.close()
  •     img = Image.open(filename)
  •     return img
  • fuhao = [ [0.085714285714285720.085714285714285720.428571428571428550.428571428571428550.114285714285714280.11428571428571428],[0.28571428571428570.00.28571428571428570.00.00.0]]
  • nums1=[
  • [0.360.440.40.40.360.44],
  • [0.240.320.00.40.240.56],
  • [0.320.40.040.40.480.32],
  • [0.320.480.160.640.320.48],
  • [0.040.480.360.520.160.44],
  • [0.40.240.280.480.320.4],
  • [0.360.320.560.480.360.48],
  • [0.320.480.040.440.240.12],
  • [0.40.480.560.640.40.48],
  • [0.40.440.40.640.240.44]
  • ]
  • nums2=[
  • [0.440.360.40.40.440.36],
  • [0.40.160.20.20.40.4],
  • [0.40.320.120.320.560.24],
  • [0.40.40.240.560.40.4],
  • [0.120.40.40.520.20.44],
  • [0.480.160.360.40.40.32],
  • [0.440.240.640.40.440.4],
  • [0.40.40.20.280.360.0],
  • [0.480.40.640.560.480.4],
  • [0.480.360.480.560.320.36]
  • ]
  • #getimg('result.jpg')  # 获取图片
  • # 先预处理、二值化
  • def Recognition(_base64):
  •     img = Base64ToImage(_base64)
  •     img = pre_hd_ez(img)  # 二值化
  •     imgs = pre_split_img(img)  # 分隔
  •     global filename
  •     os.remove(filename)
  •     code_num1 = get_features_vaule_by_img(imgs[0])  # 计算特征值
  •     code_fuhao = get_features_vaule_by_img(imgs[1])  # 计算特征值
  •     code_num2 = get_features_vaule_by_img(imgs[2])  # 计算特征值
  •     # print('code1:'+str( code_num1), 'code2:'+str(code_num2))
  •     a = 0
  •     b = 0
  •     for index in range(010):
  •         if (code_num1 == nums1[index]):
  •             # print(index)
  •             a = index
  •             break
  •     for index in range(010):
  •         if (code_num2 == nums2[index]):
  •             # print(index)
  •             b = index
  •             break
  •     if code_fuhao == fuhao[0]:
  •         print(str(a) + '+' + str(b) + '=' + str(a + b))
  •         return a+b
  •     elif code_fuhao == fuhao[1]:
  •         print(str(a) + '*' + str(b) + '=' + str(a * b))
  •         return a * b
  •     else:
  •         print('符号识别Error')
  • Recognition("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAZCAIAAABIPBwcAAACYUlEQVR42uWYPUp2QQyFsxgbO7Hy\nawUXIIKNq7CwcD8uQlyJG3APll64EEJ+Tk5mhK8QUtx33vl95kwmE/n6/P6z9v72cRj/r/yXebia\nZOHC6Ok08L+umjVZWB5TmZxHWjPOcplX1QnfeQ7rd3lV/8YFgM3HS2KGiDp1g46WXMLa1A55BLC4\nsATacgblCqzYshXqJqwKHICFewPiJXXdUhM8AHMKdo5J1Um1baAao0dy80pY7RnGu3R8XNzdO5u6\nLbDnh70+3KilrTDidNlPV9dqM1ikN03XHEkpr/YIH3b77+Uw4E0sqZTXSCZnoSWlxvCS5UtaYbkx\nlBdzXVawHClbQt7CGJYdxeoLuzABXnYay2j5DqyoqVHYxfgg11uEVeGW9saZBn7Oc23C4m/6x+dL\nbNXkV2AtiEvrVz6+vSJTWOe3wiId1hSW9fT4zkFBaXv97cA66WA7a0bX3vLC8S1JCoQmwoe/ZOiI\neS3ASv09HwlXy9FLEMQDJay0DY5Rq64BLNdE6UQ3YUlp87Tw/Dk9hk5WrSD6Y0jySsXFbL6V0hSW\nm0MLy4lrBRbAgR9uKiKHtY1LSVjxQtRjWMXu+B3C57+q5Uvlp/ALMYagzpj0SzyGqbicVUmY0SvP\n+iwAyw0kC5kNVyElReYqLaw0ho6kgOtkTpN+jGCh23CUeBw9jJnXP/ahbVoCvLGZVM8YFgMFzxVL\nmszkgYQns0LXkHyoAM1K+47h95nJprc1gevFfCshu8L2oQIOhOwk7UjV4JwyIy5wTquf2N8zb4D4\nIaN88SgEm/JagDVKP/C8qqF/AD8/f75l3isgAAAAAElFTkSuQmCC")

相关文章

【动态规划】基础背包问题

  1159. 背包问题一 (Standard IO) 时间限制: 1000 ms  空间限制: 262144 KB  具体限制   题目描述 有个背包可承受重量N,现有T件物品每件物品重量为...

【NOIP初赛 】哈夫曼树

【NOIP初赛 】哈夫曼树

根据我已刷的初赛题中基本每套的倒数第五或第六个不定项选择题就有一个关于哈夫曼树及其各种应用的题,占:0—1.5分;然而我针对这个类型的题也多次不会做,so,今晚好好研究下哈夫曼树;  概念:  给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二...

跑在内存中的数据库——H2数据库

跑在内存中的数据库——H2数据库

今天接触到了一个非常有意思的数据库,叫H2数据库。在众多数据库中,H2数据库以其独特的特性——内存数据库模式,吸引了大量开发者的关注。今天,就来深入探讨一下这个跑在内存中的数据库——H2数据库。 一、H2数据库简介 H2是一个轻量级的关系型数据库,它支持嵌入式和客户...

记录一次如何自己使用国外服务器搭建梯子

记录一次如何自己使用国外服务器搭建梯子

机缘巧合之下,租了一台亚马逊的美国服务器,想着这么大的服务器不能就跑一个业务吧,得利用起来,于是,就开始了搭建梯子之旅。 第一步:使用root账号登上ssh服务器。 第二步:执行一键搭建脚本: bash <(wget -qO- -o- https://git.io/v2ray.sh)...

【已解决】Window命令行报错:无法加载文件,因为在此系统上禁止运行脚本。

错误:无法加载文件 D:\Program Files\nodejs\tsc.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。 解决方法:...

【PHP】大量 HTTP 请求调第三方接口,接口堵塞引起的 FD 耗尽(too many file open)问题

“FD耗尽”中的“FD”指的是“文件描述符”(File Descriptor)。在Unix和类Unix系统(如Linux)中,文件描述符是一个非负整数,用于标识一个进程打开的文件或其他输入/输出资源,比如网络套接字(socket...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。