传统图像分割算法-基于边缘检测的图像分割

1、基于边缘检测的图像语义分割算法试图通过检测包含不同区域的边缘来解决分割问题。它可以说是人们最先想到也是研究最多的方法之一。通常不同区域的边界上像素的灰度值变化比较剧烈,如果将图片从空间域通过傅里叶变换到频率域,边缘就对应着高频部分,这是一种非常简单的边缘检测算法。最简单的边缘检测方法是并行微分算子法,它利用相邻区域的像素值不连续的性质,采用一阶或者二阶导数来检测边缘点。

2、一阶导数和二阶导数的不同显示

3、常用的一阶微分算子有Roberts、Prewitt、Sobel等算子,常用的二阶微分算子有Laplace和Kirsh等算子。在实际处理操作中常用模板矩阵与图像像素值矩阵卷积来实现微分运算。

 

4、Kirsch算子在这篇博客进行了实现。

5、Canny是当前最为流行的一种边缘检测方法。由1986年由JOHN CANNY首次在论文《A Computational Approach to Edge Detection》中提出。其中Canny使用了变分法。Canny检测器中的最优函数使用四个指数项的和来描述,它可以由高斯函数的一阶导数来近似。这个博客对canny算子六个步骤进行了详细的介绍,可以看看。

个人理解canny算子每个步骤:python实现

1)、因为使用该方法,颜色对于边缘检测作用不是很大,所以一般会将其先从RGB图像转换为灰度图。gray=0.3*R+0.59*G+0.11*B

2)、采用高斯滤波器平滑图像。这一步骤主要是为了降低图像中阴影部分或者光照对于检测的影响,具体就是太黑的变亮一点,太亮的变黑一点,不要使他们太剧烈(从图像上看,理解可能有误,有了解的,评论区给点建议)。其次采用高斯滤波可以消除一些噪音。(但是很有可能将一些边缘也消除掉)

3)计算图像每个像素的梯度幅值和方向

3)、采用非极大值抑制。这一步主要是为了细化边缘,只保留幅值局部变化变化最大的点。

4)、双阈值检测与链接。就是为了将边缘划分为不是边缘,弱边缘和强边缘。小于低阈值的不是边缘,大于低阈值小于高阈值是弱边缘,大于高阈值的是强边缘。

5)、抑制孤立的弱边缘完成边缘检测。这句话很明白,就是第四步怎么都会产生一些弱边缘,那么我们就将一些孤立的弱边缘排除掉,而把其他的弱边缘保留下(其实就另类的当做强边缘输出了)。

 

6、sobel算子具体计算过程:

 一些简单实现:

import cv2
import numpy as np
import matplotlib.pyplot as plt

def put(path):
    # 读取图像
    img = cv2.imread(path)
    b, g, r = cv2.split(img)
    img2 = cv2.merge([r, g, b])

    # 灰度化处理图像
    grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # 高斯滤波
    gaussianBlur = cv2.GaussianBlur(grayImage, (3, 3), 0)

    # 二值化
    ret, binary = cv2.threshold(grayImage, 127, 255, cv2.THRESH_BINARY)

    # Sobel算子
    x = cv2.Sobel(grayImage, cv2.CV_16S, 1, 0)  # 对x求一阶导
    y = cv2.Sobel(grayImage, cv2.CV_16S, 0, 1)  # 对y求一阶导
    absX = cv2.convertScaleAbs(x)
    absY = cv2.convertScaleAbs(y)
    Sobel = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)

    # Roberts算子
    kernelx = np.array([[-1, 0], [0, 1]], dtype=int)
    kernely = np.array([[0, -1], [1, 0]], dtype=int)
    x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)
    y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
    # 转uint8
    absX = cv2.convertScaleAbs(x)
    absY = cv2.convertScaleAbs(y)
    Roberts = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)

    # 拉普拉斯算子
    dst = cv2.Laplacian(grayImage, cv2.CV_16S, ksize=3)
    Laplacian = cv2.convertScaleAbs(dst)

    # 高斯滤波降噪
    gaussian = cv2.GaussianBlur(grayImage, (5, 5), 0)

    # Canny算子
    Canny = cv2.Canny(gaussian, 50, 150)

    # Prewitt算子
    kernelx = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]], dtype=int)
    kernely = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]], dtype=int)
    x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)
    y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
    # 转uint8
    absX = cv2.convertScaleAbs(x)
    absY = cv2.convertScaleAbs(y)
    Prewitt = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)

    # 高斯拉普拉斯算子
    gaussian = cv2.GaussianBlur(grayImage, (3, 3), 0)  # 先通过高斯滤波降噪
    dst = cv2.Laplacian(gaussian, cv2.CV_16S, ksize=3)  # 再通过拉普拉斯算子做边缘检测
    LOG = cv2.convertScaleAbs(dst)

    # 用来正常显示中文标签
    plt.rcParams['font.sans-serif'] = ['SimHei']

    # 显示图形
    plt.subplot(241), plt.imshow(img2), plt.title('原始图像'), plt.axis('off')
    plt.subplot(242), plt.imshow(binary, plt.cm.gray), plt.title('二值图'), plt.axis('off')
    plt.subplot(243), plt.imshow(Sobel, plt.cm.gray), plt.title('Sobel算子'), plt.axis('off')
    plt.subplot(244), plt.imshow(Roberts, plt.cm.gray), plt.title('Roberts算子'), plt.axis('off')
    plt.subplot(245), plt.imshow(Laplacian, plt.cm.gray), plt.title('拉普拉斯算子'), plt.axis('off')
    plt.subplot(246), plt.imshow(Canny, plt.cm.gray), plt.title('Canny算子'), plt.axis('off')
    plt.subplot(247), plt.imshow(Prewitt, plt.cm.gray), plt.title('Prewitt算子'), plt.axis('off')
    plt.subplot(248), plt.imshow(LOG, plt.cm.gray), plt.title('高斯拉普拉斯算子'), plt.axis('off')

    # plt.savefig('1.new-2.jpg')
    plt.show()

# 图像处理函数,要传入路径
put(r'laohu.jpg')

结果:

 

posted @ 2022-10-31 16:05  九叶草  阅读(1290)  评论(0编辑  收藏  举报