OpenCV入门(十四)-- Sobel导数,拉普拉斯变换和 Canny算子

本文深入探讨了图像处理中的关键概念,包括空间滤波、锐化滤波器、梯度算子、Sobel导数、拉普拉斯变换以及Canny算法。详细解释了这些技术如何用于图像边缘检测,并提供了实现代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

知识点概述

1.空间滤波和空间滤波器的定义

使用空间模板进行的图像处理,被称为空间滤波。模板本身被称为空间滤波器


2. 锐化滤波器



锐化滤波器的分类:

a. 二阶微分滤波器-拉普拉斯算子

b. 一阶微分滤波器-梯度算子

3. 梯度算子





微分滤波器模板系数设计

 a,   Roberts交叉梯度算子
 b,   Prewitt梯度算子
 c ,  Sobel梯度算子


导数计算是一个重要的卷积

Sobel导数

用来表达微分的最常用的操作是Sobel微分算子。Sobel算子包含任意阶的微分及融合偏导。

Sobel导数可以定义任意大小的核,而且这些核可以用快速且迭代的方式构造,大核对导数有更好的逼近,因为小核对噪声更敏感

再者,Sobel导数并不是真正的导数,因为Sobel算子定义在一个离散的空间上。Sobel算子真正表示的是多项式拟合。


Sobel

使用扩展 Sobel 算子计算一阶、二阶、三阶或混合图像差分

void cvSobel( const CvArr* src, CvArr* dst, int xorder, int yorder, int aperture_size=3 );
src
输入图像.
dst
输出图像.
xorder
x 方向上的差分阶数
yorder
y 方向上的差分阶数
aperture_size
扩展 Sobel 核的大小,必须是 1, 3, 5 或 7。 除了尺寸为 1, 其它情况下, aperture_size ×aperture_size 可分离内核将用来计算差分。对 aperture_size=1的情况, 使用 3x1 或 1x3 内核 (不进行高斯平滑操作)。这里有一个特殊变量 CV_SCHARR (=-1),对应 3x3 Scharr 滤波器,可以给出比 3x3 Sobel 滤波更精确的结果。Scharr 滤波器系数是:

\begin{bmatrix}     -3 & 0 & 3 \\     -10 & 0 & 10 \\     -3 & 0 & 3  \end{bmatrix}

对 x-方向 或矩阵转置后对 y-方向。

函数 cvSobel 通过对图像用相应的内核进行卷积操作来计算图像差分:

dst(x,y) = \frac{d^{xorder+yorder}src} {dx^{xorder} dy^{yorder}} |(x,y)

由于Sobel 算子结合了 Gaussian 平滑和微分,所以,其结果或多或少对噪声有一定的鲁棒性。通常情况,函数调用采用如下参数 (xorder=1, yorder=0, aperture_size=3) 或 (xorder=0, yorder=1, aperture_size=3) 来计算一阶 x- 或 y- 方向的图像差分。第一种情况对应:

\begin{bmatrix}     -1 & 0 & 1 \\     -2 & 0 & 2 \\     -1 & 0 & 1  \end{bmatrix} 核。

第二种对应:

\begin{bmatrix}     -1 & -2 & -1 \\     0 & 0 & 0 \\     1 & 2 & 1  \end{bmatrix}

或者

\begin{bmatrix}     1 & 2 & 1 \\     0 & 0 & 0 \\     -1 & -2 & -1  \end{bmatrix}

核的选则依赖于图像原点的定义 (origin 来自 IplImage 结构的定义)。由于该函数不进行图像尺度变换,所以和输入图像(数组)相比,输出图像(数组)的元素通常具有更大的绝对数值(译者注:即像素的位深)。为防止溢出,当输入图像是 8 位的,要求输出图像是 16 位的。当然可以用函数 cvConvertScale 或 cvConvertScaleAbs 把运算结果(dst)转换为 8 位的。除了8-位图像,函数也接受 32-位 浮点数图像。所有输入和输出图像都必须是单通道的,并且具有相同的图像尺寸或者ROI尺寸。


拉普拉斯变换

拉普拉斯算子可以用二次导数的形式定义,可假设其离散实现类似于二阶Sobel导数



Laplace

计算图像的 Laplacian 变换

void cvLaplace( const CvArr* src, CvArr* dst, int aperture_size=3 );
src
输入图像.
dst
输出图像.
aperture_size
核大小 (与 cvSobel 中定义一样).

函数 cvLaplace 计算输入图像的 Laplacian变换,方法是先用 sobel 算子计算二阶 x- 和 y- 差分,再求和:

dst(x,y) = \frac{d^{2}src}{dx^{2}} + \frac{d^{2}src} {dy^{2}}

对 aperture_size=1 则给出最快计算结果,相当于对图像采用如下内核做卷积:

\begin{bmatrix}     0 & 1 & 0 \\     1 & -4 & 1 \\     0 & 1 & 0  \end{bmatrix}

类似于 cvSobel 函数,该函数也不作图像的尺度变换,所支持的输入、输出图像类型的组合和cvSobel一致。


实现代码:

/*
* Sobel导数,拉普拉斯变换,Canny
*/

#include "highgui.h"
#include "cv.h"

void doSobel(IplImage* img)
{
	IplImage* dst = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3);
	//Sobel导数
	//cvSobel(img,dst,0,1,3);

	//拉普拉斯变换
	cvLaplace(img, dst, 3);

	cvNamedWindow("dst");
	cvShowImage("dst", dst);

	cvReleaseImage(&dst);
	cvWaitKey(0);
	cvDestroyWindow("dst");
}

结果: 第一幅图为Sobel的结果,第二幅图为拉普拉斯变换的结果



Canny算子

与拉普拉斯算法不同,Canny算法中,首先在x和y方向求一阶导数, 然后组合为四个方向的导数。这些方向导数达到局部最大值的点就是组成边缘的候选点。

Canny算法最重要的特点是其试图将独立边的候选像素拼装成轮廓。

轮廓的形成是对这些像素运用滞后性阈值。这意味着有两个阈值,上限和下限。

如果一个像素的梯度大于上限阈值,则认为是边缘像素,如果低于下限阈值,则抛弃,在二者之间的,只有其余高于上限阈值的像素连接时才会被接受。


Canny

采用 Canny 算法做边缘检测

void cvCanny( const CvArr* image, CvArr* edges, double threshold1,
              double threshold2, int aperture_size=3 );
image
单通道输入图像.
edges
单通道存储边缘的输出图像
threshold1
第一个阈值
threshold2
第二个阈值
aperture_size
Sobel 算子内核大小 (见 cvSobel).

函数 cvCanny 采用 CANNY 算法发现输入图像的边缘而且在输出图像中标识这些边缘。threshold1和threshold2 当中的小阈值用来控制边缘连接,大的阈值用来控制强边缘的初始分割。


  • 注意事项:cvCanny只接受单通道图像作为输入。

实现代码:

/*
* Sobel导数,拉普拉斯变换,Canny
*/

#include "highgui.h"
#include "cv.h"

void doSobel(IplImage* img)
{
	//IplImage* dst = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3);
	//Sobel导数
	//cvSobel(img,dst,0,1,3);

	//拉普拉斯变换
	//cvLaplace(img, dst, 3);

	IplImage* dst = cvCreateImage(
		cvGetSize(img),IPL_DEPTH_8U,
		1); // Canny只接受单通道图像
	cvCanny(img, dst, 50, 150, 3);

	cvNamedWindow("dst");
	cvShowImage("dst", dst);

	cvReleaseImage(&dst);
	cvWaitKey(0);
	cvDestroyWindow("dst");
}

结果:



参考:《学习OpenCV》及


### 梯度算子、拉普拉斯算子 Canny 算子的本质区别 在图像处理中,梯度算子、拉普拉斯算子 Canny 算子都是常用的边缘检测工具,但它们的设计目标实现方式存在显著差异。以下是这三种算子的核心特点及其本质区别。 #### 1. **梯度算子** 梯度算子是一类通过计算图像局部变化来检测边缘的方法。它通常基于一阶偏导数的估计,能够反映图像亮度沿某一方向上的快速变化位置。常见的梯度算子包括 Sobel 算子、Prewitt 算子等。这些算子通过对图像进行卷积操作,分别估算水平方向 \( G_x \) 垂直方向 \( G_y \) 的梯度分量,进而合成整体梯度大小: \[ |\nabla f| = \sqrt{G_x^2 + G_y^2} \] - 特点:梯度算子对噪声较为敏感,因为它是基于一阶差分的操作。 - 缺点:无法区分真实的边缘其他高频信号(如噪声)[^1]。 #### 2. **拉普拉斯算子** 拉普拉斯算子是一种二阶微分算子,主要用于寻找图像中的零交叉点(zero-crossings)。它的核心思想是通过计算图像的曲率变化来定位边缘。具体而言,拉普拉斯算子会对图像施加一个二维离散模板,该模板反映了像素值的凹凸特性。如果某个像素周围的灰度值呈现从亮到暗再到亮的趋势,则此处可能存在一条边缘。 - 特点:拉普拉斯算子不仅关注灰度突变的位置,还强调这种突变是否具有持续性。 - 缺点:由于直接使用二阶导数,容易放大噪声效应,因此常需配合高斯平滑滤波器一起使用(即 LoG 算子)[^3]。 #### 3. **Canny 算子** Canny 算子被公认为是最优的边缘检测算法之一,因为它综合考虑了多种因素以达到最佳性能。整个过程分为以下几个阶段: - 使用高斯滤波器去除图像中的随机噪声; - 运用 Sobel 算子或其他类似的梯度算子计算每个像素点的梯度幅度与方向; - 执行非极大值抑制(Non-Maximum Suppression),保留最有可能构成真实边缘的部分; - 设置高低两档阈值并通过滞后连接机制进一步筛选候选边缘。 - 特点:相比其他方法,Canny 算子能够在保持较低误报率的同时获得较高的召回率。 - 缺点:参数调校相对复杂,尤其是阈值的选择直接影响最终效果的好坏[^2]。 --- ### 总结对比表 | 特性 | 梯度算子 | 拉普拉斯算子 | Canny 算子 | |-----------------|-----------------------|----------------------|------------------------| | 基础理论 | 一阶微分 | 二阶微分 | 多步优化流程 | | 主要功能 | 提供初步边缘指示 | 定位精确边缘 | 综合分析生成高质量边缘 | | 对噪声的鲁棒性 | 较弱 | 更弱 | 强 | | 参数需求 | 少 | 中 | 多 | --- ### 示例代码 下面是一个简单的 Python 实现,展示如何利用 OpenCV 来比较这三种算子的结果: ```python import cv2 import numpy as np from matplotlib import pyplot as plt # 加载测试图像 image = cv2.imread('test_image.jpg', 0) # 应用梯度算子 (Sobel) sobel_x = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3) sobel_y = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3) gradient_magnitude = np.sqrt(sobel_x**2 + sobel_y**2).astype(np.uint8) # 应用拉普拉斯算子 laplacian_result = cv2.Laplacian(image, cv2.CV_64F).astype(np.uint8) # 应用 Canny 算子 canny_edges = cv2.Canny(image, threshold1=50, threshold2=150) # 显示结果 plt.subplot(2, 2, 1), plt.imshow(image, cmap='gray') plt.title('Original Image'), plt.xticks([]), plt.yticks([]) plt.subplot(2, 2, 2), plt.imshow(gradient_magnitude, cmap='gray') plt.title('Gradient Magnitude'), plt.xticks([]), plt.yticks([]) plt.subplot(2, 2, 3), plt.imshow(laplacian_result, cmap='gray') plt.title('Laplacian Result'), plt.xticks([]), plt.yticks([]) plt.subplot(2, 2, 4), plt.imshow(canny_edges, cmap='gray') plt.title('Canny Edges'), plt.xticks([]), plt.yticks([]) plt.show() ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值