opencv(4)實現數據增加小工具
數據增加(data augmentation),作為一種深度學習中的常用手段,數據增加對模型的泛化性和準確性都有幫助。數據增加的具體使用方式一般有兩種,一種是實時增加,比如在Caffe中加入數據擾動層,每次圖像都先經過擾動操作,再去訓練,這樣訓練經過幾代(epoch)之後,就等效於數據增加。還有一種是更加直接簡單一些的,就是在訓練之前就通過圖像處理手段對數據樣本進行擾動和增加。
常見的擾動有:隨機裁剪,隨機旋轉和隨機顏色/明暗。
隨機裁剪
在裁剪的時候考慮圖像寬高比的擾動。在絕大多數用於分類的圖片中,樣本進入網絡前都是要變為統一大小,所以寬高比擾動相當於對物體的橫向和縱向進行了縮放,這樣除了物體的位置擾動,又多出了一項擾動。只要變化範圍控制合適,目標物體始終在畫面內,這種擾動是有助於提升泛化性能的。實現這種裁剪的思路如下圖所示:
圖中最左邊是一幅需要剪裁的畫面,首先根據這幅畫面我們可以算出一個寬高比w/h。然後設定一個小的擾動範圍δ和要裁剪的畫面占原畫面的比例β,從-到之間按均勻采樣,獲取一個隨機數作為裁剪後畫面的寬高比擾動的比例,則裁剪後畫面的寬和高分別為:
想象一下先把這個寬為w’,高為h’的區域置於原畫面的右下角,則這個區域的左上角和原畫面的左上角框出的小區域,如圖中的虛線框所示,就是裁剪後區域左上角可以取值的範圍。所以在這個區域內隨機采一點作為裁剪區域的左上角,就實現了如圖中位置隨機,且寬高比也隨機的裁剪。
隨機旋轉
做數據增加時,一般希望旋轉是沿著畫面的中心。這樣除了要知道旋轉角度,還得計算平移的量才能讓仿射變換的效果等效於旋轉軸在畫面中心,好在OpenCV中有現成的函數cv2.getRotationMatrix2D()可以使用。這個函數的第一個參數是旋轉中心,第二個參數是逆時針旋轉角度,第三個參數是縮放倍數,對於只是旋轉的情況下這個值是1,返回值就是做仿射變換的矩陣。
直接用這個函數並接著使用cv2.warpAffine()會有一個潛在的問題,就是旋轉之後會出現黑邊。如果要旋轉後的畫面不包含黑邊,就得沿著原來畫面的輪廓做個內接矩形,該矩形的寬高比和原畫面相同,如下圖所示:
在圖中,可以看到,限制內接矩形大小的主要是原畫面更靠近中心的那條邊,也就是圖中比較長的一條邊AB。因此我們只要沿著中心O和內接矩形的頂點方向的直線,求出和AB的交點P,就得到了內接矩形的大小。先來看長邊的方程,考慮之前畫面和橫軸相交的點,經過角度-θ旋轉後,到了圖中的Q點所在:
因為長邊所在直線過Q點,且斜率為1/tan(θ),所以有:
這時候考慮OP這條直線:
把這個公式帶入再前邊一個公式,求解可以得到:
註意到在這個問題中,每個象限和相鄰象限都是軸對稱的,而且旋轉角度對剪裁寬度和長度的影響是周期(T=π)變化,再加上我們關心的其實並不是四個點的位置,而是旋轉後要截取的矩形的寬w’和高h’,所以復雜的分區間情況也簡化了,首先對於旋轉角度,因為周期為π,所以都可以化到0到π之間,然後因為對稱性,進一步有:
於是對於0到π/2之間的θ,有:
當然需要註意的是,對於寬高比非常大或者非常小的圖片,旋轉後如果裁剪往往得到的畫面是非常小的一部分,甚至不包含目標物體。所以是否需要旋轉,以及是否需要裁剪,如果裁剪角度多少合適,都要視情況而定。
隨機顏色和明暗
給HSV空間的每個通道,分別加上一個微小的擾動。其中對於色調,從-到之間按均勻采樣,獲取一個隨機數作為要擾動的值,然後新的像素值x’為原始像素值x +;對於其他兩個空間則是新像素值x’為原始像素值x的(1+)倍,從而實現色調,飽和度和明暗度的擾動。
因為明暗度並不會對圖像的直方圖相對分布產生大的影響,所以在HSV擾動基礎上,考慮再加入一個Gamma擾動,方法是設定一個大於1的Gamma值的上限γ,因為這個值通常會和1是一個量級,再用均勻采樣的近似未必合適,所以從-logγ到logγ之間均勻采樣一個值α,然後用
作為Gamma值進行變換。
opencv(4)實現數據增加小工具