1. python 验证码 怎样去掉干扰线

如果是想让代码识别的话,要看验证码的复杂程度了,如果比较简单,使用图像处理说不定可以解决(我不会,不过网上应该有资料,就算没有python的,其他语言的也有),但是如果是复杂的,建议你把验证码下载下来,如果有图形界面,就在界面中显示...

2. 如何利用Python做简单的验证码识别

1摘要

验证码是目前互联网上非常常见也是非常重要的一个事物,充当着很多系统的防火墙功能,但是随时OCR技术的发展,验证码暴露出来的安全问题也越来越严峻。本文介绍了一套字符验证码识别的完整流程,对于验证码安全和OCR识别技术都有一定的借鉴意义。

然后经过了一年的时间,笔者又研究和get到了一种更强大的基于CNN卷积神经网络的直接端到端的验证识别技术(文章不是我的,然后我把源码整理了下,介绍和源码在这里面):

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

2关键词

关键词:安全,字符图片,验证码识别,OCR,Python,SVM,PIL

3免责声明

本文研究所用素材来自于某旧Web框架的网站完全对外公开的公共图片资源。

本文只做了该网站对外公开的公共图片资源进行了爬取,并未越权做任何多余操作。

本文在书写相关报告的时候已经隐去漏洞网站的身份信息。

本文作者已经通知网站相关人员此系统漏洞,并积极向新系统转移。

本报告的主要目的也仅是用于OCR交流学习和引起大家对验证安全的警觉。

4引言

关于验证码的非技术部分的介绍,可以参考以前写的一篇科普类的文章:

互联网安全防火墙(1)--网络验证码的科普

里面对验证码的种类,使用场景,作用,主要的识别技术等等进行了讲解,然而并没有涉及到任何技术内容。本章内容则作为它的技术补充来给出相应的识别的解决方案,让读者对验证码的功能及安全性问题有更深刻的认识。

5基本工具

要达到本文的目的,只需要简单的编程知识即可,因为现在的机器学习领域的蓬勃发展,已经有很多封装好的开源解决方案来进行机器学习。普通程序员已经不需要了解复杂的数学原理,即可以实现对这些工具的应用了。

主要开发环境:

  • python3.5

  • python SDK版本

  • PIL

  • 图片处理库

  • libsvm

  • 开源的svm机器学习库

  • 关于环境的安装,不是本文的重点,故略去。

    6基本流程

    一般情况下,对于字符型验证码的识别流程如下:

  • 准备原始图片素材

  • 图片预处理

  • 图片字符切割

  • 图片尺寸归一化

  • 图片字符标记

  • 字符图片特征提取

  • 生成特征和标记对应的训练数据集

  • 训练特征标记数据生成识别模型

  • 使用识别模型预测新的未知图片集

  • 达到根据“图片”就能返回识别正确的字符集的目标

  • 7素材准备

    7.1素材选择

    由于本文是以初级的学习研究目的为主,要求“有代表性,但又不会太难”,所以就直接在网上找个比较有代表性的简单的字符型验证码(感觉像在找漏洞一样)。

    最后在一个比较旧的网站(估计是几十年前的网站框架)找到了这个验证码图片。

    原始图:

  • def get_feature(img): """

  • 获取指定图片的特征值,

  • 1. 按照每排的像素点,高度为10,则有10个维度,然后为6列,总共16个维度

  • :param img_path:

  • :return:一个维度为10(高度)的列表 """


  • width, height = img.size


  • pixel_cnt_list = []

  • height = 10 for y in range(height):

  • pix_cnt_x = 0 for x in range(width): if img.getpixel((x, y)) == 0: # 黑色点

  • pix_cnt_x += 1


  • pixel_cnt_list.append(pix_cnt_x) for x in range(width):

  • pix_cnt_y = 0 for y in range(height): if img.getpixel((x, y)) == 0: # 黑色点

  • pix_cnt_y += 1


  • pixel_cnt_list.append(pix_cnt_y) return pixel_cnt_list

  • 然后就将图片素材特征化,按照libSVM指定的格式生成一组带特征值和标记值的向量文

3. 怎么让python单元测试setup只执行一次

怎么让python单元测试setup只执行一次
看上去不怎么难,没有干扰线没有粘连没有扭曲.但我还回是没答能用pytesser直接将它识别出来,因为当中有噪点和其他背景噪声的存在.我的工作就是去掉这些讨厌的东西 先介绍一下,我们的工具: 1.Pytesser它是基于一个c语言实现名为tesser的识别工具的pyth...

题主在程序中输入验证码,主要是想尽量模仿真人的搜索,结果发现所有cookie是一样的,无需做这一步验证码的输入,如果是这样的话,无需验证码。另外,按题主的代码来看,题主只要比较一下输入验证码之前和之后的cookie,如果没有差别,就去掉验证码处理。

4. 如何用python搞定验证码中的噪点

看上去不怎么难,没有干扰线没有粘连没有扭曲.但我还是没能用pytesser直接将它识别出来,因为当中有噪点和其他背景噪声的存在.我的工作就是去掉这些讨厌的东西
先介绍一下,我们的工具:
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)View Code

结果呢,不是很理想因为这个体积参数设小了,噪点没去干净,设大了数字部分可能也去了一小块.最重要的是这里噪点的大小不是很规律,很难找到一个不错的面积参数.
失败只是暂时的,经过观察发现背景噪声颜色明显比数字要浅的多.这也意味着它的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%以上基本满足接口的需求

5. 请教生成如图验证码的python算法

def gene_text():
source = list(string.letters)
for index in range(0,10):
source.append(str(index))
return ''.join(random.sample(source,number))#number是生成验证码的位数
然后我们要创建一个图片,写入字符串,需要说明的这里面的字体是不同系统而定,如果没有找到系统字体路径的话,也可以不设置
def gene_code():
width,height = size #宽和高
image = Image.new('RGBA',(width,height),bgcolor) #创建图片
font = ImageFont.truetype(font_path,25) #验证码的字体和字体大小
draw = ImageDraw.Draw(image) #创建画笔
text = gene_text() #生成字符串
font_width, font_height = font.getsize(text)
draw.text(((width - font_width) / number, (height - font_height) / number),text,
font= font,fill=fontcolor) #填充字符串
接下来,我们要在图片上画几条干扰线

#用来绘制干扰线
def gene_line(draw,width,height):
begin = (random.randint(0, width), random.randint(0, height))
end = (random.randint(0, width), random.randint(0, height))
draw.line([begin, end], fill = linecolor)
最后创建扭曲,加上滤镜,用来增强验证码的效果。
image = image.transform((width+20,height+10), Image.AFFINE, (1,-0.3,0,-0.1,1,0),Image.BILINEAR) #创建扭曲
image = image.filter(ImageFilter.EDGE_ENHANCE_MORE) #滤镜,边界加强
image.save('idencode.png') #保存验证码图片

6. python 验证码加时间戳的功能是怎么实现的

验证码要成功显示就必须要有一个验证码生成器,所以就要写一个验证码生成器。我在app中新建了一个py文件check_coed.py文件,这就是验证码生成器。代码如下
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter

_letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z
_upper_cases = _letter_cases.upper() # 大写字母
_numbers = ''.join(map(str, range(3, 10))) # 数字
init_chars = ''.join((_letter_cases, _upper_cases, _numbers))

def create_validate_code(size=(120, 30),
chars=init_chars,
img_type="GIF",
mode="RGB",
bg_color=(255, 255, 255),
fg_color=(0, 0, 255),
font_size=18,
font_type="Monaco.ttf",
length=4,
draw_lines=True,
n_line=(1, 2),
draw_points=True,
point_chance=2):
"""
@todo: 生成验证码图片
@param size: 图片的大小,格式(宽,高),默认为(120, 30)
@param chars: 允许的字符集合,格式字符串
@param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG
@param mode: 图片模式,默认为RGB
@param bg_color: 背景颜色,默认为白色
@param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
@param font_size: 验证码字体大小
@param font_type: 验证码字体,默认为 ae_AlArabiya.ttf
@param length: 验证码字符个数
@param draw_lines: 是否划干扰线
@param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
@param draw_points: 是否画干扰点
@param point_chance: 干扰点出现的概率,大小范围[0, 100]
@return: [0]: PIL Image实例
@return: [1]: 验证码图片中的字符串
"""

width, height = size # 宽高
# 创建图形
img = Image.new(mode, size, bg_color)
draw = ImageDraw.Draw(img) # 创建画笔

def get_chars():
"""生成给定长度的字符串,返回列表格式"""
return random.sample(chars, length)

def create_lines():
"""绘制干扰线"""
line_num = random.randint(*n_line) # 干扰线条数

for i in range(line_num):
# 起始点
begin = (random.randint(0, size[0]), random.randint(0, size[1]))
# 结束点
end = (random.randint(0, size[0]), random.randint(0, size[1]))
draw.line([begin, end], fill=(0, 0, 0))

def create_points():
"""绘制干扰点"""
chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100]

for w in range(width):
for h in range(height):
tmp = random.randint(0, 100)
if tmp > 100 - chance:
draw.point((w, h), fill=(0, 0, 0))

def create_strs():
"""绘制验证码字符"""
c_chars = get_chars()
strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开

# font = ImageFont.truetype(font_type, font_size)
font = ImageFont.load_default().font
font_width, font_height = font.getsize(strs)

draw.text(((width - font_width) / 3, (height - font_height) / 3),
strs, font=font, fill=fg_color)

return ''.join(c_chars)

if draw_lines:
create_lines()
if draw_points:
create_points()
strs = create_strs()

# 图形扭曲参数
params = [1 - float(random.randint(1, 2)) / 100,
0, 0, 0, 1 - float(random.randint(1, 10)) / 100, float(random.randint(1, 2)) / 500, 0.001, float(random.randint(1, 2)) / 500 ]
img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲
img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大)

7. pythonchallenge 去除验证码干扰线用什么算法好

struct模块还提供了pack_into() 和 unpack_from()的方法用来解决这样的问题,也就是对一个已经提前分配好的buffer进行字节的填充,而不会每次都产生一个新对象对字节进行存储。

8. python怎么批量提交验证码

现在的网页中,为了防止机器人提交表单,图片验证码是很常见的应对手段之一。这里就不详细介绍了,相信大家都遇到过。
现在就给出用Python的PIL库实现验证码图片的代码。代码中有详细注释。
#!/usr/bin/env python
#coding=utf-8
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
_letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z
_upper_cases = _letter_cases.upper() # 大写字母
_numbers = ''.join(map(str, range(3, 10))) # 数字
init_chars = ''.join((_letter_cases, _upper_cases, _numbers))
def create_validate_code(size=(120, 30),
chars=init_chars,
img_type="GIF",
mode="RGB",
bg_color=(255, 255, 255),
fg_color=(0, 0, 255),
font_size=18,
font_type="ae_AlArabiya.ttf",
length=4,
draw_lines=True,
n_line=(1, 2),
draw_points=True,
point_chance = 2):
'''
@todo: 生成验证码图片
@param size: 图片的大小,格式(宽,高),默认为(120, 30)
@param chars: 允许的字符集合,格式字符串
@param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG
@param mode: 图片模式,默认为RGB
@param bg_color: 背景颜色,默认为白色
@param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
@param font_size: 验证码字体大小
@param font_type: 验证码字体,默认为 ae_AlArabiya.ttf
@param length: 验证码字符个数
@param draw_lines: 是否划干扰线
@param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
@param draw_points: 是否画干扰点
@param point_chance: 干扰点出现的概率,大小范围[0, 100]
@return: [0]: PIL Image实例
@return: [1]: 验证码图片中的字符串
'''
width, height = size # 宽, 高
img = Image.new(mode, size, bg_color) # 创建图形
draw = ImageDraw.Draw(img) # 创建画笔
def get_chars():
'''生成给定长度的字符串,返回列表格式'''
return random.sample(chars, length)
def create_lines():
'''绘制干扰线'''
line_num = random.randint(*n_line) # 干扰线条数
for i in range(line_num):
# 起始点
begin = (random.randint(0, size[0]), random.randint(0, size[1]))
#结束点
end = (random.randint(0, size[0]), random.randint(0, size[1]))
draw.line([begin, end], fill=(0, 0, 0))
def create_points():
'''绘制干扰点'''
chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100]

for w in xrange(width):
for h in xrange(height):
tmp = random.randint(0, 100)
if tmp > 100 - chance:
draw.point((w, h), fill=(0, 0, 0))
def create_strs():
'''绘制验证码字符'''
c_chars = get_chars()
strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开

font = ImageFont.truetype(font_type, font_size)
font_width, font_height = font.getsize(strs)
draw.text(((width - font_width) / 3, (height - font_height) / 3),
strs, font=font, fill=fg_color)

return ''.join(c_chars)
if draw_lines:
create_lines()
if draw_points:
create_points()
strs = create_strs()
# 图形扭曲参数
params = [1 - float(random.randint(1, 2)) / 100,
0,
0,
0,
1 - float(random.randint(1, 10)) / 100,
float(random.randint(1, 2)) / 500,
0.001,
float(random.randint(1, 2)) / 500
]
img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲
img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大)
return img, strs
if __name__ == "__main__":
code_img = create_validate_code()
code_img.save("validate.gif", "GIF")
最后结果返回一个元组,第一个返回值是Image类的实例,第二个参数是图片中的字符串(比较是否正确的作用)。
最后结果返回一个元组,第一个返回值是Image类的实例,第二个参数是图片中的字符串(比较是否正确的作用)。
需要提醒的是,如果在生成ImageFont.truetype实例的时候抛出IOError异常,有可能是运行代码的电脑没有包含指定的字体,需要下载安装。
生成的验证码图片效果:

这时候,细心的同学可能要问,如果每次生成验证码,都要先保存生成的图片,再显示到页面。这么做让人太不能接受了。这个时候,我们需要使用python内置的StringIO模块,它有着类似file对象的行为,但是它操作的是内存文件。于是,我们可以这么写代码:
try:
import cStringIO as StringIO
except ImportError:
import StringIO

mstream = StringIO.StringIO()

img = create_validate_code()[0]
img.save(mstream, "GIF")
这样,我们需要输出的图片的时候只要使用“mstream.getvalue()”即可。比如在Django里,我们首先定义这样的url:
from django.conf.urls.defaults import *

urlpatterns = patterns('example.views',
url(r'^validate/$', 'validate', name='validate'),
)
在views中,我们把正确的字符串保存在session中,这样当用户提交表单的时候,就可以和session中的正确字符串进行比较。
from django.shortcuts import HttpResponse

from validate import create_validate_code

def validate(request):
mstream = StringIO.StringIO()

validate_code = create_validate_code()
img = validate_code[0]
img.save(mstream, "GIF")

request.session['validate'] = validate_code[1]

return HttpResponse(mstream.getvalue(), "image/gif")

9. python 验证码 阈值有什么用

看上去不怎么难,没有干扰线没有粘连没有扭曲.但我还是没能用pytesser直接将它识别出来,因为当中有噪点和其他背景噪声的存在.我的工作就是去掉这些讨厌的东西
先介绍一下,我们的工具:
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)View Code

结果呢,不是很理想因为这个体积参数设小了,噪点没去干净,设大了数字部分可能也去了一小块.最重要的是这里噪点的大小不是很规律,很难找到一个不错的面积参数.
失败只是暂时的,经过观察发现背景噪声颜色明显比数字要浅的多.这也意味着它的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%以上基本满足接口的需求