0.引言
平时上网干啥的基本上都会接触验证码,或者在机器学习学习过程中,大家或许会接触过手写体识别/验证码识别之类问题,会用到手写体的数据集;
自己尝试写了一个生成手写体图片的python程序,在此分享下生成单张30*30像素的手写体数字1-9图像的一种实现方法;
我是利用random生成随机数1-9,然后PIL写到图像上,然后经过旋转、扭曲处理,得到“手写体”,这里没有加干扰线和干扰点;
得到的手写体数字图像如图1所示;
实现比较简单,用了PIL库,不需要额外安装opencv啥的,有兴趣可以自己试试。
图1 生成的手写体数字1-9
图2 文件夹3下生成的数字3图像
1.设计流程
图3 整体设计流程
1.1 新建一个空白图像img_50,尺寸大小为50*50
1 img_50_blank = Image.new('RGB', (50, 50), (255, 255, 255))
为什么我这里要先生成50*50的空白图像?
因为图像背景(50*50像素的画布)初始化的时候设置为白色(颜色数组(255, 255, 255)),而背景色之外的其实是黑色;
之后需要进行旋转处理,如果直接新建30*30像素的画布,旋转之后边上会出现黑边,如图4所示;
所以我新建了一个50*50,然后旋转之后从中间裁出来一个30*30的图像出来;
图4 直接用30*30像素的画布写字旋转(会出现黑边)
1.2 利用PIL在图像上写文字
利用PIL的ImageDraw,创建画笔,然后利用draw.text在指定位置写字;
xy=(18,11)是从图像左上角开始的坐标,取值自己根据需求调整;
1 #创建画笔
2 draw =ImageDraw.Draw(img_50_blank)3
4 #生成随机数1-9
5 num = str(random.randint(1, 9))6
7 #设置字体,这里选取字体大小25
8 font = ImageFont.truetype('simsun.ttc', 20)9
10 #xy是左上角开始的位置坐标
11 draw.text(xy=(18, 11), font=font, text=num, fill=(0, 0, 0))
1.3 将图像随机旋转一定角度
利用 rotate(angel) 进行旋转图像,angel取的是度数,这里让它随机旋转-10到+10度:
1 #随机旋转-10-10角度
2 random_angle = random.randint(-10, 10)3 img_50_rotated = img_50_blank.rotate(random_angle)
1.4 图像扭曲
这里是生成“手写体”数字的核心步骤,一个正常的图像经过扭曲之后就可以得到想要的验证码了:
1 #图形扭曲参数
2 params = [1 - float(random.randint(1, 2)) / 100,3 0,4 0,5 0,6 1 - float(random.randint(1, 10)) / 100,7 float(random.randint(1, 2)) / 500,8 0.001,9 float(random.randint(1, 2)) / 500]10
11 #创建扭曲
12 img_50_transformed = img_50_rotated.transform((50, 50), Image.PERSPECTIVE, params)
2.py源码介绍
2.1 generate_folders_1to9.py
因为我们要将指定的图像分类放入指定文件夹,所以我们需要先在项目目录下面新建9个文件夹:
(当然你也可以自己新建,新建9个文件夹工作量还不大,但是如果要生成的验证码包含英文字母那就比较多了,大写A-Z共24个+小写a-z共24个+数字1-9共9个=57个子文件夹)
1 #-01-9
2 #By TimeStamp
3 #cnblogs: /AdaminXie/
4 #generate_folders_1to9.py
5 #在目录下生成用来存放数字1-9的9个文件夹,分别用1-9命名
6
7
8 importos9
10 path_folders = "F:/***/P_generate_handwritten_number/data_pngs/"
11
12 #1-9
13 for i in range(49,58):14 if (os.path.isdir(path_folders +chr(i))):15 pass
16 else:17 #print(i,": ",path_1+chr(i))
18 #生成目录
19 os.mkdir(path_folders+chr(i))
图5 自动生成的用来存放指定图像的文件夹
2.2generate_pngs.py
生成手写体数字,然后存放到本地文件夹1-9:
1 #-01-9
2 #By TimeStamp
3 #cnblogs: /AdaminXie/
4 #generate_pngs.py
5 #生成手写体数字
6
7
8 importrandom9 from PIL importImage, ImageDraw, ImageFilter, ImageFont10
11 random.seed(3)12
13 #生成单张扭曲的数字图像
14 defgenerate_single():15
16 #先绘制一个50*50的空图像
17 img_50_blank = Image.new('RGB', (50, 50), (255, 255, 255))18
19 #创建画笔
20 draw =ImageDraw.Draw(img_50_blank)21
22 #生成随机数1-9
23 num = str(random.randint(1, 9))24
25 #设置字体,这里选取字体大小25
26 font = ImageFont.truetype('simsun.ttc', 20)27
28 #xy是左上角开始的位置坐标
29 draw.text(xy=(18, 11), font=font, text=num, fill=(0, 0, 0))30
31 #随机旋转-10-10角度
32 random_angle = random.randint(-10, 10)33 img_50_rotated =img_50_blank.rotate(random_angle)34
35 #图形扭曲参数
36 params = [1 - float(random.randint(1, 2)) / 100,37 0,38 0,39 0,40 1 - float(random.randint(1, 10)) / 100,41 float(random.randint(1, 2)) / 500,42 0.001,43 float(random.randint(1, 2)) / 500]44
45 #创建扭曲
46 img_50_transformed = img_50_rotated.transform((50, 50), Image.PERSPECTIVE, params)47
48 #生成新的30*30空白图像
49 img_30 = img_50_transformed.crop([10, 10, 40, 40])50
51 returnimg_30, num52
53 path_pic = "F:/***/P_generate_handwritten_number/data_pngs/"
54
55
56 #生成手写体数字1-9存入指定文件夹1-9
57
58 #用cnt_num[1]-cnt_num[9]来计数数字1-9生成的个数,方便之后进行命名
59 cnt_num =[]60 for i in range(10):61 cnt_num.append(0)62
63 #生成次数
64 samples = 200
65
66 for m in range(1, samples+1):67
68 #调用生成图像文件函数
69 img, generate_num =generate_single()70
71 #取灰度
72 imgray = img.convert('1')73
74 #计数生成的数字1-9的个数,用来命名图像文件
75 for j in range(1, 10):76 if(generate_num ==str(j)):77 cnt_num[j] = cnt_num[j]+1
78
79 #路径如 "F:/code/***/P_generate_handwritten_number/data_pngs/1/1_231.png"
80 #输出显示路径
81 print(path_pic + str(j) + "/" + str(j) + "_" + str(cnt_num[j]) + ".png")82 #将图像保存在指定文件夹中
83 imgray.save(path_pic + str(j) + "/" + str(j) + "_" + str(cnt_num[j]) + ".png")84
85 #输出显示1-9的分布
86 print("\n", "生成的1-9的分布:")87 for k in range(9):88 print(k+1, ":", cnt_num[k+1], "张")
output:
D:\***\anaconda\python.exe F:/***/P_generate_handwritten_number/generate_pngs.py
F:/***/P_generate_handwritten_number/data_pngs/4/4_1.png
F:/***/P_generate_handwritten_number/data_pngs/1/1_1.png
F:/***/P_generate_handwritten_number/data_pngs/8/8_1.png
F:/***/P_generate_handwritten_number/data_pngs/3/3_1.png
F:/***/P_generate_handwritten_number/data_pngs/1/1_2.png
...
生成的1-9的分布:1 : 25张2 : 17张3 : 21张4 : 19张5 : 20张6 : 22张7 : 25张8 : 24张9 : 27 张
修改 generate_pngs.py中的samples你就可以生成自己想要的数据集大小。
2.3del_pngs.py
删除指定目录下子文件夹1-9中的所有图片:
1 #-01-9
2 #By TimeStamp
3 #cnblogs: /AdaminXie/
4 #del_pngs.py
5 #删除路径下生成的图像文件
6
7 importos8
9 path_pic = "F:/***/P_generate_handwritten_number/data_pngs/"
10
11 #删除路径下的图片
12 defdel_pic():13 for i in range(1, 10):14 #print(path_png+chr(i))
15 namedir = os.listdir(path_pic+str(i))16
17 for tmppng innamedir:18 if( tmppng innamedir):19 #print(tmppng)
20 os.remove(path_pic+str(i)+"/"+tmppng)21
22 del_pic()
3.总结
自己动手丰衣足食,有兴趣可以自己做手写体数字数据集;
# 交流学习可以联系邮箱 coneypo@