Problem: 使用 Python 生成类似于下图中的字母验证码图片。

Solution: Generate CAPTCHA, Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# @Date : 2015-03-19 10:46:23
# @Author : NSSimacer
# @Version : 1.0
import string
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
def generate_captcha(image_mode='RGB',
image_type='gif',
image_size=(240, 60),
image_bg_color=(150, 160, 160),
captcha_text=None,
font_size=36,
font='YaHei.Consolas.1.11b.ttf',
draw_lines=True,
draw_points=True,
line_nums=(5, 8)):
'''
生成验证码
'''
image = Image.new( # 创建 Image 对象
image_mode,
image_size,
image_bg_color)
image_width, image_height = image_size
draw = ImageDraw.Draw(image) # 创建 ImageDraw 对象
font = ImageFont.truetype(font, font_size) # 创建 ImageFont 对象
def draw_lines(draw):
'''
添加干扰线
'''
line_n = random.randint(*line_nums)
for i in xrange(line_n):
start_point = (random.randint(0, image_width),
random.randint(0, image_height))
end_point = (random.randint(0, image_width),
random.randint(0, image_height))
# 画线
draw.line([start_point, end_point], fill=(generate_channel(),
generate_channel(),
generate_channel()))
def draw_points(draw):
'''
添加干扰点
'''
point_n = random.randint(500, 1000)
for i in xrange(point_n):
draw.point((random.randint(0, image_width),
random.randint(0, image_height)),
fill=(generate_channel(),
generate_channel(),
generate_channel()))
def generate_channel():
'''
产生颜色通道值
'''
return random.randint(0, 255)
def generate_chars(length=4):
'''
产生验证码字符
'''
letters = list(string.letters)
chars = ''
for i in xrange(length):
chars += random.choice(letters)
return chars
captcha_text = generate_chars(4)
for index, char in enumerate(captcha_text): # 画出验证码的每个字符
font_color = (generate_channel(),
generate_channel(),
generate_channel())
draw.text(
(image_width / 4 + index * font_size * random.uniform(0.5, 0.9),
random.randint(0, (image_height - font_size) / 4)),
char,
font=font,
fill=font_color)
if draw_lines:
draw_lines(draw)
if draw_points:
draw_points(draw)
del draw
# 图像变换参数,比如:如果参数是一个 8 元组,参数是 PERSPECTIVE代表从图像中 (ax + by + c)/(gx + hy + 1), (dx + ey + f)/(gx + hy + 1) 位置取出的值作为新图像 (x, y) 位置的值
params = [0.99, 0, 0, 0, 0.99, 0.02, 0.01, 0.02]
image = image.transform(image_size, Image.AFFINE, params) # 仿射效果
image = image.filter(ImageFilter.SMOOTH_MORE) # 添加滤镜
image.save('captcha_01.gif', quality=100, optimize=True, progressive=True)
if __name__ == '__main__':
generate_captcha()

这道题主要练习 Python 图像库 PIL 的基本 API 的使用。

生成一个字母验证码图片的大致流程 —— 产生验证码字符 generate_chars(self, args),新建图像 Image.new(self, args) ,设置图像参数,比如图像尺寸,字体,图像背景等等,将字符写到图片上 draw.text(self, args),添加干扰线或干扰点 draw.line(self, args)/point(self, args) ,根据需要,再对图像进行一些变换 image.transform(self, args),比如:仿射 Image.AFFINE 或者扭曲 Image.PERSPECTIVE,添加滤镜 image.filter(self, args),比如:平滑 ImageFilter.SMOOTH_MORE,高斯模糊 ImageFilter.GaussianBlur 等操作,最后保存生成的验证码图片 image.save(self, args)

更多详细的 PIL API,请参考:Python Imaging Library Handbook 或者 Pillow — Pillow v2.7.0 (PIL fork).

题目来源:Python 练习册,每天一个小程序 THX!