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

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

1、图片读取

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

2、图片灰度化、二值化

灰度化,在RGB模型中,如果R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫灰度值,因此,灰度图像每个像素只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为0-255。

通过PIL中的算法即可快速实现灰度化:

img=img.convert("L")

这样我们就得到了R=G=B的代码

接下来我们要进行二值化,二值化的目的就是把文字和背景部分严格区分开。可以通过尝试的方法,找到一个阈值,然后将RGB大于阈值的置为1,否则置为0。

点击查看代码
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

3、降噪

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

4、分割

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

点击查看代码
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

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

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

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

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

点击查看代码
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

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.08571428571428572, 0.08571428571428572, 0.42857142857142855, 0.42857142857142855, 0.11428571428571428, 0.11428571428571428],[0.2857142857142857, 0.0, 0.2857142857142857, 0.0, 0.0, 0.0]]
nums1=[
[0.36, 0.44, 0.4, 0.4, 0.36, 0.44],
[0.24, 0.32, 0.0, 0.4, 0.24, 0.56],
[0.32, 0.4, 0.04, 0.4, 0.48, 0.32],
[0.32, 0.48, 0.16, 0.64, 0.32, 0.48],
[0.04, 0.48, 0.36, 0.52, 0.16, 0.44],
[0.4, 0.24, 0.28, 0.48, 0.32, 0.4],
[0.36, 0.32, 0.56, 0.48, 0.36, 0.48],
[0.32, 0.48, 0.04, 0.44, 0.24, 0.12],
[0.4, 0.48, 0.56, 0.64, 0.4, 0.48],
[0.4, 0.44, 0.4, 0.64, 0.24, 0.44]
]
nums2=[
[0.44, 0.36, 0.4, 0.4, 0.44, 0.36],
[0.4, 0.16, 0.2, 0.2, 0.4, 0.4],
[0.4, 0.32, 0.12, 0.32, 0.56, 0.24],
[0.4, 0.4, 0.24, 0.56, 0.4, 0.4],
[0.12, 0.4, 0.4, 0.52, 0.2, 0.44],
[0.48, 0.16, 0.36, 0.4, 0.4, 0.32],
[0.44, 0.24, 0.64, 0.4, 0.44, 0.4],
[0.4, 0.4, 0.2, 0.28, 0.36, 0.0],
[0.48, 0.4, 0.64, 0.56, 0.48, 0.4],
[0.48, 0.36, 0.48, 0.56, 0.32, 0.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(0, 10):
if (code_num1 == nums1[index]):
# print(index)
a = index
break
for index in range(0, 10):
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")

python实现对简单的运算型验证码的识别【不使用OpenCV】的更多相关文章

  1. 使用python内置库pytesseract实现图片验证码的识别

    环境准备: 1.安装Tesseract模块 git文档地址:https://digi.bib.uni-mannheim.de/tesseract/ 下载后就是一个exe安装包,直接右击安装即可,安装完 ...

  2. Python爬虫学习笔记之点触验证码的识别

    代码: Chaojiying.py: #!/usr/bin/env python # coding:utf-8 import requests from hashlib import md5 clas ...

  3. Python爬虫学习笔记之极限滑动验证码的识别

    代码: import time from io import BytesIO from PIL import Image from selenium import webdriver from sel ...

  4. 基于python语言的tensorflow的‘端到端’的字符型验证码识别源码整理(github源码分享)

    基于python语言的tensorflow的‘端到端’的字符型验证码识别 1   Abstract 验证码(CAPTCHA)的诞生本身是为了自动区分 自然人 和 机器人 的一套公开方法, 但是近几年的 ...

  5. 基于tensorflow的‘端到端’的字符型验证码识别源码整理(github源码分享)

    基于tensorflow的‘端到端’的字符型验证码识别 1   Abstract 验证码(CAPTCHA)的诞生本身是为了自动区分 自然人 和 机器人 的一套公开方法, 但是近几年的人工智能技术的发展 ...

  6. Python学习_02_数字和运算

    python具有强大的科学运算功能,python由于支持更加强大的面向对象和动态特性,相比R语言.matlab.mathmatic等传统的科学计算工具具有非常大的优势. Python的数字 pytho ...

  7. Python爬虫学习笔记之微信宫格验证码的识别(存在问题)

    本节我们将介绍新浪微博宫格验证码的识别.微博宫格验证码是一种新型交互式验证码,每个宫格之间会有一条 指示连线,指示了应该的滑动轨迹.我们要按照滑动轨迹依次从起始宫格滑动到终止宫格,才可以完成验证,如 ...

  8. python中 and 和 or 运算的核心思想 ——— 短路逻辑

    python中 and 和 or 运算的核心思想 --- 短路逻辑 1. 包含一个逻辑运算符 首先从基本的概念着手,python中哪些对象会被当成 False 呢?而哪些又是 True 呢? 在Pyt ...

  9. Python django实现简单的邮件系统发送邮件功能

    Python django实现简单的邮件系统发送邮件功能 本文实例讲述了Python django实现简单的邮件系统发送邮件功能. django邮件系统 Django发送邮件官方中文文档 总结如下: ...

随机推荐

  1. hql常用查询语句

    // HQL: Hibernate Query Language.// 特点:// >> 1,与SQL相似,SQL中的语法基本上都可以直接使用.// >> 2,SQL查询的是表 ...

  2. CSS简单样式练习(四)

    运行效果: 源代码: 1 <!DOCTYPE html> 2 <html lang="zh"> 3 <head> 4 <meta char ...

  3. SpringMVC 解析(四)编程式路由

    多数情况下,我们在使用Spring的Controller时,会使用@RequestMapping的形式把请求按照URL路由到指定方法上.Spring还提供了一种编程的方式去实现请求和路由方法之间的路由 ...

  4. SpringMVC-拦截器快速入门

    1.创建拦截器类实现HandlerInterceptor //该拦截器类必须实现HandlerInterceptor接口,手动覆盖其中的方法 public class MyInterceptor1 i ...

  5. Leetcode216/39/40/77之回溯解决经典组合问题

    Leetcode216-组合总和三 找出所有相加之和为 n 的 k 个数的组合,且满足下列条件: 只使用数字1到9 每个数字 最多使用一次 返回 所有可能的有效组合的列表 .该列表不能包含相同的组合两 ...

  6. FinClip 黑客马拉松正式开赛,码力集结,等你来战!

    从2017到2022,小程序已经走过了5年的光景.从无人问津到互联网巨头纷纷入局,短短数年间,小程序已然发展成为超级 App 的标配!微信.支付宝.百度.抖音.今日头条--这些超级app的背后都有巨量 ...

  7. MySQL存储引擎、基础数据类型、约束条件

    MySQL存储引擎 存储引擎 # 存储引擎可以堪称是处理数据的不同方式 # 查看存储引擎的方式 show engines; # 需要掌握的四个存储引擎 MyISAM MySQL5.5之前的默认的存储引 ...

  8. POP3协议(电子邮件邮局协议)中UIDL和TOP命令在实际使用中的作用

    POP3是电子邮件协议中用于接收邮件的协议,相较于发送邮件的SMTP协议,POP3的命令要多一些.主要的命令有LIST.STAT.RETR.DELE.UIDL.TOP.QUIT,以及用于登录邮箱的US ...

  9. windows10家庭版启用组策略gpedit.msc

    启用组策略gpedit.msc 家庭版很多功能不能使用,凑巧用的就是家庭版. 还想使用gpedit.msc来关闭windows10的更新. 找到一个可行的方法. 需要创建一个脚本. 如果你没有编辑器, ...

  10. 【vue】$attrs的作用和使用方法

    之前一直不了解$attrs的作用和使用场景,然后自己翻阅了相关资料整理了下,如有不对的地方请大家指教 $attrs: $attrs是vue版本2.40以上新增的属性: 使用场景: vue项目里面,大家 ...