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 像素;

  1.    79 # 生成新的30*30空白图像
  2.   80 im_30 = im_50_transformed.crop([10, 10, 40, 40])

  Line 105 给定生成手写体数字的次数:

  1.   116 # generate n times
  2.   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. import random
  9. import os
  10. from PIL import Image, ImageDraw, ImageFont
  11.  
  12. random.seed(3)
  13. path_img = "data_pngs/"
  14.  
  15. # 在目录下生成用来存放数字 1-9 的 9个文件夹,分别用 1-9 命名
  16. def mkdir_for_imgs():
  17. for i in range(49, 58):
  18. if os.path.isdir(path_img + "Num_" + chr(i)):
  19. pass
  20. else:
  21. print(path_img + "Num_" + chr(i))
  22. os.mkdir(path_img + "Num_" + chr(i))
  23.  
  24. # generate folders
  25. # mkdir_for_imgs()
  26.  
  27. # 删除路径下的图片
  28. def del_imgs():
  29. for i in range(1, 10):
  30. dir_nums = os.listdir(path_img+ "Num_" + str(i))
  31. for tmp_img in dir_nums:
  32. if tmp_img in dir_nums:
  33. # print("delete: ", tmp_img)
  34. os.remove(path_img + "Num_" + str(i) + "/" + tmp_img)
  35. print("Delete finish", "\n")
  36.  
  37. del_imgs()
  38.  
  39. # 生成单张扭曲的数字图像
  40. def generate_single():
  41. # 先绘制一个50*50的空图像
  42. im_50_blank = Image.new('RGB', (50, 50), (255, 255, 255))
  43.  
  44. # 创建画笔
  45. draw = ImageDraw.Draw(im_50_blank)
  46.  
  47. # 生成随机数1-9
  48. num = str(random.randint(1, 9))
  49.  
  50. # 设置字体,这里选取字体大小25
  51. font = ImageFont.truetype('simsun.ttc', 20)
  52.  
  53. # xy是左上角开始的位置坐标
  54. draw.text(xy=(18, 11), font=font, text=num, fill=(0, 0, 0))
  55.  
  56. # 随机旋转-10-10角度
  57. random_angle = random.randint(-10, 10)
  58. im_50_rotated = im_50_blank.rotate(random_angle)
  59.  
  60. # 图形扭曲参数
  61. params = [1 - float(random.randint(1, 2)) / 100,
  62. 0,
  63. 0,
  64. 0,
  65. 1 - float(random.randint(1, 10)) / 100,
  66. float(random.randint(1, 2)) / 500,
  67. 0.001,
  68. float(random.randint(1, 2)) / 500]
  69.  
  70. # 创建扭曲
  71. im_50_transformed = im_50_rotated.transform((50, 50), Image.PERSPECTIVE, params)
  72.  
  73. # 生成新的30*30空白图像
  74. im_30 = im_50_transformed.crop([10, 10, 40, 40])
  75.  
  76. return im_30, num
  77.  
  78. # 生成手写体数字1-9存入指定文件夹1-9
  79. def generate_1to9(n):
  80. # 用cnt_num[1]-cnt_num[9]来计数数字1-9生成的个数,方便之后进行命名
  81. cnt_num = []
  82. for i in range(10):
  83. cnt_num.append(0)
  84.  
  85. for m in range(1, n + 1):
  86. # 调用生成图像文件函数
  87. im, generate_num = generate_single()
  88.  
  89. # 取灰度
  90. im_gray = im.convert('')
  91.  
  92. # 计数生成的数字1-9的个数,用来命名图像文件
  93. for j in range(1, 10):
  94. if generate_num == str(j):
  95. cnt_num[j] = cnt_num[j] + 1
  96.  
  97. # 路径如 "F:/code/***/P_generate_handwritten_number/data_pngs/1/1_231.png"
  98. # 输出显示路径
  99. print("Generate:", path_img + "Num_" + str(j) + "/" + str(j) + "_" + str(cnt_num[j]) + ".png")
  100. # 将图像保存在指定文件夹中
  101. im_gray.save(path_img + "Num_" + str(j) + "/" + str(j) + "_" + str(cnt_num[j]) + ".png")
  102.  
  103. print("\n")
  104. # 输出显示1-9的分布
  105. print("生成的1-9的分布:")
  106. for k in range(9):
  107. print("Num", k + 1, ":", cnt_num[k + 1], "in all")
  108.  
  109. # generate n times
  110. 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 生成手写体数字数据集的更多相关文章

  1. Python 3 利用机器学习模型 进行手写体数字识别

    0.引言 介绍了如何生成数据,提取特征,利用sklearn的几种机器学习模型建模,进行手写体数字1-9识别. 用到的四种模型: 1. LR回归模型,Logistic Regression 2. SGD ...

  2. Python 3 利用机器学习模型 进行手写体数字检测

    0.引言 介绍了如何生成手写体数字的数据,提取特征,借助 sklearn 机器学习模型建模,进行识别手写体数字 1-9 模型的建立和测试. 用到的几种模型: 1. LR,Logistic Regres ...

  3. caffe-windows之手写体数字识别例程mnist

    caffe-windows之手写体数字识别例程mnist 一.训练测试网络模型 1.准备数据 Caffe不是直接处理原始数据的,而是由预处理程序将原始数据变换存储为LMDB格式,这种方式可以保持较高的 ...

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

    Python是一款非常强大的语言.用于测试时它非常有效,因此Python越来越受到欢迎. 因此,在此次教程中我将聊一聊如何在Python中生成字典,并将它用于任何你想要的用途. 前提要求 1,Pyth ...

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

    Python随机生成验证码的方法有很多,今天给大家列举两种,大家也可以在这个基础上进行改造,设计出适合自己的验证码方法方法一:利用range Python随机生成验证码的方法有很多,今天给大家列举两种 ...

  6. 使用sphinx快速为你python注释生成API文档

    sphinx简介sphinx是一种基于Python的文档工具,它可以令人轻松的撰写出清晰且优美的文档,由Georg Brandl在BSD许可证下开发.新版的Python3文档就是由sphinx生成的, ...

  7. Python小游戏——猜数字教程(random库教程)

    今天来开发一个简单的数字逻辑游戏,猜数字(数字炸弹) 首先开发游戏第一件事,了解需求. 猜数字游戏规则: 计算机随机生成一个指定范围的数字,由玩家来猜测, 之后计算机会根据玩家提供数字来与自己生成的数 ...

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

    本文介绍Python3中String模块ascii_letters和digits方法,其中ascii_letters是生成所有字母,从a-z和A-Z,digits是生成所有数字0-9.string.p ...

  9. Python自动生成代码工具

    项目中有一个需求,对一个基类而言,拥有一个比较方法和拷贝方法,某些地方需要频繁地对这两个方法进行调用.对于所有子类而言,需要重写这两个方法,并在其中维护类内一些成员变量.例如有一个变量m_iMyVal ...

随机推荐

  1. [Micropython][ESP8266] TPYBoard V202 之MQTT协议接入OneNET云平台

    随着移动互联网的发展,MQTT由于开放源代码,耗电量小等特点,将会在移动消息推送领域会有更多的贡献,在物联网领域,传感器与服务器的通信,信息的收集,MQTT都可以作为考虑的方案之一.在未来MQTT会进 ...

  2. form注册表单圆角 demo

    form注册表单圆角 <BODY> <div class="form"> <ul class="list"> <li& ...

  3. 总结基础OOP(面向对象)

    OOP其实也就是面向对象编程.  一:什么是对象:  我们最常见的理解方式无非是:对象(object)是任何看得见.摸得着.感觉得到,可以获得的东西,有自己的标识的任何东西.对象是某一类的事物的具体个 ...

  4. 移动端H5页面惯性滑动监听

    移动端H5页面惯性滑动监听 在移动端,当你快速滑动有滚动条的页面时,当你手指离开屏幕时,滚动条并不会立即停止,而是会随着"惯性"继续滑动一段距离. 在做项目的过程中,需要监听惯性滑 ...

  5. Anaconda使用

    转自PeterYuan   序 Python易用,但用好却不易,其中比较头疼的就是包管理和Python不同版本的问题,特别是当你使用Windows的时候.为了解决这些问题,有不少发行版的Python, ...

  6. Android Studio C/C++开发环境配置

    Android Studio C/C++开发环境配置  我的开发环境 : Win 10 + android studio 1.5   一, 安装NDK 开发环境: 1.  Settings -> ...

  7. 学习总结:gcc/g++ 编译与链接

    gcc/g++ 编译与链接 编译与链接的过程可以分解为四个步骤:预处理.编译.汇编.链接 预处理:源代码文件和相关的头文件,被预处理器cpp预处理成一个后缀为 .i 的文件(选项:-E) 编译:把预处 ...

  8. js中的稀疏数组和密集数组

    原文地址: http://www.2ality.com/2012/06/dense-arrays.html 一般来说JavaScript中的数组都是稀疏的,也就是说数组中的元素与元素之间是由空格的,因 ...

  9. python的运维交流学习笔记

    #!/usr/bin/env | #!/usr/bin/python#coding:gbk #python 运维练习 #需求: #1.利用python实现自动监控服务器性能 #2.并将监控到的数据进行 ...

  10. 【java开发系列】—— 集合使用方法

    一.首先看一下集合的框架图: 由于collection也继承了Iterator和comparable接口,因此我们可以使用Iterator来遍历元素,也可以通过自定义compareTo函数来重新编写自 ...