挑戰圖像處理100問(16)——Prewitt濾波器

在這裏插入圖片描述

Prewitt濾波器

Author: Tian YJ

Prewitt是一種常用的檢測圖像邊緣的濾波器,它分爲橫向和縱向算子,分別用於檢測縱向和橫向的邊緣(注意:橫向形式的濾波器檢測圖像的縱向邊緣,縱向形式的濾波器檢測圖像的橫向邊緣)。

縱向:
K=[111000111] K=\left[ \begin{matrix} -1&-1&-1\\ 0&0&0\\ 1&1&1 \end{matrix} \right]
橫向:
K=[101101101] K=\left[ \begin{matrix} -1&0&-1\\ -1&0&-1\\ -1&0&-1 \end{matrix} \right]
注意比較記憶 Prewitt 濾波器和 Sobel 濾波器,它們在形式和功能上十分相近,Sobel濾波器的算子如下兩圖:

縱向:
K=[121000121] K=\left[ \begin{matrix} 1&2&1\\ 0&0&0\\ -1&-2&-1 \end{matrix} \right]
橫向:
K=[101202101] K=\left[ \begin{matrix} 1&0&-1\\ 2&0&-2\\ 1&0&-1 \end{matrix} \right]

代碼實現
import cv2 # 我只用它來做圖像讀寫和繪圖,沒調用它的其它函數哦
import numpy as np # 進行數值計算

# padding 函數
def padding(img, K_size=3):
	# img 爲需要處理圖像
	# K_size 爲濾波器也就是卷積核的尺寸,這裏我默認設爲3*3,基本上都是奇數

	# 獲取圖片尺寸
	H, W, C = img.shape

	pad = K_size // 2 # 需要在圖像邊緣填充的0行列數,
	# 之所以我要這樣設置,是爲了處理圖像邊緣時,濾波器中心與邊緣對齊

	# 先填充行
	rows = np.zeros((pad, W, C), dtype=np.uint8)
	# 再填充列
	cols = np.zeros((H+2*pad, pad, C), dtype=np.uint8)
	# 進行拼接
	img = np.vstack((rows, img, rows)) # 上下拼接
	img = np.hstack((cols, img, cols)) # 左右拼接

	return img

# Prewitt 濾波函數
def prewitt(img, K_size=3):

	# 獲取圖像尺寸
	H, W, C = img.shape

	# 進行padding
	pad = K_size // 2
	out = padding(img, K_size=3)

	# 縱向濾波器係數
	K_v = np.array([[-1., -1., -1.],[0., 0., 0.], [1., 1., 1.]])
	# 橫向濾波器係數
	K_h = np.array([[-1., 0., 1.],[-1., 0., 1.],[-1., 0., 1.]])

	# 進行濾波
	tem = out.copy()
	out_v = out.copy()
	out_h = out.copy()

	for h in range(H):
		for w in range(W):
			for c in range(C):
				out_v[pad+h, pad+w, c] = np.sum(K_v * tem[h:h+K_size, w:w+K_size, c], dtype=np.float)
				out_h[pad+h, pad+w, c] = np.sum(K_h * tem[h:h+K_size, w:w+K_size, c], dtype=np.float)

	out_v = np.clip(out_v, 0, 255)
	out_h = np.clip(out_h, 0, 255)

	out_v = out_v[pad:pad+H, pad:pad+W].astype(np.uint8)
	out_h = out_h[pad:pad+H, pad:pad+W].astype(np.uint8)

	return out_v, out_h

# 這裏需要把圖像先灰度化
# 直接用之前的灰度化代碼
# 灰度化函數
def BGR2GRAY(img):

	# 獲取圖片尺寸
	H, W, C = img.shape

	# 灰度化
	out = np.ones((H,W,3))
	for i in range(H):
		for j in range(W):
			out[i,j,:] = 0.299*img[i,j,0] + 0.578*img[i,j,1] + 0.114*img[i,j,2]

	out = out.astype(np.uint8)

	return out

# 讀取圖片
path = 'C:/Users/86187/Desktop/image/'


file_in = path + 'cake.jpg' 
file_out_1 = path + 'cake_prewitt_filter_v.jpg' 
file_out_2 = path + 'cake_prewitt_filter_h.jpg'
img = cv2.imread(file_in)

# 調用函數進行灰度化
img = BGR2GRAY(img)
# 調用函數進行sobel濾波
out = prewitt(img)

# 保存圖片
# 縱向
cv2.imwrite(file_out_1, out[0])
cv2.imshow("result", out[0])

# 橫向
cv2.imwrite(file_out_2, out[1])
cv2.imshow("result", out[1])

cv2.waitKey(0)
cv2.destroyAllWindows()

結果展示

Prewitt濾波器和Sobel濾波器比較

原圖 縱向prewitt 橫向prewitt
在這裏插入圖片描述 在這裏插入圖片描述 在這裏插入圖片描述
原圖 縱向sobel 橫向sobel
在這裏插入圖片描述 在這裏插入圖片描述 在這裏插入圖片描述

從實驗結果,我們可以觀察到,對比使用 Sobel算子 和 Prewitt算子 進行圖像邊緣檢測 ,Sobel濾波器能夠獲得更加清晰明亮的邊緣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章