8.3Sobel算子边缘检测

实验原理

Sobel算子是一种广泛使用的一阶导数边缘检测算子,它通过计算图像在水平和垂直方向上的梯度来检测边缘。Sobel算子使用一对3x3的掩模来实现这一功能。相比于其他边缘检测算子,Sobel算子在检测边缘的同时还能提供一定的抗噪能力。

在OpenCV中,Sobel算子是一种常用的边缘检测技术,它通过计算图像灰度值的一阶导数来突出图像中的边缘。Sobel算子能够检测水平和垂直方向上的边缘,并且具有一定的噪声抑制能力。

在OpenCV中,Sobel函数用于计算图像的一阶或二阶导数,通常用于边缘检测。Sobel函数通过对图像应用特定的卷积核来估计图像局部区域的梯度,从而帮助识别图像中的边缘。

Sobel算子的基本原理

Sobel算子使用两个3x3的核来分别计算水平和垂直方向上的梯度。这两个核如下所示:

通过这两个核分别对图像进行卷积操作,可以获得图像在水平和垂直方向上的梯度。通常还会计算梯度的大小(幅度)和方向(角度)。

函数原型

void Sobel(InputArray src, OutputArray dst, int ddepth, int dx, int dy, 
           int ksize=3, double scale=1, double delta=0, int borderType=BORDER_DEFAULT);
参数说明
src: 输入图像。可以是单通道或多通道图像。如果是多通道图像,每个通道都将独立处理。
dst: 输出图像。它将具有与输入图像相同的尺寸,但深度取决于ddepth参数。
ddepth: 输出图像的深度。常见的选择有:
CV_16S: 16位有符号整数。
CV_32F: 32位浮点数。
CV_64F: 64位浮点数。
-1: 保持输入图像的深度不变。
dx: 在x方向上的导数阶数(0表示不求导,1表示一阶导数,2表示二阶导数)。
dy: 在y方向上的导数阶数(同dx)。
ksize: Sobel核的大小,默认为3。可以是1、3、5或7。较大的核可以提供更好的抗噪性能。
scale: 可选的缩放因子。默认为1,即不缩放。
delta: 可选的常数值,将在卷积操作后加到每个像素上。
borderType: 边界处理类型。当卷积核覆盖图像边界时,需要指定如何处理边界外的数据。常见的边界处理方式有:
BORDER_CONSTANT: 使用常数值填充边界外区域。
BORDER_REPLICATE: 复制边界像素。
BORDER_REFLECT: 镜像反射边界。
BORDER_WRAP: 边界环绕(类似于纹理坐标)。
BORDER_REFLECT_101 或 BORDER_DEFAULT: 默认的边界反射方式。

示例代码1

使用OpenCV中的Sobel函数步骤
在OpenCV中,可以直接使用Sobel函数来计算图像的梯度。下面是一个基于C++的示例程序,展示如何使用Sobel算子进行边缘检测。

步骤一:包含必要的头文件

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

步骤二:加载图像
int main(int argc, char** argv)
{
    Mat src = imread("path_to_your_image.jpg", IMREAD_GRAYSCALE);
    if (src.empty())
    {
       cout << "Error: Image cannot be loaded!" << endl;
        return -1;
    }

步骤三:定义输出图像
    Mat grad_x, grad_y;
    Mat abs_grad_x, abs_grad_y;

步骤四:应用Sobel算子
    // 计算水平梯度
    Sobel(src, grad_x, CV_16S, 1, 0);
    // 计算垂直梯度
    Sobel(src, grad_y, CV_16S, 0, 1);

    // 转换为绝对值
    convertScaleAbs(grad_x, abs_grad_x);
    convertScaleAbs(grad_y, abs_grad_y);
这里CV_16S指定了输出图像的深度为16位有符号整数。
Sobel函数的第一个参数是输入图像,
第二个参数是输出图像,
第三个参数指定了输出图像的深度,
第四个和第五个参数分别指定在X轴和Y轴方向上的导数阶数。

步骤五:组合梯度
    // 合并梯度结果
    Mat grad;
    addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);

这里使用addWeighted函数将水平和垂直梯度合并成一个图像。你可以根据需要调整权重。

步骤六:显示结果
    namedWindow("Original Image", WINDOW_AUTOSIZE);
    imshow("Original Image", src);

    namedWindow("Horizontal Gradient", WINDOW_AUTOSIZE);
    imshow("Horizontal Gradient", abs_grad_x);

    namedWindow("Vertical Gradient", WINDOW_AUTOSIZE);
    imshow("Vertical Gradient", abs_grad_y);

    namedWindow("Combined Gradient", WINDOW_AUTOSIZE);
    imshow("Combined Gradient", grad);

    waitKey(0);
    return 0;
}
这个程序将显示原始图像、水平梯度、垂直梯度以及合并后的梯度图像。


注意事项
数据类型: Sobel操作可能导致结果溢出,因此通常输出图像的深度设置为CV_16S。在显示之前,使用convertScaleAbs函数将结果转换为CV_8U类型。
边界处理: Sobel算子在处理边界像素时可能会出现问题,因此需要选择合适的边界处理方式。
噪声: Sobel算子虽然有一定的抗噪能力,但在高噪声环境中可能会产生虚假边缘。可以考虑先对图像进行平滑处理,如使用GaussianBlur函数减少噪声的影响。

总结
使用OpenCV的Sobel函数可以方便地实现边缘检测。通过计算水平和垂直方向上的梯度,并将它们合并,可以得到一幅清晰的边缘图像。这种方法在图像处理和计算机视觉中有广泛的应用,尤其是在特征提取和目标识别等领域。

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;


int main(int argc, char** argv)
{
    Mat src = imread("path_to_your_image.jpg", IMREAD_GRAYSCALE);
    if (src.empty())
    {
       cout << "Error: Image cannot be loaded!" << endl;
        return -1;
    }


    Mat grad_x, grad_y;
    Mat abs_grad_x, abs_grad_y;


    // 计算水平梯度
    Sobel(src, grad_x, CV_16S, 1, 0);
    // 计算垂直梯度
    Sobel(src, grad_y, CV_16S, 0, 1);

    // 转换为绝对值
    convertScaleAbs(grad_x, abs_grad_x);
    convertScaleAbs(grad_y, abs_grad_y);


    // 合并梯度结果
    Mat grad;
    addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);


    namedWindow("Original Image", WINDOW_AUTOSIZE);
    imshow("Original Image", src);

    namedWindow("Horizontal Gradient", WINDOW_AUTOSIZE);
    imshow("Horizontal Gradient", abs_grad_x);

    namedWindow("Vertical Gradient", WINDOW_AUTOSIZE);
    imshow("Vertical Gradient", abs_grad_y);

    namedWindow("Combined Gradient", WINDOW_AUTOSIZE);
    imshow("Combined Gradient", grad);

    waitKey(0);
    return 0;
}

这个程序将显示原始图像、水平梯度、垂直梯度以及合并后的梯度图像。

总结
使用OpenCV的Sobel函数可以方便地实现边缘检测。通过计算水平和垂直方向上的梯度,并将它们合并,可以得到一幅清晰的边缘图像。这种方法在图像处理和计算机视觉中有广泛的应用,尤其是在特征提取和目标识别等领域。

运行结果1

实验代码2

 

#include "pch.h"
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
//#pragma comment(lib,"opencv_world450d.lib")

 int main()
{
	//读取图像,黑白图像边缘检测结果较为明显
	Mat img = imread("03.png", IMREAD_ANYCOLOR);
	if (img.empty())
	{
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}
	Mat resultX, resultY, resultXY;
	Sobel(img, resultX, CV_16S, 2, 0, 1);//X方向一阶边缘
	convertScaleAbs(resultX, resultX);
	Sobel(img, resultY, CV_16S, 0, 1, 3);//Y方向一阶边缘
	convertScaleAbs(resultY, resultY);
	resultXY = resultX + resultY;//整幅图像的一阶边缘
	//显示图像
	namedWindow("resultX", WINDOW_NORMAL);
	imshow("resultX", resultX);
	namedWindow("resultY", WINDOW_NORMAL);
	imshow("resultY", resultY);
	namedWindow("resultXY", WINDOW_NORMAL);
	imshow("resultXY", resultXY);
	waitKey(0);
	return 0;
 }

运行结果2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值