Kirsch算子边缘检测
- Kirsch算子原理
类似于Sobel算子,也利用图像中某点的梯度幅值作为像素的灰度值,Sobel算子计算出某点两个方向的梯度值,Gx、Gy;但Kirsch算子 利用8个卷积模板计算出了某点8个方向的梯度幅值和方向,并以最大的卷积值作为该点的灰度值。
对每个像素点都用 这8个模板进行进行卷积(注意,每个卷积值都应取绝对值),在利用 max{ temp0,temp1,temp2,temp3,temp4,temp5,temp6,temp7} 求出该点的最大卷积值。
- 算法实现
import cv2
import numpy as np
from matplotlib import pyplot as plt
#计算Kirsch 边沿检测算子
#定义Kirsch 卷积模板
m1 = np.array([[5, 5, 5],[-3,0,-3],[-3,-3,-3]])
m2 = np.array([[-3, 5,5],[-3,0,5],[-3,-3,-3]])
m3 = np.array([[-3,-3,5],[-3,0,5],[-3,-3,5]])
m4 = np.array([[-3,-3,-3],[-3,0,5],[-3,5,5]])
m5 = np.array([[-3, -3, -3],[-3,0,-3],[5,5,5]])
m6 = np.array([[-3, -3, -3],[5,0,-3],[5,5,-3]])
m7 = np.array([[5, -3, -3],[5,0,-3],[5,-3,-3]])
m8 = np.array([[5, 5, -3],[5,0,-3],[-3,-3,-3]])
img = cv2.imread("lena_1.tiff",0)
# img = cv2.GaussianBlur(img,(3,3),5)
#周围填充一圈
#卷积时,必须在原图周围填充一个像素
img = cv2.copyMakeBorder(img,1,1,1,1,borderType=cv2.BORDER_REPLICATE
temp = list(range(8))
img1 = np.zeros(img.shape) #复制空间 此处必须的重新复制一块和原图像矩阵一样大小的矩阵,以保存计算后的结果
for i in range(1,img.shape[0]-1):
for j in range(1,img.shape[1]-1):
temp[0] = np.abs( ( np.dot( np.array([1,1,1]) , ( m1*img[i-1:i+2,j-1:j+2]) ) ).dot(np.array([[1],[1],[1]])) )
#利用矩阵的二次型表达,可以计算出矩阵的各个元素之和
temp[1] = np.abs(
(np.dot(np.array([1, 1, 1]), (m2 * img[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1],[1],[1]])) )
temp[2] = np.abs( ( np.dot( np.array([1,1,1]) , ( m1*img[i-1:i+2,j-1:j+2]) ) ).dot(np.array([[1],[1],[1]])) )
temp[3] = np.abs(
(np.dot(np.array([1, 1, 1]), (m3 * img[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1],[1],[1]])) )
temp[4] = np.abs(
(np.dot(np.array([1, 1, 1]), (m4 * img[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1],[1],[1]])) )
temp[5] = np.abs(
(np.dot(np.array([1, 1, 1]), (m5 * img[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1],[1],[1]])) )
temp[6] = np.abs(
(np.dot(np.array([1, 1, 1]), (m6 * img[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1],[1],[1]])) )
temp[7] = np.abs(
(np.dot(np.array([1, 1, 1]), (m7 * img[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1],[1],[1]])) )
img1[i,j] = np.max(temp)
if img1[i, j] > 255: #此处的阈值一般写255,根据实际情况选择0~255之间的值
img1[i, j] = 255
else:
img1[i, j] = 0
cv2.imshow("1",img1)
print(img.shape)
cv2.waitKey(0)
-
说明
在这个算法上磨蹭了好久,每次效果的很差,一直找不到原因,改来改去。最后参考了相关博文,才发现:每次计算后的值应该赋值给一个新的 img1上,这样结果才比较理想:原因是如果直接修改原始图像位置的像素值,下次用掩膜卷积时,就会和计算出的像素值 卷积(这显然不是算法原理的初衷:每次都应该和原始像素值卷积,不能涉及新像素值)。Ps:这个问题搞了好久,自己蠢得 流油。。。=.=|
-
最后给出lena女神的 测试效果图