读书笔记之sobel 滤波器

本文详细介绍了Sobel算子的工作原理及其在图像边缘检测中的应用。通过两个3*3的线性滤波器,Sobel算子能够计算图像在水平和垂直方向上的梯度,从而有效地检测出图像的边缘。文章还提供了使用OpenCV实现Sobel算子的代码示例,并展示了如何通过梯度幅值的阈值化得到二值边缘分布图。

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

Sobel算子是一种典型的用于边缘检测的线性滤波器,它基于两个简单的3*3内核,内核结构如下图所示

水平方向:

-101
-202
-101

垂直方向:

-1-2-1
000
121

 

如果把图像看做二维函数,那么sobel算子就是图像在水平和垂直方向变化的速度。在数学属于中,这种速度称为梯度。它是一个二维向量,向量的元素是横竖两个方向的函数的一阶导数:

grad(I)=\left [ \frac{\partial I}{\partial x} , \frac{\partial I}{\partial y}\right ]^{T}

sobel算子在水平和垂直方向计算像素值的差分,得到图像梯度的近似值。它在像素周围的一定范围内进行运算,以减少噪声带来的影响。

使用水平方向和垂直方向滤波器检测边缘:

#include <iostream>
#include <iomanip>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
//#include "laplacianZC.h"

int main()
{
	// Read input image
	cv::Mat image = cv::imread("E:\\OpenCV\\OpenCV3源码\\images\\boldt.jpg", 0);
	if (!image.data)
		return 0;

	// Display the image
	cv::namedWindow("Original Image");
	cv::imshow("Original Image", image);

	// Compute Sobel X derivative
	cv::Mat sobelX;
	cv::Sobel(image,  // input
		sobelX,    // output
		CV_8U,     // image type
		1, 0,      // kernel specification
		3,         // size of the square kernel 
		0.4, 128); // scale and offset(偏移量)

				   // Display the image
	cv::namedWindow("Sobel X Image");
	cv::imshow("Sobel X Image", sobelX);

	// Compute Sobel Y derivative
	cv::Mat sobelY;
	cv::Sobel(image,  // input
		sobelY,    // output
		CV_8U,     // image type
		0, 1,      // kernel specification
		3,         // size of the square kernel 
		0.4, 128); // scale and offset

				   // Display the image
	cv::namedWindow("Sobel Y Image");
	cv::imshow("Sobel Y Image", sobelY);

因为梯度是一个二维向量,所以它有范数和方向。梯度向量的范数表示变化的振幅,计算时通常被当做欧几里得范数(也成L2范数):

\left | grad(I) \right |=^{\sqrt{(\frac{\partial I}{\partial x})^{2}+(\frac{\partial I}{\partial y})^{2}}}

但是在图像处理领域,通常把绝对值之和作为范数进行计算。这称为L1范数。

梯度向量总是指向变化最剧烈的方向。对于一幅图像来说,这意味着梯度方向与边缘垂直,从较暗区域指向较亮区域。梯度的角度用下面的公式计算:

∠grade(I)=arctan(-\frac{\partial I}{\partial y}/\frac{\partial I}{\partial x})

使用L1范数边缘检测:

	// Compute norm of Sobel
	cv::Sobel(image, sobelX, CV_16S, 1, 0);
	cv::Sobel(image, sobelY, CV_16S, 0, 1);
	cv::Mat sobel;
	//compute the L1 norm
	sobel = abs(sobelX) + abs(sobelY);

	double sobmin, sobmax;
	cv::minMaxLoc(sobel, &sobmin, &sobmax);
	std::cout << "sobel value range: " << sobmin << "  " << sobmax << std::endl;

	// Compute Sobel X derivative (7x7)
	cv::Sobel(image, sobelX, CV_8U, 1, 0, 7, 0.001, 128);

	// Display the image
	cv::namedWindow("Sobel X Image (7x7)");
	cv::imshow("Sobel X Image (7x7)", sobelX);

	// Print window pixel values
	for (int i = 0; i<12; i++) {
		for (int j = 0; j<12; j++)
			std::cout << std::setw(5) << static_cast<int>(sobel.at<short>(i + 79, j + 215)) << " ";
		std::cout << std::endl;
	}
	std::cout << std::endl;
	std::cout << std::endl;
	std::cout << std::endl;

	// Conversion to 8-bit image
	// sobelImage = -alpha*sobel + 255
	cv::Mat sobelImage;
	sobel.convertTo(sobelImage, CV_8U, -255. / sobmax, 255);

	// Display the image
	cv::namedWindow("Sobel Image");
	cv::imshow("Sobel Image", sobelImage);

threshold()函数用法:https://blog.youkuaiyun.com/u012566751/article/details/77046445

对梯度幅值进行阈值化,可得到一个二值边缘分布图。

// Apply threshold to Sobel norm (low threshold value)
	cv::Mat sobelThresholded;
	cv::threshold(sobelImage, sobelThresholded, 225, 255, cv::THRESH_BINARY);

	// Display the image
	cv::namedWindow("Binary Sobel Image (low)");
	cv::imshow("Binary Sobel Image (low)", sobelThresholded);

	// Apply threshold to Sobel norm (high threshold value)
	cv::threshold(sobelImage, sobelThresholded, 190, 255, cv::THRESH_BINARY);

	// Display the image
	cv::namedWindow("Binary Sobel Image (high)");
	cv::imshow("Binary Sobel Image (high)", sobelThresholded);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值