Python 3 生成手写体数字数据集

0.引言

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

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

  我是利用random生成随机数1-9,然后PIL写到图像上,然后经过旋转扭曲处理,得到“手写体”,这里没有加干扰线和干扰点;

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

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

  

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

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

  如果你想生成手写体的字母/汉字也可以:

  

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

  源码上传到了我的GitHub: https://github.com/coneypo/Generate_handwritten_number

1.设计流程

    图4 整体设计流程

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

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像素的画布,旋转之后边上会出现黑边,如图6所示;

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

  

 图6 直接用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 # 2018-01-9
 2 # By TimeStamp
 3 # cnblogs: http://www.cnblogs.com/AdaminXie/
 4 # generate_folders_1to9.py
 5 # 在目录下生成用来存放数字1-9的9个文件夹,分别用1-9命名
 6
 7
 8 import os
 9
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))

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

2.2 generate_pngs.py

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

 1 # 2018-01-9
 2 # By TimeStamp
 3 # cnblogs: http://www.cnblogs.com/AdaminXie/
 4 # generate_pngs.py
 5 # 生成手写体数字
 6
 7
 8 import random
 9 from PIL import Image, ImageDraw, ImageFilter, ImageFont
10
11 random.seed(3)
12
13 # 生成单张扭曲的数字图像
14 def generate_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     return img_30, num
52
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.3 generate_single_png.py

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

 1 # 2018-01-9
 2 # By TimeStamp
 3 # cnblogs: http://www.cnblogs.com/AdaminXie/
 4 # generate_single_png.py
 5 # 生成手写体数字/字母/汉字
 6
 7
 8 import random
 9 from PIL import Image, ImageDraw, ImageFilter, ImageFont
10
11 random.seed(3)
12
13 # 生成单张扭曲的数字图像
14 def generate_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     # 设置字体,这里选取字体大小25
23     font = ImageFont.truetype(‘simsun.ttc‘, 20)
24
25     # xy是左上角开始的位置坐标
26     # text是你想要显示的内容,数字/字母/汉字
27     char ="呵"
28     draw.text(xy=(12, 11), font=font, text=char, fill=(0, 0, 0))
29
30     # 随机旋转-10-10角度
31     random_angle = random.randint(-10, 10)
32     img_50_rotated = img_50_blank.rotate(random_angle)
33
34     # 图形扭曲参数
35     params = [1 - float(random.randint(1, 2)) / 100,
36               0,
37               0,
38               0,
39               1 - float(random.randint(1, 10)) / 100,
40               float(random.randint(1, 2)) / 500,
41               0.001,
42               float(random.randint(1, 2)) / 500]
43
44     # 创建扭曲
45     img_50_transformed = img_50_rotated.transform((50, 50), Image.PERSPECTIVE, params)
46
47     # 生成新的30*30空白图像
48     img_30 = img_50_transformed.crop([10, 10, 40, 40])
49
50     return img_30, char
51
52 path_pic = "F:/code/python/P_generate_handwritten_number/"
53
54
55 # 调用生成图像文件函数
56 img, generated_char = generate_single()
57 imgray = img.convert(‘1‘)
58
59 print(path_pic + "test.png")
60 # 将图像保存在指定文件夹中
61 imgray.save(path_pic + "test.png")

2.4 del_pngs.py

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

 1 # 2018-01-9
 2 # By TimeStamp
 3 # cnblogs: http://www.cnblogs.com/AdaminXie/
 4 # del_pngs.py
 5 # 删除路径下生成的图像文件
 6
 7 import os
 8
 9 path_pic = "F:/***/P_generate_handwritten_number/data_pngs/"
10
11 #删除路径下的图片
12 def del_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 in namedir:
18             if( tmppng in namedir):
19               #  print(tmppng)
20                 os.remove(path_pic+str(i)+"/"+tmppng)
21
22 del_pic()

3.总结

  自己动手丰衣足食,有兴趣可以自己做手写体数字数据集;

# GitHub: https://github.com/coneypo/Generate_handwritten_number

# 请尊重他人劳动成果,转载或者使用源码请注明出处http://www.cnblogs.com/AdaminXie/

# 交流学习可以联系邮箱 [email protected]

原文地址:https://www.cnblogs.com/AdaminXie/p/8379749.html

时间: 2024-11-05 13:41:31

Python 3 生成手写体数字数据集的相关文章

利用Python自动生成暴力破解的字典

Python是一款非常强大的语言.用于测试时它非常有效,因此Python越来越受到欢迎. 因此,在此次教程中我将聊一聊如何在Python中生成字典,并将它用于任何你想要的用途. 前提要求 1,Python 2.7(对于Python 3.x的版本基本相同,你只需要做一些微小调整) 2,Peace of mine(作者开的一个玩笑,这是一首歌名) 如果你用virtualenv搭建Python开发环境,请确保已经安装了itertools.因为我们将会用到itertools生成字典.我们将一步一步地演示

Python随机生成验证码的两种方法

Python随机生成验证码的方法有很多,今天给大家列举两种,大家也可以在这个基础上进行改造,设计出适合自己的验证码方法方法一:利用range Python随机生成验证码的方法有很多,今天给大家列举两种,大家也可以在这个基础上进行改造,设计出适合自己的验证码方法 方法一: 利用range方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # -*- coding: utf-8 -*- import random def generate_verification_c

实现手写体 mnist 数据集的识别任务

实现手写体 mnist 数据集的识别任务,共分为三个模块文件,分别是描述网络结构的前向传播过程文件(mnist_forward.py). 描述网络参数优化方法的反向传播 过 程 文件 ( mnist_backward.py ). 验证 模 型 准确 率 的  测试 过 程 文件(mnist_test.py). 前向传播过程文件(mnist_forward.py) 在前向传播过程中,需要定义网络模型输入层个数.隐藏层节点数.输出层个数,定义网络参数 w.偏置 b,定义由输入到输出的神经网络架构.

pyhton2 and python3 生成随机数字、字母、符号字典(用于撞库测试/验证码等)

本文介绍Python3中String模块ascii_letters和digits方法,其中ascii_letters是生成所有字母,从a-z和A-Z,digits是生成所有数字0-9.string.punctuation是所有标点'!"#$%&\'()*+,-./:;<=>[email protected][\\]^_`{|}~' String模块中的常量: string.digits:数字0~9 string.ascii_letters:所有字母(大小写) string.l

TensorFlow 手写体数字识别

TensorFlow 手写体数字识别 • 手写体数字 MNIST 数据集介绍 MNIST 数据集介绍 MNIST 是一套手写体数字的图像数据集,包含 60,000 个训练样例和 10,000 个测试样例, 由纽约大学的 Yann LeCun 等人维护. • MNIST Softmax 网络介绍 • 实战 MNIST Softmax 网络 • MNIST CNN 网络介绍 • 实战 MNIST CNN 网络 原文地址:https://www.cnblogs.com/LXL616/p/1124795

Servlet动态验证码的生成-带数字和字母

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 一.实现的思路: (1)首先,需要创建一个Servlet.该Servlet通过字节型响应给客户端返回一个图片,该图片是通过JDK中Java 2D的类库来生成一个图片.图片的生成是依靠一个随机数来完成,然后将这个随机数写成图片格式.最后在Session将这个随机的字符串的状态保持住,以便在用户填写后进行对比. (2)其次,在需要加入验证码的JSP页面中,通过<img src="生成验证码

python直接生成exe的方法

一.简介 py2exe是一个将python脚本转换成windows上的可独立执行的可执行程序(*.exe)的工具,这样,你就可以不用装python而在windows系统上运行这个可执行程序.py2exe已经被用于创建wxPython,Tkinter,Pmw,PyGTK,pygame,win32com client和server,和其它的独立程序.py2exe是发布在开源许可证下的.目前只有python2.x的才有对应版本的.二.安装py2exe 从http://prdownloads.sourc

Python脚本生成sitemap

项目须要用脚本生成sitemap,中间学习了一下sitemap的格式和lxml库的使用方法.把结果记录一下,方便以后须要直接拿来用. 来自Python脚本生成sitemap 安装lxml 首先须要pip install lxml安装lxml库. 假设你在ubuntu上遇到了下面错误: #include "libxml/xmlversion.h" compilation terminated. error: command 'x86_64-linux-gnu-gcc' failed wi

Python判断是否是数字(无法判断浮点数)(已解决)

s为字符串s.isalnum() 所有字符都是数字或者字母s.isalpha() 所有字符都是字母s.isdigit() 所有字符都是数字s.islower() 所有字符都是小写s.isupper() 所有字符都是大写s.istitle() 所有单词都是首字母大写,像标题s.isspace() 所有字符都是空白字符.\t.\n.\r 1 def isNum2(value): 2 try: 3 x = int(value) 4 except TypeError: 5 return False 6