示例圖像
将原圖像轉換為灰階圖後進行測試
Robert算子
[ − 1 0 0 1 ] \left[ \begin{matrix} -1 & 0\\ 0 & 1 \end{matrix} \right] [−1001]
[ 0 − 1 1 0 ] \left[ \begin{matrix} 0 & -1\\ 1 & 0 \end{matrix} \right] [01−10]
robert算子由如圖所示兩個算子相加而成,以下為實作過程
def Robert(img):
operator_first = np.array([[-1,0],[0,1]])
operator_second = np.array([[0,-1],[1,0]])
"""
copyMakeBorder 邊緣擴充
* BORDER_REPLICATE 複制最邊緣像素
* BORDER_REFLECT
* BORDER_REFLECT_101 以最邊緣像素為軸,對稱
* BORDER_WRAP
* BORDER_CONSTANT 以一個常量像素值填充擴充的邊界值
* BORDER_REPLICATE: aaaaaa|abcdefgh|hhhhhhh
* BORDER_REFLECT: fedcba|abcdefgh|hgfedcb
* BORDER_REFLECT_101: gfedcb|abcdefgh|gfedcba
* BORDER_WRAP: cdefgh|abcdefgh|abcdefg
* BORDER_CONSTANT: iiiiii|abcdefgh|iiiiiii with some specified 'i'
"""
img2 = cv2.copyMakeBorder(img,1,1,1,1,cv2.BORDER_DEFAULT)
img3 = img2.copy()
for i in range(1,img2.shape[0]):
for j in range(1,img2.shape[1]):
kernel = img2[i-1:i+2,j-1:j+2]
img3[i,j] = np.abs(np.sum(kernel[1:,1:]*operator_first))+np.abs(np.sum(kernel[1:,1:]*operator_second))
cv2.imshow("img3",img3)
Sobel算子
顔色變化一階導數
(垂直梯度) [ − 1 − 2 − 1 0 0 0 1 2 1 ] \left [ \begin{matrix} -1 & -2 & -1\\ 0 & 0 & 0\\ 1 & 2 &1 \end{matrix} \right] \tag{垂直梯度} ⎣⎡−101−202−101⎦⎤(垂直梯度)
(水準梯度) [ − 1 0 1 − 2 0 2 − 1 0 1 ] \left [ \begin{matrix} -1 & 0 & 1\\ -2 & 0 & 2\\ -1 & 0 & 1 \end{matrix} \right] \tag{水準梯度} ⎣⎡−1−2−1000121⎦⎤(水準梯度)
以下為實作過程
def Sobel(img, operatorType):
if operatorType == "horizontal":
operator = np.array([[-1,-2,-1],[0,0,0],[1,2,1]])
elif operatorType == "vertical":
operator = np.array([[-1,0,1],[-2,0,2],[-1,0,1]])
else:
raise("type Error")
img2 = cv2.copyMakeBorder(img,1,1,1,1,cv2.BORDER_DEFAULT)
img3 = img2.copy()
for i in range(1,img2.shape[0]-1):
for j in range(1,img2.shape[1]-1):
kernel = img2[i-1:i+2,j-1:j+2]
img3[i-1,j-1] = np.abs(np.sum(kernel*operator))
img3 = img3*(255/np.max(img2))
img3 = img3.astype(np.uint8)
cv2.imshow("sobel"+operatorType,img3)
垂直
水準
Laplace算子
加入顔色變化二階導數
(四鄰域) [ 0 1 0 1 − 4 1 0 1 0 ] \left [ \begin{matrix} 0 & 1 & 0\\ 1 & -4 & 1\\ 0 & 1 & 0 \end{matrix} \right] \tag{四鄰域} ⎣⎡0101−41010⎦⎤(四鄰域)
(八鄰域) [ 1 1 1 1 − 8 1 1 1 1 ] \left [ \begin{matrix} 1 & 1 & 1\\ 1 & -8 & 1\\ 1 & 1 & 1 \end{matrix} \right] \tag{八鄰域} ⎣⎡1111−81111⎦⎤(八鄰域)
def Laplace(img, operatorType):
if operatorType == "fourfields":
operator = np.array([[-1,-2,-1],[0,0,0],[1,2,1]])
elif operatorType == "eightfields":
operator = np.array([[-1,0,1],[-2,0,2],[-1,0,1]])
else:
raise("type Error")
img2 = cv2.copyMakeBorder(img,1,1,1,1,cv2.BORDER_DEFAULT)
img3 = img2.copy()
for i in range(1,img2.shape[0]-1):
for j in range(1,img2.shape[1]-1):
kernel = img2[i-1:i+2,j-1:j+2]
img3[i-1,j-1] = np.abs(np.sum(kernel*operator))
img3 = img3*(255/np.max(img2))
img3 = img3.astype(np.uint8)
cv2.imshow("laplace"+operatorType,img3)
四鄰域
八鄰域
Canny算子
抗噪效果較好
流程
1.高斯模糊
使用5x5算子
(八鄰域) 1 / 159 [ 2 4 5 4 2 4 9 12 9 4 5 12 15 12 6 4 9 12 9 4 2 4 5 4 2 ] 1/159 \left [ \begin{matrix} 2 & 4 & 5 & 4 & 2\\ 4 & 9 & 12 & 9 & 4\\ 5 & 12 & 15 & 12 & 6\\ 4 & 9 & 12 & 9 & 4\\ 2 & 4 & 5 & 4 & 2 \end{matrix} \right] \tag{八鄰域} 1/159⎣⎢⎢⎢⎢⎡245424912945121512549129424642⎦⎥⎥⎥⎥⎤(八鄰域)
使用3x3算子
(八鄰域) [ 1 2 1 2 4 2 1 2 1 ] \left [ \begin{matrix} 1 & 2 & 1\\ 2 & 4 & 2\\ 1 & 2 & 1 \end{matrix} \right] \tag{八鄰域} ⎣⎡121242121⎦⎤(八鄰域)
2.計算梯度幅值和方向
G = G X 2 + G Y 2 G = \sqrt{G_X^2+G_Y^2} G=GX2+GY2
θ = a r c t a n 2 ( G Y , G X ) \theta = arctan2(G_Y,G_X) θ=arctan2(GY,GX)
3.非極大值 抑制
如果目前點的梯度強度和同方向的其他點的梯度強度相比較是最大,保留其值。否則抑制,即設為0
4.滞後門檻值
共設定兩個門檻值
如果某一像素位置的幅值超過高門檻值, 該像素被保留為邊緣像素。
如果某一像素位置的幅值小于低門檻值, 該像素被排除。
如果某一像素位置的幅值在兩個門檻值之間,該像素僅僅在連接配接到一個高于高門檻值的像素時被保留。
直接使用opencv實作
def Canny(img, kernerSize,threshold1,threshold2):
img = cv2.GaussianBlur(img,(kernerSize,kernerSize),0)
img3 = cv2.Canny(img, threshold1, threshold2)
cv2.imshow("canny",img3)
以上完整代碼
#coding:utf-8
import cv2
import numpy as np
def Robert(img):
operatorFirst = np.array([[-1,0],[0,1]])
operatorSecond = np.array([[0,-1],[1,0]])
"""
copyMakeBorder 邊緣擴充
* BORDER_REPLICATE 複制最邊緣像素
* BORDER_REFLECT
* BORDER_REFLECT_101 以最邊緣像素為軸,對稱
* BORDER_WRAP
* BORDER_CONSTANT 以一個常量像素值填充擴充的邊界值
* BORDER_REPLICATE: aaaaaa|abcdefgh|hhhhhhh
* BORDER_REFLECT: fedcba|abcdefgh|hgfedcb
* BORDER_REFLECT_101: gfedcb|abcdefgh|gfedcba
* BORDER_WRAP: cdefgh|abcdefgh|abcdefg
* BORDER_CONSTANT: iiiiii|abcdefgh|iiiiiii with some specified 'i'
"""
img2 = cv2.copyMakeBorder(img,1,1,1,1,cv2.BORDER_DEFAULT)
img3 = img2.copy()
for i in range(1,img2.shape[0]):
for j in range(1,img2.shape[1]):
kernel = img2[i-1:i+2,j-1:j+2]
img3[i,j] = np.abs(np.sum(kernel[1:,1:]*operatorFirst))+np.abs(np.sum(kernel[1:,1:]*operatorSecond))
cv2.imshow("robert",img3)
def Sobel(img, operatorType):
if operatorType == "horizontal":
operator = np.array([[0,1,0],[1,-4,1],[0,1,0]])
elif operatorType == "vertical":
operator = np.array([[1,1,1],[1,-8,1],[1,1,1]])
else:
raise("type Error")
img2 = cv2.copyMakeBorder(img,1,1,1,1,cv2.BORDER_DEFAULT)
img3 = img2.copy()
for i in range(1,img2.shape[0]-1):
for j in range(1,img2.shape[1]-1):
kernel = img2[i-1:i+2,j-1:j+2]
img3[i-1,j-1] = np.abs(np.sum(kernel*operator))
img3 = img3*(255/np.max(img2))
img3 = img3.astype(np.uint8)
cv2.imshow("sobel"+operatorType,img3)
def Laplace(img, operatorType):
if operatorType == "fourfields":
operator = np.array([[-1,-2,-1],[0,0,0],[1,2,1]])
elif operatorType == "eightfields":
operator = np.array([[-1,0,1],[-2,0,2],[-1,0,1]])
else:
raise("type Error")
img2 = cv2.copyMakeBorder(img,1,1,1,1,cv2.BORDER_DEFAULT)
img3 = img2.copy()
for i in range(1,img2.shape[0]-1):
for j in range(1,img2.shape[1]-1):
kernel = img2[i-1:i+2,j-1:j+2]
img3[i-1,j-1] = np.abs(np.sum(kernel*operator))
img3 = img3*(255/np.max(img2))
img3 = img3.astype(np.uint8)
cv2.imshow("laplace"+operatorType,img3)
def Canny(img, kernerSize,threshold1,threshold2):
img = cv2.GaussianBlur(img,(kernerSize,kernerSize),0)
img3 = cv2.Canny(img, threshold1, threshold2)
cv2.imshow("canny",img3)
if __name__ == "__main__":
img = cv2.imread("imgs/ev0001.bmp")
grayimg = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
Robert(grayimg)
Sobel(grayimg,"horizontal")
Sobel(grayimg,"vertical")
Laplace(grayimg,"fourfields")
Laplace(grayimg,"eightfields")
Canny(grayimg,3,50,150)
cv2.waitKey(0)