Python 生成手写体数字数据集

0.引言

平时上网干啥的基本上都会接触验证码,或者在机器学习学习过程中,大家或许会接触过手写体识别/验证码识别之类问题,会用到手写体的数据集;

自己尝试写了一个生成手写体图片的python程序,在此分享下生成单张30*30像素的手写体数字1-9图像的一种实现方法;

我是利用random生成随机数1-9,然后PIL写到图像上,然后经过旋转扭曲处理,得到“手写体”,这里没有加干扰线和干扰点,然后根据手写体的数值存入对应文件夹1-9构成数据集;

得到的手写体数字图像如图1所示;

实现比较简单,用了PIL库,不需要额外安装opencv啥的,有兴趣可以自己试试;

除了生成手写体数字之后,字母/汉字稍加改动也可以生成(适用于生成单个字符):

图1 生成的手写体数字1-9

图2 利用generate_single_png.py生成汉字的手写体

图3 利用generate_pngs.py写入到相应文件夹3的数字3图像

源码上传到了我的GitHub:

https://github.com/coneypo/Generate_handwritten_number

1.设计流程

    图4 整体设计流程

图5 生成的图像经过的处理

1.1 新建一个空白图像img_50,尺寸大小为50*50

1img_50_blank = Image.new('RGB', (50, 50), (255, 255, 255))

为什么我这里要先生成50*50的空白图像?

因为图像背景(50*50像素的画布)初始化的时候设置为白色(颜色数组(255, 255, 255)),而背景色之外的其实是黑色;

之后需要进行旋转处理,如果直接新建30*30像素的画布,旋转之后边上会出现黑边,如图6所示;

所以我新建了一个50*50,然后旋转之后从中间裁出来一个30*30的图像出来;

图6 直接用30*30像素的画布写字旋转(会出现黑边)

1.2 利用PIL在图像上写文字

利用PIL的ImageDraw,创建画笔,然后利用draw.text在指定位置写字;

xy=(18,11)是从图像左上角开始的坐标,取值自己根据需求调整;

1# 创建画笔

2draw =ImageDraw.Draw(img_50_blank)

3

4# 生成随机数1-9

5num = str(random.randint(1, 9))

6

7# 设置字体,这里选取字体大小25

8font = ImageFont.truetype('simsun.ttc', 20)

9

10# xy是左上角开始的位置坐标11draw.text(xy=(18, 11), font=font, text=num, fill=(0, 0, 0))

1.3 将图像随机旋转一定角度

利用 rotate(angel) 进行旋转图像,angel取的是度数,这里让它随机旋转-10到+10度:

1# 随机旋转-10-10角度

2random_angle = random.randint(-10, 10)

3img_50_rotated = img_50_blank.rotate(random_angle)

1.4 图像扭曲

 这里是生成“手写体”数字的核心步骤,一个正常的图像经过扭曲之后就可以得到想要的验证码了:

1# 图形扭曲参数

2params = [1 - float(random.randint(1, 2)) / 100,

30,

40,

50,

61 - float(random.randint(1, 10)) / 100,

7float(random.randint(1, 2)) / 500,

80.001,

9float(random.randint(1, 2)) / 500]

10

11# 创建扭曲

12img_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# 2018-01-29

2# By TimeStamp

3# cnblogs: http://www.cnblogs.com/AdaminXie/

4# generate_folders_1to9.py

5# 在目录下生成用来存放数字1-9的9个文件夹,分别用1-9命名

6

7

8importos

9

10path_folders ="F:/***/data_pngs/"

11

12# 1-9

13foriinrange(49,58):

14if(os.path.isdir(path_folders +chr(i))):

15pass

16else:

17# print(i,": ",path_1+chr(i))

18# 生成目录

19os.mkdir(path_folders+chr(i))

图7 自动生成的用来存放指定图像的文件夹

2.2generate_pngs.py

根据给定随机次数samples,生成samples个手写体数字1-9,然后存放到本地文件夹1-9生成数据集;

在49行可以修改生成图像的大小,我这里取的是30*30像素;

1# 2018-01-29

2# By TimeStamp

3# cnblogs: http://www.cnblogs.com/AdaminXie/

4# generate_pngs.py

5# 生成手写体数字

6

7

8importrandom

9fromPILimportImage, ImageDraw, ImageFilter, ImageFont

10

11random.seed(3)

12

13# 生成单张扭曲的数字图像

14defgenerate_single():

15

16# 先绘制一个50*50的空图像

17img_50_blank = Image.new('RGB', (50, 50), (255, 255, 255))

18

19# 创建画笔

20draw =ImageDraw.Draw(img_50_blank)

21

22# 生成随机数1-9

23num = str(random.randint(1, 9))

24

25# 设置字体,这里选取字体大小25

26font = ImageFont.truetype('simsun.ttc', 20)

27

28# xy是左上角开始的位置坐标

29draw.text(xy=(18, 11), font=font, text=num, fill=(0, 0, 0))

30

31# 随机旋转-10-10角度

32random_angle = random.randint(-10, 10)

33img_50_rotated =img_50_blank.rotate(random_angle)

34

35# 图形扭曲参数

36params = [1 - float(random.randint(1, 2)) / 100,

370,

380,

390,

401 - float(random.randint(1, 10)) / 100,

41float(random.randint(1, 2)) / 500,

420.001,

43float(random.randint(1, 2)) / 500]

44

45# 创建扭曲

46img_50_transformed = img_50_rotated.transform((50, 50), Image.PERSPECTIVE, params)

47

48# 生成新的30*30空白图像,(在此处可以更改生成的图像大小)

49img_30 = img_50_transformed.crop([10, 10, 40, 40])

50

51returnimg_30, num

52

53path_pic ="F:/***/P_generate_handwritten_number/data_pngs/"545556# 生成手写体数字1-9存入指定文件夹1-9

57

58# 用cnt_num[1]-cnt_num[9]来计数数字1-9生成的个数,方便之后进行命名

59cnt_num =[]

60foriinrange(10):

61cnt_num.append(0)

62

63# 生成次数64samples = 20065

66forminrange(1, samples+1):

67

68# 调用生成图像文件函数

69img, generate_num =generate_single()

70

71# 取灰度

72imgray = img.convert('1')

73

74# 计数生成的数字1-9的个数,用来命名图像文件

75forjinrange(1, 10):

76if(generate_num ==str(j)):

77cnt_num[j] = cnt_num[j]+1

78

79# 路径如"F:/code/***/data_pngs/1/1_231.png"

80# 输出显示路径

81print(path_pic + str(j) +"/"+ str(j) +"_"+ str(cnt_num[j]) +".png")

82# 将图像保存在指定文件夹中

83imgray.save(path_pic + str(j) +"/"+ str(j) +"_"+ str(cnt_num[j]) +".png")

84

85# 输出显示1-9的分布

86print("\n","生成的1-9的分布:")

87forkinrange(9):

88print(k+1,":", cnt_num[k+1],"张")

output:

D:\***\anaconda\python.exe F:/***/P_generate_handwritten_number/generate_pngs.pyF:/***/P_generate_handwritten_number/data_pngs/4/4_1.pngF:/***/P_generate_handwritten_number/data_pngs/1/1_1.pngF:/***/P_generate_handwritten_number/data_pngs/8/8_1.pngF:/***/P_generate_handwritten_number/data_pngs/3/3_1.pngF:/***/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.3 generate_single_png.py

更改27行的char=" "(可以是数字/字母/汉字),生成单张手写体扭曲图像:

1# 2018-01-29

2# By TimeStamp

3# cnblogs: http://www.cnblogs.com/AdaminXie/

4# generate_single_png.py

5# 生成手写体数字/字母/汉字

6

7

8importrandom

9fromPILimportImage, ImageDraw, ImageFilter, ImageFont

10

11random.seed(3)

12

13# 生成单张扭曲的数字图像

14defgenerate_single():

15

16# 先绘制一个50*50的空图像

17img_50_blank = Image.new('RGB', (50, 50), (255, 255, 255))

18

19# 创建画笔

20draw =ImageDraw.Draw(img_50_blank)

21

22# 设置字体,这里选取字体大小25

23font = ImageFont.truetype('simsun.ttc', 20)

24

25# xy是左上角开始的位置坐标

26# text是你想要显示的内容,数字/字母/汉字

27char ="呵"

28draw.text(xy=(12, 11), font=font, text=char, fill=(0, 0, 0))

29

30# 随机旋转-10-10角度

31random_angle = random.randint(-10, 10)

32img_50_rotated =img_50_blank.rotate(random_angle)

33

34# 图形扭曲参数

35params = [1 - float(random.randint(1, 2)) / 100,

360,

370,

380,

391 - float(random.randint(1, 10)) / 100,

40float(random.randint(1, 2)) / 500,

410.001,

42float(random.randint(1, 2)) / 500]

43

44# 创建扭曲

45img_50_transformed = img_50_rotated.transform((50, 50), Image.PERSPECTIVE, params

46

47# 生成新的30*30空白图像

48img_30 = img_50_transformed.crop([10, 10, 40, 40])

49

50returnimg_30, char

51

52path_pic ="F:/***/P_generate_handwritten_number/"

53

54

55# 调用生成图像文件函数

56img, generated_char =generate_single()

57imgray = img.convert('1')

58

59print(path_pic +"test.png")

60# 将图像保存在指定文件夹中

61imgray.save(path_pic +"test.png")

2.4 del_pngs.py

删除指定目录下子文件夹1-9中的所有图片:

1# 2018-01-29

2# By TimeStamp

3# cnblogs: http://www.cnblogs.com/AdaminXie/

4# del_pngs.py

5# 删除路径下生成的图像文件

6

7importos

8

9path_pic ="F:/***/data_pngs/"

10

11#删除路径下的图片

12defdel_pic():

13foriinrange(1, 10):

14# print(path_png+chr(i))

15namedir = os.listdir(path_pic+str(i))

16

17fortmppnginnamedir:

18if( tmppnginnamedir):

19# print(tmppng)

20os.remove(path_pic+str(i)+"/"+tmppng)

21

22del_pic()

3.总结

自己动手丰衣足食,有兴趣可以自己做手写体数字数据集,字母和汉字的数据集稍加修改也可以做;

# 源码上传到了我的GitHub,如果对你有帮助欢迎star:

https://github.com/coneypo/Generate_handwritten_number

# 请尊重他人劳动成果,转载或者使用源码请注明出处

http://www.cnblogs.com/AdaminXie/

# 交流学习可以联系本人邮箱

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20180130G19LIW00?refer=cp_1026

扫码关注云+社区