Python 3 生成手写体数字数据集
Posted coneypo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 3 生成手写体数字数据集相关的知识,希望对你有一定的参考价值。
0.引言
平时经常会接触到验证码,或者在机器学习学习过程中,大家或许会接触过手写体识别/验证码识别之类问题,会用到手写体的数据集;
自己尝试写了一个生成手写体图片的 Python 程序,可以批量生成手写体数字数据集,在此分享下生成 30*30像素 的手写体数字 1-9 图片 的一种实现方法;
大概流程:新建空白图像 >>> 生成随机数 1-9 >>> 将数字写到空白图像上 >>> 旋转、扭曲 处理 >>> 得到 “手写体数字”;
得到的手写体数字图像如 图1 所示,实现比较简单,有兴趣可以自己试;
源码上传到了我的 GitHub,如果对您有帮助欢迎 star 支持下: https://github.com/coneypo/Generate_handwritten_number ;
图1 生成的手写体数字 1-9
图 2 利用 generate_imgs.py 得到数字 3 图像
1. 设计流程
图 4 整体设计流程
图 5 生成的图像经过的处理
1.1 新建一个空白图像 img_50,尺寸大小为 50*50
1 img_50_blank = Image.new(\'RGB\', (50, 50), (255, 255, 255))
想要的 30*30 的图像,为什么我这里要先生成 50*50 的空白图像?
因为图像背景(50*50像素的画布)初始化的时候设置为白色(颜色数组(255, 255, 255)),而背景色之外的其实是黑色;
之后需要进行旋转处理,如果直接新建 30*30 像素的画布,旋转之后边上会出现黑边,如 图6 所示;
所以我新建了一个 50*50,然后旋转之后从中间裁出来一个 30*30 的图像出来;
图 6 直接用 30*30 像素的画布写字旋转(会出现黑边)
1.2 利用 PIL 在图像上写文字 text
利用 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. Source Code 介绍
2.1 函数 mkdir_for_imgs()
因为我们要将指定的图像分类放入指定文件夹,所以我们需要先在项目目录下面新建 9 个文件夹:
(当然你也可以自己新建,新建 9 个文件夹工作量还不大,但是如果要生成的验证码包含英文字母那就比较多了,大写 A-Z 共 24 个 + 小写 a-z 共 24 个 + 数字 1-9 共 9 个 = 57个子文件夹)
1 # 在目录下生成用来存放数字 1-9 的 9个文件夹,分别用 1-9 命名 2 def mkdir_for_imgs(): 3 for i in range(49, 58): 4 if os.path.isdir(path_img + "Num_" + chr(i)): 5 pass 6 else: 7 print(path_img + "Num_" + chr(i)) 8 os.mkdir(path_img + "Num_" + chr(i))
图 7 mkdir_for_imgs() 生成的用来存放指定图像的文件夹
2.2 函数 del_imgs()
删除子文件夹 Num_1-9 中的所有图片:
1 # 删除路径下的图片 2 def del_imgs(): 3 for i in range(1, 10): 4 dir_nums = os.listdir(path_img+ "Num_" + str(i)) 5 for tmp_img in dir_nums: 6 if tmp_img in dir_nums: 7 # print("delete: ", tmp_img) 8 os.remove(path_img + "Num_" + str(i) + "/" + tmp_img) 9 print("Delete finish", "\\n")
2.3 完整的代码 generate_imgs.py
mkdir_for_imgs() >>> del_imgs() >>> generate_1to9(n)
根据给定随机次数生成手写体数字 1-9,然后存放到本地文件夹 Num_1-9 ;
Line 67 修改生成图像的大小,我这里取的是 30*30 像素;
79 # 生成新的30*30空白图像
80 im_30 = im_50_transformed.crop([10, 10, 40, 40])
Line 105 给定生成手写体数字的次数:
116 # generate n times 117 generate_1to9(1000)
generate_imgs.py:
1 # Created on: 2018-01-09 2 # Updated on: 2018-09-03 3 # Author: coneypo 4 # Blog: http://www.cnblogs.com/AdaminXie/ 5 # Github: https://github.com/coneypo/Generate_handwritten_number 6 # 生成手写体数字 7 8 9 import random 10 import os 11 from PIL import Image, ImageDraw, ImageFont 12 13 random.seed(3) 14 path_img = "data_pngs/" 15 16 17 # 在目录下生成用来存放数字 1-9 的 9个文件夹,分别用 1-9 命名 18 def mkdir_for_imgs(): 19 for i in range(49, 58): 20 if os.path.isdir(path_img + "Num_" + chr(i)): 21 pass 22 else: 23 print(path_img + "Num_" + chr(i)) 24 os.mkdir(path_img + "Num_" + chr(i)) 25 26 27 # generate folders 28 # mkdir_for_imgs() 29 30 31 # 删除路径下的图片 32 def del_imgs(): 33 for i in range(1, 10): 34 dir_nums = os.listdir(path_img+ "Num_" + str(i)) 35 for tmp_img in dir_nums: 36 if tmp_img in dir_nums: 37 # print("delete: ", tmp_img) 38 os.remove(path_img + "Num_" + str(i) + "/" + tmp_img) 39 print("Delete finish", "\\n") 40 41 42 del_imgs() 43 44 45 # 生成单张扭曲的数字图像 46 def generate_single(): 47 # 先绘制一个50*50的空图像 48 im_50_blank = Image.new(\'RGB\', (50, 50), (255, 255, 255)) 49 50 # 创建画笔 51 draw = ImageDraw.Draw(im_50_blank) 52 53 # 生成随机数1-9 54 num = str(random.randint(1, 9)) 55 56 # 设置字体,这里选取字体大小25 57 font = ImageFont.truetype(\'simsun.ttc\', 20) 58 59 # xy是左上角开始的位置坐标 60 draw.text(xy=(18, 11), font=font, text=num, fill=(0, 0, 0)) 61 62 # 随机旋转-10-10角度 63 random_angle = random.randint(-10, 10) 64 im_50_rotated = im_50_blank.rotate(random_angle) 65 66 # 图形扭曲参数 67 params = [1 - float(random.randint(1, 2)) / 100, 68 0, 69 0, 70 0, 71 1 - float(random.randint(1, 10)) / 100, 72 float(random.randint(1, 2)) / 500, 73 0.001, 74 float(random.randint(1, 2)) / 500] 75 76 # 创建扭曲 77 im_50_transformed = im_50_rotated.transform((50, 50), Image.PERSPECTIVE, params) 78 79 # 生成新的30*30空白图像 80 im_30 = im_50_transformed.crop([10, 10, 40, 40]) 81 82 return im_30, num 83 84 85 # 生成手写体数字1-9存入指定文件夹1-9 86 def generate_1to9(n): 87 # 用cnt_num[1]-cnt_num[9]来计数数字1-9生成的个数,方便之后进行命名 88 cnt_num = [] 89 for i in range(10): 90 cnt_num.append(0) 91 92 for m in range(1, n + 1): 93 # 调用生成图像文件函数 94 im, generate_num = generate_single() 95 96 # 取灰度 97 im_gray = im.convert(\'1\') 98 99 # 计数生成的数字1-9的个数,用来命名图像文件 100 for j in range(1, 10): 101 if generate_num == str(j): 102 cnt_num[j] = cnt_num[j] + 1 103 104 # 路径如 "F:/code/***/P_generate_handwritten_number/data_pngs/1/1_231.png" 105 # 输出显示路径 106 print("Generate:", path_img + "Num_" + str(j) + "/" + str(j) + "_" + str(cnt_num[j]) + ".png") 107 # 将图像保存在指定文件夹中 108 im_gray.save(path_img + "Num_" + str(j) + "/" + str(j) + "_" + str(cnt_num[j]) + ".png") 109 110 print("\\n") 111 # 输出显示1-9的分布 112 print("生成的1-9的分布:") 113 for k in range(9): 114 print("Num", k + 1, ":", cnt_num[k + 1], "in all") 115 116 # generate n times 117 generate_1to9(1000)
图 8 利用 generate_imgs.py 得到数字 1 图像
3.总结
有兴趣可以自己生成手写体数字数据集,感谢你的支持;
# 代码已上传到了我的GitHub,如果对您有帮助欢迎 Star下:https://github.com/coneypo/Generate_handwritten_number
# 请尊重他人劳动成果,转载或者使用源码请注明出处:http://www.cnblogs.com/AdaminXie
# 如有问题请留言或者联系邮箱 coneypo@foxmail.com
以上是关于Python 3 生成手写体数字数据集的主要内容,如果未能解决你的问题,请参考以下文章
[Pytorch系列-61]:生成对抗网络GAN - 基本原理 - 自动生成手写数字案例分析