用python的图像库生成验证码

用python的图像库生成验证码

验证码是指全自动区分计算机和人类的公开图灵测试(英语:Completely Automated Public Turing test to tell Computers and Humans Apart,是一种区分用户是计算机或人的公共全自动程序。在CAPTCHA测试中,作为服务器的计算机会自动生成一个问题由用户来解答。这个问题可以由计算机生成并评判,但是必须只有人类才能解答。由于计算机无法解答CAPTCHA的问题,所以回答出问题的用户就可以被认为是人类

原理

  • 验证码是将一串随机产生的数字或符号,生成一幅图片,图片上加上干扰元素,用户识别图片中的信息提交网站验证。在本文中,利用random和string模块生成随机字符串和随机背景色
  • PIL是python的图像处理库,功能强大,其中ImageDraw模块可用来在已有图像上创作,本文就使用此方法添加干扰元素

过程

1. 导入需要的库

from PIL import Image,ImageDraw,ImageFont,ImageFilter
import random
import string

2. 创建Captcha类,这个类主要包含以下内容:

  • 属性:

    • 验证码的背景大小
    • 验证码的背景颜色
    • 验证码字符串的大小
    • 验证码字符串的颜色
  • 方法:

    • _center_coords用背景大小减去字体大小除以二,找出验证码中字体应该放在什么位置(居中)
    • _add_noise_dots给验证码添加圆点噪声
    • _add_noise_lines给验证码添加直线和弧线噪声
    • _random_text获得字母和数字随机组合的7位字符串
    • _random_color在(0,0,0)到(255,255,255)中随机生成一种颜色
    • trans对得到的验证码进行扭曲变化
    • get_captcha调用以上方法生成验证码

3. 创建Captcha对象,调用get_captcha生成验证码

函数详细代码

扭曲函数

def trans(self):
  self.image = self.image.transform((self.size[0],self.size[1]), Image.AFFINE,
  (1,-0.2,0,0.2,1,0.2))
    for i in range(self.size[0]):
        for j in range(self.size[1]):
            data = self.image.getpixel((i, j))
            if data == (0, 0, 0):
                self.image.putpixel((i, j), self.bgcolor)
    return self.image
    

image.transform利用仿射函数对得到的验证码进行扭曲,但扭曲后的图像背景有一部分是黑色的:

直接扭曲后的图片

为了解决这个问题,在函数中增加了for循环,按像素级遍历颜色,把黑色填充为背景色

生成验证码函数


def get_captcha(self,size=None,text=None,bgcolor=None):
    
    #一系列检查是否为空操作
    if text is not None:
        self.text=text
    if size is not None:
        self.size=size
    if bgcolor is not None:
        self.bgcolor=bgcolor
    
    #新建一张图片
    self.image=Image.new("RGB",self.size,self.bgcolor)
    
    #设置字体样式和大小
    font=ImageFont.truetype("D:\source\Consolas.ttf", 
                       self.fontsize)
    
    #在新建的图像上创建draw对象用来绘制验证码
    draw=ImageDraw.Draw(self.image)
    
    #获取字体位置(居中)
    xy = self._center_coords(draw, font)
    
    #把随机获得的字符串画到图像上
    draw.text(xy=xy,text=self.text,font=font,fill=self._random_color())
    
    #进行扭曲变换
    draw=ImageDraw.Draw(self.trans())
    
    #添加噪声
    draw=self._add_noise_dots(draw)
    draw=self._add_noise_lines(draw)
    
    #添加模糊滤镜
    self.image=self.image.filter(ImageFilter.BLUR)
    
    self.image.show()
    return self.image,self.text

结果

得到的验证码

有待改进

因为验证码背景和字体的颜色都是随机生成的,有时可能两个颜色搭配不协调,或者对比度不够强不好分辨,如下图:

背景色和字体颜色对比不明显的验证码

考虑可以加一个函数,判断背景和字体颜色是否相近,如果相近,就重新生成验证码

posted @ 2020-03-13 21:25  iClaire  阅读(825)  评论(0)    收藏  举报