要求
對一副圖像加噪聲,進行平滑,銳化作用。
待處理圖像:
加噪
生成椒鹽噪聲:
def sp_noisy(image, s_vs_p=0.5, amount=0.08):
out = np.copy(image)
num_salt = np.ceil(amount * image.size * s_vs_p)
coords = [np.random.randint(0, i - 1, int(num_salt)) for i in image.shape]
out[tuple(coords)] = 255
num_pepper = np.ceil(amount * image.size * (1. - s_vs_p))
coords = [np.random.randint(0, i - 1, int(num_pepper)) for i in image.shape]
out[tuple(coords)] = 0
return out
結果
胡椒和鹽各佔0.5,總密度0.08的椒鹽噪聲:
平滑空間濾波(線性)
均值濾波
均值濾波過程:
m=n=3方形卷積模板:
kernel = np.array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]], np.float32)/9
外圍補0的線性濾波器:
def linear_filter(image, x, y, kernel, out):
sum_wf = 0
m = kernel.shape[0]
n = kernel.shape[1]
a = int((m - 1) / 2)
b = int((n - 1) / 2)
for s in range(-a, a + 1):
for t in range(-b, b + 1):
# convolution rotation 180
x_s = (x - s) if (x - s) in range(0, image.shape[0] - 1) else 0
y_t = (y - t) if (y - t) in range(0, image.shape[1] - 1) else 0
sum_wf += kernel[a + s][b + t] * image[x_s][y_t]
out[x][y] = sum_wf
空間濾波函數實現:
def spatial_filtering(image, kernel, filter_):
out = np.copy(image)
h = image.shape[0]
w = image.shape[1]
for x in range(h):
print(str(int(x/h * 100)) + "%")
for y in range(w):
filter_(image, x, y, kernel, out)
return out
調用
leaf_smooth = sp_convolution(leaf_sp_nose, k, linear_filter)
3 * 3均值濾波後:
另一個3 * 3 的均值濾波模板結果:
kernel = np.array([[1, 2, 1],
[2, 4, 2],
[1, 2, 1]], np.float32)/16
opencv 實現:
opencv速度要快很多,最後的效果是一樣
5 * 5均值濾波:
kernel = np.ones((5, 5), np.float32)/(5**2)
15 * 15均值濾波:
kernel = np.ones((15, 15), np.float32)/(15**2)
圖像太過模糊,因爲對外圍取了0,可以明顯看到周圍有暗邊
opencv:
opencv外圍不是補0
Embossment算子
kernel = np.array([[2, 0, 0],
[0, 0, 0],
[0, 0, 2]], np.float32)/4
對去椒鹽燥沒什麼效果
統計排序濾波(非線性)
中值濾波
過程爲求領域內像素值的中值,窗口由kernel給出,置1爲需要統計的像素
中值濾波器:
def nonlinear_median_filter(image, x, y, kernel, out):
sp = []
m = kernel.shape[0]
n = kernel.shape[1]
a = int((m - 1) / 2)
b = int((n - 1) / 2)
for s in range(-a, a + 1):
for t in range(-b, b + 1):
x_s = (x + s) if (x + s) in range(0, image.shape[0] - 1) else 0
y_t = (y + t) if (y + t) in range(0, image.shape[1] - 1) else 0
if kernel[a + s][b + t]:
sp.append(image[x_s][y_t])
out[x][y] = np.median(sp)
3*3中值濾波結果
模板:
k = np.ones((3, 3), np.float32)/(3**2)
最大值最小值同理,下面是去取椒鹽噪聲對比圖(均值,中值,最大值,最小值):
可以看到中值效果最好,最大值和最小值不適用於去除椒鹽噪聲
不同模板對比
k1 = np.array([
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]
], np.float32)
k2 = np.ones((5, 5))
k3 = np.array([
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
])
使用k2圖像整體顏色偏暗,個人感覺k3效果最好
空間銳化濾波器
待處理圖:
二階微分-拉普拉斯算子(線性)
線性濾波實現函數基本和平滑的一樣,但是銳化運算時會出現小於0或大於255的情況,所以需要對其處理
也是進行卷積運算:
def spatial_filtering(image, kernel, filter_):
out = np.copy(image)
h = image.shape[0]
w = image.shape[1]
for x in range(h):
# print(str(int(x/h * 100)) + "%")
for y in range(w):
filter_(image, x, y, kernel, out)
return out
def linear_filter(image, x, y, kernel, out):
sum_wf = 0
m = kernel.shape[0]
n = kernel.shape[1]
a = int((m - 1) / 2)
b = int((n - 1) / 2)
for s in range(-a, a + 1):
for t in range(-b, b + 1):
# convolution rotation 180
x_s = (x - s) if (x - s) in range(0, image.shape[0] - 1) else 0
y_t = (y - t) if (y - t) in range(0, image.shape[1] - 1) else 0
sum_wf += kernel[a + s][b + t] * image[x_s][y_t]
if sum_wf < 0:
sum_wf = 0
if sum_wf > 255:
sum_wf = 255
out[x][y] = int(sum_wf)
模板:
laplacian_mask1 = np.array([
[0, 1, 0],
[1, -4, 1],
[0, 1, 0],
])
laplacian_mask2 = np.array([
[1, 1, 1],
[1, -8, 1],
[1, 1, 1],
])
laplacian_mask3 = np.array([
[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1],
])
模板2考慮了對角項,模板3對原圖像進銳化,由於是線性操作,直接調用線性濾波
調用:
image_laplacian_mask_ = spatial_filtering(leaf, laplacian_mask_ , linear_filter)
結果
可以看到模板2的濾波效果要好與模板1,模板3實現了對原圖像的銳化
一階微分-梯度(非線性)
雖然是非線性的操作,但是求是線性操作,因此可以分開求解,最後做非線性的操作,如求開方和絕對值:
簡單起見,直接修改原來的線性濾波函數,改成求絕對值:
def linear_filter(image, x, y, kernel, out):
sum_wf = 0
m = kernel.shape[0]
n = kernel.shape[1]
a = int((m - 1) / 2)
b = int((n - 1) / 2)
for s in range(-a, a + 1):
for t in range(-b, b + 1):
# convolution rotation 180
x_s = (x - s) if (x - s) in range(0, image.shape[0] - 1) else 0
y_t = (y - t) if (y - t) in range(0, image.shape[1] - 1) else 0
sum_wf += kernel[a + s][b + t] * image[x_s][y_t]
sum_wf = abs(sum_wf)
if sum_wf > 255:
sum_wf = 255
out[x][y] = int(sum_wf)
然後分別求:
gradient_mask_1 = np.array([
[0, 0, 0],
[0, -1, 1],
[0, 0, 0],
])
gradient_mask_2 = np.array([
[0, 0, 0],
[0, -1, 0],
[0, 1, 0],
])
image_gradient_mask_1 = spatial_filtering(image, gradient_mask_1, linear_filter)
image_gradient_mask_2 = spatial_filtering(image, gradient_mask_1, linear_filter)
image_gradient_mask = image_gradient_mask_1 + image_gradient_mask_2
結果:
Roberts 算法 交叉差分
調用
roberts_mask_1 = np.array([
[0, 0, 0],
[0, -1, 0],
[0, 0, 1],
])
roberts_mask_2 = np.array([
[0, 0, 0],
[0, 0, -1],
[0, 1, 0],
])
image_soble_mask_1 = spatial_filtering(image, gradient_mask_1, linear_filter)
image_soble_mask_2 = spatial_filtering(image, gradient_mask_1, linear_filter)
image_soble_mask = image_soble_mask_1 + image_soble_mask_2
結果
Soble算子
調用:
soble_mask_1 = np.array([
[-1, -2, -1],
[0, 0, 0],
[1, 2, 1],
])
soble_mask_2 = np.array([
[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1],
])
image_soble_mask_1 = spatial_filtering(image, soble_mask_1, linear_filter)
image_soble_mask_2 = spatial_filtering(image, soble_mask_2, linear_filter)
image_soble_mask = image_soble_mask_1 + image_soble_mask_2
結果
最後都增加到原圖中的效果:
可以看到:從梯度算子、Roberts 算子、Soble算子,效果依次增強