Discuss / Python / PIL生成防君子不防大学生的图片验证码,请问文字扭曲的效果怎么实现?

PIL生成防君子不防大学生的图片验证码,请问文字扭曲的效果怎么实现?

Topic source

看到评论里有朋友问旋转字符的事情,我查了PIL的文档,摸索出了文字旋转的效果. 我们例程里验证码图片的背景是由杂色构成,然后再用ImageDraw在上方进行draw.text().

我做旋转字符的思路是,首先单独做一个透明的背景层,然后在这个透明的层上写字. 然后再从这个透明的层上切出各个字符,旋转,扭曲(扭曲不会做)一下,最后粘贴到原本的杂色背景层上.

from PIL import Image,ImageDraw,ImageFont,ImageFilter
import random,math,copy

char_width=40
width=char_width*4
height=40

samples='ABCDEFGHJKLMNPRSTUVWXYabcdefghjkmnpqrtuvwxy34578'

def sampling():
    global sample
    sample=random.sample(samples,4)

def randChar():
    global sample
    return sample.pop()

def randColor():
    return (random.randint(64,255),random.randint(64,255),random.randint(64,255))

def randColor2():
    return (random.randint(32,127),random.randint(32,127),random.randint(32,127))

def regular_start_position(i):
    sign=1
    if random.randint(0,100) > 60:
        sign=-1
    start=char_width*i+random.randint(5,15)*sign
    if start-10<0:
        start=random.randint(1,5)
    elif start+char_width+10>width:
        start=width-char_width-random.randint(1,5)
    return (start,random.randint(-10,0))

def twist(img): #不会写
    pass

def gen_bg():
    img_bg=Image.new('RGBA',(width,height),(255,255,255,255))
    draw=ImageDraw.Draw(img_bg)
    for x in range(width):
        for y in range(height):
            draw.point((x,y),fill=randColor())
    return img_bg

def rotate(img,deg_left,deg_right):
    return img.rotate(random.randint(deg_left,deg_right),expand=False)

def gen_captcha_img():
    sampling()
    text_layer=Image.new('RGBA',(width,height),(255,255,255,0)) #创建文字透明层
    draw=ImageDraw.Draw(text_layer)
    for t in range(4):#在透明层写字
        font=ImageFont.truetype('path/dejavu.ttf',random.randint(40,48))
        draw.text((char_width*t,0),randChar(),font=font,fill=randColor2())
    img_bg=gen_bg()#创建杂色背景层
    for  t in range(4):
        box=(char_width*t,0,char_width*(t+1),height)
        region=text_layer.crop(box) #从文字层上切文字
        region=rotate(region,-30,30) #把切出的文字旋转一下
        #region=twist(region)
        *drop,alpha=region.split() #取出alpha通道备用,我也不知道为什么会这样
        img_bg.paste(region,regular_start_position(t),mask=alpha) #这里不传alpha通道进来,文字切片的周围透明部分会显示成黑色

    img_bg=img_bg.filter(ImageFilter.BLUR)
    #img_bg.show()
    img_bg.save('savepath/captcha.jpg','jpeg')


gen_captcha_img()

哪位朋友实现了文字扭曲效果的,麻烦指导一下.

运行没有错误但验证码不出现,代码是和老师的一模一样的

@我要换一个谁都不知道的昵称 写代码也得讲基本法呀. 一模一样的代码,运行没有错误,人家生成了验证码,你的没有. 那你是起诉你的电脑制造商了.

import math
def twist(img): #图像扭曲填坑
    src_img=img.copy() #将原始图像复制一个副本,这是关键。开始的时候忘记将原始像素复制出来一份,下边的代码里在原始像素里覆盖来覆盖去,总是没有满意的效果,我还以为公式写错了。
    cycle=2.5 #sin函数2*PI一个周期,这里设置要整几个周期
    y_amp=3 #y跟随正弦曲线变化的幅度,4就不少了。在本例中5像素以上数字会碎。
    for y in range(0,height):
        for x in range(0,char_width):
            new_y=y+round(math.sin(x*2*math.pi*cycle/char_width)*y_amp)
            #三角函数是高中学的,(x/char_width*2*pi)代表(x/char_width)个周期,这样就把像素坐标(x,y)的变化与正弦曲线扯上了关系.
            if new_y < height and new_y > 0:
                img.putpixel((x,new_y),src_img.getpixel((x,y))) 
    return img

我试了下,效果还是有的。 小伙伴们用的时候,自行调整扭曲,旋转 ,粘连,模糊到你满意就可以啦.


  • 1

Reply