1. 程式人生 > >機器視覺 OpenCV—python 資料增強

機器視覺 OpenCV—python 資料增強

一、前言

大家好,我之前做過影象分類或識別時,經常感慨資料集不夠大,導致模型的準確度不夠高,雖然用過一些影象增強的方法,也見過別人用過一些資料增強的方法,接下來主要統計一些常見的影象增強的方法。 作為一種深度學習中的常用手段,影象增加對模型的泛化性和準確性都有幫助。資料增加的具體使用方式一般有兩種:

  • 一種是實時增加,比如在Caffe中加入資料擾動層,每次影象都先經過擾動操作,再去訓練,這樣訓練經過幾代(epoch)之後,就等效於資料增加。
  • 一種是更加直接簡單一些的,就是在訓練之前就通過影象處理手段對資料樣本進行擾動和增加

二、影象增強(data augmentation):

1.隨機裁剪 2.隨機旋轉 3.隨機顏色/明暗。 4.仿射變換 5. 影象翻轉(映象:x軸,y軸,xy軸)

2.1 隨機裁剪

在裁剪的時候考慮影象寬高比的擾動:寬高比擾動相當於對物體的橫向和縱向進行了縮放,這樣除了物體的位置擾動,又多出了一項擾動。只要變化範圍控制合適,目標物體始終在畫面內,這種擾動是有助於提升泛化效能的。 在這裡插入圖片描述 第二圖的左上角區域內隨機採一點作為裁剪區域的左上角,就實現瞭如圖中位置隨機,且寬高比也隨機的裁剪。

2.2 隨機旋轉

旋轉:旋轉中心,旋轉角度

cv2.getRotationMatrix2D()
"""
	第一個引數是旋轉中心,
	第二個引數是逆時針旋轉角度,
	第三個引數是縮放倍數,對於只是旋轉的情況下這個值是1,返回值就是做仿射變換的矩陣。

"""

cv2.warpAffine(
) """ 旋轉之後在缺失區域會出現黑邊 """
2.3 隨機的顏色和明暗

隨機的顏色以及明暗的方法相對簡單很多,就是給HSV空間的每個通道,分別加上一個微小的擾動。 其中對於色調: 從 -δ\deltaδ\delta之間按均勻取樣,獲取一個隨機數 δ^\hat \delta 作為要擾動的值,然後新的畫素值 xx' 為原始畫素值 x+δ^x +\hat \delta;對於其他兩個空間則是新畫素值 xx' 為原始畫素值 xx(1+δ^)(1+\hat \delta) 倍,從而實現色調,飽和度和明暗度的擾動。

因為明暗度並不會對影象的直方圖相對分佈產生大的影響,所以在HSV擾動基礎上,考慮再加入一個Gamma擾動,方法是設定一個大於1的Gamma值的上限 γγ,因為這個值通常會和1是一個量級,再用均勻取樣的近似未必合適,所以從logγ-\logγlogγ\logγ 之間均勻取樣一個值 αα,然後用 eαe^{\alpha} 作為Gamma值進行變換。

"""
	image_augmentation.py
"""
import numpy as np
import cv2

'''
定義裁剪函式,四個引數分別是:
左上角橫座標x0
左上角縱座標y0
裁剪寬度w
裁剪高度h
'''
crop_image = lambda img, x0, y0, w, h: img[y0:y0+h, x0:x0+w]

'''
隨機裁剪
area_ratio為裁剪畫面佔原畫面的比例
hw_vari是擾動佔原高寬比的比例範圍
'''
def random_crop(img, area_ratio, hw_vari):
    h, w = img.shape[:2]
    hw_delta = np.random.uniform(-hw_vari, hw_vari)
    hw_mult = 1 + hw_delta
	
	# 下標進行裁剪,寬高必須是正整數
    w_crop = int(round(w*np.sqrt(area_ratio*hw_mult)))
	
	# 裁剪寬度不可超過原圖可裁剪寬度
    if w_crop > w:
        w_crop = w
		
    h_crop = int(round(h*np.sqrt(area_ratio/hw_mult)))
    if h_crop > h:
        h_crop = h
	
	# 隨機生成左上角的位置
    x0 = np.random.randint(0, w-w_crop+1)
    y0 = np.random.randint(0, h-h_crop+1)
	
    return crop_image(img, x0, y0, w_crop, h_crop)

'''
定義旋轉函式:
angle是逆時針旋轉的角度
crop是個布林值,表明是否要裁剪去除黑邊
'''
def rotate_image(img, angle, crop):
    h, w = img.shape[:2]
	
	# 旋轉角度的週期是360°
    angle %= 360
	
	# 用OpenCV內建函式計算仿射矩陣
    M_rotate = cv2.getRotationMatrix2D((w/2, h/2), angle, 1)
	
	# 得到旋轉後的影象
    img_rotated = cv2.warpAffine(img, M_rotate, (w, h))

	# 如果需要裁剪去除黑邊
    if crop:
        angle_crop = angle % 180             	    # 對於裁剪角度的等效週期是180°
        if angle_crop > 90:                        	# 並且關於90°對稱
            angle_crop = 180 - angle_crop
		
        theta = angle_crop * np.pi / 180.0    		# 轉化角度為弧度
        hw_ratio = float(h) / float(w)    		    # 計算高寬比
		

        tan_theta = np.tan(theta)                   # 計算裁剪邊長係數的分子項
        numerator = np.cos(theta) + np.sin(theta) * tan_theta
		

        r = hw_ratio if h > w else 1 / hw_ratio		# 計算分母項中和寬高比相關的項
        denominator = r * tan_theta + 1		 		# 計算分母項

        crop_mult = numerator / denominator			# 計算最終的邊長係數
        w_crop = int(round(crop_mult*w))			# 得到裁剪區域
        h_crop = int(round(crop_mult*h))
        x0 = int((w-w_crop)/2)
        y0 = int((h-h_crop)/2)
        img_rotated = crop_image(img_rotated, x0, y0, w_crop, h_crop)
    return img_rotated

'''
隨機旋轉
angle_vari是旋轉角度的範圍[-angle_vari, angle_vari)
p_crop是要進行去黑邊裁剪的比例
'''
def random_rotate(img, angle_vari, p_crop):
    angle = np.random.uniform(-angle_vari, angle_vari)
    crop = False if np.random.random() > p_crop else True
    return rotate_image(img, angle, crop)

'''
定義hsv變換函式:
hue_delta是色調變化比例
sat_delta是飽和度變化比例
val_delta是明度變化比例
'''
def hsv_transform(img, hue_delta, sat_mult, val_mult):
    img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV).astype(np.float)
    img_hsv[:, :, 0] = (img_hsv[:, :, 0] + hue_delta) % 180
    img_hsv[:, :, 1] *= sat_mult
    img_hsv[:, :, 2] *= val_mult
    img_hsv[img_hsv > 255] = 255
    return cv2.cvtColor(np.round(img_hsv).astype(np.uint8), cv2.COLOR_HSV2BGR)

'''
隨機hsv變換
hue_vari是色調變化比例的範圍
sat_vari是飽和度變化比例的範圍
val_vari是明度變化比例的範圍
'''
def random_hsv_transform(img, hue_vari, sat_vari, val_vari):
    hue_delta = np.random.randint(-hue_vari, hue_vari)
    sat_mult = 1 + np.random.uniform(-sat_vari, sat_vari)
    val_mult = 1 + np.random.uniform(-val_vari, val_vari)
    return hsv_transform(img, hue_delta, sat_mult, val_mult)

'''
定義gamma變換函式:
gamma就是Gamma
'''
def gamma_transform(img, gamma):
    gamma_table = [np.power(x / 255.0, gamma) * 255.0 for x in range(256)]
    gamma_table = np.round(np.array(gamma_table)).astype(np.uint8)
    return cv2.LUT(img, gamma_table)

'''
隨機gamma變換
gamma_vari是Gamma變化的範圍[1/gamma_vari, gamma_vari)
'''
def random_gamma_transform(img, gamma_vari):
    log_gamma_vari = np.log(gamma_vari)
    alpha = np.random.uniform(-log_gamma_vari, log_gamma_vari)
    gamma = np.exp(alpha)
    return gamma_transform(img, gamma)

主程式裡首先定義三個子模組:

  1. 定義一個函式 parse_arg() 通過Python的argparse模組定義了各種輸入引數和預設值。需要注意的是這裡用argparse來輸入所有引數是因為引數總量並不是特別多,如果增加了更多的擾動方法,更合適的引數輸入方式可能是通過一個配置檔案。
  2. 定義一個生成待處理影象列表的函式 generate_image_list(),根據輸入中要增加圖片的數量和並行程序的數目儘可能均勻地為每個程序生成了需要處理的任務列表。執行隨機擾動的程式碼定義在augment_images()中,這個函式是每個程序內進行實際處理的函式,執行順序是映象\rightarrow 裁剪\rightarrow 旋轉HSVGamma\rightarrow HSV\rightarrow Gamma。需要注意的是映象\rightarrow 裁剪,因為只是個演示例子,這未必是一個合適的順序。
  3. 定義一個 main 函式進行呼叫,程式碼如下:定義一個main函式進行呼叫,程式碼如下:
"""
	run_augmentation.py
"""
import os
import argparse
import random
import math
from multiprocessing import Process
from multiprocessing import cpu_count

import cv2

# 匯入image_augmentation.py為一個可呼叫模組
import image_augmentation as ia

# 利用Python的argparse模組讀取輸入輸出和各種擾動引數
def parse_args():
    parser = argparse.ArgumentParser(
        description='A Simple Image Data Augmentation Tool',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)

    parser.add_argument('input_dir',
                        help='Directory containing images')
    parser.add_argument('output_dir',
                        help='Directory for augmented images')
    parser.add_argument('num',
                        help='Number of images to be augmented',
                        type=int)

    parser.add_argument('--num_procs',
                        help='Number of processes for paralleled augmentation',
                        type=int, default=cpu_count())

    parser.add_argument('--p_mirror',
                        help='Ratio to mirror an image',
                        type=float, default=0.5)

    parser.add_argument('--p_crop',
                        help='Ratio to randomly crop an image',
                        type=float, default=1.0)
    parser.add_argument('--crop_size',
                        help='The ratio of cropped image size to original image size, in area',
                        type=float, default=0.8)
    parser.add_argument('--crop_hw_vari',
                        help='Variation of h/w ratio',
                        type=float, default=0.1)

    parser.add_argument('--p_rotate',
                        help='Ratio to randomly rotate an image',
                        type=float, default=1.0)
    parser.add_argument('--p_rotate_crop',
                        help='Ratio to crop out the empty part in a rotated image',
                        type=float, default=1.0)
    parser.add_argument('--rotate_angle_vari',
                        help='Variation range of rotate angle',
                        type=float, default=10.0)

    parser.add_argument('--p_hsv',
                        help='Ratio to randomly change gamma of an image',
                        type=float, default=1.0)
    parser.add_argument('--hue_vari',
                        help='Variation of hue',
                        type=int, default=10)
    parser.add_argument('--sat_vari',
                        help='Variation of saturation',
                        type=float, default=0.1)
    parser.add_argument('--val_vari',
                        help='Variation of value',
                        type=float, default=0.1)

    parser.add_argument('--p_gamma',
                        help='Ratio to randomly change gamma of an image',
                        type=float, default=1.0)
    parser.add_argument('--gamma_vari',
                        help='Variation of gamma',
                        type=float, default=2.0)

    args = parser.parse_args()
    args.input_dir = args.input_dir.rstrip('/')
    args.output_dir = args.output_dir.rstrip('/')

    return args

'''
根據程序數和要增加的目標圖片數,
生成每個程序要處理的檔案列表和每個檔案要增加的數目
'''
def generate_image_list(args):
    # 獲取所有檔名和檔案總數
    filenames = os.listdir(args.input_dir)
    num_imgs = len(filenames)

	# 計算平均處理的數目並向下取整
    num_ave_aug = int(math.floor(args.num/num_imgs))
	
	# 剩下的部分不足平均分配到每一個檔案,所以做成一個隨機幸運列表
	# 對於幸運的檔案就多增加一個,湊夠指定的數目
    rem = args.num - num_ave_aug*num_imgs
    lucky_seq = [True]*rem + [False]*(num_imgs-rem)
    random.shuffle(lucky_seq)

	# 根據平均分配和幸運表策略,
	# 生成每個檔案的全路徑和對應要增加的數目並放到一個list裡
    img_list = [
        (os.sep.join([args.input_dir, filename]), num_ave_aug+1 if lucky else num_ave_aug)
        for filename, lucky in zip(filenames, lucky_seq)
    ]
	
	# 檔案可能大小不一,處理時間也不一樣,
	# 所以隨機打亂,儘可能保證處理時間均勻
    random.shuffle(img_list)

	# 生成每個程序的檔案列表,
	# 儘可能均勻地劃分每個程序要處理的數目
    length = float(num_imgs) / float(args.num_procs)
    indices = [int(round(i * length)) for i in range(args.num_procs + 1)]
    return [img_list[indices[i]:indices[i + 1]] for i in range(args.num_procs)]

# 每個程序內呼叫影象處理函式進行擾動的函式
def augment_images(filelist, args):
    # 遍歷所有列表內的檔案
    for filepath, n in filelist:
        img = cv2.imread(filepath)
        filename = filepath.split(os.sep)[-1]
        dot_pos = filename.rfind('.')
		
		# 獲取檔名和字尾名
        imgname = filename[:dot_pos]
        ext = filename[dot_pos:]

        print('Augmenting {} ...'.format(filename))
        for i in range(n):
            img_varied = img.copy()
			
			# 擾動後文件名的字首
            varied_imgname = '{}_{:0>3d}_'.format(imgname, i)
			
			# 按照比例隨機對影象進行映象
            if random.random() < args.p_mirror:
			    # 利用numpy.fliplr(img_varied)也能實現
                img_varied = cv2.flip(img_varied, 1)
                varied_imgname += 'm'
			
			# 按照比例隨機對影象進行裁剪
            if random.random() < args.p_crop:
                img_varied = ia.random_crop(
                    img_varied,
                    args.crop_size,
                    args.crop_hw_vari)
                varied_imgname += 'c'
			
			# 按照比例隨機對影象進行旋轉
            if random.random() < args.p_rotate:
                img_varied = ia.random_rotate(
                    img_varied,
                    args.rotate_angle_vari,
                    args.p_rotate_crop)
                varied_imgname += 'r'
			
			# 按照比例隨機對影象進行HSV擾動
            if random.random() < args.p_hsv:
                img_varied = ia.random_hsv_transform(
                    img_varied,
                    args.hue_vari,
                    args.sat_vari,
                    args.val_vari)
                varied_imgname += 'h'
			
			# 按照比例隨機對影象進行Gamma擾動
            if random.random() < args.p_gamma:
                img_varied = ia.random_gamma_transform(
                    img_varied,
                    args.gamma_vari)
                varied_imgname += 'g'
			
			# 生成擾動後的檔名並儲存在指定的路徑
            output_filepath = os.sep.join([
                args.output_dir,
                '{}{}'.format(varied_imgname, ext)])
            cv2.imwrite(output_filepath, img_varied)

# 主函式
def main():
    # 獲取輸入輸出和變換選項
    args = parse_args()
    params_str = str(args)[10:-1]

	# 如果輸出資料夾不存在,則建立資料夾
    if not os.path.exists(args.output_dir
            
           

相關推薦

機器視覺 OpenCVpython 資料增強

一、前言 大家好,我之前做過影象分類或識別時,經常感慨資料集不夠大,導致模型的準確度不夠高,雖然用過一些影象增強的方法,也見過別人用過一些資料增強的方法,接下來主要統計一些常見的影象增強的方法。 作為一種深度學習中的常用手段,影象增加對模型的泛化性和準確性都有幫

機器視覺 OpenCVpython 影象資料集獲取工具(視訊取幀)

一、前言 之前在做影象分類的時候,人臉識別(開原始碼)的練手,資料集獲取麻煩(沒人願意將自己照片給人家做資料集),於是就用自己造資料集,但是拍照拍幾百張訓練效果不好,也嫌麻煩,乾脆就是視訊取幀的方式,在這之前使用專門的軟體。不過opencv自帶了視訊處理的API

機器視覺 OpenCVpython 基於LSTM網路的OCR文字檢測與識別

一、背景與環境搭建 OpenCV的文字識別流程: OpenCV EAST 文字檢測器執行文字檢測, 我們提取出每個文字 ROI 並將其輸入 Tesseract,從而構建完整的 OpenCV OCR 流程! 環境搭建 Tesseract (v4) 最新版本

機器視覺 OpenCVpython 基於深度學習的實時目標檢測

一、目標檢測原理 運動目標在工廠,監控,自動駕駛中有著舉足輕重的地位。在做實時目標檢測之前,我做過OpenCV的目標檢測和運動軌跡及運動方向預判等,但這些都是基於OpenCV的,有一定的侷限性。為此,從這篇部落格開始將給大家帶來一系列的實時目標檢測,與大家一起

機器學習」Python資料分析之Numpy進階

請點選此處輸入圖片描述 進階 廣播法則(rule) 廣播法則能使通用函式有意義地處理不具有相同形狀的輸入。 廣播第一法則是,如果所有的輸入陣列維度不都相同,一個“1”將被重複地新增在維度較小的陣列上直至所有的陣列擁有一樣的維度。 廣播第二法則確定長度為1的陣列沿著特

機器學習」Python資料分析之Numpy

請點選此處輸入圖片描述 NumPy的主要物件是同種元素的多維陣列。這是一個所有的元素都是一種型別、通過一個正整數元組索引的元素表格(通常是元素是數字)。在NumPy中維度(dimensions)叫做軸(axes),軸的個數叫做秩(rank)。 例如,在3D空間一個點的座標[1,

學習OpenCV-Python——影象增強

影象增強 影象增強可以分為兩種: 領域處理技術。對畫素點及其周圍的點進行處理,即使用卷積核。 點處理技術。只對單個畫素進行處理。 歸一化 cv2.normalize(src, dst, alpha, beta, norm_type, dtype, mask

深度學習與計算機視覺(PB-02)-資料增強

在深度學習實踐中,當訓練資料量少時,可能會出現過擬合問題。根據Goodfellow等人的觀點,我們對學習演算法的任何修改的目的都是為了減小泛化誤差,而不是訓練誤差。 我們已經在sb[後續補充]中提到了不同型別的正則化手段來防止模型的過擬合,然而,這些都是針對引數的正則化形式,往往要求我們

OpenCVpython 影象增強

一、影象增強 import os import cv2 import random import numpy as np def random_crop(img, area_ratio, hw_vari): """ :param img:

OpenCV--Python 影象增強

                          OpenCV--Python 影象增強 影象增強主要解決由於影象的灰度級範圍較小造成的對比度較低的問題,目的就是將

機器學習實戰與python資料探勘 與python計算機視覺

兩本書的 pdf都比較好找  點這裡是機器學習實戰的CSDN介紹   這裡是對應原始碼     個人部落格也列出過可執行的pythin資料探勘原始碼  python計算機視覺的官網與原始碼在這裡 因為看了機器學習實戰

R語言機器學習與大資料視覺化暨Python文字挖掘與自然語言處理核心技術研修

中國通訊工業協會通訊和資訊科技創新人才培養工程專案辦公室通人辦〔2017〕 第45號“R語言機器

Python下的資料處理和機器學習,對資料線上及本地獲取、解析、預處理和訓練、預測、交叉驗證、視覺

<!doctype html> <html> <head> <title>Example Domain</title> <meta charset="utf-8" /> <meta http-equiv=

Opencv入門-第一回-夢牽機器視覺翼,初識Opencv域(安裝Opencv

x64 配置 發展 免費 -c 找到 版本號 開始 名稱 各位看官,您是不是瞅著Opencv進來的?(你這不是廢話嗎>_>) 這Opencv(開源計算機視覺庫)啊,說來話長,最初是上個世紀末(1999年)由Intel建立起來的。近十多年人工智能這匹黑馬突然出現,

opencv機器視覺識別鋼板層數備忘錄】

原圖: 首先想到的是基於邊緣檢測或者閾值分割的方法進行檢測: #include<opencv2\opencv.hpp> #include<iostream> using namespace std; using namespace cv; Mat o

Python資料處理 | (三) Matplotlib資料視覺

本篇部落格所有示例使用Jupyter NoteBook演示。 Python資料處理系列筆記基於:Python資料科學手冊電子版  下載密碼:ovnh 示例程式碼  下載密碼:02f4   目錄 一、Matplotlib常用技巧 1.匯入

Python機器視覺(x)影象修復

本系列部落格主要分享Python在機器視覺/計算機視覺下的程式設計應用 cv2包是著名的視覺庫OpenCV的Python實現 影象修復 很多時候遇到受損的圖片我們需要利用機器視覺的手段對其進行修復,opencv中提供了inpaint函式實現了這一功能。 1.先來

python中使用PIL模組中的ImageEnhance進行圖片資料增強

使用此方法將圖片進行資料增強,具體增強圖片的形式是如下幾種: """ 1、對比度:白色畫面(最亮時)下的亮度除以黑色畫面(最暗時)下的亮度; 2、色彩飽和度::彩度除以明度,指色彩的鮮豔程度,也稱色彩的純度; 3、色調:向負方向調節會顯現紅色,正方向調節則增加黃色。適合對膚色物件進行微調; 4、

Python資料視覺化之密度圖的繪製

密度圖表現與資料值對應的邊界或域物件的一種理論圖形表示方法。一般用於呈現連續變數。 *摘自百度百科* 在電腦科學當中,資料的視覺化常常被提起。近日,在影象處理當中,需要統計圖片中的人流密度並繪製相應密度圖,於是小小研究一番。效果如下: 所有程式碼儲存在Github上。 首

分享《OpenCV 3計算機視覺Python語言實現(第2版)》中文PDF+英文PDF+原始碼

下載:https://pan.baidu.com/s/1gGgEk8Y6X58gfvsmD8U8Xw 更多資料分享:https://www.cnblogs.com/javapythonstudy/ 《OpenCV 3計算機視覺:Python語言實現(第2版)》中文PDF+英文PDF+原始碼中文PDF,20