使用python PIL库实现简单验证码的去噪方法步骤

字符型图片验证码识别完整过程及Python实现的博主,我的大部分知识点都是从他那里学来的。

想要识别验证码,收集足够多的样本后,首先要做的就是对验证码原始图片进行处理,对验证码识别分类之前,一般包括:将彩色图片转换成灰度图、将灰度图二值化和去除噪点三个基本过程。这里仅以比较简单的验证码为例,介绍一下如何通过python的PIL库对图片去噪。

首先看一下未经处理的验证码图片:

对图片处理主要使用了PIL库的Image类。

1.彩色图片转换成灰度图

首先使用Image的open方法打开上面的图片,可以得到一个PIL.Image.Image对象,之后就可以调用convert、filter、point和putpixel等方法来处理图片。

我们可以通过convert方法将上面的彩色图片转换成灰度图:

# encoding=utf8

from PIL import Image

def main():
	image = Image.open('RandomPicture.png')
	imgry = image.convert('L')
	imgry.save('gray.png')

if __name__ == '__main__':
	main()

运行结果:

通过保存的图片可以看出来,已经由原来的彩图变成了灰度图,或者也可以认为是黑白图。什么叫灰度图?我们知道彩色图片是由不同的颜色的像素组合到一起的,那灰度图可以类似的认为是由不同灰度值的像素组合在一起后呈现出来的。任何颜色都有红、绿、蓝三原色组成,假如原来某点的颜色为RGB(R,G,B),那么,我们可以通过下面几种方法,将其转换为灰度:

1.浮点算法:Gray=R*0.3+G*0.59+B*0.11
2.整数方法:Gray=(R*30+G*59+B*11)/100
3.移位方法:Gray =(R*76+G*151+B*28)>>8;
4.平均值法:Gray=(R+G+B)/3;
5.仅取绿色:Gray=G;

通过上述任一种方法求得Gray后,将原来的RGB(R,G,B)中的R,G,B统一用Gray替换,形成新的颜色RGB(Gray,Gray,Gray),用它替换原来的RGB(R,G,B)就是灰度图了。

用代码实现看一下:

# encoding=utf8

from PIL import Image

def main():
	image = Image.open('RandomPicture.png')
	print 'image mode: ', image.mode
	print image.getpixel((0, 0))
	print '-' * 40
	imgry = image.convert('L')
	print 'imgry mode: ', imgry.mode
	print imgry.getpixel((0, 0))

if __name__ == '__main__':
	main()

运行结果:

image mode: RGB
(21, 10, 26)
----------------------------------------
imgry mode: L
15

代码说明:

通过image.mode方法可以获得当前的PIL.Image.Image对象(也就是当前打开的图片)的mode值,而mode值表示图片的单位颜色是由RGB三个值组成的还是由灰度值组成的;

而getpixel可以获取某个像素的RGB值或者灰度值。我们知道图片是由许多像素组成的,每个像素在图片上都有一个对应的坐标x和y,而“(0, 0)”就表示该图片左上角顶点的像素。

由上面的结果我们可以知道,在将图片转换成灰度图之前,“(0, 0)”代表的像素的颜色是由RGB组成的:(21, 10, 26);在通过concert将彩色图片转换成灰度后,“(0, 0)”代表的像素的颜色值就变成了一个值:“15”,通过打印imgry.mode我们也可以知道,此时图片已经变成了灰度图,它的每一个像素的颜色都变成了一个灰度值。

其实这时候我们也可以简单的计算一下,使用前面说的浮点算法将上面的(21, 10, 26)三个值带入计算:

>>> 21*0.3+10*0.59+26*0.11
15.059999999999999

结果显示确实由浮点算法将RGB值变成了灰度值。

2.灰度图二值化

我们已经得到了灰度图,接下来就是将灰度图二值化。所谓二值化就是将灰度图像转换成由黑白二色组成的图像。思路就是确定一个阈值,大于阈值的像素表示为白色,小于阈值的像素表示为黑色,以此将图片的像素(灰度值)划分为两部分:0和1,例如0代表黑色,1代表白色,然后我们就可以用一串0和1组成的数字来表示一张图片。

将灰度图二值化会用到point方法,它可以接收一个灰度转二值的映射table,具体原理暂时还没弄明白,代码实现过程是这样的:

# encoding=utf8

from PIL import Image

def get_bin_table(threshold=115):
	'''
	获取灰度转二值的映射table
	0表示黑色,1表示白色
	'''
	table = []
	for i in range(256):
		if i < threshold:
			table.append(0)
		else:
			table.append(1)
	return table

def main():
	image = Image.open('RandomPicture.png')
	imgry = image.convert('L')
	table = get_bin_table()
	binary = imgry.point(table, '1')
	binary.save('binary.png')

if __name__ == '__main__':
	main()

运行结果:

通过结果不难看出,我们已经将最开始的彩色图由灰度图转变成了仅由黑白二色组成的图片,实现了二值化。这里需要说明的是,threshold参数值针对当前的验证码图片合适,该值需要根据验证码类型不同进行调试来确定。

然后我们再看看(0, 0)坐标代表的像素的颜色值是什么:

# encoding=utf8

from PIL import Image

def get_bin_table(threshold=115):
	'''
	获取灰度转二值的映射table
	0表示黑色,1表示白色
	'''
	table = []
	for i in range(256):
		if i < threshold:
			table.append(0)
		else:
			table.append(1)
	return table

def main():
	image = Image.open('RandomPicture.png')
	print 'image mode: ', image.mode
	print image.getpixel((0, 0))
	co = image.getcolors()
	print co
	print '-' * 40
	imgry = image.convert('L')
	print 'imgry mode: ', imgry.mode
	print imgry.getpixel((0, 0))
	co = imgry.getcolors()
	print co
	print '-' * 40
	table = get_bin_table()
	binary = imgry.point(table, '1')
	print 'binary mode: ', binary.mode
	print binary.getpixel((0, 0))
	co = binary.getcolors()
	print co

if __name__ == '__main__':
	main()

运行结果:

image mode: RGB
(21, 10, 26)
None
----------------------------------------
imgry mode: L
15
[(1, 2), (2, 3), (1, 4), (1, 5), (4, 6), (3, 8), (3, 9), (6, 10), (4, 11), (4, 12), (7, 13), (8, 14), (3, 15), (12, 16), (7, 17), (6, 18), (5, 19), (13, 20), (9, 21), (9, 22), (4, 23), (5, 24), (7, 25), (3, 26), (6, 27), (7, 28), (3, 29), (3, 30), (3, 31), (5, 32), (1, 33), (3, 35), (2, 36), (2, 37), (2, 38), (2, 39), (1, 41), (3, 42), (1, 43), (2, 44), (7, 45), (3, 46), (5, 47), (1, 48), (3, 49), (3, 50), (3, 51), (5, 52), (4, 53), (1, 54), (7, 55), (7, 56), (10, 57), (4, 58), (5, 59), (6, 60), (5, 61), (12, 62), (7, 63), (10, 64), (12, 65), (14, 66), (15, 67), (11, 68), (9, 69), (11, 70), (7, 71), (9, 72), (5, 73), (10, 74), (5, 75), (5, 76), (5, 77), (8, 78), (7, 79), (3, 80), (5, 81), (6, 82), (5, 83), (3, 84), (3, 85), (6, 86), (2, 87), (3, 88), (2, 90), (3, 91), (1, 93), (2, 94), (3, 95), (1, 96), (3, 97), (2, 99), (3, 100), (3, 101), (1, 102), (3, 104), (4, 105), (1, 106), (3, 108), (4, 110), (4, 111), (4, 112), (3, 113), (3, 114), (5, 115), (2, 116), (3, 117), (8, 118), (8, 119), (8, 120), (7, 121), (9, 122), (9, 123), (11, 124), (11, 125), (2, 126), (10, 127), (9, 128), (7, 129), (13, 130), (11, 131), (11, 132), (9, 133), (16, 134), (11, 135), (12, 136), (8, 137), (14, 138), (12, 139), (13, 140), (20, 141), (22, 142), (19, 143), (14, 144), (23, 145), (17, 146), (10, 147), (18, 148), (13, 149), (11, 150), (26, 151), (16, 152), (14, 153), (11, 154), (17, 155), (10, 156), (12, 157), (12, 158), (20, 159), (18, 160), (16, 161), (22, 162), (20, 163), (16, 164), (13, 165), (14, 166), (13, 167), (11, 168), (17, 169), (8, 170), (16, 171), (20, 172), (12, 173), (10, 174), (10, 175), (10, 176), (11, 177), (7, 178), (8, 179), (7, 180), (5, 181), (7, 182), (4, 183), (7, 184), (4, 185), (4, 186), (5, 187), (6, 188), (2, 189), (1, 190), (4, 191), (6, 192), (12, 193), (8, 194), (10, 195), (3, 196), (13, 197), (9, 198), (19, 199), (18, 200), (20, 201), (16, 202), (18, 203), (24, 204), (33, 205), (25, 206), (33, 207), (38, 208), (31, 209), (46, 210), (39, 211), (53, 212), (54, 213), (33, 214), (42, 215), (54, 216), (60, 217), (50, 218), (36, 219), (48, 220), (32, 221), (45, 222), (28, 223), (24, 224), (21, 225), (19, 226), (21, 227), (13, 228), (12, 229), (12, 230), (13, 231), (5, 232), (8, 233), (4, 234), (5, 235), (1, 236), (1, 237), (2, 238), (1, 239), (1, 240), (1, 242), (1, 243)]
----------------------------------------
binary mode: 1
0
[(503, 0), (1993, 1)]

代码说明:

通过binary mode的值我们可以知道二值化后得到的图片的像素值由0或1表示,而且当前(0, 0)代表的像素值的为0,它代表黑色,通过上面的图片我们也可以知道,左上角顶点确实是黑色的。

上面的代码中我们还使用了getcolors方法,它用来返回像素信息,是一个含有元素的列表:[(该种像素的数量,(该种像素)),(...),...],当该列表特别大的时候,它会返回None,这也是为什么上面彩色图片调用getcolors的时候会返回None。而[(503, 0), (1993, 1)]就表示我们得到的二值化黑白图片,由503个黑色像素点和1993个白色像素点组成。

通过binary.size我们可以得到二值化后的黑白图片的width和height值:(78, 32),它就表示该图片由78X32个像素点组成,正好等于503+1993的和。(78, 32)也说明该图片横向上共有32行,每行有78个像素点。将由0和1表示的图片打印出来看一下:

# encoding=utf8

from PIL import Image

def get_bin_table(threshold=115):
	'''
	获取灰度转二值的映射table
	0表示黑色,1表示白色
	'''
	table = []
	for i in range(256):
		if i < threshold:
			table.append(0)
		else:
			table.append(1)
	return table

def main():
	image = Image.open('RandomPicture.png')
	imgry = image.convert('L')
	table = get_bin_table()
	binary = imgry.point(table, '1')
	width, height = binary.size
	lis = binary.getdata()	# 返回图片所有的像素值,要使用list()才能显示出具体数值
	lis = list(lis)
	start = 0
	step = width
	for i in range(height):
		for p in lis[start: start+step]:
			if p == 1:	# 将白色的点变成空格,方便人眼看
				p = ' '
			print p,
		print
		start += step

if __name__ == '__main__':
	main()

运行结果:

通过上面的结果已经大致可以看出该图片表示的就是“959c”。

3.去除噪点

由上面的结果也不难看出,除了表示“959c”的“0”,图片中还有其他的“0”代表的“噪点”,我们要尽可能的去除它们,方便后期的识别训练。

对于去除噪点,我这里也是借鉴了字符型图片验证码识别完整过程及Python实现里面的“九宫格”方法,代码实现:

# encoding=utf8

from PIL import Image

def sum_9_region_new(img, x, y):
	'''确定噪点 '''
	cur_pixel = img.getpixel((x, y)) # 当前像素点的值
	width = img.width
	height = img.height

	if cur_pixel == 1: # 如果当前点为白色区域,则不统计邻域值
		return 0

	# 因当前图片的四周都有黑点,所以周围的黑点可以去除
	if y < 3: # 本例中,前两行的黑点都可以去除
		return 1
	elif y > height - 3: # 最下面两行
		return 1
	else: # y不在边界
		if x < 3: # 前两列
			return 1
		elif x == width - 1: # 右边非顶点
			return 1
		else: # 具备9领域条件的
			sum = img.getpixel((x - 1, y - 1)) \
				 + img.getpixel((x - 1, y)) \
				 + img.getpixel((x - 1, y + 1)) \
				 + img.getpixel((x, y - 1)) \
				 + cur_pixel \
				 + img.getpixel((x, y + 1)) \
				 + img.getpixel((x + 1, y - 1)) \
				 + img.getpixel((x + 1, y)) \
				 + img.getpixel((x + 1, y + 1))
			return 9 - sum

def collect_noise_point(img):
	'''收集所有的噪点'''
	noise_point_list = []
	for x in range(img.width):
		for y in range(img.height):
			res_9 = sum_9_region_new(img, x, y)
			if (0 < res_9 < 3) and img.getpixel((x, y)) == 0: # 找到孤立点
				pos = (x, y)
				noise_point_list.append(pos)
	return noise_point_list

def remove_noise_pixel(img, noise_point_list):
	'''根据噪点的位置信息,消除二值图片的黑点噪声'''
	for item in noise_point_list:
		img.putpixel((item[0], item[1]), 1)

def get_bin_table(threshold=115):
	'''获取灰度转二值的映射table,0表示黑色,1表示白色'''
	table = []
	for i in range(256):
		if i < threshold:
			table.append(0)
		else:
			table.append(1)
	return table

def main():
	image = Image.open('RandomPicture.png')
	imgry = image.convert('L')
	table = get_bin_table()
	binary = imgry.point(table, '1')
	noise_point_list = collect_noise_point(binary)
	remove_noise_pixel(binary, noise_point_list)
	binary.save('finaly.png')

if __name__ == '__main__':
	main()

运行结果:

通过截图可以知道,我们已经去除了图片四周的噪点以及一些孤立的噪点。

还要再说一句的就是,除了上面的步骤,我们还可以通过PIL的ImageEnhance,和ImageFilter对图片做其他处理(例如增加对比度、亮度、锐化等),这里就不举例说明了,因为不同的图片经过这些处理后,可能效果会不同。

最后,要感谢这些博主的分享,为我学习验证码识别相关知识提供了不少参考:

字符型图片验证码识别完整过程及Python实现

Python3.5+sklearn 使用SVM自动识别字母验证码

python简单验证码识别

基于Python的PIL库学习(一)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • python使用pil生成图片验证码的方法

    本文实例讲述了python使用pil生成图片验证码的方法.分享给大家供大家参考.具体实现方法如下: # -*- coding: utf-8 -*- #导入三个模块 import Image,ImageDraw,ImageFont import random import math '''基本功能''' #图片宽度 width = 100 #图片高度 height = 40 #背景颜色 bgcolor = (255,255,255) #生成背景图片 image = Image.new('RGB',

  • Python+Selenium+PIL+Tesseract自动识别验证码进行一键登录

    本文介绍了Python+Selenium+PIL+Tesseract自动识别验证码进行一键登录,分享给大家,具体如下: Python 2.7 IDE Pycharm 5.0.3 Firefox浏览器:47.0.1 Selenium PIL Pytesser Tesseract 扯淡 ​ 我相信每个脚本都有自己的故事,我这个脚本来源于自己GRD教务系统,每次进行登录时,即使我输入全部正确,第一次登录一定是登不上去的!我不知道设计人员什么想法?难道是为了反爬机制?你以为一次登不上,我tm就不爬了?我

  • Python使用PIL模块生成随机验证码

    Python生成随机验证码,需要使用PIL模块,具体内容如下 安装: pip3 install pillow 基本使用 1. 创建图片 from PIL import Image img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255)) # 在图片查看器中打开 # img.show() # 保存在本地 with open('code.png','wb') as f: img.save(f,format='png') 2.

  • python PIL模块与随机生成中文验证码

    在这之前,你首先得了解Python中的PIL库.PIL是Python Imaging Library的简称,PIL是一个Python处理图片的库,提供了一系列模块和方法,比如:裁切,平移,旋转,改变尺寸等等.在PIL库中,任何一个图像都是用Image对象来表示的,所以要加载一张图片,最简单的形式如下: from PIL import Image image = Image.open("1.jpeg") 在PIL库中,最常用的模块有Image,ImageDraw,ImageEnhance

  • Python实现基于PIL和tesseract的验证码识别功能示例

    本文实例讲述了Python实现基于PIL和tesseract的验证码识别功能.分享给大家供大家参考,具体如下: 之前搞这个搞了一段时间,后面遇到了点小麻烦,导致识别率太低了,最多也就百分之20的样子.心灰意冷,弃了一段时间.上次在论坛看到一篇大牛的关于PIL对图片各种处理各种算法的博突然又想起了这个,又随便搞了下,大大提高了识别率啊.先给代码: 原图: im = Image.open("C:\Users\Administrator\Desktop\python\\3.png") #调色

  • Python使用PIL库实现验证码图片的方法

    本文实例讲述了Python使用PIL库实现验证码图片的方法.分享给大家供大家参考,具体如下: 现在的网页中,为了防止机器人提交表单,图片验证码是很常见的应对手段之一.这里就不详细介绍了,相信大家都遇到过. 现在就给出用Python的PIL库实现验证码图片的代码.代码中有详细注释. #!/usr/bin/env python #coding=utf-8 import random from PIL import Image, ImageDraw, ImageFont, ImageFilter _l

  • python3 pillow生成简单验证码图片的示例

    使用Python的pillow模块 random 模块随机生成验证码图片,并应用到Django项目中 安装pillow $ pip3 install pillow 生成验证码图片 \vericode.py from PIL import Image,ImageDraw,ImageFont,ImageFilter import random #随机码 默认长度=1 def random_code(lenght=1): code = '' for char in range(lenght): cod

  • python中使用PIL制作并验证图片验证码

    验证码制作 #string模块自带数字.字母.特殊字符变量集合,不需要我们手写集合 import string import random import os import uuid import settings from PIL import Image, ImageDraw, ImageColor, ImageFilter, ImageFont class Code(object): # 生成随机生成数字或字母 def random_hexdigits(self, len=1): retu

  • 使用python PIL库实现简单验证码的去噪方法步骤

    字符型图片验证码识别完整过程及Python实现的博主,我的大部分知识点都是从他那里学来的. 想要识别验证码,收集足够多的样本后,首先要做的就是对验证码原始图片进行处理,对验证码识别分类之前,一般包括:将彩色图片转换成灰度图.将灰度图二值化和去除噪点三个基本过程.这里仅以比较简单的验证码为例,介绍一下如何通过python的PIL库对图片去噪. 首先看一下未经处理的验证码图片: 对图片处理主要使用了PIL库的Image类. 1.彩色图片转换成灰度图 首先使用Image的open方法打开上面的图片,可

  • PHP 用session与gd库实现简单验证码生成与验证的类方法

    验证码是为了防止机器灌水给网站带来污染以及增加服务器负担而出现的.目前大大小小的网站都有验证码.今天自己实现了一个简单的验证码类.说简单是因为没有加一些干扰的弧线等等,只是将文字旋转了一下.当然,因为字体的原因,要想一眼看出来并不容易.同时,为了避免字母的大小写与数字混淆,又去掉了那些看起来很像的字母数字. 类: <?php /** *简单生成验证码类 */ class Captcha { private $width;//验证码宽度 private $height;//验证码高度 privat

  • python sklearn库实现简单逻辑回归的实例代码

    Sklearn简介 Scikit-learn(sklearn)是机器学习中常用的第三方模块,对常用的机器学习方法进行了封装,包括回归(Regression).降维(Dimensionality Reduction).分类(Classfication).聚类(Clustering)等方法.当我们面临机器学习问题时,便可根据下图来选择相应的方法. Sklearn具有以下特点: 简单高效的数据挖掘和数据分析工具 让每个人能够在复杂环境中重复使用 建立NumPy.Scipy.MatPlotLib之上 代

  • Python PIL库图片灰化处理

    2020年4月4日,是个特殊的日子,我们看到朋友圈很多灰化的图片.今天我们就聊聊图片灰度处理这事儿. PIL的基本概念: PIL中所涉及的基本概念有如下几个:通道(bands).模式(mode).尺寸(size).坐标系统(coordinate system).调色板(palette).信息(info)和滤波器(filters). PIL(Python Image Library)是python的第三方图像处理库,但是由于其强大的功能与众多的使用人数,几乎已经被认为是python官方图像处理库了

  • Python lxml库的简单介绍及基本使用讲解

    1.lxml库介绍 lxml是XML和HTML的解析器,其主要功能是解析和提取XML和HTML中的数据:lxml和正则一样,也是用C语言实现的,是一款高性能的python HTML.XML解析器,也可以利用XPath语法,来定位特定的元素及节点信息 HTML是超文本标记语言,主要用于显示数据,他的焦点是数据的外观 XML是可扩展标记语言,主要用于传输和存储数据,他的焦点是数据的内容 2.安装lxml方法 方法1: 在cmd运行窗口中输入:pip install lxml 方法2: 在Pychar

  • Python2.7+pytesser实现简单验证码的识别方法

    本文实例讲述了Python2.7+pytesser实现简单验证码的识别方法.分享给大家供大家参考,具体如下: 首先,安装Python2.7版本 然后,安装PIL工具,下载的地址是:http://www.pythonware.com/products/pil/,pytesser的使用需要PIL库的支持. 接着下载pytesser,下载的地址是:http://code.google.com/p/pytesser/downloads/list 由于code.google.com网站无法访问.可点击此处

  • python根据出生年份简单计算生肖的方法

    本文实例讲述了python根据出生年份简单计算生肖的方法.分享给大家供大家参考.具体分析如下: 这里使用python根据出生年份计算生肖,看了代码会发现原来这么简单 #计算生肖 def ChineseZodiac(year): return u'猴鸡狗猪鼠牛虎兔龙蛇马羊'[year%12] ChineseZodiac(1990) 希望本文所述对大家的Python程序设计有所帮助.

  • python中for语句简单遍历数据的方法

    本文实例讲述了python中for语句简单遍历数据的方法.分享给大家供大家参考.具体如下: 复制代码 代码如下: for name in ["kak", "John", "Mani", "Matt"]:    print(name) 运行结果如下: 复制代码 代码如下: kak John Mani Matt 希望本文所述对大家的Python程序设计有所帮助.

  • python使用socket进行简单网络连接的方法

    本文实例讲述了python使用socket进行简单网络连接的方法.分享给大家供大家参考.具体如下: import socket print "Creating socket...", s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print "done." print "Connecting to www.jb51.net", s.connect(("www.jb51.net

  • 利用PHP绘图函数实现简单验证码功能的方法

    index.php <?php //===================================>>使用绘图技术绘制验证码 //1.随机产生4个随机数 $checkCode=""; for ($i=0;$i<4;$i++){ $checkCode.=dechex(rand(1, 15));// decheck()十进制转换为十六进制,即验证码上要显示的数字 } //2.存入列 session_start(); $_SESSION['checkCode'

随机推荐