如何用python搞定验证码中的噪点
背景:朋友在为"关山口男子职业技术学校"写一款校园应用,于是找MoonXue写一个学生选课系统的登录接口.为了搞定这个接口,不得不先搞定这个系统的验证码.
验证码大概是这个样子
看上去不怎么难,没有干扰线没有粘连没有扭曲.但还是没能用pytesser直接将它识别出来,因为当中有噪点和其他背景噪声的存在.MoonXue的工作就是去掉这些讨厌的东西
先介绍一下,我们的工具:
1.Pytesser 它是基于一个c语言实现名为tesser的识别工具的python封装.可惜比较笨,只能做最简单的识别而且不认识汉字
2.Requests 它是我们喜欢写爬虫的孩子的最爱,提供人性化的接口,代价是失去了一点效率(写python就别考虑效率啦)
3.BeautifulSoup 它和Requests是一对好机油,让提取文档中所需的内容变成一件简单的事情
4.PIL 它是今天的主角,PIL是专门用作图像处理的库,很好很强大.熟练的人甚至可以用它来P图
如何写爬虫去实现模拟登录此处不细说,下面说说怎么解决验证码识别
解决思路如下:
1.先用PIL对图像做一次图像增强,因为原图中数字的边缘和背景中的噪声并不是太分明,做了增强之后能将两者分离.如果不分离,可能会在去噪点的时候导致数字中有部分会缺失
im = Image.open("randomimage/randomImage11.jpg")
im = ImageEnhance.Sharpness(im).enhance(3)
参数为3是经过实验之后感觉比较理想的值,太强不好,太弱也不好
2.做完预处理之后,就是去背景噪声了.背景噪声指的是背景中各种明暗变换的色块,肉眼也许不会注意到这个.但是它的存在会给识别带来影响.我最初的做法是将图像转换为只有黑白两色,这样自然就将噪声转换成了噪点.
效果如图
但我希望能去掉噪点,成为这样
最先想到的是种子染色法 ,什么是种子染色法请参看这个链接
为了防止坏链,此处做部分转载
种子染色法英文叫做Flood Fill ,实际上Flood Fill这个名称更贴切一点,因为这个方法作用在一个图的结点上时恰似洪水一样“淹没”与之相连的其他结点并以相同的方式蔓延出去,这个方法通常用于计算一个图的极大连通子图(这里的“图”是图论的概念)。设想一个无向图,我们从这个图中一个未标号(“标号”可以理解为“染色”)的结点开始,将此结点和从这个结点出发可达的所有结点都赋予相同的标号(染上相同的颜色),那么我们就得到了这些被标号的结点所组成的一个极大连通子图,搜索下一个未标号的结点并重复上述过程我们便可以找到所有的极大连通子图。“染色”的过程可以用DFS或者BFS实现,如果结点数为V,边数为E,因为我们在Flood Fill过程中“造访”每个结点两次,“造访”每条边两次,所以得到所有极大连通子图的时间复杂度为o(V+E) 。
来自Wikipedia的一个示例:
.gif)
想象每个白色方块为图中的结点,相邻的方块(上下左右)有边相连,那么这个图就有三个极大连通子图,这演示了Flood Fill查找其中一个极大连通子图的过程。
在这是借要用种子染色法计算每块的面积,然后把小体积的块当作噪点去除.
代码在这
def check(j,i):
try:
if pix[j,i] == 0 and matrix[j][i] != -1:
return True
else:
return False
except:
return False def juli(r,s):
return abs(r[0]-s[0])+abs(r[1]-s[1])+abs(r[2]-s[2]) for i in range(w):
for j in range(h):
r = [0,0,0]
s = [0,0,0]
if pix[j,i] == 0:
if check(j-1,i):
r[0],r[1],r[2] = im2.getpixel((j,i))
s[0],s[1],s[2] = im2.getpixel((j-1,i))
print r
print s
print "-"*55
if juli(r,s) <=l:
matrix[j][i] = matrix[j-1][i]
maps[str(matrix[j][i])]+=1
elif check(j-1,i-1):
r[0],r[1],r[2] = im2.getpixel((j,i))
s[0],s[1],s[2] = im2.getpixel((j-1,i-1))
if juli(r,s) <=l:
matrix[j][i] = matrix[j-1][i-1]
maps[str(matrix[j][i])]+=1
elif check(j,i-1):
r[0],r[1],r[2] = im2.getpixel((j,i))
s[0],s[1],s[2] = im2.getpixel((j-1,i))
if juli(r,s) <=l:
matrix[j][i] = matrix[j][i-1]
maps[str(matrix[j][i])]+=1
elif check(j+1,i+1):
r[0],r[1],r[2] = im2.getpixel((j,i))
s[0],s[1],s[2] = im2.getpixel((j+1,i+1))
if juli(r,s) <=l:
matrix[j][i] = matrix[j+1][i+1]
maps[str(matrix[j][i])]+=1
elif check(j,i+1):
r[0],r[1],r[2] = im2.getpixel((j,i))
s[0],s[1],s[2] = im2.getpixel((j,i+1))
if juli(r,s) <=l:
matrix[j][i] = matrix[j][i+1]
maps[str(matrix[j][i])]+=1
elif check(j-1,i+1):
pr[0],r[1],r[2] = im2.getpixel((j,i))
s[0],s[1],s[2] = im2.getpixel((j-1,i+1))
if juli(r,s) <=l:
matrix[j][i] = matrix[j-1][i+1]
maps[str(matrix[j][i])]+=1
elif check(j+1,i-1):
r[0],r[1],r[2] = im2.getpixel((j,i))
s[0],s[1],s[2] = im2.getpixel((j+1,i-1))
if juli(r,s) <=l:
matrix[j][i] = matrix[j+1][i-1]
maps[str(matrix[j][i])]+=1
elif check(j+1,i):
r[0],r[1],r[2] = im2.getpixel((j,i))
s[0],s[1],s[2] = im2.getpixel((j+1,i))
if juli(r,s) <=l:
matrix[j][i] = matrix[j+1][i]
maps[str(matrix[j][i])]+=1
else:
n+=1
maps[str(n)]=1
matrix[j][i] = n for i in range(w):
for j in range(h):
if matrix[j][i]!=-1 and maps[str(matrix[j][i])]<=2:
im.putpixel((j,i),255)
结果呢,不是很理想因为这个体积参数设小了,噪点没去干净,设大了数字部分可能也去了一小块.最重要的是这里噪点的大小不是很规律,很难找到一个不错的面积参数.
失败只是暂时的,经过观察发现背景噪声颜色明显比数字要浅的多.这也意味着它的RGB值要比数字小的多,通过分析RGB值能去掉大部分噪声,剩下来的噪点可以再通过种子染色法处理.也就是说,分别在两张图片(分别是黑白和彩色)上获取信息,在一张图片上做处理最后做识别
核心代码在这
r[0],r[1],r[2] = im2.getpixel((j,i))
if r[0]+r[1]+r[2]>=400 or r[0]>=250 or r[1]>=250 or r[2]>=250 :
im2.putpixel((j,i),(255,255,255))
至此,本次识别的问题就搞定啦,成功率在50%以上基本满足接口的需求
想交流或想要源码的朋友可以邮件联系
如何用python搞定验证码中的噪点的更多相关文章
- 面试大总结:Java搞定面试中的链表题目总结
package LinkedListSummary; import java.util.HashMap; import java.util.Stack; /** * http://blog.csdn. ...
- 面试大总结之二:Java搞定面试中的二叉树题目
package BinaryTreeSummary; import java.util.ArrayList; import java.util.Iterator; import java.util.L ...
- (转)面试大总结之一:Java搞定面试中的链表题目
面试大总结之一:Java搞定面试中的链表题目 分类: Algorithm Interview2013-11-16 05:53 11628人阅读 评论(40) 收藏 举报 链表是面试中常出现的一类题目, ...
- Java原来还可以这么学:如何搞定面试中必考的集合类
原创声明 本文作者:黄小斜 转载请务必在文章开头注明出处和作者. 系列文章介绍 本文是<五分钟学Java>系列文章的一篇 本系列文章主要围绕Java程序员必须掌握的核心技能,结合我个人三年 ...
- 三步轻松搞定delphi中CXGRID手动添加复表头(多行表头,报表头)
网上有代码动态生成cxgrid多行表头的源码,地址为:http://mycreature.blog.163.com/blog/static/556317200772524226400/ 如果要手动设计 ...
- 轻松搞定面试中的二叉树题目(java&python)
树是一种比较重要的数据结构,尤其是二叉树.二叉树是一种特殊的树,在二叉树中每个节点最多有两个子节点,一般称为左子节点和右子节点(或左孩子和右孩子),并且二叉树的子树有左右之分,其次序不能任意颠倒.二叉 ...
- 如何通过热修复,搞定开发中的那些 Bug?
作为程序员,Bug 修复终究是绕不开的话题,本期移动开发精英俱乐部讨论的主题便是 Bug 修复中的 Hotfix,即热修复.接下来让我们跟随大牛的脚步来了解 Hotfix,就算你不能一下豁然开朗,相信 ...
- Cordova - 彻底搞定安卓中的微信支付插件!
Cordova:8.0.0 Android studio:3.2.1 cordova-plugin-adam-wechat : 3.0.6 你看到这个标题肯定会惊讶,一个Cordova的微信支付插件, ...
- 用Python搞定九宫格式的朋友圈。内附“马云”朋友圈
PIL(Python Imaging Library)是一个非常强大的Python库,但是它支持Python2.X, 在Python3中则使用的是Pillow库,它是从PIL中fork出来的一个分支. ...
随机推荐
- GOLANG 变量
语法格式 var 变量名 类型 类型: 可以是go语言内置的各种基本数据类型.复合数据类型,甚至是函数.方法.接口以及自定义类型. 声明变量会给变量设定零值.数值类型变量 ...
- IE11 iframe alternative
<OBJECT classid=clsid:8856F961-340A-11D0-A96B-00C04FD705A2> <PARAM NAME=Location VALUE=http ...
- OpenLayers元素选择工具
OpenLayers的selector工具相信挺多人都没有用过,其实这个工具用处还是不少的.比如完成元素查询时,需要实现图属性联动,使用这个工具很方便.最近做项目时也使用到这个工具,使用起来确实挺方便 ...
- Redis学习-基础环境介绍(二)
1.通过VMware安装了Centos6.8系统 2.Reids安装过程,需要GCC环境 »通过下面命令,根据提示直接安装 1 yum install gcc 3.Redis选用的是3.2.4(建议使 ...
- Linux启动/停止/重启Mysql数据库的方法
1.查看mysql版本 方法一:status; 方法二:select version(); 2.Mysql启动.停止.重启常用命令 a.启动方式 1.使用 service 启动: [root@loca ...
- 简述Session 、Cookie、cache 区别
区别: 1.session是把数据保存在服务器上,每一个用户都有自己的session. 2.cookie是保存在客户端(也就是本机电脑). 3.cache是保存在服务器上,每个用户都可以访问的对象. ...
- 关于margin的一些问题
引 在平时处理样式的过程中,会出现各种问题.比如: 包含在父元素中的子元素设置了浮动,子元素高度变化的时候父元素的高度没有随着变化,就是没有被撑高,父元素仍然是原来设置的那个高度 包含在父元素中的子元 ...
- sql常用语句
选择:select * from table1 where 范围 插入:insert into table1(field1,field2) values(value1,value2) 删除:delet ...
- (十八)WireShark 过滤语法
1.过滤IP,如来源IP或者目标IP等于某个IP例子:ip.src eq 192.168.1.107 or ip.dst eq 192.168.1.107或者ip.addr eq 192.168.1. ...
- Ajax form表单提交
1. 使用 $("form").serialize() 来获取表单数据 $.ajax({ type: 'post', url: 'your url', data: $(" ...