如何用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的一个示例:
想象每个白色方块为图中的结点,相邻的方块(上下左右)有边相连,那么这个图就有三个极大连通子图,这演示了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出来的一个分支. ...
随机推荐
- ReportService未指定 OverwriteDataSources
报表服务器部署好之后,查看报表就显示ConnectionString 属性尚未初始化. 然后重启部署并查看部署时控制台的输出信息,发现之前的部署成功消息是假象,实际上部署的时候有一个警告: 不能将数据 ...
- Query Designer:Condition,根据KeyFigure值来过滤数据
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- caffe python 接口设置
安装编译完成后, 运行 cd sudogedit ~/.bashrc 在打开的文件末尾加入 export PYTHONPATH=/home/caffe-master/python:$PYTHONPA ...
- JFinal 国际化
要支持国际化,需要在容器初始化的时候配置一个处理国际化的全局拦截器.比如可以使用 com.jfinal.i18n.I18nInterceptor 配置拦截器: public class MppConf ...
- mac上的git环境配置
git生成ssh key for mac 打开终端 cd ~/.ssh 看有没有文件 没有的时候 有有ssh key是这样的多了id_rsa(私钥)和 id_rsa.pub(公钥) 没有的话创建 ss ...
- HBase的Write Ahead Log (WAL) —— API与基本概念
HBase的数据写入操作,会先记录到HLog中,再真正写入到MemStore中.前者是对写入友好的格式,后者是对查询友好的格式.所以前者吞吐量更高,写入成功率大,提高了系统的可靠性,“基本”可以实现宕 ...
- 理论基础知识之————KB Kb Kbps 相关单位的区别和换算
换算公式 8bit(位)=1Byte(字节) 1024Byte(字节)=1KB 1024KB=1MB 1024MB=1GB 1024GB=1TB 容量是大写的 B 而传输的速度是小写的 b bps ...
- (十八)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. ...
- 【java基础】 合并两个类型相同的list
将两个类型相同的list合并,可以用 addAll(Collection<? extends E> c) import java.util.ArrayList; import java.u ...
- WF2013Low Power芯片
Description 有n个机器,每个机器有2个芯片,每个芯片可以放k个电池. 每个芯片能量是k个电池的能量的最小值. 两个芯片的能量之差越小,这个机器就工作的越好. ...