课题总结报告OpenCV 抠图项目实战边缘检测

Posted 小白YouCans

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了课题总结报告OpenCV 抠图项目实战边缘检测相关的知识,希望对你有一定的参考价值。

Python 小白的课题报告—OpenCV 抠图项目实战(7)

本系列是 Python 小白的课题作业《基于OpenCV 的图像分割和抠图》。
需要说明的是,本系列并不能算是 OpenCV 的抠图项目教程,只是以此为主题的课题报告。其中包括了一个较为完整的 PyQt 项目。
从学生课题作业报告的角度,还是可以晒出来给大家参考的。

欢迎关注『Python 小白的项目实战 @ youcans』 原创作品
Python 小白的课题报告—OpenCV 抠图项目实战(1)
Python 小白的课题报告—OpenCV 抠图项目实战(2)
Python 小白的课题报告—OpenCV 抠图项目实战(3)
Python 小白的课题报告—OpenCV 抠图项目实战(4)
Python 小白的课题报告—OpenCV 抠图项目实战(5)
Python 小白的课题报告—OpenCV 抠图项目实战(6)
Python 小白的课题报告—OpenCV 抠图项目实战(7)边缘检测


第四章 图像分割

4.1 边缘检测

边缘是指图像中两个不同区域的边界线上连续的像素点的集合,是图像局部特征不连续性的反映,体现了灰度、颜色、纹理等图像特性的突变。
边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点。
边缘的灰度值呈现出阶跃型或屋顶型变化。阶跃型边缘两边像素点的灰度值存在着明显的差异,而屋顶型边缘则位于灰度值上升或下降的转折处。

梯度指出了像素值的最大变化率的方向,使用微分算子可以进行边缘检测:

  • 恒定灰度区域,一阶导数为零,二阶导数为零;
  • 灰度台阶或斜坡起点区域,一阶导数非零,,二阶导数非零;
  • 灰度斜坡区域,一阶导数非零,二阶导数为零。
    一阶导数、二阶导数的有限差分公式为:
    ∂ f / ∂ x = f ( x + 1 ) − f ( x ) ( ∂ 2 f ) / ( ∂ x 2 ) = f ( x + 1 ) − 2 f ( x ) + f ( x − 1 ) ∂f/∂x=f(x+1)-f(x)\\\\ (∂^2 f)/(∂x^2 )=f(x+1)-2f(x)+f(x-1) f/x=f(x+1)f(x)(2f)/(x2)=f(x+1)2f(x)+f(x1)

图像梯度提取方法简单直接,能够有效的描述图像的原始状态,因此发展出多种图像梯度算子,常用的有Laplacian、Soble和Canny算子。


1. 拉普拉斯算子(Laplacian)

最简单的各向同性导数算子(卷积核)是拉普拉斯算子(Laplacian)。

Laplace 是导数算子,会突出图像中的急剧灰度变化,抑制灰度缓慢变化区域,往往会产生暗色背景下的灰色边缘和不连续图像。将拉普拉斯图像与原图叠加,可以得到保留锐化效果的图像。

拉普拉斯卷积核很容易通过卷积操作 cv. filter_2d 实现,OpenCV 也提供了拉普拉斯算子 cv.Laplacian 来实现。

函数说明:

cv.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]]) → dst

参数说明:

  • src:输入图像,可以是灰度图像,也可以是多通道的彩色图像
  • ddepth:输出图片的数据深度:
  • dst:输出图像,大小和类型与 src 相同
  • ksize:计算二阶导数滤波器的孔径大小,必须为正奇数,可选项
  • scale:缩放比例因子,可选项,默认值为 1
  • delta:输出图像的偏移量,可选项,默认值为 0
  • borderType:边界扩充的类型,注意不支持对侧填充(BORDER_WRAP)

使用Laplacian算子进行边缘检测的基本程序如下:


# MattingLaplacian.py
# edge detection by Laplacian
# Copyright 2021 youcans, XUPT
# Crated:2021-12-10

import cv2 as cv
from matplotlib.figure import Figure

img = cv2.imread("../images/Fig0338a.tif", flags=0)  # NASA 月球影像图

# 使用 cv2.Laplacian 实现 Laplace 卷积算子
imgLaplace2 = cv2.Laplacian(img, -1, ksize=3)
imgRecovery = cv2.add(img, imgLaplace2)  # 恢复原图像

# 二值化边缘图再卷积
ret, binary = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_TRIANGLE)
imgLaplace3 = cv2.Laplacian(binary, cv2.CV_64F)
imgLaplace3 = cv2.convertScaleAbs(imgLaplace3)

plt.figure(figsize=(9, 6))
plt.subplot(131), plt.axis('off'), plt.title("Original")
plt.imshow(img, cmap='gray', vmin=0, vmax=255)
plt.subplot(132), plt.axis('off'), plt.title("cv.Laplacian")
plt.imshow(imgLaplace2, cmap='gray', vmin=0, vmax=255)
plt.subplot(133), plt.axis('off'), plt.title("thresh-Laplacian")
plt.imshow(imgLaplace3, cmap='gray', vmin=0, vmax=255)
plt.tight_layout()
plt.show()

使用Laplacian算子进行边缘检测的结果如下图所示。

图4.1 Laplacian算子进行边缘检测

2. 索贝尔梯度算子(Sobel)

Sobel 算子是一种离散的微分算子,是高斯平滑和微分求导的联合运算,抗噪声能力强。
Sobel 梯度算子利用局部差分寻找边缘,计算得到梯度的近似值。先计算水平、垂直方向的梯度,再求总梯度。编程实现时,可以用绝对值近似平方根。
OpenCV 也提供了函数 cv.Sobel() 实现 Sobel 梯度算子。

函数说明:

cv.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]]) → dst

参数说明:

  • src:输入图像,灰度图像,不适用彩色图像
  • dst:输出图像,大小和类型与 src 相同
  • ddepth:输出图片的数据深度,由输入图像的深度进行选择
  • dx:x 轴方向导数的阶数,1 或 2
  • dy:y 轴方向导数的阶数,1 或 2
  • ksize:Sobel算子卷积核的大小
  • scale:缩放比例因子,可选项,默认值为 1
  • delta:输出图像的偏移量,可选项,默认值为 0

使用Sobel算子进行边缘检测的基本程序如下:

# MattingSobel.py
# edge detection by Sobel
# Copyright 2021 youcans, XUPT
# Crated:2021-12-10

import cv2 as cv
from matplotlib.figure import Figure

img = cv2.imread("../images/imgGaia.tif", flags=0)

# 使用函数 filter2D 实现 Sobel 算子
kernSobelX = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])  # SobelX kernel
kernSobelY = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])  # SobelY kernel
imgSobelX = cv2.filter2D(img, -1, kernSobelX, borderType=cv2.BORDER_REFLECT)
imgSobelY = cv2.filter2D(img, -1, kernSobelY, borderType=cv2.BORDER_REFLECT)

# 使用 cv2.Sobel 实现 Sobel 算子
SobelX = cv2.Sobel(img, cv2.CV_16S, 1, 0)  # 计算 x 轴方向
SobelY = cv2.Sobel(img, cv2.CV_16S, 0, 1)  # 计算 y 轴方向
absX = cv2.convertScaleAbs(SobelX)  # 转回 uint8
absY = cv2.convertScaleAbs(SobelY)  # 转回 uint8
SobelXY = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)  # 用绝对值近似平方根

plt.figure(figsize=(10, 6))
plt.subplot(141), plt.axis('off'), plt.title("Original")
plt.imshow(img, cmap='gray', vmin=0, vmax=255)
plt.subplot(142), plt.axis('off'), plt.title("SobelX")
plt.imshow(SobelX, cmap='gray', vmin=0, vmax=255)
plt.subplot(143), plt.axis('off'), plt.title("SobelY")
plt.imshow(SobelY, cmap='gray', vmin=0, vmax=255)
plt.subplot(144), plt.axis('off'), plt.title("SobelXY")
plt.imshow(SobelXY, cmap='gray')
plt.tight_layout()
plt.show()

使用Sobel算子进行边缘检测的结果如下图所示。

图4.2 Sobel算子进行边缘检测


3. Canny 边缘检测

Canny边缘检测是由Jhon F.Canny提出的算法,具有低错误率、定位良好、最小响应的特点。
Canny算子在过滤噪声、计算梯度的同时实现非最大值抑制,不容易受噪声的干扰。采用双阈值法可以分别检测到强边缘和弱边缘,并且仅当弱边缘与强边缘相连时,才将弱边缘包含在输出结果中,这就保障了检测到真正的弱边缘。

Canny算法的工作原理为:
(1)使用高斯滤波器对图像进行平滑去噪;
(2)计算输入图像梯度;
(3)在边缘上使用非极大值抑制(NMS)进行过滤;
(4)在检测到的边缘上使用双阈值法去除假阳性;
(5)分析所有的边缘及其连接,以保留真正的边缘并消除不明显的边缘;

OpenCV 也提供了函数 cv.Sobel() 实现 Sobel 梯度算子。

函数说明:

cv.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]]) → edges

参数说明:

  • image:输入图像,灰度图像,不适用彩色图像
  • edges:输出图像,单通道 8bit图像,大小与images相同
  • threshold1:滞后过程的较小阈值,用于边缘连接
  • threshold2:滞后过程的较大阈值,用于查找明显的边缘
  • apertureSize:Sobel算子的卷积核大小
  • L2gradient:标志,使用 L1范数或 L2范数正则化

使用 Canny()进行边缘检测的基本程序如下:

# MattingCanny.py
# edge detection by Cann
# Copyright 2021 youcans, XUPTy
# Crated:2021-12-10

import cv2 as cv
from matplotlib.figure import Figure

imgOri = cv2.imread("../images/imgGaia.tif", flags=0)

# canny(): 边缘检测
imgBlur = cv2.GaussianBlur(imgOri, (3, 3), 0)
imgCanny = cv2.Canny(imgBlur, 50, 150)

# 形态学:边缘检测
_, imgThr = cv2.threshold(imgOri, 200, 255, cv2.THRESH_BINARY)  # 固定阈值二值化
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))  # 定义矩形结构元素
gradient = cv2.morphologyEx(Thr_img, cv2.MORPH_GRADIENT, kernel)  # 梯度

plt.figure(figsize=(9, 6))
plt.subplot(221), plt.axis('off'), plt.title("Original")
plt.imshow(imgOri, cmap='gray', vmin=0, vmax=255)
plt.subplot(222), plt.axis('off'), plt.title("GaussianBlur")
plt.imshow(imgBlur, cmap='gray', vmin=0, vmax=255)
plt.subplot(223), plt.axis('off'), plt.title("Canny detection")
plt.imshow(imgCanny, cmap='gray', vmin=0, vmax=255)
plt.subplot(224), plt.axis('off'), plt.title("Gradient detection")
plt.imshow(gradient, cmap='gray')
plt.tight_layout()
plt.show()

使用Canny算子进行边缘检测的结果如下图所示。

图4.3 Canny 算子进行边缘检测

【本节完】


版权声明:

欢迎关注『Python 小白的项目实战 @ youcans』 原创作品

原创作品,转载必须标注原文链接:https://blog.csdn.net/youcans/article/details/122296231

Copyright 2022 youcans, XUPT

Crated:2022-01-05


欢迎关注『Python 小白的项目实战 @ youcans』 原创作品
Python 小白的课题报告—OpenCV 抠图项目实战(1)
Python 小白的课题报告—OpenCV 抠图项目实战(2)
Python 小白的课题报告—OpenCV 抠图项目实战(3)
Python 小白的课题报告—OpenCV 抠图项目实战(4)
Python 小白的课题报告—OpenCV 抠图项目实战(5)
Python 小白的课题报告—OpenCV 抠图项目实战(6)
Python 小白的课题报告—OpenCV 抠图项目实战(7)边缘检测

以上是关于课题总结报告OpenCV 抠图项目实战边缘检测的主要内容,如果未能解决你的问题,请参考以下文章

课题总结报告OpenCV 抠图项目实战

课题总结报告OpenCV 抠图项目实战色彩范围抠图

课题总结报告OpenCV 抠图项目实战图像轮廓

课题总结OpenCV 抠图项目实战(11)算法实验平台

课题总结OpenCV 抠图项目实战图像轮廓

课题总结OpenCV 抠图项目实战(12)源程序代码