天天看點

常用邊緣檢測算法

示例圖像

将原圖像轉換為灰階圖後進行測試

常用邊緣檢測算法

Robert算子

[ − 1 0 0 1 ] \left[ \begin{matrix} -1 & 0\\ 0 & 1 \end{matrix} \right] [−10​01​]

[ 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−1​000​121​⎦⎤​(水準梯度)

以下為實作過程

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{四鄰域} ⎣⎡​010​1−41​010​⎦⎤​(四鄰域)

(八鄰域) [ 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{八鄰域} ⎣⎡​111​1−81​111​⎦⎤​(八鄰域)

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⎣⎢⎢⎢⎢⎡​24542​491294​51215125​491294​24642​⎦⎥⎥⎥⎥⎤​(八鄰域)

使用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{八鄰域} ⎣⎡​121​242​121​⎦⎤​(八鄰域)

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)