【OpenCV(C++)】图像变换:边缘检测

【OpenCV(C++)】图像变换:边缘检测

边缘检测的步骤

  • 滤波
    边缘检测的算法主要是基于图像强度的一阶和二阶导数,但导数通常对噪声很敏感,因此必须采用滤波器来改善与噪声有关的边缘检测器的性能。
  • 增强
    增强边缘的基础是确定图像各点邻域的变化值。增强算法可以将图像灰度点邻域强度值有显著变化的点凸显出来。
  • 检测
    经过增强的图像,往往邻域中有很多点的梯度值比较大,而在特定的应用中,这些点并不是要找的边缘点,所以应该采用某种方法来对这些点进行取舍。

Canny算子

canny边缘检测算子是一个多级边缘检测算法。
最优边缘检测的评价标准:低错误率高定位性最小响应。为了满足这些要求,Canny使用了变分法,这是一种寻找满足特定功能的函数的方法。最优检测用4个指数函数项的和表示,但是它非常近似于高斯函数的一阶导数。

Canny函数利用Canny算子来进行图像的边缘检测操作。

void Canny(
InputArray image, 
OutputArray edges, 
double threshold1, 
double threshold2, 
int apertureSize=3, 
bool L2gradient=false) ;

在这里插入图片描述

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

int main()
{
	Mat srcImage = imread("fg.jpg");
	imshow("[原图]Canny边缘检测", srcImage);

	Mat dstImage, edge, grayImage;
	dstImage.create(srcImage.size(), srcImage.type());
	cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
	blur(grayImage, edge, Size(3, 3));
	Canny(edge, edge, 3, 9, 3);
	imshow("[效果图]Canny边缘检测", edge);
	waitKey(0);

	return 0;
}

运行效果如下:
在这里插入图片描述

Sobel算子

Sobel算子是一个主要用于边缘检测的离散微分算子。它结合了高斯平滑和微分求导,用来计算图像灰度函数的近似梯度。在图像的任何一点使用此算子,都将会产生对应的梯度矢量或是其法矢量。

Sobel函数使用扩展的Sobel算子,来计算一阶、二阶、三阶或混合图像差分。

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) ;

在这里插入图片描述

#include <opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>

using namespace cv;

int main()
{
	Mat grad_x, grad_y;
	Mat abs_grad_x, abs_grad_y, dst;

	Mat src = imread("fg.jpg");

	imshow("【原始图】sobel边缘检测", src);

	Sobel(src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
	convertScaleAbs(grad_x, abs_grad_x);
	imshow("【效果图】 X方向Sobel", abs_grad_x);

	Sobel(src, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);
	convertScaleAbs(grad_y, abs_grad_y);
	imshow("【效果图】Y方向Sobel", abs_grad_y);

	addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
	imshow("【效果图】整体方向Sobel", dst);

	waitKey(0);
	return 0;
}

运行效果如下:
在这里插入图片描述

Laplacian算子

Laplacian算子是n维欧几里得空间中的一个二阶微分算子,定义为梯度grad的散度div。根据图像处理的原理可知,二阶导数可以用来进行边缘检测,因为图像是二维的,需要在两个方向进行求导。使用Laplacian算子将会使求导过程变得简单。
Laplacian算子的定义:
在这里插入图片描述
Laplacian函数可以计算出图像经过拉普拉斯变换后的结果。

void Laplacian(
InputArray src,
OutputArray dst ,
int ddepth,
int ksize=1,
double scale=1,
double delta=0 ,
intborderType=BORDER_DEFAULT) ;

在这里插入图片描述

#include <opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;

int main()
{
	Mat src, src_gray, dst, abs_dst;
 
	src = imread("fg.jpg");
 
	imshow("【原始图】图像Laplace变换", src);

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

	cvtColor(src, src_gray, CV_RGB2GRAY);

	Laplacian(src_gray, dst, CV_16S, 3, 1, 0, BORDER_DEFAULT);

	convertScaleAbs(dst, abs_dst);

	imshow("【效果图】图像Laplace变换", abs_dst);

	waitKey(0);

	return 0;
}

运行效果如下:
在这里插入图片描述

scharr滤波器

我们一般直接称scharr为滤波器,而不是算子。它在OpenCV中主要是配合Sobel算子的运算而存在的。
使用Scharr滤波器运算符计算x或y方向的图像差分,其参数变量和Sobel基本上是一样的,除了没有ksize核的大小。

void Scharr(
InputArray src,
OutputArray dst,
int ddepth,
int dx,
int dy,
double scale=1 ,
double delta=0 ,
intborderType=BORDER_DEFAULT) ;
#include <opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;



int main()
{

	Mat grad_x, grad_y;
	Mat abs_grad_x, abs_grad_y, dst;

	Mat src = imread("fg.jpg");

	imshow("【原始图】Scharr滤波器", src);

	Scharr(src, grad_x, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT);
	convertScaleAbs(grad_x, abs_grad_x);
	imshow("【效果图】 X方向Scharr", abs_grad_x);

	Scharr(src, grad_y, CV_16S, 0, 1, 1, 0, BORDER_DEFAULT);
	convertScaleAbs(grad_y, abs_grad_y);
	imshow("【效果图】Y方向Scharr", abs_grad_y);

	addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);

	imshow("【效果图】合并梯度后Scharr", dst);

	waitKey(0);
	return 0;
}

运行效果如下:
在这里插入图片描述

发布了31 篇原创文章 · 获赞 23 · 访问量 5410

猜你喜欢

转载自blog.csdn.net/weixin_43645790/article/details/104089225
今日推荐