0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

圖像增強的主要方法及其Python實現(xiàn)

zhKF_jqr_AI ? 來源:未知 ? 作者:李倩 ? 2018-06-30 10:07 ? 次閱讀

編者按:倫敦帝國學院計算成像PhD學生Rob Robinson介紹了圖像增強的主要方法及其Python實現(xiàn)。

進行有效的深度學習網(wǎng)絡訓練的最大限制因素是訓練數(shù)據(jù)。為了很好地完成分類任務,我們需要給我們的CNN等模型盡可能多的樣本。然而,并不是所有情況下都可能做到這一點,特別是處于一些訓練數(shù)據(jù)很難收集的情形,比如醫(yī)學影像數(shù)據(jù)。在本文中,我們將學習如何應用數(shù)據(jù)增強策略至n維圖像,以充分利用數(shù)量有限的樣本。

介紹

如果我們將任何圖像(比如下面的機器人)整體向右移動一個像素,視覺上幾乎毫無差別。然而,數(shù)值上這是兩張完全不同的圖像!想象一下有一組10張這樣的圖像,每張相對前一張平移一個像素?,F(xiàn)在考慮圖像[20, 25]處的像素或某個任意的位置。聚焦到這一點,每個像素有不同的顏色,不同的周邊平均亮度,等等。一個CNN在進行卷積和決定權重時,會將這些考慮在內(nèi)。如果我們將這組10張圖像傳給CNN,應該能夠有效地讓CNN學習忽略這類平移。

原圖

向右平移1像素

向右平移10像素

當然,平移不是在保證視覺上看起來一樣的前提下改動圖像的唯一方式。考慮下將圖片旋轉(zhuǎn)1度,或者5度。它仍然是機器人。用不帶平移和旋轉(zhuǎn)版本的圖像訓練CNN可能導致CNN過擬合,認為所有機器人的圖像都是不偏不倚的。

給深度學習模型提供平移、旋轉(zhuǎn)、縮放、改變亮度、翻轉(zhuǎn)的圖像,我們稱之為數(shù)據(jù)增強。

在本文中,我們將查看如何應用這些變換至圖像,包括3D圖像,及其對深度學習模型表現(xiàn)的影響。我們將使用flickr用戶andy_emcee拍攝的照片作為2D自然圖像的樣本。由于這是一幅RGB(彩色)圖像,因此它的形狀為[512, 640, 3],每層對應一個色彩頻道。我們可以抽掉一層,將圖像轉(zhuǎn)為灰度圖像(真2D),不過我們處理的大部分圖像都是彩色圖像,因此我們這里保留原樣。我們將使用3D MRI掃描圖作為3D圖像的樣本。

RGB圖像

增強

我們將使用python編寫數(shù)據(jù)增強函數(shù)(基于numpy和scipy)。

平移

在我們的函數(shù)中,圖像是一個2D或3D數(shù)組——如果它是一個3D數(shù)組,我們需要小心地在offset參數(shù)中指定方向。我們并不想在z方向上移動,原因如下:首先,如果這是一個2D圖像,第三維將是色彩頻道,如果我們在這一維度上移動了-2、2或更多,整個圖像將變成全紅、全藍或全黑;其次,在全3D圖像中,第三維常常是最小的,例如,在大多數(shù)醫(yī)學掃描圖像中。在下面的平移函數(shù)中,offset是一個長度為2的數(shù)組,定義了y和x方向的平移。我們硬編碼z方向為0,不過,根據(jù)你的具體情況,你可以加以改動。為了確保我們平移的像素是整數(shù),我們強制使用int。

def translateit(image, offset, isseg=False):

order = 0if isseg == Trueelse5

return scipy.ndimage.interpolation.shift(image, (int(offset[0]), int(offset[1]), 0), order=order, mode='nearest')

當我們平移圖像時,會在圖像邊緣留下一條縫隙。我們需要找到填補這一縫隙的方式:shift默認將使用一個常量(0)。但在某些情況下,這可能無濟于事,所以最好將mode設為nearest,使用鄰近的像素值填充。平移值較小時,幾乎難以察覺這一點。不過平移值較大時,看起來就不對勁了。所以我們需要小心,僅對我們的數(shù)據(jù)應用較小的平移。

另外,我們提供了一個布爾值選項isseg,供選擇order參數(shù)的值。isseg為真時(處理分割圖),order為0,也就是直接使用最近的像素值填充;isseg為假時,order為5,也就是進行5次B樣條插值(綜合考量目標周圍的許多像素)。

原圖

右移5像素

右移25像素

原圖、分割圖

平移[-3, 1]像素

平移4, -5像素

縮放

我們根據(jù)一個特定的倍數(shù)(factor)縮放圖像。倍數(shù)大于1.0時,放大圖像;倍數(shù)小于1.0時,縮小圖像。注意我們需要為每個維度指定倍數(shù):其中,最后一個維度(2D圖像中為色彩頻道)倍數(shù)為1.0。我們使用柵格(網(wǎng)格)來決定結(jié)果圖像每個像素的亮度(使用周圍像素的亮度進行插值)。scipy提供了一個方便的函數(shù),稱為zoom。

定義大概要比你想象的復雜:

def scaleit(image, factor, isseg=False):

order = 0if isseg == Trueelse3

height, width, depth= image.shape

zheight = int(np.round(factor * height))

zwidth = int(np.round(factor * width))

zdepth = depth

if factor < 1.0:

newimg = np.zeros_like(image)

row = (height - zheight) // 2

col = (width - zwidth) // 2

layer = (depth - zdepth) // 2

newimg[row:row+zheight, col:col+zwidth, layer:layer+zdepth] = interpolation.zoom(image, (float(factor), float(factor), 1.0), order=order, mode='nearest')[0:zheight, 0:zwidth, 0:zdepth]

return newimg

elif factor > 1.0:

row = (zheight - height) // 2

col = (zwidth - width) // 2

layer = (zdepth - depth) // 2

newimg = interpolation.zoom(image[row:row+zheight, col:col+zwidth, layer:layer+zdepth], (float(factor), float(factor), 1.0), order=order, mode='nearest')

extrah = (newimg.shape[0] - height) // 2

extraw = (newimg.shape[1] - width) // 2

extrad = (newimg.shape[2] - depth) // 2

newimg = newimg[extrah:extrah+height, extraw:extraw+width, extrad:extrad+depth]

return newimg

else:

return image

我們需要考慮三種可能性——放大、縮小、不變。在每種情形下,我們想要返回與輸入圖像尺寸相等的數(shù)組??s小時,這牽涉創(chuàng)建一張大小形狀和輸入圖像一致的空圖像,并在當中相應的位置放入縮小后的圖像。放大時,不需要放大整張圖像,只需放大“縮放”的區(qū)域——因此我們只將數(shù)組的一部分傳給zoom函數(shù)。取整可能造成最終形狀中的一些誤差,所以我們在返回圖像前進行了一些修剪。不縮放時,我們返回原圖。

原圖

原圖、分割圖

縮放倍數(shù)1.07

縮放倍數(shù)0.95

重采樣

有時我們需要修改圖像,使其符合CNN的輸入格式要求。例如,對大多數(shù)圖像和照片而言,一個維度比另一個維度大,或者分辨率參差不齊。而大多數(shù)CNN需要尺寸一致的正方形輸入。我們同樣可以使用scipy函數(shù)interpolation.zoom辦到這一點:

def resampleit(image, dims, isseg=False):

order = 0if isseg == Trueelse5

image = interpolation.zoom(image, np.array(dims)/np.array(image.shape, dtype=np.float32), order=order, mode='nearest')

if image.shape[-1] == 3: # rgb圖像

return image

else:

return image if isseg else (image-image.min())/(image.max()-image.min())

這里的關鍵部分是我們將factor參數(shù)替換為類型為列表的dims參數(shù)。dims的長度應當和圖像的維度相等,即,2或3. 我們計算每個維度需要改變的倍數(shù)以將整個圖像變動到dims目標。

在這一步中,當圖像不是分割圖時,我們同時將圖像的亮度轉(zhuǎn)換至0.0至1.0區(qū)間,以確保所有圖像的亮度位于同一區(qū)間。

旋轉(zhuǎn)

我們利用了另一個scipy函數(shù)rotate。它的theta參數(shù)接受一個浮點數(shù),用來指定旋轉(zhuǎn)的角度(負數(shù)表示逆時針旋轉(zhuǎn))。我們想要返回和輸入圖像大小和形狀相同的圖像,因此使用了reshape = False。同樣,我們需要指定order決定插值方法。rotate函數(shù)支持3D圖像,使用相同的theta值旋轉(zhuǎn)每個切片。

def rotateit(image, theta, isseg=False):

order = 0if isseg == Trueelse5

return rotate(image, float(theta), reshape=False, order=order, mode='nearest')

原圖

theta = -10.0

theta = 10.0

原圖、分割圖

theta = 6.18

theta = -1.91

亮度變動

我們還可以縮放像素的亮度,也就是加亮或壓暗圖像。我們指定一個倍數(shù):倍數(shù)小于1.0將壓暗圖像;倍數(shù)大于1.0將加亮圖像。注意倍數(shù)不能為0.0,否則會得到全黑的圖像。

def intensifyit(image, factor):

return image*float(factor)

翻轉(zhuǎn)

對自然圖像(狗、貓、風景等)而言,最常見的圖像增強過程是翻轉(zhuǎn)。其依據(jù)是不管狗朝向哪一邊,始終是狗。不管樹在右邊還是在左邊,它仍然是一棵樹。

我們可以進行左右翻轉(zhuǎn),也可以進行上下翻轉(zhuǎn)。有可能只有一種翻轉(zhuǎn)有意義(比如,我們知道狗不能通過它們的頭行走)。我們通過由2個布爾值組成的列表指定如何進行翻轉(zhuǎn):如果每個值都是1,那么同時進行兩種翻轉(zhuǎn)。我們使用numpy函數(shù)fliplr和flipup。

def flipit(image, axes):

if axes[0]:

image = np.fliplr(image)

if axes[1]:

image = np.flipud(image)

return image

剪切

這可能是一個小眾的函數(shù),但在我的案例中很重要。處理自然圖像時,常常在圖像上進行隨機剪切,以得到補丁——這些補丁常常包含大部分圖像數(shù)據(jù),例如,基于299 x 299圖像得到的224 x 224補丁。這不過是另一種給網(wǎng)絡提供視覺上非常相似而數(shù)值上完全不同的圖像的方法。同時也進行中央剪切。我的案例有一個不同的需求,我希望提供給網(wǎng)絡的圖像中,分割永遠是完全可見的(我處理的是3D心臟MRI分割)。

所以下面的函數(shù)查找分割,然后創(chuàng)建一個包圍盒。我們將生成“正方形”分割,邊長等于圖像的寬度(最短邊之長,不計入深度)。在這一情形下,創(chuàng)建了包圍盒之后,如有必要,上下移動窗口以確保整個分割可見。函數(shù)同時確保輸出總是正方形的,即使包圍盒部分移出圖像數(shù)組的界限。

def cropit(image, seg=None, margin=5):

fixedaxes = np.argmin(image.shape[:2])

trimaxes = 0if fixedaxes == 1else1

trim = image.shape[fixedaxes]

center = image.shape[trimaxes] // 2

print image.shape

print fixedaxes

print trimaxes

print trim

print center

if seg isnotNone:

hits = np.where(seg!=0)

mins = np.argmin(hits, axis=1)

maxs = np.argmax(hits, axis=1)

if center - (trim // 2) > mins[0]:

while center - (trim // 2) > mins[0]:

center = center - 1

center = center + margin

if center + (trim // 2) < maxs[0]:

while center + (trim // 2) < maxs[0]:

center = center + 1

center = center + margin

top = max(0, center - (trim //2))

bottom = trim if top == 0else center + (trim//2)

if bottom > image.shape[trimaxes]:

bottom = image.shape[trimaxes]

top = image.shape[trimaxes] - trim

if trimaxes == 0:

image = image[top: bottom, :, :]

else:

image = image[:, top: bottom, :]

if seg isnotNone:

if trimaxes == 0:

seg = seg[top: bottom, :, :]

else:

seg = seg[:, top: bottom, :]

return image, seg

else:

return image

注意,即使在不給定分割的情況下,該函數(shù)仍能剪切出正方形圖像。

原圖

剪切后

原圖、分割圖

剪切后

應用

應用轉(zhuǎn)換函數(shù)時需要小心。例如,如果我們對同一圖像應用多種轉(zhuǎn)換,我們需要確保不在“改變亮度”后進行“重采樣”,否則將重置圖像的亮度區(qū)間,抵消“改變亮度”的效果。不過,由于我們通常希望數(shù)據(jù)處于同一區(qū)間,全圖亮度平移很少見。我們同時也希望確保我們對數(shù)據(jù)增強不過分狂熱——倍數(shù)和其他參數(shù)需要設定限制。

當我實現(xiàn)數(shù)據(jù)增強時,我將所有轉(zhuǎn)換函數(shù)放在一個腳本transform.py中,之后在其他腳本中調(diào)用該腳本的函數(shù)。

我們在一定范圍內(nèi)隨機抽取增強參數(shù)(避免過于極端的增強參數(shù)),以及需要進行的增強類型(我們并不打算每次應用所有增強)。

np.random.seed()

numTrans = np.random.randint(1, 6, size=1)

allowedTrans = [0, 1, 2, 3, 4]

whichTrans = np.random.choice(allowedTrans, numTrans, replace=False)

我們每次分配一個新的random.seed,以確保每次運行和上次運行不同。共有5種可能的增強類型,所以numTrans是1到5之間的隨機整數(shù)。我們不想重復應用相同類型的增強,所以replace設為False。

經(jīng)過一些試錯,我發(fā)現(xiàn)以下參數(shù)比較好:

旋轉(zhuǎn)theta ∈ [?10.0,10.0]度

縮放factor ∈ [0.9,1.1],即,10%的放大或縮小

亮度factor ∈ [0.8,1.2],即,20%的增減

平移offset ∈ [?5,5]像素

邊緣我傾向于設置為5到10個像素

來看一個例子吧。假設圖像為thisim,分割為thisseg:

if0in whichTrans:

theta = float(np.around(np.random.uniform(-10.0,10.0, size=1), 2))

thisim = rotateit(thisim, theta)

thisseg = rotateit(thisseg, theta, isseg=True) if withseg else np.zeros_like(thisim)

if1in whichTrans:

scalefactor = float(np.around(np.random.uniform(0.9, 1.1, size=1), 2))

thisim = scaleit(thisim, scalefactor)

thisseg = scaleit(thisseg, scalefactor, isseg=True) if withseg else np.zeros_like(thisim)

if2in whichTrans:

factor = float(np.around(np.random.uniform(0.8, 1.2, size=1), 2))

thisim = intensifyit(thisim, factor)

# 不改變分割圖的亮度

if3in whichTrans:

axes = list(np.random.choice(2, 1, replace=True))

thisim = flipit(thisim, axes+[0])

thisseg = flipit(thisseg, axes+[0]) if withseg else np.zeros_like(thisim)

if4in whichTrans:

offset = list(np.random.randint(-5,5, size=2))

currseg = thisseg

thisim = translateit(thisim, offset)

thisseg = translateit(thisseg, offset, isseg=True) if withseg else np.zeros_like(thisim)

在每種情形下,尋找一組隨機參數(shù),傳給轉(zhuǎn)換函數(shù)。圖像和分割圖分別傳給轉(zhuǎn)換函數(shù)。在我的例子中,我只通過隨機選擇0或1進行水平翻轉(zhuǎn),并附加[0]使轉(zhuǎn)換函數(shù)忽略第二軸。另外加入了一個布爾值變量withseg,其為真時增強分割圖,否則返回一張空圖像。

最后,我們剪切圖像為正方形,然后重采樣至所需dims。

thisim, thisseg = cropit(thisim, thisseg)

thisim = resampleit(thisim, dims)

thisseg = resampleit(thisseg, dims, isseg=True) if withseg else np.zeros_like(thisim)

將這些都放在同一腳本中,以便于測試增強。關于這個腳本,有一些需要說明的地方:

腳本接受一個必選參數(shù)(圖像文件名)和一個可選分割圖文件名

腳本中包含一點檢測錯誤的邏輯——文件能否加載?它是rgb圖像還是全3D圖像(第三維大于3)?

我們指定最終圖像的維度,例如[224, 224, 8]

我們同時為參數(shù)聲明了一些默認值……

……以便在最后打印出應用的轉(zhuǎn)換及其參數(shù)

定義了一個plotit函數(shù),該函數(shù)創(chuàng)建一個2 x 2矩陣,其中上面兩張圖像是原圖,下面兩張為增強圖像

注釋掉的部分是我用來保存本文創(chuàng)建的圖像的代碼

在一個在線設定下,我們希望即時進行數(shù)據(jù)增強?;旧?,我們將調(diào)用這一腳本,接受一些待增強的文件名或圖像矩陣,然后創(chuàng)建我們想要的增強。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 圖像增強
    +關注

    關注

    0

    文章

    54

    瀏覽量

    10037
  • python
    +關注

    關注

    56

    文章

    4797

    瀏覽量

    84694
  • 深度學習
    +關注

    關注

    73

    文章

    5503

    瀏覽量

    121175

原文標題:N維圖像的數(shù)據(jù)增強方法概覽

文章出處:【微信號:jqr_AI,微信公眾號:論智】歡迎添加關注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關推薦

    labview 實現(xiàn)圖像增強

    labview 實現(xiàn)圖像增強該怎么做啊,是大概構思是labview調(diào)用matlabM文件,然后按下按鈕直接顯示處理圖片的結(jié)果。畢業(yè)設計要用,老師和我說很簡單,但是以前沒用過labview,很氣。有沒有大佬能幫幫我。。。。。。沒有
    發(fā)表于 05-12 19:47

    基于Matlab的圖像增強與復原技術在SEM圖像中的應用

    原來不清晰的圖片變得清晰,使之改善圖像質(zhì)量和豐富信息量,提高圖像的視覺效果和圖像成分的清晰度,加強圖像判讀和識別效果的圖像處理的
    發(fā)表于 11-14 15:47

    增強技術的總結(jié)說明

    圖像數(shù)據(jù)增強方法一覽(附python代碼)
    發(fā)表于 08-23 14:35

    python圖像數(shù)據(jù)增強——imgaug

    python圖像數(shù)據(jù)增強——imgaug (三)
    發(fā)表于 05-18 10:06

    python圖像數(shù)據(jù)增強——imgaug

    python圖像數(shù)據(jù)增強——imgaug (一)
    發(fā)表于 06-02 11:13

    基于GFO算子的圖像增強算法如何去實現(xiàn)?

    基于GFO算子(廣義模糊算子)的圖像增強算法如何去實現(xiàn)?怎樣對圖像增強算法進行分析?
    發(fā)表于 06-04 06:24

    基于DSP的夜間圖像實時增強系統(tǒng)

    為了實現(xiàn)夜間圖像的實時增強,本文設計了基于DSP 的夜間圖像實時增強系統(tǒng),然后對Ardely 提出的DADPEQU 夜間
    發(fā)表于 07-07 13:07 ?14次下載

    基于無抽樣Contourlet變換的圖像增強方法

    為了有效增強圖像的細節(jié)信息,研究了基于無抽樣Contourlet變換的圖象增強方法。首先將待增強圖像
    發(fā)表于 10-26 15:12 ?0次下載

    實時圖像增強算法改進及FPGA實現(xiàn)

    實時圖像增強算法改進及FPGA實現(xiàn),下來看看
    發(fā)表于 09-17 07:28 ?14次下載

    改進的紅外圖像增強算法及其在FPGA上的實現(xiàn)

    細節(jié)的原理,以及其相對于經(jīng)典直方圖增強的優(yōu)勢,同時指出其迭代算法在硬件實現(xiàn)上的局限性,提出簡化后的平臺值直方圖增強算法。然后再結(jié)合基于背景中值的灰度映射,通過加權平均得到最后
    發(fā)表于 12-22 11:25 ?2次下載
    改進的紅外<b class='flag-5'>圖像</b><b class='flag-5'>增強</b>算法<b class='flag-5'>及其</b>在FPGA上的<b class='flag-5'>實現(xiàn)</b>

    MATLAB如何實現(xiàn)圖像增強灰度變換直方圖均衡匹配

    在MATLAB數(shù)字圖像處理領域,如何實現(xiàn)空間域圖像增強的灰度變換,以及圖像直方圖的均衡和匹配(配準)?本文通過大量的圖片
    發(fā)表于 01-13 21:56 ?1.1w次閱讀
    MATLAB如何<b class='flag-5'>實現(xiàn)</b><b class='flag-5'>圖像</b><b class='flag-5'>增強</b>灰度變換直方圖均衡匹配

    python中的字典(dict)對象以及其使用方法

    本文通過以英文的形式全面講解了python中的字典(dict)對象以及其使用方法。
    發(fā)表于 05-15 10:00 ?1次下載

    利用模擬技術進行圖像增強方法設計詳解

    量化過程大量減少了圖像中低對比度信息,也會造成超出量化量程的圖像信息完全丟失。本文針對不能采用數(shù)字算法對以上圖像進行有效增強的問題,提出使用模擬技術進行
    發(fā)表于 08-09 16:20 ?2446次閱讀
    利用模擬技術進行<b class='flag-5'>圖像</b><b class='flag-5'>增強</b>的<b class='flag-5'>方法</b>設計詳解

    如何使用Python和Numpy等技術實現(xiàn)圖像處理

    本文檔的主要內(nèi)容詳細介紹的是如何使用Python、Numpy、Scipy和matplotlib執(zhí)行圖像處理任務。
    發(fā)表于 08-28 09:36 ?8次下載
    如何使用<b class='flag-5'>Python</b>和Numpy等技術<b class='flag-5'>實現(xiàn)</b><b class='flag-5'>圖像</b>處理

    如何使用FPGA實現(xiàn)實時圖像增強算法

    針對復雜背景的多目標圖像,提出了一種基于直方圖的實時自適應圖像增強方法。該方法根據(jù)自適應直方圖窗口選擇高低閾值,通過灰度線性變換及灰度級等間
    發(fā)表于 02-03 15:21 ?10次下載
    如何使用FPGA<b class='flag-5'>實現(xiàn)</b>實時<b class='flag-5'>圖像</b><b class='flag-5'>增強</b>算法