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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM