1. 程式人生 > 實用技巧 >資料增廣之詳細理解

資料增廣之詳細理解

資料增廣之詳細理解

燕小花 只有腳踏實地的人,才能夠說:路,就在我的腳下

引言

資料增廣是深度學習中常用的技巧之一,主要用於增加訓練資料集,讓資料集儘可能的多樣化,使得訓練的模型具有更強的泛化能力.現有的各大深度學習框架都已經自帶了資料增廣,但是平時在用的使用只是直接呼叫了對應的介面函式,而沒有進行詳細的分析.在實際應用中,並非所有的增廣方式都適用當前的訓練資料,你需要根據自己的資料集特徵來確定應該使用哪幾種資料增廣方式.這篇文章的目的是為了更好地理解各種增廣方式及其背後的真正原理.
目前資料增廣主要包括:水平/垂直翻轉,旋轉,縮放,裁剪,剪下,平移,對比度,色彩抖動,噪聲等,這裡因為時間問題,有部分還每有完成,後續會進行更新.

資料增廣

所有的資料增廣在操作的時候預設是以影象中心點進行的.從數學角度來看,任何操作都可以分成以下幾個步驟:1). 首先將旋轉點移動到原點處 ;2). 執行如2所描述的繞原點的旋轉;3). 再將旋轉點移回到原來的位置;這裡為了更好地理解,給出一個示例:

假設影象的原始座標為,平移後的座標為,則平移前和平移後的座標關係為:

影象平移

平移是指所有的畫素在x和y方向各平移和,平移變換對應的數學矩陣為

這裡給出平移後的具體例項(這裡平移後我採用的是倒映填充):

影象翻轉(影象映象)

影象翻轉包括水平翻轉和垂直翻轉.水平翻轉的變換矩陣為:

垂直翻轉的變換矩陣為:

這裡給出翻轉後的具體例項(這裡平移後我採用的是倒映填充):

影象旋轉

影象旋轉是指以某個點(預設為影象中心點)為中心進行任意角度的旋轉,其變換矩陣為:

這裡給出旋轉後的具體例項(這裡平移後我採用的是倒映填充):

影象縮放

影象縮放是指對當前影象進行任意尺度的縮放,其變換矩陣為:

這裡給出縮放後的具體例項(這裡平移後我採用的是倒映填充):

影象錯切

影象,其變換矩陣為:

這裡給出錯切後的具體例項(這裡平移後我採用的是倒映填充):

影象裁剪

深度學習的裁剪的常用做法是將圖片縮放到原圖的1.1倍,然後在縮放後的影象上進行裁剪操作,具體的裁剪例項如下:

組合變換

在深度學習中的資料增廣一般會採用多種增廣方式的組合,這裡就會涉及到矩陣乘法運算,根據其運算的規則,可以知道不同的組合順序結果是不一樣的,即線性代數中的,當然特例除外.

為了更好地解釋,假設給定平移變換矩陣,旋轉矩陣,縮放矩陣,為了說明這裡我給出兩個不同的組合變換.對於組合變換一,其組合後的矩陣如下:;對於組合變換二,其組合後的矩陣如下:,對於兩種不同的組合其結果如下:

資料增廣之原始碼實現

這裡使用python和opencv來實現上述中的各種變換,具體的原始碼如下:

#coding=utf-8
################################################
# 資料增廣,包括
# 2018.09.02 add 
################################################
import numpy as np
import os
import cv2
import copy


class DataAugment:
    def __init__(self,debug=False):
        self.debug=debug
        print("Data augment...")

    def basic_matrix(self,translation):
        """基礎變換矩陣"""
        return np.array([[1,0,translation[0]],[0,1,translation[1]],[0,0,1]])

    def adjust_transform_for_image(self,img,trans_matrix):
        """根據影象調整當前變換矩陣"""
        transform_matrix=copy.deepcopy(trans_matrix)
        height, width, channels = img.shape
        transform_matrix[0:2, 2] *= [width, height]
        center = np.array((0.5 * width, 0.5 * height))
        transform_matrix = np.linalg.multi_dot([self.basic_matrix(center), transform_matrix, self.basic_matrix(-center)])
        return transform_matrix

    def apply_transform(self,img,transform):
        """仿射變換"""
        output = cv2.warpAffine(img, transform[:2, :], dsize=(img.shape[1], img.shape[0]),
                                flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT, borderValue=0,)   #cv2.BORDER_REPLICATE,cv2.BORDER_TRANSPARENT
        return output

    def apply(self,img,trans_matrix):
        """應用變換"""
        tmp_matrix=self.adjust_transform_for_image(img, trans_matrix)
        out_img=self.apply_transform(img, tmp_matrix)
        if self.debug:
            self.show(out_img)
        return out_img

    def random_vector(self,min,max):
        """生成範圍矩陣"""
        min=np.array(min)
        max=np.array(max)
        print(min.shape,max.shape)
        assert min.shape==max.shape
        assert len(min.shape) == 1
        return np.random.uniform(min, max)

    def show(self,img):
        """視覺化"""
        cv2.imshow("outimg",img)
        cv2.waitKey()

    def random_transform(self,img,min_translation,max_translation):
        """平移變換"""
        factor=self.random_vector(min_translation,max_translation)
        trans_matrix=np.array([[1, 0, factor[0]],[0, 1, factor[1]],[0, 0, 1]])
        out_img=self.apply(img,trans_matrix)
        return trans_matrix, out_img

    def random_flip(self,img,factor):
        """水平或垂直翻轉"""
        flip_matrix = np.array([[factor[0], 0, 0],[0, factor[1], 0],[0, 0, 1]])
        out_img=self.apply(img,flip_matrix)
        return flip_matrix, out_img

    def random_rotate(self,img,factor):
        """隨機旋轉"""
        angle=np.random.uniform(factor[0],factor[1])
        print("angle:{}".format(angle))
        rotate_matrix=np.array([[np.cos(angle), -np.sin(angle), 0],[np.sin(angle), np.cos(angle), 0],[0, 0, 1]])
        out_img=self.apply(img,rotate_matrix)
        return rotate_matrix, out_img

    def random_scale(self,img,min_translation,max_translation):
        """隨機縮放"""
        factor=self.random_vector(min_translation, max_translation)
        scale_matrix = np.array([[factor[0], 0, 0],[0, factor[1], 0],[0, 0, 1]])
        out_img=self.apply(img,scale_matrix)
        return scale_matrix, out_img

    def random_shear(self,img,factor):
        """隨機剪下,包括橫向和眾向剪下"""
        angle = np.random.uniform(factor[0], factor[1])
        print("fc:{}".format(angle))
        crop_matrix = np.array([[1, factor[0], 0], [factor[1], 1, 0], [0, 0, 1]])
        out_img=self.apply(img,crop_matrix)
        return crop_matrix, out_img


if __name__=="__main__":
    demo=DataAugment(debug=True)
    img=cv2.imread("/pathto/dataArgu/wr.jpg")

    # 平移測試
    _,outimg=demo.random_transform(img,(0.1,0.1),(0.2,0.2))  #(-0.3,-0.3),(0.3,0.3)


   # 垂直變換測試
    _, outimg =demo.random_flip(img,(1.0,-1.0))

    # 水平變換測試
    _, outimg =demo.random_flip(img, (-1.0, 1.0))
   

    # 旋轉變換測試
     _, outimg =demo.random_rotate(img,(0.5,0.8))
   
    # # 縮放變換測試
     _, outimg =demo.random_scale(img,(1.2, 1.2),(1.3,1.3))

    # 隨機裁剪測試
    _, outimg =demo.random_shear(img,(0.2,0.3))

    # 組合變換
    t1,_=demo.random_transform(img,(-0.3,-0.3),(0.3,0.3))
    t2,_=demo.random_rotate(img,(0.5,0.8))
    t3,_=demo.random_scale(img,(1.5,1.5),(1.7,1.7))
    tmp=np.linalg.multi_dot([t1,t2,t3])
    print("tmp:{}".format(tmp))
    out=demo.apply(img,tmp)

本章中還有幾個方法未實現,後續會補上.如果文中有理解錯誤的地方,歡迎指正.

編輯於 2018-09-05 深度學習(Deep Learning) 計算機視覺 影象處理

文章被以下專欄收錄

小石頭的碼瘋窩 也歡迎關注同名公眾號小石頭的碼瘋窩,不定期資料分享

推薦閱讀

深度學習的預處理:從協方差矩陣到影象白化

深度智慧發表於深度學習理...

【論文復現】基於深度學習的影象匹配演算法(二)

一瓶可樂發表於計算機視覺...

RANSAC演算法詳解(附Python擬合直線模型程式碼)

李鑫

超越EfficientNets!無需注意力,也能讓你的網路更快更強!

CVer發表於CVer計...

13 條評論

寫下你的評論...
  • 採石工2018-09-03

    DataArgement的拼寫有誤, 應為DataAugment

  • 燕小花(作者)2018-09-04 謝謝提醒,已修改。