2013-02-08 136 views
14

我想嘗試編寫一個簡單的函數來平滑輸入的圖像。我試圖用Image和numpy庫來做到這一點。我正在考慮使用卷積蒙版將是一個解決這個問題的方法,並且我知道numpy具有內置的卷積函數。Python中的圖像平滑

如何使用numpy.convolve來平滑圖像?

+2

你可能需要一個二維卷積,如'scipy.signal.convolve2d' – wim

回答

16

不錯的問題! tcaswell這裏的帖子是一個很好的建議,但你不會學到太多這種方式,因爲scipy正在爲你做所有的工作!因爲你的問題說你想嘗試並編寫函數,我會告訴你一些更粗糙和基本的方式來手動完成所有這些,希望你能更好地理解卷積等背後的數學,然後你可以用你自己的想法和努力來改善它!

注意:您將獲得與內核的不同形狀/大小不同的結果,高斯是通常的方式,但你可以嘗試一些其他的樂趣(餘弦,三角形等!)。我只是在現場做了這個,我認爲這是一種金字塔形。

import scipy.signal 
import numpy as np 
import matplotlib.pyplot as plt 

im = plt.imread('example.jpg') 
im /= 255. # normalise to 0-1, it's easier to work in float space 

# make some kind of kernel, there are many ways to do this... 
t = 1 - np.abs(np.linspace(-1, 1, 21)) 
kernel = t.reshape(21, 1) * t.reshape(1, 21) 
kernel /= kernel.sum() # kernel should sum to 1! :) 

# convolve 2d the kernel with each channel 
r = scipy.signal.convolve2d(im[:,:,0], kernel, mode='same') 
g = scipy.signal.convolve2d(im[:,:,1], kernel, mode='same') 
b = scipy.signal.convolve2d(im[:,:,2], kernel, mode='same') 

# stack the channels back into a 8-bit colour depth image and plot it 
im_out = np.dstack([r, g, b]) 
im_out = (im_out * 255).astype(np.uint8) 

plt.subplot(2,1,1) 
plt.imshow(im) 
plt.subplot(2,1,2) 
plt.imshow(im_out) 
plt.show() 

enter image description here

+0

你知不知道'scipy.signals.convolve2d'和'scipy.ndimage.convolve'之間是否有真正的區別,因爲它們看起來都是用同樣的東西做的,只是參數略有不同。 – tacaswell

+0

我認爲後者被推廣到更高的維度,前者被指定爲2d陣列。雖然通常不想將顏色通道「塗抹」到彼此之中,但使用3D內核來處理圖像會很奇怪。 – wim

+0

對不起,愚蠢的問題後,我在我的答案中評論說,「convolve」進入更高維度.....認爲是時候睡覺了。 – tacaswell

16

你想看看ndimage,這是scipy模塊。它有許多過濾器 作爲函數設置,以及用於卷積任意內核的漂亮包裝。

例如,

img_gaus = ndimage.filters.gaussian_filter(img, 2, mode='nearest') 

用的2

如果你想卷積任意內核西格瑪高斯卷積你的形象,說一個跨

k = np.array([[0, 1, 0], 
       [1, 1, 1], 
       [0, 1, 0]]) 

img2 = ndimage.convolve(img, k, mode='constant') 

這些功能對於更高維度也是很好的,所以你可以使用幾乎相同的代碼(只是擴展你的內核的維度)來平滑更高維度的數據。

modecval參數控制卷積如何處理圖像邊緣的像素(對於邊緣像素,內核需要查看的一半區域不存在,因此您需要選取用來填充圖像的東西)。

4

如果你不想使用SciPy的,你有三種選擇:

1)你可以使用卷積定理與傅里葉變換相結合,因爲numpy的具有2D FFT。 2)你可以使用一個可分離的內核,然後你可以在平坦的數組上進行兩個一維卷積,一個在x方向,另一個在y方向(ravel the transpose),這樣會給出相同的結果結果作爲2D卷積。

3)如果你有一個小內核,說,3x3的,它很容易只是寫出來的卷積乘法和款項。這聽起來像一個麻煩,但它並沒有那麼糟糕。

如果你想使用SciPy的,你可以使用ngimage,作爲tcaswell建議。 scipy也有convolve2d。