用PIL实现带旋转字符的验证码生成

在学习PIL中,我们可能会去生成随机字符验证码,添加直线、选字符这些都是比较简单的操作,但如何将我们随机生成的字符旋转起来,是相较复杂一点的。就我目前了解,可以使用numpy的数组操作,或是直接用opencv解决。本文主要通过PIL的模块对字符实现旋转,主要方法是Image.composite(),建议大家可以先了解一下这个方法。
目前,PIL中的rotate方法只能针对图片进行操作,而ImageDraw中的text()方法不能控制字符的方向。所以我的思路是,将字符旋转后的图片设为RGBA模式,将alpha通道设置为比较小的数,以此在合成图片时,字符以外的背景不会覆盖之前生成的字符。通过循环将旋转后的字符图片依次放入一张白色背景的图,每次生成的旋转图作为下一次合成的背景板,这样我们就得到了一张“RGBA”格式的旋转字符图。
第一次调用composite方法生成旋转后背景矩形被填充为白色的图片
经过循环将验证码的字符依次填充,可以实现重叠,只是我这次结果没有重叠
之后,我们生成一张背景马赛克图。

将字符图转化为“RGB”模式,将马赛克背景图“覆盖到”字符图上,效果如下:

详细代码:

from PIL import Image,ImageDraw,ImageFont
import numpy as np
import random


def randomchar():
    a = chr(random.randint(65,90))
    b = chr(random.randint(97,122))
    c = str(random.randint(0,9))
    return random.choice([a,b,c])

def randomcolor():#随机设置某一背景像素点的颜色
    return (random.randint(0,255),
            random.randint(0,255),
            random.randint(0,255))

def randomcolor2():#随机设置验证码字符或干扰直线的颜色
    return (random.randint(80,255),
            random.randint(80,255),
            random.randint(80,255))
def randomcolor_light():#返回比较亮的颜色
    return (random.randint(123,255),
            random.randint(123,255),
            random.randint(123,255))
def randomcolor_dark():#返回比较暗的颜色
    return (random.randint(0,100),
            random.randint(0,100),
            random.randint(0,100))


def randomline(img,n):#在图上任意位置画n条线
    draw = ImageDraw.Draw(img)
    for i in range(n):
        draw.line((random.randint(0,img.width-1),random.randint(0,img.height-1),
                   random.randint(0,img.width-1),random.randint(0,img.height-1)),
                  fill=randomcolor2(),width=2)
    return img


font = ImageFont.truetype("msyh.ttc",40)#设置显示的字符字体,需要将对应的字体文件放到同级目录



mask2 = Image.fromarray(np.uint8(np.random.uniform(0,255,(214,214,3))))

distance = 0
mask = Image.new("RGBA",(240,240),(255,255,255,0))
for i in range(4):
    s_background = Image.new("RGBA",(240,60),(255,255,255,0))#alpha通道设为0,保证透明度
    s_draw = ImageDraw.Draw(s_background)
    s_draw.text((5+distance,5),randomchar(),font=font,fill=randomcolor_dark())
    s_rotate = s_background.rotate(random.randint(-60,60),expand=1)#图像会转动随机的角度
    
    mask.resize(s_rotate.size)
    
    out1 = Image.composite(s_rotate, mask, s_rotate)#第一次复合生成的图片是旋转后去黑色背景图片
    mask = out1
    distance = distance+random.randint(-30,30)+50#修改下次字符绘画的初始位置
    
   

out1 = out1.convert("RGB")
mask2.resize(out1.size)
r,g,b = mask2.split()
out2 = Image.composite(mask2,out1,r)#将我们生成的随机马赛克图片覆盖到旋转字符图片上去
out2 = randomline(out2,4)
out2.show()

总结:单用PIL可以,但是存在一些明显的缺点,1.在合成最终图片时,马赛克背景某一颜色通道会消失(存疑),导致最后背景效果不好。2.由于我们用的是composite方法,最后字符上会存留背景的像素点(机器更难识别?),而且该方法需要我们合成的两张图片大小一致,所以整张图的大小会随着循环的变化而变化,一般情况下,字符不会在同一水平位置,用numpy数组操作可以改进。3.当字符颜色较亮时,可能会很难识别出验证码。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值