1. 程式人生 > >深度學習(六)——自動生成圖片資料集

深度學習(六)——自動生成圖片資料集

    最近做了一個漢字驗證碼識別的專案,該專案最大的難點就是資料集的準備。在自己沒有資料集的情況下選擇了自動生成,不過自己生成的資料集訓練出來的模型,只在用自己方法生成的資料上表現比較好,但是在真實資料集上表現比較差,也算是自己為自己踩了一格坑。不過自己生成資料集的經歷,還是學到了很多知識。並且該方法產生的資料集,可以產生無限的大量資料,可以供後面一些模型的測試,提供了很好的資源,今天我也把產生資料集的方法分享給大家。

一、問題的產生背景和自己生成資料集的意義

      我作的專案是破解驗證碼,沒錯,是不是感覺有點像黑客。哈哈,也是自己以為,其實業界人會覺得很low。破解驗證碼的目的是為了網路爬蟲準備,在爬資料的過程中會遇到跳出驗證嗎的問題。影響到機器的自動爬,需要輸進去驗證碼,這樣我的工作就有了意義。但是,遇到一個很大的問題,我沒資料,我沒資料。所以有了兩個思路,第一個思慮就是爬驗證碼,然後在標註訓練。不過開始想了想真是特別誇張,要多少人力,漢字那麼多分類我要多少資料。因此產生了第二個想法,自己生成資料,這樣誰也管不住老子產生多少資料了。

二、真實資料樣例

資料樣本分析:

背景色相同,有四個干擾線,顏色不同。字型經過自己子產生資料過程中的對比是書宋,有干擾點,分佈均勻。這不是明顯機器自動生成的資料嘛,更加堅信了我產生資料的想法。

三、資料的生成過程

我就寫一下步驟吧:

1、產生與真實資料相同的背景

2、產生干擾點,你們會想為什麼這麼早產生干擾點,因為我是用改變畫素點的方法產生,我遍歷整個圖的畫素,根據自己的設定隨機改變一些畫素值,就會產生了干擾點,而對後面漢字產生沒有影響。(經過實驗比較好的方法)

3、用drawimage的方法在背景上生成漢字,漢字我用的是shusong.ttf

4、旋轉字型,字型寫上以後就是整張圖旋轉了,但是旋轉以後背景圖的四個角是改變的。因為背景是有層次感的,導致旋轉後四個角遮擋不聊了,漏出黑色。

5、這一步大家應該知道,把四個角的黑色三角變成白色。網上很多方法,先對圖片根據畫素值對其進行擷取,只留下漢字所在的方框,然後在放在另外一個背景下,讓背景統一。不過博主有一個另外簡單想法,就是根據三通道值進行判斷哪一部分是黑色三角,如果三通道值都是0,則代表是。但是這種方法應該最前面字型產生有個要求,黑色字型的畫素不能是0,要是從1開始,這樣對視覺沒啥影響吧。

6、旋轉以後,我們就要對圖片產生干擾線。隨機生成四條線,寬度和漢字的相同,顏色隨機產生。

7、批量產生,我把常用漢字存到一個字典裡,然後產生某個漢字的圖片,都放在漢字所對應的key值資料夾下,這樣我在訓練的時候,根據訪問資料夾就知道樣本的標籤啦。

四、程式碼分享和分析

from PIL import Image
import matplotlib.pyplot as plt
from PIL import ImageFont
from PIL import ImageDraw
import tensorflow as tf
import numpy as np
import random
import os
import cv2
import skimage.util
from code7 import ImageChar

class Creatimage(object):
    def __init__(self, font=ImageFont.truetype('fangzheng_shusong.ttf', 30),
                 img_r=Image.new("RGB", (50, 50), (255, 255, 255)), size=(50, 50),
                 chars="作", image_arr=np.zeros((256, 256, 3), np.uint8), value=0,
                 count=0, image_list = [[255,240,245],[185,211,238],[187,255,255]]):
        self.font = font
        self.img_r = img_r
        self.image_arr = image_arr
        self.size = size
        self.char = chars
        self.value = value
        self.count = count
        self.image_list=image_list
    def addnoise(self):
        self.img_r = np.array(self.img_r)
        for i in range(50):
            for j in range(50):
                if i%2 ==0 and j%2==0:
                    list =self.image_list[random.randint(0,2)]
                    self.img_r[i][j][0]=list[0]
                    self.img_r[i][j][1]=list[1]
                    self.img_r[i][j][2]=list[2]
    def drawText(self):
        self.img_r = Image.fromarray(self.img_r)
        draw = ImageDraw.Draw(self.img_r)
        draw.text((15, 20), self.char, self.randRGB(), font=self.font)
        del draw
    def rotate(self):
        self.img_r = self.img_r.rotate(random.randint(0,90), expand=0)

    def randLine(self, num):
        draw = ImageDraw.Draw(self.img_r)
        lineColor = self.randRGB()
        for i in range(0, num):
            draw.line([self.randPoint(), self.randPoint()], lineColor, 2)
        del draw

    def randPoint(self):
        (width, height) = self.size
        return (random.randint(0, width), random.randint(0, height))

    def randRGB(self):
        return (random.randint(1, 255),
                random.randint(1, 255),
                random.randint(1, 255))


    def changeIm(self):
        self.image_arr = np.array(self.img_r)
        for i in range(50):
            for j in range(50):
                if self.image_arr[i][j][0]==0 and self.image_arr[i][j][0]==0 and self.image_arr[i][j][0]==0:
                    self.image_arr[i][j][0]=255
                    self.image_arr[i][j][1]=255
                    self.image_arr[i][j][2]=255
                    if i % 2 == 0 and j % 2 == 0:
                        list = self.image_list[random.randint(0, 2)]
                        self.image_arr[i][j][0] = list[0]
                        self.image_arr[i][j][1] = list[1]
                        self.image_arr[i][j][2] = list[2]
        # print(self.image_arr)
    #im=np.array(img_r)
    #imshow(im)

    def printimage(self):
        plt.imshow(self.image_arr)
        plt.show()


    def createImage(self, num):
        self.addnoise()
        self.drawText()
        self.rotate()
        self.randLine(num)
        self.changeIm()
        self.printimage()

    def saveImage(self):
        out_dir = os.path.expanduser("./dateset")
        train_images_dir = os.path.join(out_dir, "train")
        if not os.path.isdir(train_images_dir):
            os.makedirs(train_images_dir)
        char_dir = os.path.join(train_images_dir, "%0.5d" % self.value)
        path_image = os.path.join(char_dir, "%d.jpeg" % self.count)
        if not os.path.isdir(char_dir):
            os.makedirs(char_dir)
        cv2.imwrite(path_image, self.image_arr)
        im = Image.fromarray(self.image_arr)

        im.save(path_image)

if __name__ == "__main__":
    ic = Creatimage()
    ic.createImage(4)
    ic.saveImage()

六、產生資料的樣例

七、總結

良心說我感覺很像了,也是我嘔心瀝血,用了渾身解數的模仿,加各種技巧產生的。分享給大家,批量生產的原始碼在我的github上()