[传统图像处理]边缘检测之----Sobel算子

一、作用:

sobel算子是图像边缘检测的最重要的算子之一。

Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。

二、原理:

Sobel算子输入的图像是灰度图,所以正常图片进行sobel算子提取边缘前,先要把图片转成灰度图。

边缘是指在图像上像素灰度变化最显著的地 方,边缘检测算子则利用图像边缘灰度的突变来检 测边缘。Sobel算子包含两组3×3的滤波器,分别对水平垂直方向上的边缘敏感。

水平方向和垂直方向的Sobel算子分别如下:

具体与图像的运算如下:

然后分别用这两个算子对输入图像进行卷积操作,得到x,y方向上各点的卷积结果,即垂直梯度Gx和水平梯度Gy。

然后作一个平方和运算:

或者:

如果某点梯度 G 大于某一阈值,则认为该点(x,y)为边缘点。

代码:

python:

# coding=utf-8
import cv2

img = cv2.imread("D:/fangzi.jpg", 0)
cv2.imshow('origin',img)
#Sobel函数求完导数后会有负值,还有会大于255的值。而原图像是uint8,即8位无符号数,
#所以Sobel建立的图像位数不够,会有截断。因此要使用16位有符号的数据类型,即cv2.CV_16S。
x = cv2.Sobel(img, cv2.CV_16S, 1, 0)#垂直方向梯度
y = cv2.Sobel(img, cv2.CV_16S, 0, 1)#水平方向梯度

absX = cv2.convertScaleAbs(x) #转回原来的uint8格式,否则图像无法显示。
absY = cv2.convertScaleAbs(y) #转回原来的uint8格式,否则图像无法显示。
#两个方向的梯度加起来形成最终的梯度
dst = cv2.addWeighted(absX, 1, absY, 1, 0)

cv2.imshow("absX", absX)
cv2.imshow("absY", absY)
cv2.imshow("Result", dst)
cv2.waitKey(0)

效果:

输入:

垂直方向:

水平方向:

最终结果:

这张图可以太简单了,我们来看看复杂的:

垂直方向:

水平方向:

最终结果:

c++:

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
	Mat m_img = imread("D:\\fangzi.jpg");
	Mat src(m_img.rows, m_img.cols, CV_8UC1, Scalar(0));
	cvtColor(m_img, src, CV_RGB2GRAY); //转成灰度图

	Mat dstImage(src.rows, src.cols, CV_8UC1, Scalar(0));
	for (int i = 1; i < src.rows - 1; i++)
	{
		for (int j = 1; j < src.cols - 1; j++)
		{
			dstImage.data[i*dstImage.step + j] = sqrt((src.data[(i - 1)*src.step + j + 1] //step 为图象像素行的实际宽度
				+ 2 * src.data[i*src.step + j + 1]
				+ src.data[(i + 1)*src.step + j + 1]
				- src.data[(i - 1)*src.step + j - 1] - 2 * src.data[i*src.step + j - 1]
				- src.data[(i + 1)*src.step + j - 1])*(src.data[(i - 1)*src.step + j + 1]
					+ 2 * src.data[i*src.step + j + 1] + src.data[(i + 1)*src.step + j + 1]
					- src.data[(i - 1)*src.step + j - 1] - 2 * src.data[i*src.step + j - 1]
					- src.data[(i + 1)*src.step + j - 1]) + (src.data[(i - 1)*src.step + j - 1] + 2 * src.data[(i - 1)*src.step + j]
						+ src.data[(i - 1)*src.step + j + 1] - src.data[(i + 1)*src.step + j - 1]
						- 2 * src.data[(i + 1)*src.step + j]
						- src.data[(i + 1)*src.step + j + 1])* (src.data[(i - 1)*src.step + j - 1] + 2 * src.data[(i - 1)*src.step + j]
							+ src.data[(i - 1)*src.step + j + 1] - src.data[(i + 1)*src.step + j - 1]
							- 2 * src.data[(i + 1)*src.step + j]
							- src.data[(i + 1)*src.step + j + 1]));

		}

	}
	Mat grad_y(src.rows, src.cols, CV_8UC1, Scalar(0));
	{
		for (int i = 1; i < src.rows - 1; i++)
		{
			for (int j = 1; j < src.cols - 1; j++)
			{
				grad_y.data[i*grad_y.step + j] = abs((src.data[(i - 1)*src.step + j + 1]
					+ 2 * src.data[i*src.step + j + 1]
					+ src.data[(i + 1)*src.step + j + 1]
					- src.data[(i - 1)*src.step + j - 1] - 2 * src.data[i*src.step + j - 1]
					- src.data[(i + 1)*src.step + j - 1]));
			}
		}
	}
	Mat grad_x(src.rows, src.cols, CV_8UC1, Scalar(0));
	{
		for (int i = 1; i < src.rows - 1; i++)
		{
			for (int j = 1; j < src.cols - 1; j++)
			{
				grad_x.data[i*grad_x.step + j] = sqrt((src.data[(i - 1)*src.step + j - 1] + 2 * src.data[(i - 1)*src.step + j]
					+ src.data[(i - 1)*src.step + j + 1] - src.data[(i + 1)*src.step + j - 1]
					- 2 * src.data[(i + 1)*src.step + j]
					- src.data[(i + 1)*src.step + j + 1])* (src.data[(i - 1)*src.step + j - 1] + 2 * src.data[(i - 1)*src.step + j]
						+ src.data[(i - 1)*src.step + j + 1] - src.data[(i + 1)*src.step + j - 1]
						- 2 * src.data[(i + 1)*src.step + j]
						- src.data[(i + 1)*src.step + j + 1]));
			}
		}
	}
	imshow("origin", src);
	imshow("gradient", dstImage);
	imshow("Vertical gradient", grad_y);
	imshow("Horizontal gradient", grad_x);

	waitKey(0);
	return 0;
}

效果:

输入:

水平梯度:

垂直梯度:

最终结果:

优缺点:

优点:计算简单,速度很快;

缺点:计算方向单一,对复杂纹理的情况显得乏力;

  直接用阈值来判断边缘点欠合理解释,会造成较多的噪声点误判。

  • 10
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值