12- OpenCV:算子(Sobel和Laplance) 和Canny边缘检测 详解

本文详细介绍了Sobel算子、Laplacian算子以及Canny边缘检测算法,涉及卷积应用、边缘定义、算子原理、OpenCV提供的相关API及其在图像处理流程中的应用实例。
摘要由CSDN通过智能技术生成

目录

一、Sobel算子

1、卷积应用-图像边缘提取

2、Sobel算子(索贝尔算子)

3、相关的API(代码例子)

二、Laplance算子

1、理论

2、API使用(代码例子)

三、Canny边缘检测

1、Canny算法介绍

2、API使用(代码例子)


一、Sobel算子

1、卷积应用-图像边缘提取

         在这个红点变化最大,变化率很高的,梯度也是最陡。变化率做成一根曲线,所以变化率最大的就在顶点。

(1)边缘是什么 :是像素值发生跃迁的地方,是图像的显著特征之一,在图像特征提取、对象检测、模式识别等方面都有重要的作用。

(2)如何捕捉/提取边缘 – 对图像求它的一阶导数       

                delta =  f(x) – f(x-1), delta越大,说明像素在X方向变化越大,边缘信号越强,

(3)用Sobel算子就好!卷积操作!

2、Sobel算子(索贝尔算子)

(1)是离散微分算子(discrete differentiation operator),用来计算图像灰度的近似梯度;

(2)Soble算子功能集合高斯平滑和微分求导;

(3)又被称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到图像X方法与Y方向梯度图像;

(4)求取导数的近似值,kernel=3时不是很准确,OpenCV使用改进版本Scharr函数,算子如下:放大了权重,差异性更加大了,不过也更加准确些。

3、相关的API(代码例子)

(1)cv_Sobel函数原型

cv::Sobel (

InputArray Src // 输入图像

OutputArray dst// 输出图像,大小与输入图像一致

int depth // 输出图像深度.

int dx.  // X方向,几阶导数

int dy // Y方向,几阶导数.

int ksize, SOBEL算子kernel大小,必须是奇数,1、3、5、7,一般是3

double scale  = 1

double delta = 0

int borderType = BORDER_DEFAULT

)

(2)cv::Scharr

cv::Scharr (

InputArray Src // 输入图像

OutputArray dst// 输出图像,大小与输入图像一致

int depth // 输出图像深度.

int dx.  // X方向,几阶导数

int dy // Y方向,几阶导数.

double scale  = 1

double delta = 0

int borderType = BORDER_DEFAULT

)

(3)其他的API

— GaussianBlur( src, dst, Size(3,3), 0, 0, BORDER_DEFAULT );

— cvtColor( src,  gray, COLOR_RGB2GRAY );

— addWeighted( A, 0.5,B, 0.5, 0, AB); convertScaleAbs(A, B)// 计算图像A的像素绝对值,输出到图像B

(4)代码演示

图像处理流程:

-高斯平滑(高斯模糊)GaussianBlur( )

-转灰度

-求梯度X和Y:做Sobel索贝尔计算

-得到振幅图像

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>

using namespace cv;
int main(int argc, char** argv) {
	Mat src, dst;
	src = imread("test.jpg");
	if (!src.data) {
		printf("could not load image...\n");
		return -1;
	}

	char INPUT_TITLE[] = "input image";
	char OUTPUT_TITLE[] = "sobel-demo";
	namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
	namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
	imshow(INPUT_TITLE, src);

	Mat gray_src;
	GaussianBlur(src, dst, Size(3, 3), 0, 0);
	cvtColor(dst, gray_src, CV_BGR2GRAY);
	imshow("gray image", gray_src);

	Mat xgrad, ygrad;
	Scharr(gray_src, xgrad, CV_16S, 1, 0);
	Scharr(gray_src, ygrad, CV_16S, 0, 1);

	// Sobel(gray_src, xgrad, CV_16S, 1, 0, 3);
	// Sobel(gray_src, ygrad, CV_16S, 0, 1, 3);

    // 转为绝对值
	convertScaleAbs(xgrad, xgrad);
	convertScaleAbs(ygrad, ygrad);
	imshow("xgrad", xgrad);
	imshow("ygrad", ygrad);

	Mat xygrad = Mat(xgrad.size(), xgrad.type());
	printf("type : %d\n", xgrad.type());
	int width = xgrad.cols;
	int height = ygrad.rows;
	for (int row = 0; row < height; row++) {
		for (int col = 0; col < width; col++) {
			int xg = xgrad.at<uchar>(row, col);
			int yg = ygrad.at<uchar>(row, col);
			int xy = xg + yg;
			xygrad.at<uchar>(row, col) = saturate_cast<uchar>(xy);
		}
	}
	//addWeighted(xgrad, 0.5, ygrad, 0.5, 0, xygrad);
	imshow(OUTPUT_TITLE, xygrad);

	waitKey(0);
	return 0;
}

效果展示:

二、Laplance算子

1、理论

解释:在二阶导数的时候,最大变化处的值为零即边缘是零值。通过二阶 导数计算,依据此理论我们可以计算图像二阶导数,提取边缘。

实际上就是:拉普拉斯算子操作(Laplance operator)-> cv::Laplance

2、API使用(代码例子)

(1)cv::Laplacian原型:

Laplacian(

InputArray src,

OutputArray dst,

int depth, //深度CV_16S

int kisze, // 3

double scale = 1,

double delta =0.0,

int borderType = 4

)

(2)代码演示

图像处理流程:

- 高斯模糊 – 去噪声GaussianBlur()

- 转换为灰度图像cvtColor()

- 拉普拉斯 – 二阶导数计算Laplacian()

-取绝对值convertScaleAbs()

-显示结果

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>

using namespace cv;
int main(int argc, char** argv) {
	Mat src, dst;
	src = imread("test.jpg");
	if (!src.data) {
		printf("could not load image");
	}
	char input_title[] = "input image";
	char output_title[] = "Laplaiance Result";
	namedWindow(input_title, CV_WINDOW_AUTOSIZE);
	imshow(input_title, src);

	Mat gray_src, edge_image;
	GaussianBlur(src, dst, Size(3, 3), 0, 0);
	cvtColor(dst, gray_src, CV_BGR2GRAY);

	Laplacian(gray_src, edge_image, CV_16S, 3);
	convertScaleAbs(edge_image, edge_image);

    // 边缘处理
	threshold(edge_image, edge_image, 0, 255, THRESH_OTSU | THRESH_BINARY);
	namedWindow(output_title, CV_WINDOW_AUTOSIZE);
	imshow(output_title, edge_image);

	waitKey(0);
	return 0;
}

效果展示:

三、Canny边缘检测

1、Canny算法介绍

(1)简介:Canny算法是一种经典的边缘检测算法,常用于计算机视觉和图像处理领域。

它由John F. Canny在1986年提出,并被广泛应用于图像分割、目标检测等任务中。

(3)图像处理流程:

图像处理流程:

- 高斯模糊 - GaussianBlur,对图像进行降噪,避免影响最终的结果

- 灰度转换 - cvtColor,必须是8位的灰度图像

- 计算梯度 – Sobel/Scharr

- 非最大信号抑制

- 高低阈值

- 输出二值图像

(3)非最大信号抑制:图表边缘的信号很强,边缘信号只有一个,要对非边缘信号进行抑制。要对法线或者切线方向的值去掉。

        对梯度幅值图像进行非极大值抑制。这一步骤的目的是将边缘细化为单像素宽度,并抑制非最大值区域。具体来说,对于每个像素,只有在其梯度方向上具有最大幅值的像素才被保留。

(4)高低阈值输出二值图像:

        根据两个阈值(高阈值和低阈值)对非极大值抑制后的图像进行阈值处理。高阈值用于确定强边缘,而低阈值用于确定弱边缘。具体来说,如果某个像素的梯度幅值大于高阈值,则将其标记为强边缘;如果某个像素的梯度幅值介于低阈值和高阈值之间,则将其标记为弱边缘;如果某个像素的梯度幅值小于低阈值,则将其丢弃。

一个为高阈值,一个为低阈值(T1和T2);

— T1, T2为阈值,凡是高于T2的都保留(是很强的边缘像素 ),凡是小于T1都丢弃,从高于T2的像素出发,凡是大于T1而且相互连接的,都保留。最终得到一个输出二值图像。

— 推荐的高低阈值比值为 T2: T1 = 3:1/2:1,其中T2为高阈值,T1为低阈值。

(5)边缘连接

        通过连接强边缘和与之相连的弱边缘来形成完整的边缘。具体来说,如果某个弱边缘与某个强边缘在空间上相邻接,则将其标记为强边缘。

2、API使用(代码例子)

(1)cv::Canny原型

Canny(

InputArray src, // 8-bit的输入图像

OutputArray edges,// 输出边缘图像, 一般都是二值图像,背景是黑色

double threshold1,// 低阈值,常取高阈值的1/2或者1/3

double threshold2,// 高阈值

int aptertureSize,// Soble算子的size,通常3x3,取值3

bool L2gradient // 选择 true表示是L2来归一化,否则用L1归一化

(2)代码演示

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>

using namespace cv;
Mat src, gray_src, dst;
int t1_value = 50;
int max_value = 255;
const char* OUTPUT_TITLE = "Canny Result";
void Canny_Demo(int, void*);
int main(int argc, char** argv) {
	src = imread("test,jpg");
	if (!src.data) {
		printf("could not load image...\n");
		return -1;
	}

	char INPUT_TITLE[] = "input image";
	namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
	namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
	imshow(INPUT_TITLE, src);

	cvtColor(src, gray_src, CV_BGR2GRAY);
	createTrackbar("Threshold Value:", OUTPUT_TITLE, &t1_value, max_value, Canny_Demo);
	Canny_Demo(0, 0);

	waitKey(0);
	return 0;
}

void Canny_Demo(int, void*) {
	Mat edge_output;
	blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);
	Canny(gray_src, edge_output, t1_value, t1_value * 2, 3, false);

	//dst.create(src.size(), src.type());

    // 使用遮罩层,只有非零的元素才会被copy到模板中
	//src.copyTo(dst, edge_output);

    // ~取反输出
	imshow(OUTPUT_TITLE, ~edge_output);
}

效果展示:

  • 19
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenCV是一款强大的计算机视觉库,提供了丰富的图像处理和计算机视觉算法,其中包括边缘检测算法。本文将介绍OpenCV中的SobelCanny算子边缘检测Sobel算子边缘检测 Sobel算子是一种基于图像灰度值的一阶微分算子,可以检测图像中的边缘。Sobel算子可以分别计算图像在x和y方向上的梯度值,然后将两个方向的梯度值进行加权求和,得到边缘梯度的大小和方向。 在OpenCV中,可以使用Sobel函数进行Sobel算子边缘检测。以下是一个示例代码: ``` import cv2 img = cv2.imread('image.jpg', 0) # 读取灰度图像 sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3) # 在x方向上计算Sobel梯度 sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3) # 在y方向上计算Sobel梯度 sobel = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0) # 将x和y方向上的梯度值加权求和 cv2.imshow('Sobel', sobel) # 显示边缘检测结果 cv2.waitKey(0) cv2.destroyAllWindows() ``` 在上面的代码中,使用cv2.Sobel函数分别计算了x和y方向上的梯度值,并使用cv2.addWeighted函数将两个方向的梯度值进行加权求和。最后,使用cv2.imshow函数显示边缘检测结果。 Canny算子边缘检测 Canny算子是一种多阶段的边缘检测算法,可以检测出较细的边缘,并且对噪声有很好的抑制能力。Canny算子首先使用高斯滤波器对图像进行平滑处理,然后计算图像的梯度值和方向,接着使用非极大值抑制算法和双阈值处理算法进行边缘检测。 在OpenCV中,可以使用Canny函数进行Canny算子边缘检测。以下是一个示例代码: ``` import cv2 img = cv2.imread('image.jpg', 0) # 读取灰度图像 edges = cv2.Canny(img, 100, 200) # 使用Canny算子进行边缘检测 cv2.imshow('Canny', edges) # 显示边缘检测结果 cv2.waitKey(0) cv2.destroyAllWindows() ``` 在上面的代码中,使用cv2.Canny函数对图像进行Canny算子边缘检测,并将结果保存在edges变量中。最后,使用cv2.imshow函数显示边缘检测结果。 总结 本文介绍了OpenCV中的SobelCanny算子边缘检测方法,Sobel算子适用于简单的边缘检测Canny算子适用于更复杂的边缘检测。在实际应用中,可以根据不同的需求选择合适的算法进行边缘检测

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值