1. 程式人生 > >Python 3 生成手寫體數字數據集

Python 3 生成手寫體數字數據集

mkdir 畫布 初始化 pass 機器 pat 圖像分類 -s gef

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 : 252 : 173 : 214 : 195 : 206 : 227 : 258 : 249 : 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]

Python 3 生成手寫體數字數據集