深度學習數據增強(data_augmentation):Keras ImageDataGenerator

目錄

一.大殺氣之keras ImageDataGenerator

二.詳解單幅圖像增強

三.最後的拆分分別保存train_img和train_label

四.圖像增強之批處理

五、最後,補充單文件夾圖像的數據增強



今天就來一招搞定數據增強(data_Augmentation),讓你在機器學習/深度學習圖像處理的路上,從此不再爲數據不夠而發愁。且來看圖片從250張>>>>任意張的華麗增強,每一張都與衆不同。

開始之前呢,我們先把這件大事給細分下,一步一步的來:

  • 首先,圖像讀取,需要對文件夾操作;

  • 然後,增強圖像(重點,重點,重點);

  • 最後,保存圖像。

來看下此次任務中,待增強的圖像和標籤,主要是爲了做圖像分割做圖像準備。這個圖像懂的應該能看出來,這是一個嬰兒頭圍的醫學圖像,現實場景意義很強。上圖(以3張圖爲例):

train_img

train_label


成雙成對,這樣在後續的文件讀取中會比較的方便(大神可以自己改改,練練動手能力)

那動手吧!!!

一.大殺氣之keras ImageDataGenerator

from keras.preprocessing.image import ImageDataGenerator

ImageDataGenerator()是keras.preprocessing.image模塊中的圖片生成器,同時也可以在batch中對數據進行增強,擴充數據集大小,增強模型的泛化能力。比如進行旋轉,變形,歸一化等,它所能實現的功能且看下面的詳細部分吧。

keras.preprocessing.image.ImageDataGenerator(
               featurewise_center=False,  
               samplewise_center=False, 
               featurewise_std_normalization=False, 
               samplewise_std_normalization=False, 
               zca_whitening=False, 
               zca_epsilon=1e-06, 
               rotation_range=0, #整數。隨機旋轉的度數範圍。
               width_shift_range=0.0, #浮點數、一維數組或整數
               height_shift_range=0.0, #浮點數。剪切強度(以弧度逆時針方向剪切角度)。
               brightness_range=None, 
               shear_range=0.0, 
               zoom_range=0.0, #浮點數 或 [lower, upper]。隨機縮放範圍
               channel_shift_range=0.0, #浮點數。隨機通道轉換的範圍。
               fill_mode='nearest', # {"constant", "nearest", "reflect" or "wrap"} 之一。默認爲 'nearest'。輸入邊界以外的點根據給定的模式填充:
               cval=0.0, 
               horizontal_flip=False, 
               vertical_flip=False, 
               rescale=None, 
               preprocessing_function=None, 
               data_format=None, 
               validation_split=0.0, 
               dtype=None)

這裏就以單張圖片爲例,詳述下這個圖像增強大殺器的具體用法,分別以旋轉(rotation_range),長寬上平移(width_shift_range,height_shift_range)

輸入圖像:

train_img

train_label


先來看下兩者合併後的圖像:

merge


到這裏,我們進行增強變換,演示下這裏增強部分是咋用的,且看:


(溫馨提示)
滑慢點,有GIF圖


(1)旋轉(rotation_range=1.2)

otation=1.2


(2)寬度變換(width_shift_range=0.05)

width_shift_range=0.05
(3)高度變換(height_shift_range=0.05)

eight_shift_range=0.05


這裏才只是演示了三個就那麼的強大,詳細,這要能增強多少圖片啊,想想都可怕,想都不敢想啊!!!

增強彙總


這裏是合併部分,單幅增強的大圖效果詳情看這裏:

merge改變通道排布方式

這裏,且看單幅圖像的增強代碼(建議去下載仔細看,往後看,有方式):

__author__ = "lingjun"
# E-mail: [email protected]
# 微信公衆號:小白CV

import os
from keras.preprocessing.image import ImageDataGenerator,load_img,img_to_array,array_to_img

class Augmentation(object):
    def __init__(self,img_type="png"):
        self.datagen=ImageDataGenerator(
            #rotation_range=1.2,
            #width_shift_range=0.05,
            height_shift_range=0.05,
            # shear_range=0.05,
            # zoom_range=0.05,
            # horizontal_flip=True,
            fill_mode='nearest')

    def augmentation(self):
        # 讀入3通道的train和label, 分別轉換成矩陣, 然後將label的第一個通道放在train的第2個通處, 做數據增強
        print("運行 Augmentation")
        # Start augmentation.....
        img_t = load_img("../one/img/0.png")  # 讀入train
        img_l = load_img("../one/label/0.png")  # 讀入label

        x_t = img_to_array(img_t)  # 轉換成矩陣
        x_l = img_to_array(img_l)
        x_t[:, :, 2] = x_l[:, :, 0]  # 把label當做train的第三個通道
        #x_t = x_t[..., [2,0,1]]#image-102,120,210
        img_tmp = array_to_img(x_t)
        img_tmp.save("../one/merge/0.png")  # 保存合併後的圖像
        img = x_t
        img = img.reshape((1,) + img.shape)  # 改變shape(1, 512, 512, 3)
        savedir = "../one/aug_merge"  # 存儲合併增強後的圖像
        if not os.path.lexists(savedir):
            os.mkdir(savedir)
        print("running %d doAugmenttaion" % 0)
        self.do_augmentate(img, savedir, str(0))  # 數據增強

    def do_augmentate(self, img, save_to_dir, save_prefix, batch_size=1, save_format='png', imgnum=30):
        # augmentate one image
        datagen = self.datagen
        i = 0
        for _ in datagen.flow(
                img,
                batch_size=batch_size,
                save_to_dir=save_to_dir,
                save_prefix=save_prefix,
                save_format=save_format):
            i += 1
            if i > imgnum:
                break
if __name__=="__main__":
    aug=Augmentation()
    aug.augmentation()

這裏不做過多的解釋,打個廣告,歡迎關注微信公衆號:小白算法。對代碼中的詳細內容,我們且看第二部分


二.詳解單幅圖像增強

這裏先說下對圖像和標籤一起增強的步驟,有人該問爲什麼還要標籤了。這裏針對的問題是圖像分割,pix2pix的任務,即輸入時一般圖像,輸出是目標分割後圖像,在上面就是train_img和train_label的一一對應關係,這裏開始分解步驟來說增強:

1.train_img+train_label=merge,也就是圖像+橢圓形的那個;
2.對merge圖像進行增強;
3.將merge圖像按通道拆分,1的逆過程。

前面只涉及步驟1和2,故先對這兩塊做詳述,如下:
着重講下Augmentation類中augmentation函數部分和對單幅圖像增強部分。

1.讀取train_img,train_label;

 # load_image
img_t = load_img("../one/img/0.png")
img_l = load_img("../one/label/0.png")

2.因爲要講上述img_t和img_l進行合併,採用矩陣形式進行操作,這裏將讀取到的圖像轉換爲矩陣形式;

 # img_to_array
x_t = img_to_array(img_t) 
        x_l = img_to_array(img_l)

3.train_img+train_label=merge.把label當做train的第三個通道

後面註釋部分,是對合並後的通道進行任意組合的形式,會出現不同的效果,如前文中三個特寫圖(具體自己可嘗試)

# 把label當做train的第三個通道
x_t[:, :, 2] = x_l[:, :, 0]  
#x_t = x_t[..., [2,0,1]]#image-102,120,210

4.爲了保存merge後圖像,此時該從array_to_image了,然後保存圖像文件;

img_tmp = array_to_img(x_t)
img_tmp.save("../one/merge/0.png")  # 保存合併後的圖像

5.此時執行對merge圖像的增強操作;

開始前,既然我們要def do_augmentate(),我們先想想對一幅圖像的增強,需要些什麼:

  • image圖像文件;

  • save_to_dir保存增強後的文件夾地址;

  • 批增強的數量。

至於別的,先看這裏

flow(self, X, y, batch_size=32, shuffle=True, seed=None, save_to_dir=None, save_prefix='', save_format='png')
'''
x:樣本數據,秩應爲4,在黑白圖像的情況下channel軸的值爲1,在彩色圖像情況下值爲3
y:標籤
batch_size:整數,默認32
shuffle:布爾值,是否隨機打亂數據,默認爲True
save_to_dir:None或字符串,該參數能讓你將提升後的圖片保存起來,用以可視化
save_prefix:字符串,保存提升後圖片時使用的前綴, 僅當設置了save_to_dir時生效
save_format:"png"或"jpeg"之一,指定保存圖片的數據格式,默認"jpeg"
yields:形如(x,y)的tuple,x是代表圖像數據的numpy數組.y是代表標籤的numpy數組.該迭代器無限循環.
seed: 整數,隨機數種子
'''

flow:接收numpy數組和標籤爲參數,生成經過數據提升或標準化後的batch數據,並在一個無限循環中不斷的返回batch數據

6.由於flow的輸入X需要一個秩爲4的數組,所以需要對他變形,加上img.shape=3

# 改變shape(1, 512, 512, 3)
img = img.reshape((1,) + img.shape)  

好了,這裏應該是對代碼部分描述的已經夠清楚了(哪裏還有不理解的,歡迎留言評論,大家一起進步哦)


三.最後的拆分分別保存train_img和train_label

話不多說,先看下拆分代碼部分,還是先說步驟:

1.讀取merge文件夾內圖片;
2.按照之前組合的形式進行拆分爲img_train和img_label,同時保存在兩個文件夾內,一一對應。

    def split_merge(self):
        # 讀入合併增強之後的數據(aug_merge), 對其進行分離, 分別保存至 aug_merge_img, aug_merge_label
        print("running split_Merge_image")

        # split merged image apart
        path_merge = "../one/aug_merge"  # 合併增強之後的圖像
        path_train = "../one/aug_merge_img"  # 增強之後分離出來的train
        path_label = "../one/aug_merge_label"  # 增強之後分離出來的label
        if not os.path.lexists(path_train):
            os.mkdir(path_train)
        if not os.path.lexists(path_label):
            os.mkdir(path_label)

        train_imgs = glob.glob(path_merge + "/*." + "png")  # 所有訓練圖像
        savedir = path_train   # 保存訓練集的路徑
        if not os.path.lexists(savedir):
            os.mkdir(savedir)
        savedir = path_label  # 保存label的路徑
        if not os.path.lexists(savedir):
            os.mkdir(savedir)
        for imgname in train_imgs:  # rindex("/") 是返回'/'在字符串中最後一次出現的索引
            midname = imgname[imgname.rindex("/") + 1:imgname.rindex("." + "png")]  # 獲得文件名(不包含後綴)
            #print("midname:",midname)
            img = cv2.imread(imgname)  # 讀入訓練圖像
            img_train = img[:, :, 2]  # 訓練集是第2個通道, label是第0個通道
            img_label = img[:, :, 0]
            newname=midname.split('\\')[1]
            #print("new:",new)
            cv2.imwrite(path_train + "/"  + newname + "_train" + "." + "png", img_train)  # 保存訓練圖像和label
            print(path_train + "/"  + "/" + newname + "_train" + "." + "png")
            cv2.imwrite(path_label + "/" + newname + "_label" + "." + "png", img_label)
            print(path_label + "/"  + "/" + newname + "_label" + "." + "png")

代碼部分不做詳述了,和之前組合的形式差不多,着重說下這裏,是自己不懂的部分:

# 獲得文件名(不包含後綴)
# rindex("/") 是返回'/'在字符串中最後一次出現的索引
midname = imgname[imgname.rindex("/") + 1:imgname.rindex("." + "png")]  

Python rindex() 返回子字符串 str 在字符串中最後出現的位置,如果沒有匹配的字符串會報異常,你可以指定可選參數[beg:end]設置查找的區間。

舉個栗子:

import glob
path_merge = "../one/aug_merge"  # 合併增強之後的圖像

print("imgname:",path_merge)
print(path_merge.rindex("/"))

打印的結果


現在,把上文中的一段專門來看下打印結果

import glob
path_merge = "../one/aug_merge"  # 合併增強之後的圖像
train_imgs = glob.glob(path_merge + "/*." + "png")  # 所有訓練圖像
for imgname in train_imgs:  # rindex("/") 是返回'/'在字符串中最後一次出現的索引
    print("imgname:",imgname)
    print("imgname.rindex:",imgname.rindex("." + "png"))
    print(imgname.rindex("/"))
    midname = imgname[imgname.rindex("/") + 1:imgname.rindex("." + "png")]  # 獲得文件名(不包含後綴)
    print("midname===",midname)
    print("*"*20)

截取圖像地址


最後,看下拆分後的圖片保存的結果吧!!!
 

aug_train_img

aug_train_label


這裏特意說下,圖像的數量是自己設置的,在這裏,imgnum數量,決定了對單幅圖像增強的數量。(如果你需要對其中增強的多一些,就把這塊給修改下)

 def do_augmentate(self, img, save_to_dir, save_prefix, batch_size=1, save_format='png', imgnum=30):

四.圖像增強之批處理

這塊的內容,不想做太多的解釋了,只是由單幅圖像的讀取,改爲對文件夾內所有圖片的讀取。

但是,會把結果圖片這裏放一下,具體的代碼部分,歡迎去Github詳閱,地址:https://github.com/QianLingjun/Keras_image_aug,或者關注微信公衆號:小白算法,回覆關鍵字:Keras_image_aug。歡迎你的光臨哦。

批處理部分train_img,2是文件名

批處理部分train_label,14是文件名


最後,歡迎關注“小白CV”公衆號,長按關注哦。在文章的最後,再重複一次。歡迎去Github詳閱,地址:https://github.com/QianLingjun/Keras_image_aug,或者關注微信公衆號:小白CV,回覆關鍵字:Keras_image_aug。想獲得更多福利,關注公衆號後續更新。


五、最後,補充單文件夾圖像的數據增強(法一)

__author__ = "lingjun"
# E-mail: [email protected]
# 微信公衆號:小白CV

from keras.preprocessing.image import ImageDataGenerator

path = 'D:/image'  # 類別子文件夾的上一級
dst_path ='D:/image_gen'
#  圖片生成器
datagen = ImageDataGenerator(

    rotation_range=5,
    width_shift_range=0.02,
    height_shift_range=0.02,
    shear_range=0.02,
    horizontal_flip=True,
    vertical_flip=True
)

gen = datagen.flow_from_directory(
    path,
    target_size=(512, 512),
    batch_size=30,
    save_to_dir=dst_path,  # 生成後的圖像保存路徑
    save_prefix='xx',
    save_format='jpg')

for i in range(15):
    gen.next()

注意:待增強的圖像放在image文件夾下的子文件夾下,例如,待增強圖片在文件夾flower內,則此事flower的文件夾是image的子文件夾,這裏多進行嘗試就好。

原圖

增強後的圖像

同時呢,自己需要哪些變換,可以自行對ImageDataGenerator內容就行查詢修改,這裏不贅述;


六、基於Augmentor的數據增強

簡單粗暴,原圖是這樣的:

簡單的幾句代碼,就能夠實現許許多多的增強結果

import Augmentor
# 待增強圖像放在test文件夾下即可
# 會自動的創建output文件,用於保存增強後的圖像
p=Augmentor.Pipeline("./test")

# 增強的方式,逆時針隨機旋轉90度(隨機概率可自行設定)
p.rotate90(probability=0.5)
p.skew_corner(probability=0.7,magnitude=1)

# 增強的個數
p.sample(20)

來看下增強後的結果,代碼中的註釋部分很詳細,主要是做了這幾件事情:

  1. 導入庫,確定待增強圖像所在的位置
  2. 確定增強的方式
  3. 增強的個數

更加多樣的增強方式和數量可以自行增加。(美女都被拉變形了,罪惡啊罪惡)

之後也會持續的關注一些圖像增強的第三方好庫,也會都更新到這裏,持續關注,收藏哦

小白CV:公衆號旨在專注CV(計算機視覺)、AI(人工智能)領域相關技術,文章內容主要圍繞C++、Python編程技術,機器學習(ML)、深度學習(DL)、OpenCV等圖像處理技術,深度發掘技術要點,記錄學習工作中常用的操作,做你學習工作的問題小助手。只關注技術,做CV領域專業的知識分享平臺。
————————————————


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章