边缘检测之Kirsch算子实现(python + opencv)

Kirsch算子边缘检测

  1. Kirsch算子原理
    类似于Sobel算子,也利用图像中某点的梯度幅值作为像素的灰度值,Sobel算子计算出某点两个方向的梯度值,Gx、Gy;但Kirsch算子 利用8个卷积模板计算出了某点8个方向的梯度幅值和方向,并以最大的卷积值作为该点的灰度值。
    边缘检测之Kirsch算子实现(python + opencv)_第1张图片边缘检测之Kirsch算子实现(python + opencv)_第2张图片
    对每个像素点都用 这8个模板进行进行卷积(注意,每个卷积值都应取绝对值),在利用 max{ temp0,temp1,temp2,temp3,temp4,temp5,temp6,temp7} 求出该点的最大卷积值。
  2. 算法实现
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)

  1. 说明
    在这个算法上磨蹭了好久,每次效果的很差,一直找不到原因,改来改去。最后参考了相关博文,才发现:每次计算后的值应该赋值给一个新的 img1上,这样结果才比较理想:原因是如果直接修改原始图像位置的像素值,下次用掩膜卷积时,就会和计算出的像素值 卷积(这显然不是算法原理的初衷:每次都应该和原始像素值卷积,不能涉及新像素值)。Ps:这个问题搞了好久,自己蠢得 流油。。。=.=|

  2. 最后给出lena女神的 测试效果图
    边缘检测之Kirsch算子实现(python + opencv)_第3张图片边缘检测之Kirsch算子实现(python + opencv)_第4张图片

你可能感兴趣的:(随笔)